django模型表单。包含关联模型的字段

33 投票
4 回答
29522 浏览
提问于 2025-04-15 14:38

我有一个模型,叫做学生(Student),里面有一些字段,并且和用户(django.contrib.auth.User)有一对一的关系。

class Student(models.Model):

    phone = models.CharField(max_length = 25 )
    birthdate = models.DateField(null=True) 
    gender = models.CharField(max_length=1,choices = GENDER_CHOICES) 
    city = models.CharField(max_length = 50)
    personalInfo = models.TextField()
    user = models.OneToOneField(User,unique=True)

然后,我为这个模型创建了一个ModelForm。

class StudentForm (forms.ModelForm):
    class Meta:
        model = Student

通过在Meta类里使用fields属性,我成功地只在模板中显示了一些字段。但是,我能指定显示哪些用户字段吗?

像这样:

   fields =('personalInfo','user.username')

现在什么都没有显示。不过只用学生字段是可以的。

提前谢谢你。

4 个回答

4

你可以考虑一种替代的方法,就是通过扩展AbstractUser或AbstractBaseUser模型来创建一个自定义用户模型,而不是使用与Profile模型(在这个例子中是学生模型)的一对一关联。这样,你就能创建一个单一的扩展用户模型,方便你使用一个ModelForm。

比如,你可以通过扩展AbstractUser模型来实现:

from django.contrib.auth.models import AbstractUser

class Student(AbstractUser):

    phone = models.CharField(max_length = 25 )
    birthdate = models.DateField(null=True) 
    gender = models.CharField(max_length=1,choices = GENDER_CHOICES) 
    city = models.CharField(max_length = 50)
    personalInfo = models.TextField()
    # user = models.OneToOneField(User,unique=True)   <= no longer required

在settings.py文件中,更新AUTH_USER_MODEL。

AUTH_USER_MODEL = 'appname.models.Student'

在你的管理界面中更新模型:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Student

admin.site.register(Student, UserAdmin)

这样,你就可以使用一个包含你所需的额外字段和原始用户模型字段的单一ModelForm。在forms.py中:

from .models import Student    

class StudentForm (forms.ModelForm):
    class Meta:
        model = Student
        fields = ['personalInfo', 'username']

还有一种更复杂的方法是扩展AbstractBaseUser,详细信息可以在文档中找到

不过,我不太确定以这种方式创建自定义用户模型是否真的适合你的情况,因为为了方便使用单一ModelForm而创建自定义用户模型可能会有些复杂。这是一个设计上的决定,你需要自己考虑,因为创建自定义用户模型可能会比较棘手。

8

这两个答案都是对的:使用内联表单集可以让这个过程变得简单。

不过要注意,内联表单集只能单向使用,也就是说只能从包含外键的模型出发。如果两个模型之间没有主键的连接(这样不好,因为可能会出现A指向B,然后B又指向A2的情况),你就不能在相关的模型中使用内联表单集。

举个例子,如果你有一个用户资料(UserProfile)类,想要在显示时把相关的用户对象以内联的方式展示出来,那你就没办法实现了。

你可以在模型表单(ModelForm)上添加自定义字段,这样会更灵活,但要知道,这样就不再像标准的模型表单或内联表单集那样“自动”了。

31

一个常见的做法是使用两个表单来实现你的目标。

  • 一个表单用于 User 模型:

    class UserForm(forms.ModelForm):
        ... Do stuff if necessary ...
        class Meta:
            model = User
            fields = ('the_fields', 'you_want')
    
  • 另一个表单用于 Student 模型:

    class StudentForm (forms.ModelForm):
        ... Do other stuff if necessary ...
        class Meta:
            model = Student
            fields = ('the_fields', 'you_want')
    
  • 在你的视图中使用这两个表单(使用示例):

    def register(request):
        if request.method == 'POST':
            user_form = UserForm(request.POST)
            student_form = StudentForm(request.POST)
            if user_form.is_valid() and student_form.is_valid():
                user_form.save()
                student_form.save()
    
  • 在你的模板中一起渲染这两个表单:

    <form action="." method="post">
        {% csrf_token %}
        {{ user_form.as_p }}
        {{ student_form.as_p }}
        <input type="submit" value="Submit">
    </form>
    

另一种选择是把关系从 OneToOne 改为 ForeignKey(这完全取决于你,我只是提一下,并不是推荐)并使用 inline_formsets 来达到你想要的效果。

撰写回答