繁体   English   中英

Django 多对多关系

[英]Django ManyToMany relationship

models.py 中

from django.db import models
from django.utils.translation import ugettext as _

# Create your models here.
class Category(models.Model):
    name            = models.CharField(_(u"Name"), max_length=250)
    products        = models.ManyToManyField("Product", verbose_name=_(u"Products"), \
                      blank=True, null=True, related_name="+")
        
class Product(models.Model):
    name            = models.CharField(_(u"Name"), max_length=250)    
    category        = models.ManyToManyField("Category", verbose_name=_(u"Category"), \
                      blank=True, null=True, related_name="+")

在管理页面:

m2m关系

问题:
如何设置models.pyproductscategory m2m 字段之间的关系,以便在管理页面中,如图所示, b2 (产品)被标记为属于a2 (类别)。
欢迎就 [产品、类别] 的实施提出任何建议,谢谢。

聚苯乙烯
我是 Django 的新手。对不起我的英语。

问题是你有两个 ManyToMany字段。 正如您所指出的那样,当关系设置在其中一个中时,它就不在另一个中。

解决方案很简单:删除其中一个字段。 您只需要在关系的一侧使用ManyToManyField。 Django让您自动访问另一方。 因此,如果您在Product型号上保留了categories字段,则可以执行my_product.categories.all()以获取与产品相关联的类别; my_category.product_set.all()获取属于某个类别的产品。

你还需要删除related_name="+"属性:你可能会把它放进去因为你遇到了冲突,这应该是一个线索。

2022 年 3 月更新:

Django中有两种创建“多对多”关系的方法。 一个不使用“ManyToManyField()” ,一个使用“ManyToManyField()” 首先,我将向您展示不使用"ManyToManyField()"的方法。

<没有“ManyToManyField()”的方法>

要创建多对多关系,必须有2 个其他表之间的中间表,并且它必须具有来自 2 个其他表的每个外键,并且这些外键必须是唯一的 因此,我在“Category”和“Product”表之间创建了中间表“CategoryProduct” ,它具有来自“Category”和“Product”表的每个外键这些外键是唯一的,如下所示。

“模型.py”

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=255)
    
    def __str__(self):
        return self.name

class Product(models.Model):
    name = models.CharField(max_length=255)    
    
    def __str__(self):
        return self.name

# The middle table between "Category" and "Product" tables
class CategoryProduct(models.Model): 
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)

    class Meta:
        unique_together = [['category', 'product']]

这就是将中间表“CategoryProduct”内联到“Product”表的方式,如下所示。

“管理员.py”

from django.contrib import admin
from .models import CategoryProduct, Product

class CategoryProductInline(admin.TabularInline):
    model = CategoryProduct
    min_num = 1 
    extra = 2
    max_num = 5

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = [CategoryProductInline]

这是它的样子:

在此处输入图像描述

这就是将中间表“CategoryProduct”内联到“Category”表的方式,如下所示。

“管理员.py”

from django.contrib import admin
from .models import CategoryProduct, Category

class CategoryProductInline(admin.TabularInline):
    model = CategoryProduct
    min_num = 1 # 1 required inline field displayed
    extra = 2   # 2 unrequired inline fields displayed
    max_num = 5 # 5 inline fields as a maximum

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    inlines = [CategoryProductInline]

这是它的样子:

在此处输入图像描述

<使用“ManyToManyField()”的方法>

这是“ManyToManyField()”的方法,如下所示。 上面使用“ManyToManyField()”的方式和没有使用 ManyToManyField()”的方式之间的区别是在这种情况下使用“ManyToManyField()”的方式,带有 ManyToManyField()”“类别”字段被添加到“产品” “ class正如您在下面看到的,它们之间唯一的代码不同,所以其他都是一样的。

“模型.py”

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name
    
class Product(models.Model):
    name = models.CharField(max_length=255)
    categories = models.ManyToManyField(
        Category, 
        through='CategoryProduct'
    ) # "categories" field is added

    def __str__(self):
        return self.name

