Django中content_type的使用

contenttypes 是Django内置的一个应用,可以追踪项目中所有app和model的对应关系,并记录在ContentType表中。

models.py文件的表结构写好后,通过makemigrations和migrate两条命令迁移数据后,在数据库中会自动生成一个django_content_type表:

通过下边的示例来理解content_type的具体应用:

创建:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey,GenericRelation
# Create your models here.
class Food(models.Model):
    name = models.CharField(max_length=32)
    coupon = GenericRelation("Coupon")
class Cloth(models.Model):
    name = models.CharField(max_length=32)
    coupon = GenericRelation("Coupon")
class Coupon(models.Model):
    """
    id      food_id     cloth_id  ……
    1         null        null
    2           1         null
    """
    name = models.CharField("活动名称",max_length=64)
    brief = models.TextField(blank=True,null=True,verbose_name="优惠券介绍")
    content_type = models.ForeignKey(ContentType,blank=True,null=True) # 代表哪个app下的哪张表
    object_id = models.PositiveIntegerField("绑定商品",blank=True,null=True) # 代表哪张表中的对象id
    content_obj = GenericForeignKey("content_type","object_id") #不会生成额外的列
复制代码

注意:ContentType只运用于1对多的关系!!!并且多的那张表中有多个ForeignKey字段。

创建记录和查询:

from django.shortcuts import render, HttpResponse
from api import models
from django.contrib.contenttypes.models import ContentType


def test(request):
    if request.method == 'GET':
        # ContentType表对象有model_class() 方法,取到对应model
        content = ContentType.objects.filter(app_label='Api', model='bed').first()
        bed_class = content.model_class() # bed_class 就相当于models.Bed
        res = cloth_class.objects.all()
        print(res)

        # 为bed(id=2)创建一条优惠记录
        bed_obj = models.Bed.objects.filter(id=1).first()
        models.Coupon.objects.create(name='床の优惠券', content_object=bed_obj)

        # 查询优惠券(id=1)绑定了哪个商品
        coupon_obj = models.Coupon.objects.filter(id=1).first()
        prod = coupon_obj.content_object
        print(prod)

        # 查询bed(id=1)的所有优惠券
        res = bed_obj.coupons.all()
        print(res)

        # 查询obj的所有优惠券:如果没有定义反向查询字段,通过如下方式:
        content = ContentType.objects.filter(app_label='Api', model='model_name').first()
        res = models.OftenAskedQuestion.objects.filter(content_type=content, object_id=obj.pk).all()

        return HttpResponse('ok')

复制代码

总结:

  当一张表作为多个表的FK,并且只能选择其中一个或者几个时,就可以使用content_type表;例如上面的优惠券表,被食物和床当作FK,数据库表一旦建立就难以更改,如果以后需要增加电器等表并把优惠券表作为FK表,这时就不能做到在优惠券表增加列字段electr_id,因为表只能增加行记录而不能增加列字段,因此就可以使用content_type表来将表与表中的对象进行关联,从而做到不增加列字段的情况下增加FK关系。

  在使用content_type表时,需要在FK表中增加content_type作为FK字段,并增加GenericForeignKey便于优惠券表记录的建立以及单个优惠券对象对应的其他商品的查找。在优惠券表关联的关系表中增加GenericRelation字段便于查找关联的优惠券记录的查找。

转载于:https://juejin.im/post/5c7ccf8ce51d4569943bba0c

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值