简体   繁体   English

Django管理员:通过非相邻的ManyToMany关系使用内联

[英]Django admin: using inlines through a non-adjacent ManyToMany relationship

Consider the following models.py , where a Group contains multiple Persons who each have zero or more Phone numbers. 考虑以下models.py ,其中一个组包含多个具有零个或多个电话号码的人。 In this particular case, Persons who share a Group will often share at least one Phone number, so a many-to-many relationship is used. 在这种情况下,共享一个群组的人通常会共享至少一个电话号码,因此使用了多对多关系。

class Group(models.Model):
    name = models.CharField(max_length=30)

class Person(models.Model):
    group = models.ForeignKey(Group)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class Phone(models.Model):
    persons = models.ManyToManyField(Person)
    number = models.CharField(max_length=30)

I would like to show these models in the Django admin, in a single view, as shown below. 我想在Django管理员中以单一视图显示这些模型,如下所示。

class PersonInline(admin.StackedInline):
    model = Person

class PhoneInline(admin.StackedInline):
    model = Phone # also tried: Phone.persons.through

@admin.register(Group)
class GroupAdmin(admin.ModelAdmin):
    inlines = [PersonInline, PhoneInline]

However, there is no foreign key between Group and Phone, so this raises a SystemCheckError (one of the following): 但是,Group和Phone之间没有外键,因此会引发SystemCheckError (以下之一):
<class 'myapp.admin.PhoneInline'>: (admin.E202) 'myapp.Phone' has no ForeignKey to 'myapp.Group'.
<class 'myapp.admin.PhoneInline'>: (admin.E202) 'myapp.Phone_persons' has no ForeignKey to 'myapp.Group'.

Is it possible to make this work through the Person model? 是否可以通过“人”模型来完成这项工作? The goal is for the Phone inline to show phone number records for all Persons in the Group (bonus: when adding a new Phone, the Person SelectMultiple widget will need to only show other Persons in the Group). 电话内联的目标是显示组中所有人员的电话号码记录(奖金:添加新电话时,Person SelectMultiple小部件将只需要显示组中其他人员)。 I would prefer to avoid modifying any templates. 我宁愿避免修改任何模板。 A third-party app could be integrated if necessary. 如有必要,可以集成第三方应用程序。 I can use Django 1.10 or 1.11. 我可以使用Django 1.10或1.11。

Thanks! 谢谢!

I solved this by slightly modifying my requirements. 我通过稍微修改需求来解决了这个问题。 Rather than requiring a relationship between Phone and Person only, I added another many-to-one relationship: between Phone and Group . 我不是只要求在PhonePerson之间建立关系,而是添加了另一对多关系: PhoneGroup之间。 For my particular case, it actually works out better this way; 对于我的特殊情况,这种方法实际上效果更好。 and a Group should cascade to both related Person s and related Phone s on delete. Group应该在删除时级联到相关的Person和相关的Phone

There is no change to the admin.py shown in the question. 问题中显示的admin.py没有变化。 The models.py has one more line in the Phone class, a ForeignKey field: models.pyPhone类中的另一行是ForeignKey字段:

class Phone(models.Model):
    group = models.ForeignKey(Group)
    persons = models.ManyToManyField(Person)
    number = models.CharField(max_length=30)

The "bonus" above requires that the ManyToManyField form widget in the Person inline show only those Person s that are in the same Group . 上面的“奖金”要求Person内联中的ManyToManyField表单窗口小部件仅显示同一Group中的Person For this, two functions can be added to admin.py : 为此,可以将两个函数添加到admin.py

class PersonInline(admin.StackedInline):
    model = Person

class PhoneInline(admin.StackedInline):
    model = Phone

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        field = super(PhoneInline,
                      self).formfield_for_manytomany(db_field, request,
                                                     **kwargs)
        if db_field.name == 'persons':
            if request._obj_ is None:
                field.queryset = field.queryset.none()
            else:
                qs = Person.objects.filter(group=request._obj_.id)
                field.queryset = qs
                field.initial = qs
        return field

@admin.register(Group)
class GroupAdmin(admin.ModelAdmin):
    inlines = [PersonInline, PhoneInline]

    def get_form(self, request, obj=None, **kwargs):
        # Save obj reference for future processing in Phone inline
        request._obj_ = obj
        return super(GroupAdmin, self).get_form(request, obj, **kwargs)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM