管理员或视图中的自引用对称多对多 Django 模型

Posted

技术标签:

【中文标题】管理员或视图中的自引用对称多对多 Django 模型【英文标题】:Self Referencing Symmetrical Many to Many Django Model in Admin or View 【发布时间】:2018-12-17 17:03:18 【问题描述】:

如何在 M2M django 模型中获得对称自引用的另一面?

假设我们正在制作零件目录,我们有很多 Parts,我们希望有一个 Interchange 来显示哪些零件可以用来代替另一个零件:

class Part(models.Model):
    name = models.CharField(max_length=300)
    number = models.CharField(max_length=200, default 'because numberphiles like more ids')
    …
    interchanges = models.ManyToManyField("self",
                                          through='Interchange',
                                          symmetrical=False,
                                          # + sign per http://charlesleifer.com/blog/self-referencing-many-many-through/
                                          # I have tried without the plus t omaintain the references as well, but can't seem to understand the difference(s)
                                          related_name="interchanges_to+",
                                          # through_fields per docs
                                          through_fields=('reference', 'interchange')
                                          )

    # per this http://charlesleifer.com/blog/self-referencing-many-many-through/
    def add_interchange(self, part, symm=True):
        interchange = models.Interchange.objects.get_or_create(
            reference_part=self,
            interchange_part=part)
        if symm:
            # avoid recursion by passing `symm=False`
            part.add_interchange(self, False)
        return interchange

    def remove_interchange(self, part, symm=True):
        models.Interchange.objects.filter(
            reference_part=self,
            interchange_part=part).delete()
        if symm:
            # avoid recursion by passing `symm=False`
            part.remove_interchange(self, False)

    def get_interchanges(self):
        return ", ".join([str(p) for p in self.interchanges.filter(interchange_part__reference=self)])

    def get_references(self):
        return …?
        # This is where I don't know how to get the Parts that are referring to it as being an interchange

class Interchange(models.Model):
    reference = models.ForeignKey(Part, related_name="reference_part")
    interchange = models.ForeignKey(Part, related_name="interchange_part")
    # just to confirm we have a M2M table, we will add a foregin key to a User if this interchange has been personally verified
    confirmed_by = models.ForeignKey(User, null=True, blank=True)
    # … others if needed

    class Meta:
        # because self-referencing, in this case, is silly, we make sure each part references another part
        unique_together = ('reference', 'interchange')

在 Django 管理员中,我有:

@admin.register(app.Part)
class PartAdmin(admin.ModelAdmin):
    list_display = ['name', 
                    'number', 
                     # ▼ I can see the Parts itself Interchanges to
                    'get_interchanges', 
                     # ▼ I can not see the Parts that reference itself as being an Interchange
                    'get_references'] 

Admin 中的零件模型供参考...

这是我所拥有的:

这是我想要得到的:

作为确认,管理员中的交换模型:

如何获得对称自引用 M2M django 模型的另一面?如何返回在交换表中但在引用(第一)列中的Parts

注意事项:

使用 django 1.11 我知道在使用 M2M 模型时需要 False 的对称性,根据 docs This 不错的文章帮助我走得很远,但在管理中,我似乎无法让 interchange_part 在管理页面中显示其 reference_parts(因此我什至没有尝试查看如果可能在具有不同/特定功能的视图中) 在docs 中,它指出through_keys 的元组的第二部分称为target 模型,但我不知道要引用第一个的什么 我确信有一种方法可以深入多个层次,即如果第一部分交换为 2 和 2 => 3,那么 1 应该列出 2 和 3(但这不是目前的重点) 请纠正我的误解,谢谢:)

【问题讨论】:

Django: How to follow ManyToMany('self') backwards的可能重复 我展示了差异,并且能够做出答案:) ww 【参考方案1】:

如果 manytomany 有一个带有 related_name 参数的直通表并且不包括 +,那么您可以直接访问该集合:

def get_references(self):
    return ", ".join([str(p) for p in self.interchanges_to.all()])

注意,我不确定性能/复杂性

【讨论】:

以上是关于管理员或视图中的自引用对称多对多 Django 模型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQLAlchemy ORM 上实现对同一属性的自引用多对多关系?

替换表单的默认多对多小部件

Django,在 self 类中的多对多关系中,我如何在 ORM 方面相互引用?

按 django admin 中的自定义列表显示字段进行列表过滤

在 Django 中过滤第二级多对多关系

多对多模型的 Django 表单。如何从视图/模板填写表格?