Combine two models with OneToOne relationship into one form - Django

后端 未结 2 1352
你的背包
你的背包 2020-12-22 06:54

I created two custom user models (AbstractBaseUser and a separate for extra information). Is there a way to combine the two models to create one form that the user can use t

相关标签:
2条回答
  • 2020-12-22 07:17

    I think you can do something like :

    class ProfileChangeForm(forms.ModelForm):
        class Meta:
            model = UserProfile
            fields = ['user__username', 'user__email', 'user__first_name', 'user__last_name', 'bio', 'website']
    
    0 讨论(0)
  • 2020-12-22 07:24

    Following solution worked for me. I used formsets to create this solution. My models were as follows,

    Models:

    #Custom user model
    class CustomUserManager(BaseUserManager):
        def create_user(self, email, password, **extra_fields):
            if not email:
                raise ValueError(_('The Email must be set'))
            email = self.normalize_email(email)
            user = self.model(email=email, **extra_fields)
            user.set_password(password)
            user.save()
            return user
    
    class CustomUser(AbstractUser):
        username = None
        email = models.EmailField(_('email address'), unique=True)
    
        USERNAME_FIELD = 'email'
        REQUIRED_FIELDS = []
    
        objects = CustomUserManager()
    
    #Related model(One-to-One relationship with custom user)
    class Student(models.Model):
        user = models.OneToOneField(CustomUser,on_delete = models.CASCADE)
        first_name = models.CharField(max_length=50)
        middle_name = models.CharField(max_length=50,blank=True,null=True)
        last_name = models.CharField(max_length=50,blank=True,null=True)
    

    After that I created two ModelForms

    Forms

    from django.contrib.auth.forms import UserCreationForm
    from .models import CustomUser,Student
    from django import forms
    
    # Form for custom user
    class SignUpForm(UserCreationForm):
       class Meta:
          model = CustomUser
          fields = ('email', 'password1', 'password2')
    
    class StudentCreationForm(forms.ModelForm):
        class Meta:
            model = Student
            fields = ['user','first_name','middle_name','last_name']
    

    Now the main part, I created a simple inline formset factory to handle Student model as an inline form.

    Formset

    from django.forms import inlineformset_factory
    from .models import CustomUser,Student
    from .forms import StudentCreationForm
    
    # As parameters I provided parent Model(CustomUser),child Model(Student) and the Child 
    # ModelForm(StudentCreationForm) 
    
    StudentCreationFormSet = inlineformset_factory(CustomUser, Student,form=StudentCreationForm,extra=1,can_delete = False)
    

    In views, I created the SignUpForm and StudentCreationFormSet object respectively. And in the POST request first I validated the CustomUser form and saved it without comitting it(commit=False). I created an object of custom user and passed it as a instance to the StudentCreationFormSet to validate the related form. If everything goes fine my both forms will be saved else the errors will be shown in the template.

    View

    from django.shortcuts import render,redirect
    from .forms import SignUpForm
    from .formsets import StudentCreationFormSet 
    
    def createAccountView(request):
        student_account_form = SignUpForm()
        student_details_formset = StudentCreationFormSet()
    
        if request.method == 'POST':
            student_account_form = SignUpForm(request.POST)
    
            if student_account_form.is_valid():
                # Validating Custom User form and creating object of it(not comitting as  formset needed to be verified)
                student_account = student_account_form.save(commit=False)
                # Getting Custom User object as passing it as instance to formset
                student_details_formset = StudentCreationFormSet (request.POST,instance=student_account)
    
                if student_details_formset.is_valid():
                    student_account_form.save()
                    student_details_formset.save()
                    return redirect('login')    
                else:
                    student_details_formset = StudentCreationFormSet (request.POST)
    
        context = {
            'student_account_form':student_account_form,
            'student_details_form':student_details_formset
        }
        return render(request, 'account/createStudentPage.html',context=context)
    

    Also note that I am passing both the form and formset in single post request.

    Template (createStudentPage.html)

    <form method="POST" >
        {% csrf_token %}
        {{ student_account_form.as_p }}
        {{ student_details_form.as_p }}
    <button type="submit">Sign Up</button>
    </form>
    
    0 讨论(0)
提交回复
热议问题