zoukankan      html  css  js  c++  java
  • django框架基础ORM进阶长期维护

    ###############    ORM进阶---contenttype    ################

    设计思路:

    """
    路飞有两种课,专题课和学位课,
    专题课都是简单的内容,基础的课程模块,
    学位课都是大课程,全套课程, 
    怎么设计价格策略的问题?
    第一种设计:
    价格策略表:
    id,价格, 期限,专题课id,学位课id
    1    11    3个月  1       空
    1    11    6个月  1       空
    1    11    9个月  1       空
    1    11    9个月  2       空
    1    11    3个月  空      1
    1    11    6个月  空      1
    1    11    9个月  空      1
    1    11    9个月  空      2
    这种设计就是每一个课程有多个价格策略,但是会有重复,每个价格策略有的只适用专题课,有的是只适用学位课, 
    第二种设计:
    价格策略表:
    id,价格, 期限,表中数据id ,表id(使用 django_content_type)
    1    11    3个月  1            1
    1    11    6个月  2            2
    1    11    9个月  1            1
    对应的表
    1 course
    2 degree
    这种设计思路非常不错,这是django支持的方式,django里面有一张表 django_content_type
    
    
    """

     表结构

    #
    #
    # from django.contrib.contenttypes.models import ContentType
    # from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    #
    #
    # class DegreeCourse(models.Model):
    #     """学位课程"""
    #     name = models.CharField(max_length=128, unique=True)
    #     course_img = models.CharField(max_length=255, verbose_name="缩略图")
    #     brief = models.TextField(verbose_name="学位课程简介", )
    #
    #
    # class SubjectCourse(models.Model):
    #     """专题课程"""
    #     name = models.CharField(max_length=128, unique=True)
    #     course_img = models.CharField(max_length=255)
    #
    #     # 不会在数据库生成列,只用于帮助你进行查询
    #     policy_list = GenericRelation("PricePolicy")  # 不会在数据库生成列,只用于帮助你进行查询
    #
    #
    # class PricePolicy(models.Model):
    #     """价格与有课程效期表"""
    #     content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    #     object_id = models.PositiveIntegerField()  # 正整数,
    #
    #     #不会在数据库生成列,只用于帮助你进行添加和查询
    #     content_object = GenericForeignKey('content_type', 'object_id')  # 把两个字段放到一个对象里面去了
    #
    #
    #     valid_period_choices = (
    #         (1, '1天'),
    #         (3, '3天'),
    #         (7, '1周'), (14, '2周'),
    #         (30, '1个月'),
    #         (60, '2个月'),
    #         (90, '3个月'),
    #         (180, '6个月'), (210, '12个月'),
    #         (540, '18个月'), (720, '24个月'),
    #     )
    #     valid_period = models.SmallIntegerField(choices=valid_period_choices)
    #     price = models.FloatField()

    操作:

    from django.shortcuts import render,HttpResponse
    from django.contrib.contenttypes.models import ContentType
    # 在使用contenttype的时候如何操作orm,
    def test(request):
        # 1.在价格策略表中添加一条数据
        models.PricePolicy.objects.create(
            valid_period=7,
            price=6.6,
            content_type=ContentType.objects.get(model='SubjectCourse'),
            object_id=1
        )
        # 这是第二种方式,
        models.PricePolicy.objects.create(
            valid_period=14,
            price=9.9,
            content_object=models.Course.objects.get(id=1)
            # 对应的model表中需要添加这个
            # content_object = GenericForeignKey('content_type', 'object_id')  # 把两个字段放到一个对象里面去了
        )
    
        # 2. 根据某个价格策略对象,找到他对应的表和数据,如:管理课程名称
        price = models.PricePolicy.objects.get(id=2)
        print(price.content_object.name)  # 自动帮你找到
    
        # 3.找到某个课程关联的所有价格策略
        obj = models.Course.objects.get(id=1)
        for item in obj.policy_list.all():
            print(item.id,item.valid_period,item.price)
            # 需要在专题表中添加这个GenericRelation
            # policy_list = GenericRelation("PricePolicy")  # 不会在数据库生成列,只用于帮助你进行查询
    
        return HttpResponse('...')
    
    """
    总结:
    1,使用到了django的表ContentType
    2,GenericRelation
    3,GenericForeignKey
    在价格策略和优惠券的地方都会使用这种结构,评论也是,视频可以评论文章可以评论,
    这种设计非常有利于拓展,
    """

      

     ###############    django--事务,原子操作    ###############

    if __name__ == "__main__":
        import os,django
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
        django.setup()
        from app01 import models
        import datetime
    
        # 事务,原子操作,
        try:
            from django.db import transaction #导入一个transaction
            with transaction.atomic():  #atomic原子,下面的语句要么都成功,要么都不成功,这样就可以了,这就是事务,
                new_publisher = models.Publisher.objects.create(name="火星出版社")
                models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
        except Exception as e:
            print(str(e))

    ###############  Django终端打印SQL语句    ################

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }

    ###############    在Python脚本中调用Django环境    ################

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
        import django
        django.setup()
    
        from app01 import models
    
        books = models.Book.objects.all()
        print(books)

    ###############    执行原生sql   ################

    if __name__ == "__main__":
        import os, django
    
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ORM.settings")
        django.setup()
        from app01 import models
    
        # 在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询。
        # Django 提供两种方法使用原始SQL进行查询:
        # 一种是使用raw()方法,进行原始SQL查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。
    
    
        # 执行原生查询
        for p in models.Publish.objects.raw('SELECT * FROM app01_publish'):
            print(p)
        # raw()查询可以查询其他表的数据。
        for p in models.Publish.objects.raw('SELECT nid,name FROM app01_author'):
            print(p.nid,p.name)
    
        # raw()方法自动将查询字段映射到模型字段。
        # 还可以通过translations参数指定一个把查询的字段名和ORM对象实例的字段名互相对应的字典
        d = {'name': 'sname'}
        for p in models.Publish.objects.raw('SELECT * FROM app01_author', translations=d):
            print(p.nid,p.sname)
    
        # 原生SQL还可以使用参数,注意不要自己使用字符串格式化拼接SQL语句,防止SQL注入!
        d = {'name': 'sname'}
        ret = models.Publish.objects.raw('select * from app01_publish where nid > %s', translations=d, params=[1, ])
        for p in ret:
            print(p.nid,p.sname)
    
        # 直接执行自定义SQL
        # 有时候raw()方法并不十分好用,很多情况下我们不需要将查询结果映射成模型
        # 我们可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库。
        from django.db import connection, connections
        cursor = connection.cursor()  # cursor = connections['default'].cursor()
        cursor.execute("""SELECT * from app01_publish where nid = %s""", [1])
        ret = cursor.fetchone()
    
        print(ret)

    ###############    ORM进阶    ################

    django中怎么写原生SQL
    
    列举django orm中三种能写sql语句的方法
    
    1,使用extra:查询人民邮电出版社出版并且价格大于50元的书籍
    Book.objects.filter(publisher__name='人民邮电出版社').extra(where=['price>50']) 
    
    2,使用raw
    books=Book.objects.raw('select * from hello_book')  
    for book in books:  
       print(book)  
    
    3,自定义sql
    from django.db import connection  
      
    cursor = connection.cursor()  
    cursor.execute("insert into hello_author(name) VALUES ('郭敬明')")  
    cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")  
    cursor.execute("delete from hello_author where name='韩寒'")  
    cursor.execute("select * from hello_author")  
    cursor.fetchone()  
    cursor.fetchall() 

    ###############    ORM进阶    ################

    如何使用django orm批量创建数据
    使用django.db.models.query.QuerySet.bulk_create()批量创建对象,减少SQL查询次数。改进如下: querysetlist
    =[] for i in resultlist: querysetlist.append(Account(name=i)) Account.objects.bulk_create(querysetlist)

    ###############    ORM进阶    ################

     Django 三种模型继承:

    一 抽象类继承
    父类继承来自model.Model, 但不会在底层数据库生成相应的数据表,父类的属性列存储在其子类的数据表中
    作用:
    多个表若有相同的字段时,可以将这些字段统一定义在抽象类中,可以避免重复录入信息,
    要求:
    class BaseModel(models.Model):
     
        creat_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
        update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
        is_delete = models.BooleanField(default=False, verbose_name="是否删除")
     
        class Meta:
            abstract = True

    二 多表继承 每个模型类都会在底层数据库中生成相应的数据表管理数据 父类中的字段不会重复地在对个子类相关的数据表中进行定义
    from django import models class MessageBase(models.Model): id = models.AutoField() content = models.CharField(max_length=100) user_name= models.CharField(max_length=20) class Moment(MessageBase): headline = models.CharField(max_length=200) # Moment中包含的字段 id, headline # 子类可以直接引用父类定义的字段, 子类可以通过父类对象访问父类实例 三 代理模型继承 代理模型中子类只用于管理父类的数据,而不实际存储数据 使用原因: 子类中的新特性不会影响父类行为以及已有代码的行为 from django.db import models class Moment(models.Model): headline = models.CharField(max_length=200) user_name = models.CharField(max_legth=20) pub_date = models.DateField() class OrderedMoment(Moment): class Meta: proxy = True # 是否为代理模型 ordering = ["-pub_date"] #默认排序

    ###############    ORM进阶    ################

    selected_related与prefetch_related有什么区别?
    
    在Django中,所有的Queryset都是惰性的,意思是当创建一个查询集的时候,并没有跟数据库发生任何交互。
    
    因此我们可以对查询集进行级联的filter等操作,只有在访问Queryset的内容的时候,Django才会真正进行数据库的访问。
    
    而多频率、复杂的数据库查询往往是性能问题最大的根源。
    
    不过我们实际开发中,往往需要访问到外键对象的其他属性。如果按照默认的查询方式去遍历取值,那么会造成多次的数据库查询,效率可想而知。
        
    在查询对象集合的时候,把指定的外键对象也一并完整查询加载,避免后续的重复查询。
     
    1,select_related适用于外键和多对一的关系查询;
    2,prefetch_related适用于一对多或者多对多的查询。

    ###############    ORM进阶    ################


    ###############    ORM进阶    ################


    ###############    ORM进阶    ################


    ###############    ORM进阶    ################

  • 相关阅读:
    ASP.NET CORE 使用Consul实现服务治理与健康检查(2)——源码篇
    ASP.NET CORE 使用Consul实现服务治理与健康检查(1)——概念篇
    Asp.Net Core 单元测试正确姿势
    如何通过 Docker 部署 Logstash 同步 Mysql 数据库数据到 ElasticSearch
    Asp.Net Core2.2 源码阅读系列——控制台日志源码解析
    使用VS Code 开发.NET CORE 程序指南
    .NetCore下ES查询驱动 PlainElastic .Net 升级官方驱动 Elasticsearch .Net
    重新认识 async/await 语法糖
    EF添加
    EF修改部分字段
  • 原文地址:https://www.cnblogs.com/andy0816/p/12302026.html
Copyright © 2011-2022 走看看