在相同的两个模型之间使用ManyToMany关系时“已存在”错误

时间:2017-05-09 07:11:31

标签: django django-models django-admin

class Product( models.Model ):  
    name = models.CharField(verbose_name="Name", max_length=255, null=True, blank=True)
    the_products_inside_combo = models.ManyToManyField('self', verbose_name="Products Inside Combo", help_text="Only for Combo Products", blank=True)

但是,当我尝试输入重复值时出现此错误:

  

From_product-to_product与此From产品和To的关系   产品已经存在。

Screencap of the error.

1 个答案:

答案 0 :(得分:0)

每对(Product, Product)必须是唯一的。这就是导致already exists错误的原因。

  

在幕后,Django创建了一个中间连接表   代表多对多的关系。

你想要做的是在两个模型之间建立多对多关系(永远不要说它们是相同的)并存储其他信息 - 数量(所以你会ProductA = 2x ProductB + ...

为了建模这种关系,您必须创建中间模型并使用through选项。文档解释得非常好,所以看看:

https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

<强>更新

这是最小的工作示例:

class Product(models.Model):
    name = models.CharField(verbose_name='Name', max_length=255, null=True, blank=True)
    products = models.ManyToManyField('self', through='ProductGroup', symmetrical=False)

    def __str__(self):
        return self.name

class ProductGroup(models.Model):
    parent = models.ForeignKey('Product', related_name='+')
    child = models.ForeignKey('Product', related_name='+')

和管理员模型:

class ProductGroupInline(admin.TabularInline):
    model = Product.products.through
    fk_name = 'parent'

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ProductGroupInline,
    ]

admin.site.register(Product, ProductAdmin)
admin.site.register(ProductGroup)

正如您所见,递归Product - Product关系是使用ProductGroupthrough参数)建模的。几个笔记:

  1. 具有中间表的多对多字段不能是对称的,因此symmetrical=FalseDetails

  2. ProductGroup的反向访问权限被禁用('+')(通常您可以重命名它们,但是,您不想直接使用ProductGroup )。否则我们会得到Reverse accessor for 'ProductGroup.child' clashes with reverse accessor for 'ProductGroup.parent'.

  3. 为了在管理员中很好地展示ManyToMany,我们必须使用内联模型(ProductGroupInline)。在文档中阅读它们。但请注意fk_name字段。我们必须指定这个,因为ProductGroup本身是不明确的 - 两个字段都是同一模型的外键。

  4. 谨慎使用并发费用。例如,如果您要__str__ Product return self.productsProductGroup ProductGroup <form th:action="@{/moderator/new-user-form}" th:object="${caltest}" method="post" enctype="multipart/form-data" class="form-validate form row"> <!-- some code --> </form> <form th:action="@{/admin/new-user-form}" th:object="${caltest}" method="post" enctype="multipart/form-data" class="form-validate form row"> <!-- some code --> </form> 与父级相同,则无限循环。

  5. Admin example

    1. 正如您在屏幕上看到的那样,现在可以复制。或者,您只需将数量字段添加到action并在创建对象时检查重复。