【问题标题】:django model Form. Include fields from related modelsdjango模型表格。包括来自相关模型的字段
【发布时间】:2010-12-01 19:16:48
【问题描述】:

我有一个名为 Student 的模型,它有一些字段,以及与用户 (django.contrib.auth.User) 的 OneToOne 关系。

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

目前没有显示任何内容。仅适用于 StudentFields/

提前致谢。

【问题讨论】:

  • 我不确定这是不是你想要的,但你可以看看documentation for Inline Formsets
  • 如果学生模型继承了用户模型,您只需要一个模型表单。
  • @KevinL.,如果您在答案中详细说明这一点会很棒:-)
  • @cel AFAIK,在 Django 核心中没有这样的发展。此处的“自动”解决方案可能很重要,并且涉及编写您自己的自定义模型表单类或混入来执行此操作。这将比使用建议的方法复杂得多(并且可以说更脆弱)。 this answer 中可能包含一种可能的解决方案,它描述了一个 ModelForm mixin,它允许定义第二个“子”模型并声称与通用视图兼容。
  • 嘿,@Tom,我想知道,你觉得任何答案有帮助吗?

标签: python django django-forms


【解决方案1】:

一种常见的做法是使用 2 种形式来实现您的目标。

  • 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 来达到预期的结果。

【讨论】:

  • @cel 我不知道“自动”方式(如你所说),但我在这个答案中有一个手动解决方案。看看:)
【解决方案2】:

两个答案都是正确的:内联表单集让这件事变得简单。

但是请注意,内联只能采用一种方式:从具有外键的模型开始。如果两者都没有主键(不好,因为你可以有 A -> B 然后 B -> A2),你不能在 related_to 模型中拥有内联表单集。

例如,如果您有一个 UserProfile 类,并且希望能够在显示这些类时,将相关的 User 对象显示为内联,那么您将不走运。

您可以在 ModelForm 上拥有自定义字段,并将其用作更灵活的方式,但请注意,它不再像标准 ModelForm/内联表单集那样“自动”。

【讨论】:

  • 我正在解决这个问题和您的答案中描述的问题。现在已经过去很多年了。不知道现在有没有自动解决方案?
【解决方案3】:

您可以考虑的另一种方法是通过扩展 AbstractUser 或 AbstractBaseUser 模型来创建自定义用户模型,而不是使用带有 Profile 模型的one-to-one link(在本例中为 Student 模型)。这将创建一个可用于创建单个 ModelForm 的扩展 User 模型。

例如,一种方法是扩展AbstractUser model

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,它既包含您需要的附加字段,也包含原始 User 模型中的字段。在forms.py中

from .models import Student    

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

更复杂的方法是扩展 AbstractBaseUser,这在 in the docs 中有详细描述。

但是,我不确定以这种方式创建自定义用户模型以便拥有一个方便的单一 ModelForm 是否对您的用例有意义。这是您必须做出的设计决策,因为创建自定义用户模型可能是一项棘手的工作。

【讨论】:

    【解决方案4】:

    据我了解,您想更新 auth.User 的用户名字段,即 OneToOneStudent 的关系,这就是我要做的...

    class StudentForm (forms.ModelForm):
    
    username = forms.Charfield(label=_('Username'))
    class Meta:
        model = Student
        fields = ('personalInfo',)
    
    def clean_username(self):
        # using clean method change the value
        # you can put your logic here to update auth.User
        username = self.cleaned_data('username')
        # get AUTH USER MODEL
        in_db = get_user_model()._default_manager.update_or_create(username=username)
    

    希望这会有所帮助:)

    【讨论】:

    • 这怎么知道要更新哪个用户对象?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    相关资源
    最近更新 更多