Search code examples
djangodjango-authenticationdjango-1.10

Django 1.10 - Different templates for each OneToOne model


Basically, I'm trying to get the current user type, by using the OneToOne models you can see below and display different template "parts" specific for each model. I researched a bit and found out about type() and hasattr(). I was wondering if there's any way I can use them in templates or do you have any better suggestions? Thanks!

models.py

class Type1(models.Model):
user            = models.OneToOneField(User)
company_name    = models.CharField(max_length=100)

    def __unicode__(self):
        return self.company_name

class Type2(models.Model):
user            = models.OneToOneField(User)
first_name      = models.CharField(max_length=30)
second_name     = models.CharField(max_length=30)

    def __unicode__(self):
        return self.first_name

views.py

def Type1Registration(request):
if request.user.is_authenticated():
    return HttpResponseRedirect('/')
if request.method == 'POST':
    form = Type1Form(request.POST)
    if form.is_valid():
        user = User.objects.create_user(username=form.cleaned_data['username'], 
            email=form.cleaned_data['email'], password=form.cleaned_data['password'])
        user.save()
        type1 = Type1(user=user, company_name=form.cleaned_data['company_name'])
        type1.save()
        return HttpResponseRedirect('/')
    else:
        return render(request, 'type1_register.html', {'form': form})
else:
    form = Type1Form()
    context = {'form': form}
    return render(request, 'type1_register.html', context)

def Type2Registration(request):
if request.user.is_authenticated():
    return HttpResponseRedirect('/')
if request.method == 'POST':
    form = Type2Form(request.POST)
    if form.is_valid():
        user = User.objects.create_user(username=form.cleaned_data['username'], 
            email=form.cleaned_data['email'], password=form.cleaned_data['password'])
        user.save()
        type2 = Type2(user=user, first_name=form.cleaned_data['first_name'],
            second_name=form.cleaned_data['second_name'])
        type2.save()
        return HttpResponseRedirect('/')
    else:
        return render(request, 'type2_register.html', {'form': form})
else:
    form = Type2Form()
    context = {'form': form}
    return render(request, 'type2_register.html', context)

Solution

  • This is though as you have two different models. The thing I would consider here is to make one model and do it like this:

    class UserComplete(AbstractUser):
        first_name      = models.CharField(max_length=30)
        second_name     = models.CharField(max_length=30)
        company_name    = models.CharField(max_length=100)
        company         = models.BooleanField(default=False)
    
        def get_name(self):
            "Returns the person's or business name."
            if self.company:
                return self.company_name
            else:
                return self.first_name
    

    One thing I should mention here is that I am not completely sure what you want to do with the models, so I am not sure if this is indeed the best solution for you. I also used AbstractUser which is something you might not be familiar with. Basically, it extends the User class, which is, in my opinion the best way to extend the User model. More information about that here: https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#specifying-custom-user-model

    Then you have two choices. For your forms, you could create two separate forms or one. This again, depends on what you want to do with the models and where you want to edit your stuff if something has to be changed.

    Here are the two forms, if you want to go that way:

    class UserCreateForm(UserCreationForm):    
        class Meta:
            model = UserComplete
            fields = ("email", "username", "password", "first_name", "second_name")
    
    class BusinessCreateForm(UserCreationForm):  
        class Meta:
            model = UserComplete
            fields = ("email", "username", "password", "company_name")
    

    Or with just one:

    class CreateForm(UserCreationForm):    
        company_name = forms.CharField(required=False)  
        first_name = forms.CharField(required=False)  
        second_name = forms.CharField(required=False)
    
        class Meta:
            model = UserComplete
            fields = ("email", "username", "password", "company_name", "first_name", "second_name", "company")
    

    You will have to render the form manually in your template and don't display the ones you don't want. Read here if you need more info about that: https://docs.djangoproject.com/en/1.10/topics/forms/#rendering-fields-manually. With the first form option, you will have to process each form separately, like you did in your views.py. With the second option you can render one form and use the boolean from company to determine which fields need to be processed.

    Yet again, I want to say that this fully depends on what you are building. With the second option you can do something like {% if request.user.company %} in your templates. Your original code doesn't have that option. Although, there is a workaround for that. You can do: {% if request.user.type1.company_name %} it will check if the value exists. In my opinion this is a bit dirty, but it will work, though. Note: if the value is empty (a business without name) it will return false.

    Let me know if you need an example of the views.py for the second form. Hope this helps. Have fun! :)

    P.S. I would replace this:

    if request.user.is_authenticated():
        return HttpResponseRedirect('/')
    

    With login_required. Read more about that here: https://docs.djangoproject.com/en/1.10/topics/auth/default/#django.contrib.auth.decorators.login_required