将具有OneToOne关系的两个模型合并为一种形式-Django [英] Combine two models with OneToOne relationship into one form - Django

查看:96
本文介绍了将具有OneToOne关系的两个模型合并为一种形式-Django的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了两个自定义用户模型(AbstractBaseUser和一个用于获取更多信息的单独模型)。有没有一种方法可以将两个模型结合起来以创建一个表单,用户可以使用该表单来更新两个模型之间的所有信息?

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 to update all of their information between the two models?

例如,拥有这样的东西(尽管我知道不可能)的理想选择:

For example, it would be ideal to have something like this (although I know not possible):

class ProfileChangeForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['username', 'email', first_name', 'last_name', 'bio', 'website']

在此先感谢您的帮助!这些模型如下:

Thank you in advance for your help! The models are below:

MyUser:

MyUser:

class MyUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=30, unique=True)
    email = models.EmailField(max_length=255, unique=True)
    first_name = models.CharField(max_length=120, null=True, blank=True)
    last_name = models.CharField(max_length=120, null=True, blank=True)

UserProfile:

UserProfile:

class UserProfile(models.Model):
    user = models.OneToOneField(MyUser)
    bio = models.TextField(null=True, blank=True)
    website = models.CharField(max_length=120, null=True, blank=True)


推荐答案

以下解决方案对我有用。我使用表单集来创建此解决方案。
我的模型如下,

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

#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)

此后,我创建了两个ModelForms

After that I created two ModelForms

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']

现在,主要部分中,我创建了一个简单的内联 formset 工厂将学生模型作为嵌入式f

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

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)

在视图中,我分别创建了SignUpForm和StudentCreationFormSet对象。在POST请求中,我首先验证了CustomUser表单并保存了它,而未提交它(commit = False)。我创建了一个自定义用户对象,并将其作为实例传递给StudentCreationFormSet以验证相关表单。如果一切顺利,我的两个表格都将被保存,否则错误将显示在模板中。

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.

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.

<form method="POST" >
    {% csrf_token %}
    {{ student_account_form.as_p }}
    {{ student_details_form.as_p }}
<button type="submit">Sign Up</button>
</form>

这篇关于将具有OneToOne关系的两个模型合并为一种形式-Django的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