Two forms in a single view Django - CreateView

2

I am trying to create a single form for a user that has fields of both forms, both the user and the userprofile that you create to extend the model.

models.py

from django.db import models
from django.forms import ModelForm
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    date_of_birthday = models.DateField()
    address = models.TextField()
    phone_number = models.CharField(max_length=11)

    def __str__(self):
        return self.user.first_name

class UserProfileForm(ModelForm):
    class Meta:
        model = UserProfile
        fields = '__all__'

class UserForm(ModelForm):
    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'password']

views.py

from django.shortcuts import render

from django.views.generic import CreateView

from .models import UserProfile, UserProfileForm, UserForm

class UserProfileCreateView(CreateView):
    model = UserProfile
    template_name = 'userprofiles/user_create.html'
    success_url = '/'
    form_class = UserProfileForm

    def form_valid(self, form):
        form.save()
        return super(UserCreate, self).form_valid(form)

class UserCreateView(CreateView):
    model = UserProfile
    template_name = 'userprofiles/user_create.html'
    success_url = '/'
    form_class = UserForm

    def form_valid(self, form):
        form.save()
        return super(UserCreate, self).form_valid(form)

view, here using form shows me in both the same form that is the model of User that Django brings.

<form action="{% url 'users:user_create' %}" method="post">
    {% csrf_token %}
    {{ form.as_p }} 
    {{ form.as_p }}
    <button type="submit">Crear Usuario</button>
</form>

I know that maybe it can be done with formset or with prefix of the view based on class, but I think the prefix is not necessarily for that and I do not have it completely clear.

Greetings!

    
asked by ikenshu 02.09.2016 в 16:30
source

2 answers

2

Remember that in Django, we call form to the forms by custom , but just as there can not be two ikenshu users in the same site, there can not be two forms called form in one view.

Nothing prevents you from calling the first form unicornio and the second dragon .

Now, forms are objects, instances of a class Form , so you can add them to the context of a view.

You could try this StackOverflow answer: link

And when you use it, you would do something like this:

from django.shortcuts import render
from django.views.generic import CreateView
from .models import UserProfile, UserProfileForm, UserForm


class UserProfileCreateView(MultiFormsView):
    template_name = 'userprofiles/user_create.html'
    success_url = '/'
    form_class = {
        'dragon': UserProfileForm,
        'unicornio': UserForm
    }
  

Important Note :
  This example does not consider the way in which the forms are validated.

  

Note 2 :   Consider using a model instead of two, extending the User model with the fields you use in the Profile model.

    
answered by 03.09.2016 в 03:21
1

Good, to work with the profile class, you should think about an update view and not create the profile. To create the profile, you must simply generate a new instance when the user's signal post_save is executed, it could be something like this:

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

As for the update view, I will generate it from View, since the solution to this type of problems is better visualized:

class ProfileView(View):
    def get(self, request):
        user_form = UserForm(instance=request.user)
        profile_form = UserProfileForm(instance=request.user.profile)
        return render(request, 'profiles/profile.html', {
            'user_form': user_form,
            'profile_form': profile_form
        })

    def post(self, request):
        user_form = UserForm(request.POST, instance=request.user)
        profile_form = UserProfileForm(request.POST, instance=request.user.profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, _('Your profile was successfully updated!'))
            return redirect('settings:profile')

        messages.error(request, _('Please correct the error below.'))

I hope you have helped, in the following link I leave you more information on how to extend Django users .

Greetings.

    
answered by 04.09.2016 в 13:39