如何在 Django 中向多对多关系中添加字段?

Posted

技术标签:

【中文标题】如何在 Django 中向多对多关系中添加字段?【英文标题】:How can I add a field to a many-to-many relationship in Django? 【发布时间】:2021-04-02 11:16:01 【问题描述】:

这是一个关于如何在Django中为多对多关系添加字段的问题。

我有一个模型 LandingPage 和一个模型 Product。 (下面的代码)。在我的项目中,LandingPages 上可以列出许多产品,并且这些相同的产品可以出现在多个不同的 LandingPages 上。

产品通过 ManyToManyField 连接到 LandingPage。

我的目标:

我试图弄清楚如何添加一个字段,以便我可以在其关联的 LandingPages 上设置产品的顺序(1 到 10)。提醒一下,Product 实例可以出现在多个 LandingPages 上,因此每个实例都需要有不同的 order 属性。

理想情况下,我想通过内置的 Django 管理员公开此功能。现在它显示了关系表,但不显示 order 字段,因为它还不存在。 (下面的屏幕截图/模型)。

我的代码:

models.py

class LandingPage(models.Model):
    """Stores a single LandingPage and metadata.
    """

    name = models.CharField(max_length=200, help_text="The name is only used internally. It is not visible to the public.")
    slug = models.SlugField(default="", editable=False, max_length=150, null=False, verbose_name="Slug", help_text="This is not editable.")
    # Additional fields that I do not believe are relevant

class Product(models.Model):
    """Stores a single Product and metadata.
    """

    name = models.CharField(max_length=200, help_text="Used internally. Not visible to the public.")
    active = models.BooleanField(default=False, verbose_name="Product is Live on Landing Pages", help_text="Determines whether the product should be visible on the assocaited landing page or not.")
    landing_page = models.ManyToManyField(
        LandingPage,
        verbose_name="Landing Page",
        help_text="The landing page or pages that this product is assocaited with.",
    )
    # Additional fields that I do not believe are relevant

admin.py

# Inline configuration used by  LandingPageAdmin
class ProductInline(admin.TabularInline):
    """Creates Inline table format for displaying Product data."""
    model = Product.landing_page.through
    extra = 0

class LandingPageAdmin(admin.ModelAdmin):
    """Specifies LandingPage data in Admin."""
    readonly_fields=('slug',)
    inlines = [ProductInline]
    save_as = True

# Inline configuration used by Product Admin
class LandingPageInline(admin.TabularInline):
    """Creates Inline table format for displaying LandingPage data."""
    model = LandingPage.product_set.through
    extra = 0

class ProductAdmin(admin.ModelAdmin):
    """Specifies Product data in Admin."""
    inlines = [LandingPageInline]
    save_as = True

模型(为清楚起见):

当前状态

期望状态

(为了清楚起见,我在红色中添加了所需的功能。顺序整数应该是可编辑,以便可以重新排列顺序。)

我的问题

如何实现将可编辑的order 字段添加到此预先存在的关系的目标?

我应该手动将 order 字段添加到由 Django 自动创建的 product-landingpage 连接表吗?如果我这样做,有没有办法让 Django 管理员显示添加的字段?

或者我应该采取完全不同的方式吗?

提前谢谢你!

【问题讨论】:

【参考方案1】:

我找到了答案。

解决方案是创建一个中间模型并使用“through”连接它。示例如下:

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

官方文档在这里:https://docs.djangoproject.com/en/3.1/topics/db/models/#intermediary-manytomany

在我的情况下,其他人可能会发现阅读此问题/答案很有用,因为它很好地解释了各种解决方案:Define an order for ManyToManyField with Django

【讨论】:

以上是关于如何在 Django 中向多对多关系中添加字段?的主要内容,如果未能解决你的问题,请参考以下文章

Django:管理员,向多项选择字段添加一些新过滤器

更改模型以添加“通过”关系以订购多对多字段 - Django 1.7 迁移修改

多对多字段django以两种方式添加关系

如何向多对多数据透视表添加额外的列

如何解决具有多对多关系的石墨烯 django 节点字段

如何以 django 形式过滤多对多字段