Django ContentType组件

 

需求

现在我们有这样一个需求~我们的商城里有很多的商品~~节日要来了~我们要搞活动~~

那么我们就要设计优惠券~~优惠券都有什么类型呢~~满减的~折扣的~立减的~~

我们对应着我们活动类型~对我们的某类商品设计优惠券~~比如~~

家电是一类商品~~食物是一类商品~那么我们可以设计家电折扣优惠券~~以及食物满减优惠券等~

那么我们看表结构怎么设计~~

第一版本

from django.db import models


# 设计表结构      # 第一版设计
class Food(models.Model):
    name = models.CharField(max_length=32)


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


class Coupon(models.Model):
    title = models.CharField(max_length=32)
    food = models.ForeignKey(to="Food")
    fruit = models.ForeignKey(to="Fruit")
第一版 直接来个外键!

 但是 发现商品太多  name外键也要加很多   name表结构就很不合理

第二版本 

from django.db import models


class Food(models.Model):
    """食物表"""
    name = models.CharField(max_length=32)


class Fruit(models.Model):
    """水果表"""
    name = models.CharField(max_length=32)


class Coupon(models.Model):
    """优惠券表
    这时候 设计字段为  表的id   和  object的对象id
        表的id  就是找到对应的表
        object的id  就可以找到表里边对应的对象

    就是定位的方法
    """
    title = models.CharField(max_length=32)
    table = models.ForeignKey(to=MyTables)
    object_id = models.IntegerField()

class MyTables(models.Model):
    """
    id     app_name    table_name
    1       Demo        Food   # 对应的外键是 1
    2       Demo        Fruit  # 对应的外键是 2
    """
    app_name = models.CharField(max_length=32)
    table_name = models.CharField(max_length=32)
第二版

就是通过外键到第三张表MyTables找到对应的app中(水果,食物、、)等类的表,  然后通过根据表中对象对应的id拿到具体的对象这样方法可行吗?

其实django已经帮我们设计好了

遇到这种一张表要跟多张表进行外键关联的时候~我们Django提供了ContentType组件~

ContentType组件

注释所有的model文件执行数据库迁移

pythno manage.py migrate

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  # 定位django表使用
from django.contrib.contenttypes.fields import GenericForeignKey  # 定位表中字段对应对象使用
from django.contrib.contenttypes.fields import GenericRelation  # 反向查询使用


# 设计表结构      # 第三版设计
class Food(models.Model):
    """食物表"""
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")  # 不生成字段 只用于方向查询


class Fruit(models.Model):
    """水果表"""
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")  # 不生成字段 只用于方向查询


class Coupon(models.Model):
    """优惠券表"""
    title = models.CharField(max_length=32)
    # 第三版 使用Django自带的ContentType表

    # 外键到Django自带的ContentType表
    content_type = models.ForeignKey(to=ContentType)  # 相当于 找到可以定位到表
    object_id = models.IntegerField()  # 相当于 定位在表的对应的对象id

    # 不会生成字段 用于关联到对象的(建立关系)
    content_object = GenericForeignKey("content_type", "object_id")
django 自带ContentType

简单测试

添加食物数据

添加水果数据

 添加测试url

from django.conf.urls import url

from .views import TestView

urlpatterns = [

    url(r'^test', TestView.as_view()),
]
urls
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Food, Fruit, Coupon
from django.contrib.contenttypes.models import ContentType


class TestView(APIView):

    def get(self, request):
        # 找到表id以及表对象
        # content_type_obj = ContentType.objects.filter(app_label="ContentType", model="food").first()
        #
        # print(type(content_type_obj), "**", content_type_obj)  # 拿到表中表名
        # # <class 'django.contrib.contenttypes.models.ContentType'> ** food
        #
        # model_class = content_type_obj.model_class()  # 拿到模型表对象
        # print(model_class)  # <class 'ContentType.models.Food'>
        # # <class 'ContentType.models.Food'>
        # print(content_type_obj.pk)  # 获得表中对应id   # (pk和id是一样的)

        # # 给酱香饼创建优惠券
        # food_obj = Food.objects.filter(id=1).first()  # 库中的id为1
        # Coupon.objects.create(title="酱香饼半价啦", content_object=food_obj)  # 在视图中content_object做了关系
        #
        # # 给黑美人西瓜加优惠券
        # fruit_obj = Fruit.objects.get(id=2)  # 库中的id为2
        # Coupon.objects.create(title="黑美人2折", content_type_id=9, object_id=2)  # 使用原生方法创建优惠券

        # 查询优惠券绑定对象(看看id为1的优惠券是对应那个商品)
        coupon_obj = Coupon.objects.filter(id=1).first()
        print(coupon_obj.content_object.name)  # 酱香饼  # content_object建立了关系

        # 查某个对象的优惠券
        food_obj = Food.objects.filter(id=1).first()
        print(food_obj.coupons.all())  # 拿到queryset集合对象  <QuerySet [<Coupon: Coupon object>]>
        
        return Response("ok")
简单测试方便理解
原文地址:https://www.cnblogs.com/clbao/p/9991168.html