class CategoryProduct(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)

    class Meta:
        unique_together = [['category', 'product']]

您可以将带有“ManyToManyField()”“产品”字段添加到“类别”class ,并且只有代码不同,所以其他内容也相同。

“模型.py”

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name

class Category(models.Model):
    name = models.CharField(max_length=255)
    products = models.ManyToManyField(
        Product, 
        through='CategoryProduct'
    ) # "products" field is added

    def __str__(self):
        return self.name

class CategoryProduct(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)

    class Meta:
        unique_together = [['category', 'product']]

因此,将中间表“CategoryProduct”内联到“Product”表的方式也与没有“ManyToManyField()”的方式相同,如下所示。

“管理员.py”

from django.contrib import admin
from .models import CategoryProduct, Product

class CategoryProductInline(admin.TabularInline):
    model = CategoryProduct
    min_num = 1 
    extra = 2
    max_num = 5

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = [CategoryProductInline]

这是它的样子:

在此处输入图像描述

并且,将中间表“CategoryProduct”内联到“Category”表的方式与没有“ManyToManyField()”的方式相同,如下所示。

“管理员.py”

from django.contrib import admin
from .models import CategoryProduct, Category

class CategoryProductInline(admin.TabularInline):
    model = CategoryProduct
    min_num = 1 # 1 required inline field displayed
    extra = 2   # 2 unrequired inline fields displayed
    max_num = 5 # 5 inline fields as a maximum

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    inlines = [CategoryProductInline]

这是它的样子:

在此处输入图像描述

此外,当您使用“ManyToManyField()”时,您可以删除可自定义的中间表“CategoryProduct”的代码 在这种情况下,您删除中间表“CategoryProduct”的代码,隐式创建不可自定义的默认中间表 因此,我从“ManyToManyField()”中删除了中间表“CategoryProduct”“through='CategoryProduct'”的代码,如下所示。

“模型.py”

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name

class Product(models.Model):
    name = models.CharField(max_length=255)
    categories = models.ManyToManyField(Category)
    categories = models.ManyToManyField(
        Category, 
        # through='CategoryProduct'
    )

    def __str__(self):
        return self.name

# class CategoryProduct(models.Model):
#     category = models.ForeignKey(Category, on_delete=models.CASCADE)
#     product = models.ForeignKey(Product, on_delete=models.CASCADE)

#     class Meta:
#         unique_together = [['category', 'product']]

并且只需如下所示注册“Product” ,您就可以使用默认中间表的内联创建“Product”表的形式

“管理员.py”

from django.contrib import admin
from .models import Product

admin.site.register(Product)

这就是它的样子。 如您所见, “类别”的 UI(用户界面)与具有自定义中间表“CategoryProduct”时不同。 对我来说,拥有自定义中间表“CategoryProduct”时的 UI 更好:

在此处输入图像描述

即使您注册“类别”表,如下所示。

“管理员.py”

from django.contrib import admin
from .models import Category

admin.site.register(Category)

默认中间表未内联到“类别”表,如下所示:

在此处输入图像描述

要将默认中间表内联到“类别”表“类别”表必须具有如下所示的ManyToManyField()

“模型.py”

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name

class Category(models.Model):
    name = models.CharField(max_length=255)
    products = models.ManyToManyField( # Here
        Product, 
        # through='CategoryProduct'
    )

    def __str__(self):
        return self.name

# class CategoryProduct(models.Model):
#     category = models.ForeignKey(Category, on_delete=models.CASCADE)
#     product = models.ForeignKey(Product, on_delete=models.CASCADE)

#     class Meta:
#         unique_together = [['category', 'product']]

然后,只需如下所示注册“Category” ,就可以使用默认中间表的内联创建“Category”表的形式

“管理员.py”

from django.contrib import admin
from .models import Category

admin.site.register(Category)

这是它的样子:

在此处输入图像描述

这就是您在Django中创建“多对多”关系的方式。

暂无
暂无

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

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