【问题标题】:Django 1.7: how to make ManyToManyField required?Django 1.7:如何使 ManyToManyField 成为必需的?
【发布时间】:2015-03-03 19:45:10
【问题描述】:

我有一个带有 ManyToManyField 的 Django 模型。我需要要求用户在此字段中至少选择一个 M2M 值。

我尝试将 blank=False 设置为 M2M 字段,但没有帮助。

class Skill(models.Model):
    name = models.CharField(max_length=200)

class PersonSkills(models.Model):
    person = models.ForeignKey('Person')
    skill = models.ForeignKey('Skill')

class Person(models.Model):
    name = models.CharField(max_length=200)
    skills = models.ManyToManyField('Skill', through='PersonSkills')

p = Person(name='Bob')
p.save()
# success, but I expect that this should throw ValidationError, because I didn't select at least one Skill for this person

我可以使用自定义Form 定义或覆盖save() 方法来解决这种情况Person 模型。

如果没有选择至少一个Skill 并设置ManyToManyField 选项,是否可以防止创建Person?或者我需要创建自定义逻辑来处理这种情况?谢谢。

我使用Django 1.7Python 3.4


更新1.如何创建ModelForm来控制M2M?因为在cleaned_data 中,我只有为Person 表单传递的字段,而没有作为M2M 字段传递的数据。我尝试在管理站点中创建对象并控制 Skills 选择。我通过inline输入Skill

# admin.py
class PersonSkillsInline(admin.TabularInline):
    model = Person.skills.through
    extra = 2

class PersonAdmin(admin.ModelAdmin):
    inlines = [PersonSkillsInline]

admin.site.register(Person, PersonAdmin)

【问题讨论】:

  • 您需要通过 Person 的 ModelForm 类确保至少有一个值。
  • @Brandon 我同意。但是,如果我尝试在不使用自定义 Form 的情况下创建 Person 对象,这将允许我在未选择 Skill 的情况下创建用户:-(
  • 您还希望如何创建记录?我不太明白你为什么不使用 ModelForm...
  • @Brandon 谢谢。我没想到我们使用了中间模型,其中指定了两个 ForeignKey 字段。在这种情况下,我无法通过将选项传递给 M2M 字段来控制 M2M 字段。我将使用带有clean() 方法的ModelForm 来检查skills 是否通过。
  • 我已经更新了我的问题。弄清楚如何使用管理站点并检查技能对象的计数作为内联对象。

标签: python python-3.x django django-admin many-to-many


【解决方案1】:

在数据库级别...不,这是不可能的。对此的任何强制执行都必须来自您的应用程序逻辑。

原因是每一个m2m关系都有一个外键m2m关系两边的记录。 SQL 不能强制关系的引用方存在,只能强制关系的被引用方存在。

此外,您也不能在模型中强制执行它,因为必须先创建并保存Person,然后才能分配任何多对多关系。

您唯一的选择是在表单或视图中强制执行它。

InlineModelAdmin 中,这可以通过指定min_num (1.7+) 轻松完成:

class PersonSkillsInline(admin.TabularInline):
    model = Person.skills.through
    min_num = 1
    extra = 2

【讨论】:

  • 是的,我同意...感谢您的解释,现在我知道我在模型方面无法控制这个,需要创建自定义模型表单并使用clean() 方法检查@987654327 @ 在里面。
  • @AntonDanilchenko 查看我的答案。
【解决方案2】:

2022 年 3 月更新:

"min_num" 可以使内联字段成为必需。 (内联字段默认不需要,默认显示3个不需要的内联字段)

因此,如果您想要 2 个必需的内联字段,请设置 "min_num = 2" 如下所示,在这种情况下,将显示 2 个必需和 3 个非必需的内联字段,您可以添加更多不需要的内联字段内联字段,但您不能在表单中添加必需的内联字段:

from django.contrib import admin
from .models import PersonSkills, Person

class PersonSkillsInline(admin.TabularInline):
    model = PersonSkills
    min_num = 2  # 2 required inline fields displayed
                 # 3 unrequired inline fields displayed by default

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    inlines = [PersonSkillsInline]

另外,您可以使用“extra”设置显示非必填字段的数量,您可以使用“max_num”设置总内联的最大数量字段,包括必需和非必需的内联字段。因此,在下面的这种情况下,总内联字段的最大数量为 10 和 3 个必填字段,并显示 2 个不需要的内联字段,您最多可以添加 5 个不需要的内联字段,但不能在表单中添加必需的内联字段:

from django.contrib import admin
from .models import PersonSkills, Person

class PersonSkillsInline(admin.TabularInline):
    model = PersonSkills
    min_num = 3  # 3 required inline fields displayed
    extra = 2    # 2 unrequired inline fields displayed
    max_num = 10 # 10 inline fields as a maximum

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    inlines = [PersonSkillsInline]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2014-09-14
    相关资源
    最近更新 更多