Django之ContentType组件

一、需求

  给商品创建优惠券;

  看看下面表结构:

class Food(models.Model):
    """
    id   name
    1     面条
    """
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Fruit(models.Model):
    """
    id     name
    1      苹果
    """
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")  # 定义反向查询字段

    def __str__(self):
        return self.name


class Coupon(models.Model):
    """
    优惠券表
    id  name    appliance_id    food_id     fruit_id
    1   通用优惠券   null            null        null
    2   冰箱折扣券   1               null        null
    3   电视折扣券   2               null        null
    4   苹果满减卷   null            null        1
    我每增加一张表就要多增加一个字段
    """
    name = models.CharField(max_length=32)
    # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表
    appliance = models.ForeignKey(to="Appliance")
    food = models.ForeignKey(to="Food")
    fruit = models.ForeignKey(to="Fruit")

  创建第四张表,改善上面的写法:遇到这种一张表要跟多张表进行外键关联

class Appliance(models.Model):
    name = models.CharField(max_length=32)


class Food(models.Model):
    """
    id   name
    1     面条
    """
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Fruit(models.Model):
    """
    id     name
    1      苹果
    """
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")  # 定义反向查询字段

    def __str__(self):
        return self.name


class Coupon(models.Model):
    """
    优惠券表
    id       name           content_type_id     object_id
    1     面条优惠券             1                 1
    1     苹果优惠券             2                1
    """
    name = models.CharField(max_length=32)
    # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表ContentType
    content_type_id =
    object_id = 


class ContentType(models.Model):
    # django自带这张表,已经帮我们做好了,就是django的ContentType组件,我们直接拿过来用就行
    """
    id    app_name    model_class
    1      app01         Food
    2      app01         Fruit
    3      app01         Appliance
    """
    pass

  其实django已经帮我写好了这张ContentType表,我们只需要导入使用即可;

二、使用django自带的ContentType表

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

  当我们的项目做数据迁移后,会有很多django自带的表,其中就有django_content_type表;

 

ContentType组件应用:

  -- 在model中定义ForeignKey字段,并关联到ContentType表,通常这个字段命名为content-type

  -- 在model中定义PositiveIntergerField字段, 用来存储关联表中的主键,通常我们用object_id

  -- 在model中定义GenericForeignKey字段,传入上面两个字段的名字

  --  方便反向查询可以定义GenericRelation字段

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class Food(models.Model):
    """
    id   name
    1     面条
    """
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Fruit(models.Model):
    """
    id     name
    1      苹果
    """
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")  # 定义反向查询字段

    def __str__(self):
        return self.name

class Coupon(models.Model):
    """
    优惠券表
    id       name           content_type_id     object_id
    1     面条优惠券             1                 1
    1     苹果优惠券             2                1
    """
    name = models.CharField(max_length=32)
    # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表ContentType
    # appliance = models.ForeignKey(to="Appliance")
    # food = models.ForeignKey(to="Food")
    # fruit = models.ForeignKey(to="Fruit")

    # 第一步  先生成ForeignKey字段 关联ContentType
    content_type = models.ForeignKey(to=ContentType)
    # 第二步   生成一个IntergerField 字段关联
    object_id = models.PositiveIntegerField()
    # 第三步 生成一个GenericForeignKey 把上面两个字段注册进去
    content_obj = GenericForeignKey("content_type", "object_id")

    def __str__(self):
        return self.name

基本的操作:

class Test(APIView):

    def get(self, request):
        from django.contrib.contenttypes.models import ContentType
        # 通过contentType获取表名
        content = ContentType.objects.filter(app_label="app01", model="food").first()  # 表名都是小写
        model_class = content.model_class()  # 通过上一步获取的contentType对象获取 里面的表对象
        ret = model_class.objects.all()  # 查询这个表中所有的信息
        print(ret)

        # 给Food表中的面条创建一个优惠券
        noodle_obj = models.Food.objects.filter(id=2).first()  # 这里面包含了自己所在的表,和自己这条记录在那张表中的id
        models.Coupon.objects.create(name="面条优惠券", content_obj=noodle_obj)  # 只要传入上面的obj即可

        # 查询id为1的优惠券,对应那个商品信息
        coupon_obj = models.Coupon.objects.filter(id=1).first()
        goods_obj = coupon_obj.content_obj  # 拿到对应的商品对象
        print(goods_obj)
        print(goods_obj.name, goods_obj.id)

        # 查询苹果的所有优惠券
        # 因为我们定义了反向字段,所以可以这么查:
        # 首先找苹果对象
        apple_obj = models.Fruit.objects.filter(name="苹果").first()
        coupon_obj_list = apple_obj.coupons.all()  # 通过字段反向查询
        print(coupon_obj_list)
        print(coupon_obj_list.first().name)

        return Response("ok")

 原作者:https://www.cnblogs.com/glh-ty/p/9703574.html

posted @ 2018-12-11 21:02  sado  阅读(184)  评论(0编辑  收藏  举报