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

查看:17
本文介绍了将具有 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:

我的用户:

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)

用户资料:

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)

推荐答案

以下解决方案对我有用.我使用 formsets 来创建这个解决方案.我的模型如下,

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 工厂将学生模型作为内联表单处理.

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天全站免登陆