Home > OS >  Check if user doesn't have object before displaying CreateView - Prevent multiple creation
Check if user doesn't have object before displaying CreateView - Prevent multiple creation

Time:12-03

I've been slowly learning Django over the past few weeks, and applying it to a work prototype. I have a simple profile model called Applicant.

  • This stores personal fields for the a customer.
  • It contains a OnetoOne field linking to the Django Auth User model, as I'm using this to require login and control access to data.

I'm struggling to figure out how to perform checks within View classes (seemed easier within View Functions).

Therefore, I need a way to check if a user already has an Applicant entry before presenting them with the CreateView form.

Previously to display this Applicant profile data (created via admin page), I used the get_object_or_404 within the DetailView.get_object to catch Http404 and return None if they didn't have a profile.

This would then provide a link to the Create page. I need to implement the reversed logic on the CreateView, to protect them from creating multiple Applicant entries.

Any suggestions would be great, even just to point me in the right direction.

Code I used for DetailView:

class ApplicantProfileDetailView(LoginRequiredMixin, generic.DetailView):
    model = Applicant
    template_name ='profile.html'
    def get_object(self, queryset=None):
        try:
            return get_object_or_404(Applicant, user=self.request.user)
        except Http404:
            return None

<h1>Applicant Profile</h1>
{% if applicant %} 
...
{% else %}
    <p>You have not created an Applicant profile, click below to create one.</p>
    <a href="/profile/create" class="btn btn-primary"> Create Profile </a>
{% endif %}

Trying to implement the same to CreateView will just display the form no matter what:

class ApplicantProfileCreateView(LoginRequiredMixin, generic.CreateView):
    model = Applicant
    fields = [...]
    template_name = 'profile_create_form.html'
    success_url = '/'
    def get_object(self, queryset=None):
        try:
            return get_object_or_404(Applicant, user=self.request.user)
        except Http404:
            return None
{% if applicant %}
    <p>You already have an Applicant profile. If you'd like to edit it, please use the edit option on the profile page.</p>
    <a href="/profile/" class="btn btn-primary"> View Profile </a>
{% else %}
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Save">
    </form>
{% endif %}

CodePudding user response:

generic.CreateView does not define a get_object method, so your authorization check is never being run. You could put it in the get function though since presumably, the user would need to request the page before posting to it (unless this is an ajax view).

class ApplicantProfileCreateView(LoginRequiredMixin, generic.CreateView):
    model = Applicant
    fields = [...]
    template_name = 'profile_create_form.html'
    success_url = '/'

    def get(self, request, *args, **kwargs):
        if Application.objects.filter(user=self.request.user).exists():
            return redirect('/profile/') # ideally you'd use the url name here instead.
        return super().get(request, *args, **kwargs)
  • Related