【问题标题】:Combine two models with OneToOne relationship into one form - Django将两个具有 OneToOne 关系的模型组合成一种形式 - Django
【发布时间】:2015-09-28 04:24:03
【问题描述】:

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

例如,最好有这样的东西(虽然我知道不可能):

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

提前感谢您的帮助!型号如下:

我的用户:

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)

【问题讨论】:

标签: django django-models django-forms django-views


【解决方案1】:

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

型号:

#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

表格

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 工厂来处理 Student 模型作为内联表单。

表单集

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 以验证相关表单。如果一切顺利,我的两个表格都将被保存,否则错误将显示在模板中。

查看

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)

另请注意,我在单个发布请求中同时传递了表单和表单集。

模板(createStudentPage.html)

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

【讨论】:

    【解决方案2】:

    我认为你可以这样做:

    class ProfileChangeForm(forms.ModelForm):
        class Meta:
            model = UserProfile
            fields = ['user__username', 'user__email', 'user__first_name', 'user__last_name', 'bio', 'website']
    

    【讨论】:

      猜你喜欢
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多