• Django ORM 常用字段和参数


    1、常用字段

    AutoFiled

    int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。

    IntegerField

    一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

    CharField

    字符类型,必须提供max_length参数, max_length表示字符长度。

    这里需要知道的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段,下面我来自定义对应于数据库的char类型

    自定义char字段:
    
    from django.db import models
    
    class MyCharField(models.Field):
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super().__init__(max_length=max_length,*args, **kwargs)
        def db_type(self, connection):
            return 'char(%s)' % self.max_length
    
    class MyModel(models.Model):
        my_field = MyCharField(32)    
    

      

    DateField

    日期字段,日期格式  YYYY-MM-DD,相当于Python中的datetime.date()实例

    DateTimeField

    日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。

    2、字段参数

    null

           用于表示某个字段可以为空, null=True

    unique

      如果设置为unique=True 则该字段在此表中必须是唯一的 。

    db_index

      如果db_index=True 则代表着为此字段设置索引。

    default

      为该字段设置默认值

    1.3  DateFiled 和 DateTimeFiled 里的参数

    auto_now_add

      配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

    auto_now

           配置上auto_now=True,每次更新数据记录的时候会更新该字段。

    2、关系字段

    2.1 ForeignKey

    外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

    ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

     字段参数

    to : 设置要关联的表

    to_field : 设置要关联的表的字段

    on_delete : 当删除关联表中的数据时,当前表与其关联的行的行为。

    models.CASCADE : django  2.0 版本后必须加上后,删除关联数据,与之关联的数据也会被删除,在2.0以前,系统默认加上了

    db_constraint : 是否在数据库中创建外键约束,默认为True。

    2.2  OneToOneField

    通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

    字段参数:

    to : 设置要关联的表

    to_field : 设置要关联的字段

    on_delete : 当删除关联表的数据时,当前表与其关联的行为

    3、在app下的tests文件下进行运行测试,配置相关参数如下

    import os
    if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
    import django
    django.setup()
    from app01 import models # 这一句话必须在这下面导入

    4、对表数据的增删改

    新增
    
        基于create创建
        user_obj = models.User.objects.create(name='json',age=28,register_time='2019-6-6')
        print(user_obj.register_time)
        基于save创建
        user_obj = models.User(name='tank',age=10,register_time='2014-3-1')
        user_obj.save()
    
        from datetime import datetime
        ctime = datetime.now()
        models.User.objects.create(name='tank',age=22,register_time=ctime)
    
    修改
        方式一  基于对象
        user_obj = models.User.objects.filter(name='michael').first()
        # print(user_obj,type(user_obj))
        user_obj.age = 24
        user_obj.save()
        方式二 基于queryset
        models.User.objects.filter(name='egon').update(age=36)
    
    
    删除
        基于queryset
        models.User.objects.filter(name='tank').delete()
        基于对象
        user_obj = models.User.objects.filter(name='tank').first()
        user_obj.delete()
    增删改

    5、单表查询

    <1> all():                  查询所有结果
    <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> order_by(*field): 对查询结果排序('-id')/('price') <6> reverse(): 对查询结果反向排序 >>>前面要先有排序才能反向 <7> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <8> first(): 返回第一条记录 <9> last(): 返回最后一条记录 <10> exists(): 如果QuerySet包含数据,就返回True,否则返回False <11> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的是列表套字典 <12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <13> distinct(): 从返回结果中剔除重复纪录
      < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
        res = models.User.objects.exclude(name='cwj')    #queryset对象
    
    < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
        res= models.User.objects.order_by('age').reverse()
    
     < 7 > count(): 返回数据库中匹配查询(QuerySet)的对象数量。
        user_obj = models.User.objects.all().count()
    
     < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
        user_obj = models.User.objects.filter(name='michael').exists()
        print(user_obj,type(user_obj))  #True <class 'bool'>
    
        < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
        user_obj = models.User.objects.values('name')
        print(user_obj)  #<QuerySet [{'name': 'michael'}, {'name': 'egon'}, {'name': 'owen'}, {'name': 'mac'}, {'name': 'json'}]>
    
    
        < 12 > values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
        user_obj = models.User.objects.values_list('name')
        print(user_obj) #<QuerySet [('michael',), ('egon',), ('owen',), ('mac',), ('json',)]>
    
    
       < 13 > distinct(): 从返回结果中剔除重复纪录,去重的对象必须完全相同,即前面的返回值必须是一样的,与filter搭配没效果
        res = models.User.objects.values('name').distinct()
        print(res)
    例子
    6 单表查询的双下划线查询
    
       1、查询年龄大于28岁的用户
        res = models.User.objects.filter(age__gt=28)
        print(res)
    
        2、查询年龄年龄小于28岁的用户
        res = models.User.objects.filter(age__lt=28)
        print(res)
    
        3、查询年龄大于等于28岁的用户
        res = models.User.objects.filter(age__gte=28)
        print(res)
    
        4、查询年龄小于等于28岁的用户
        res = models.User.objects.filter(age__lte=28)
        print(res)
    
        5、查询年龄是36 16 18的用户
        res = models.User.objects.filter(age__in=[36 ,16 ,18])
    
        6、查询年龄在18到28的用户
        res = models.User.objects.filter(age__range=[18,28])
    
        7、查询名字中包含字母
        res = models.User.objects.filter(name__contains='E')
        print(res)
        在数据库sqlite里无法体现
        res = models.User.objects.filter(name__icontains='E')  无视大小写
        print(res)
    
        8、查询名字以m开头的用户
        res = models.User.objects.filter(name__startswith='m')
    
        9、查询名字以n结尾的用户
        res = models.User.objects.filter(name__endswith='n')
    
        10、查询注册时间是2018年的用户
        res = models.User.objects.filter(register_time__year= 2018)
        print(res)
    

     

     

    7、返回对象的总结
    
    返回QuerySet对象的方法有:
    all()
    
    filter()
    
    exclude()
    
    order_by()
    
    reverse()
    
    distinct()
    
    特殊的QuerySet
    
    values()       返回一个可迭代的字典序列
    
    values_list() 返回一个可迭代的元祖序列
    
    返回具体对象的
    get()
    
    first()
    
    last()
    
    返回布尔值的方法有:
    exists()
    
    返回数字的方法有:
    count()
    

      

    8、Django 终端打印SQL语句
    
    
    如果想知道对数据库进行操作时,Django内部到底是怎么执行它的sql语句时可以加下面的配置来查看
    
    在Django项目的settings.py文件中,复制粘贴如下代码:
    
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    
    
    配置好之后,再执行任何对数据库进行操作的语句时,会自动将Django执行的sql语句打印到pycharm终端上
    
    
    补充:除了配置外,还可以通过点.query 来查看查询语句!
    

      

    9、多表查询

    表与表之间的关系
    一对一(OneToOneField):一对一字段无论建在哪张关系表里面都可以,但是推荐建在查询频率比较高的那张表里面
    一对多(ForeignKey):一对多字段建在多的那一方
    多对多(ManyToManyField):多对多字段无论建在哪张关系表里面都可以,但是推荐建在查询频率比较高的那张表里面
    ps:如何判断表与表之间到底是什么关系
    换位思考
    A能不能有多个B
    B能不能有多个A

    多表查询的方法:
    
    create()
    
    创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。
    
    models.Author.objects.first().book_set.create(title="偷塔秘籍")
    上面这一句干了哪些事儿:
    1.由作者表中的一个对象跨到书籍比表
    2.新增名为偷塔秘籍的书籍并保存
    3.到作者与书籍的第三张表中新增两者之间的多对多关系并保存
    add()
    
    把指定的model对象添加到第三张关联表中。
    
    添加对象
    
    >>> author_objs = models.Author.objects.filter(id__lt=3)
    >>> models.Book.objects.first().authors.add(*author_objs)
    添加id
    
    >>> models.Book.objects.first().authors.add(*[1, 2])
    set()
    
    更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置
    
    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.set([2, 3])
    remove()
    
    从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)
    
    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.remove(3)
    clear()
    
    从关联对象集中移除一切对象。(移除所有与对象相关的关系信息)
    
    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.clear()
    
    #1、给书籍绑定与作者的关系
        # book_obj = models.Book.objects.filter(pk=2).first()
        # print(type(book_obj),book_obj)
        # book_obj.author.add(4)
    
        # author_obj = models.Author.objects.filter(pk=1).first()
        # author_obj1 = models.Author.objects.filter(pk=3).first()
        # book_obj = models.Book.objects.filter(pk=4).first()
        # # book_obj = models.Book.objects.filter(pk=1).first()
        # book_obj.author.add(author_obj,author_obj1)
        # # 添加关系 add:add支持传数字或对象,并且都可以传多个
    
    
    #2、修改书籍与作者之间的关系  可以传数字和对象,并且支持传多个  数据对应关系存在与否都无所谓
        # book_obj = models.Book.objects.filter(pk=3).first()
        # book_obj.author.set((2,))
        # set会将修改的数据id重新生成,之前的id被删除,但是会占位
        # book_obj = models.Book.objects.filter(pk=2).first()
        # author_obj = models.Author.objects.filter(pk=1).first()
        # author_obj1 = models.Author.objects.filter(pk=2).first()
        # book_obj.author.set((author_obj1,author_obj))
    
    
    # 3、删除书籍和作者的绑定关系 remove   建立在数据关系已存在的基础上
    #     book_obj = models.Book.objects.filter(pk=2).first()
    #     book_obj.author.remove(1)
    
        # book_obj = models.Book.objects.filter(pk=1).first()
        # author_list = models.Author.objects.all()
        # book_obj.author.remove(*author_list)  #需要将queryset打散
    
    
    #4、清空 清空的是你当前这个表记录对应的绑定关系
        # book_obj = models.Book.objects.filter(pk=4).first()
        # book_obj.author.clear()  #直接将与book的id 为4 所对应的author 全删除,更加果断!
    View Code
    多表查询:   即只要前者是正常的对象就可以继续查下去
    
      #1、地址为西湖的作者的书  反向再反向
        # author_obj = models.AuthorDetail.objects.filter(addr='西湖').first()
        # # print(author_obj.author.book_set.all())
        # print(type(author_obj))
        # print(type(author_obj.author))    #正向直接点是对象
        # print(type(author_obj.author.book_set))  #反向点是  多对多的对象
        # print(type(author_obj.author.book_set.all())) #加上all()是queryset对象
    
        # 2、查询书籍凡人修仙传的作者的地址      正向再正向
        # book_obj = models.Book.objects.filter(title='凡人修仙传').first()
        # print(book_obj.author.all().authordetail.addr)   涉及到对多的情况后无法继续查询
        # print(type(book_obj))  #book的对象
        # print(type(book_obj.author))  #多对多的对象
        # print(type(book_obj.publish)) #publish的对象
        # print(type(book_obj.author.all()))  #queryset的对象
    
        # 3、通过作者的地址查询出对应的书籍  反向在反向
        # author_obj = models.AuthorDetail.objects.filter(addr='西湖').first()
        # print(author_obj.author.book_set.all())
        # print(type(author_obj))    authordetail的对象
        # print(type(author_obj.author))  author的对象
        # print(type(author_obj.author.book_set)) 对多的对象
        # print(type(author_obj.author.book_set.all())) queryset对象
    
    基于双下划线查询
    
    #正向
        # 查询书籍为蜗居的出版社地址
        # res = models.Book.objects.filter(title='蜗居').values('publish__addr','price')
        # print(type(res))   <class 'django.db.models.query.QuerySet'>
        # print(res)  <QuerySet [{'publish__addr': '北京', 'price': Decimal('28.66')}]>
    
        #查询书籍为长征的作者的姓名,地址
        # res = models.Book.objects.filter(title='长征').values('author__name','author__authordetail__addr')
        # print(res)
    
        # book_obj = models.Book.objects.filter(title='长征').first()
        # print(book_obj.author.all().authordetail.addr)  #无法查询,对象点 适合两表查询
    
        #查询michael的家乡
        # res = models.Author.objects.filter(name='michael').values('authordetail__addr')
        # print(res)
    
    
        #反向
    
        # # 查询南方出版社出版的书名,书对应的作者
        # res = models.Publish.objects.filter(name='南方出版社').values('book__title','book__author__name')
        # print(res)
    
        # 不管正向还是方向,只要有联系,就可以找到,好用
    
        # 查询出版社为东方出版社的所有图书的名字和价格
        # res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price','book__author__authordetail_id')
        # print(res)
    
        # 查询东方出版社出版的价格大于400的书
        # res = models.Publish.objects.filter(name='东方出版社',book__price__gt=100).values('book__title')
        # print(res)
    

      

      

    10、聚合查询和分组查询
    
    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
    
    键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
    
    需要用到的内置函数,要先导入
    from django.db.models import Avg, Sum, Max, Min, Count
    
    
    聚合查询:
    示例:
    >>> from django.db.models import Avg, Sum, Max, Min, Count
    >>> models.Book.objects.all().aggregate(Avg("price"))
    {'price__avg': 13.233333}
    如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
    
    >>> models.Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 13.233333}
    如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
    
    >>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
    {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
    
    
    分组查询:
    示例:
    
    >> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
    >>> for obj in book_list:
    ...     print(obj.author_num)
    ...
    1
    示例2:统计出每个出版社买的最便宜的书的价格
    
    >>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
    >>> for obj in publisher_list:
    ...     print(obj.min_price)
    ...     
    9.90
    19.90
    方法二:
    
    >>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
    <QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>
    示例3:统计不止一个作者的图书
    
    >>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
    <QuerySet [<Book: 番茄物语>]>
    示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序
    
    >>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
    <QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>
    

     

       例子:

    # 统计每个出版社出版的书的平均价格
    # res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name', 'avg_price')
    # print(res)


    #统计每一本书的作者个数
    # res = models.Book.objects.annotate(count_num=Count('author')).values('title','count_num')
    # print(res)

    #统计每个出版社卖的zui最便宜的书的价格
    # res = models.Publish.objects.annotate(min=Min('book__price')).values('name','min')
    # print(res)

    #查询每个作者出的书的总价格
    # res = models.Author.objects.annotate(sum=Sum('book__price')).values('name','sum')
    # print(res)

      

     总结

    value里面的参数对应的是sql语句中的select要查找显示的字段,

    filter里面的参数相当于where或者having里面的筛选条件

    annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值

     

     

  • 相关阅读:
    在Lufylegend中如何设置bitmap或者sprite的缩放和旋转中心
    面试必备:文本框与按钮的最简组合
    JavaScript设计模式之策略模式(学习笔记)
    JavaScript设计模式之观察者模式(学习笔记)
    Canvas transform浅析
    JavaScript ArrayBuffer浅析
    IE8-下背景色半透明滤镜在jquery动画中失效问题记录
    JQuery__Tab实践
    memoization提升递归效率
    es6--箭头函数
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/11018570.html
Copyright © 2020-2023  润新知