Django多对多关系

hk8txs48  于 2023-02-10  发布在  Go
关注(0)|答案(2)|浏览(184)

模型. 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="+")

在管理页面中:

问题是:
如何设置models. pyproductscategory m2m字段之间的关系,以便在管理页面中,如图所示,b2(产品)被标记为属于a2(类别)。
欢迎对【产品、类别】的执行提出建议,谢谢!
附言
我是Django的新手,抱歉我的英语不好。

wqnecbli

wqnecbli1#

问题是您有 * 两个 * ManyToMany字段,正如您所注意到的,当在其中一个字段中设置了关系时,另一个字段中就没有。
解决办法很简单:删除其中一个字段。你只需要在关系的一端有一个ManyToManyField。Django会自动给你访问另一端的权限。所以,如果你保留Product模型上的categories字段,你可以执行my_product.categories.all()来获取产品关联的类别;和my_category.product_set.all()来获得属于类别的产品。
您还需要删除related_name="+"属性:你大概把它放进去是因为你遇到了冲突,这应该是一个线索。

y3bcpkx1

y3bcpkx12#

2022年3月更新:

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

〈没有"多对多字段()"的方式〉

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

  • *"www.example.com":models.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"表,如下所示。

  • *"www.example.com":admin.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"表,如下所示。

  • *"www.example.com":admin.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的方式()"" categories "字段" ManyToManyField()"一起添加到" Product "类**中,如下所示,它们之间只有代码差异,因此其他内容相同。

  • *"www.example.com":models.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()""products"字段添加到"Category"类**中,只有代码不同,因此其他内容也相同。

  • *"www.example.com":models.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()"**的方式相同,如下所示。

  • *"www.example.com":admin.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()"**的方式相同,如下所示。

  • *"www.example.com":admin.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 '"**,如下所示。

  • *"www.example.com":models.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"表的形式,内嵌默认的中间表**。

  • *"www.example.com":admin.py":
from django.contrib import admin
from .models import Product

admin.site.register(Product)

看起来是这样的。正如你所看到的,**"类别"的UI(用户界面)与拥有自定义中间表"类别产品"时的UI不同。对我来说,拥有自定义中间表"类别产品"**时的UI更好:

即使您注册了**"类别"表**,如下所示。

  • *"www.example.com":admin.py":
from django.contrib import admin
from .models import Category

admin.site.register(Category)
    • 默认的中间表格不内联到"类别"表格**,如下所示:

    • 要将默认中间表内联到"类别"表**,"类别"表必须具有ManyToManyField(),如下所示。
  • *"www.example.com":models.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"表的形式,并内联默认中间表**。

  • *"www.example.com":admin.py":
from django.contrib import admin
from .models import Category

admin.site.register(Category)

它看起来是这样的:

这就是在Django中创建**"多对多"关系**的方法。

相关问题