Django之模型层

orm常用的字段

AutoField
这个字段是代表我键的这个字段是自增的,而且里面必须要填priamry_key=True这个参数

CharField
这个就等于数据库里面的varchar()但它里面必须要填max_length这个参数来标识字符长度

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

DateField日期字段,里面有可以放参数,其中auto_now代表的是只要操作数据,其时间也会跟着变,auto_now_add代表的是只有创建的时候,才会创建时间,后面怎么改记录,时间都不会变,一般都是auto_now_add

DecimalField()可以控制小数的,max_digits表示总共几位,decimal_places=表示小数占几位

字段中的参数

null 表示这个字段可以为空
unique  如果设置为true就跟数据库中一样,表示唯一
db_index   为true表示为该字段设置索引
default 设置默认值

DateField和DateTimeField

auto_now  表示数据修改,我的时间也会跟着修改
auto_now_add 表示只有数据在创建的时候,我的时间也会跟着创建,但后面数据怎么修改,我都不会变

关系字段ForeignKey

to 设置要关联的表
to_field 设置要建立的外键字段,不填,默认是和关联的表的主键建立外键字段

on_delete  表示当删除表中的数据的时候,其和关联的表的行为

on_constranit 是否在数据库中创建外键约束,默认是true

一对一

OnetoOneField

 

多对多

ManyToManyField

单表的增删改查

1.单表操作
create_time = models.DateField()
关键性的参数
1.auto_now:每次操作数据 都会自动刷新当前操作的时间
2.auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段

在django中我们可以自定义一个测试文件,在里面写测试脚本,不需要再视图操作模型表那么麻烦了

 

 这样就可以直接运行你的test.py文件来运行测试

必知必会13条

all()查询出所有

 

 filter(**kwargs):包含了所有与筛选条件匹配的对象,就是一个列表里面套对象,没有就是一个空

 

 get是只获取一个也是对象本身,如果没有则会报错

 

 

exclude(**kwargs):取反,它包含了所有与筛选条件不匹配的内容

 

 values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列

 

 

values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

 

 

order_by(*field): 对查询结果排序

 

reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。

 

distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

first()表示返回匹配懂啊的第一个记录

 

last表示返回匹配到的最后一个记录

count(): 返回数据库中匹配查询(QuerySet)的对象数量。

 

 

exists(): 如果QuerySet包含数据,就返回True,否则返回False

总结:

返回queryset对象的有:

all()

filter()

exclude()

order_by()

reverse()

distinct()

特殊的queryset

value返回是一个字典序列

value_list返回是一个元祖序列

返回具体对象

get()

first()

last()

布尔值

exists()

返回数字的方法有

count()

Django打印sql语句有2种方式

一种是有约束的,就是queryset对象可以通过query这个方法查看相对应的sql语句

第二种是无限制的,只要你执行了表的语句,都会打印相应的sql语句,就是在settings中配置一下,具体如下:

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

 神奇的双下划线用法:

原本我们查找是这样的
models.User.objects.filer(age=10)
现在我要求大于20的怎么弄呢,不能>,当有这种特殊的需求的时候,就要用到双下划线了
__gt 大于
__lt 小于
__gte 大于等于
__lte 小于等于

__in  代表在不在里面,一个集合

__range 是什么到什么的关系,也就是一个闭区间

模糊查询,也就是判断包含不包含
__contains 这个识别大写小写
__icontains 这个忽略大小写

—startswith这个判断以什么开头

__endswith 这个是以什么结尾

__year  按年查询

多表查询

一对多字段的增删改查

增:
publish_id传数字
models.Book.objects.create(title='三国演义',price=189.99,publish_id=1)
publish直接传出版社对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj)

改

传数字的
 models.Book.objects.filter(pk=1).update(publish_id=3)
传对象的
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)


删除
models.Publish.objects.filter(pk=2).delete()  # 默认都是级联更新 级联删除

多对多增删改查

前提都是将要给增删改查的对象先找出来,然后再对象点那个虚拟字段后面跟方法来完成增删改查。
增

book_obj = models.Book.objects.filter(pk=1).first()

print(book_obj.authors)  # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
book_obj.authors.add(1)
book_obj.authors.add(2,3)  支持多个传参
还支持弄对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2)
小结:
add()
 是给书籍添加作者  括号内既可以传数字也可以传对象
并且支持一次性传多个  逗号隔开即可
改

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,])
book_obj.authors.set([2,3])

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj,])
book_obj.authors.set([author_obj, author_obj1, author_obj2])
小结:
set()
括号内必须是一个可迭代对象,可迭代对象里面可以是数字,也可以是对象,但记着不要混合用

删除

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
 book_obj.authors.remove(1,2)
 author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
 book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1,author_obj2)
小结:
remove()即支持数字,也支持对象,也可以传多个
将关系全部清空用clear()即可
book_obj.authors.clear()不用传参

 

跨表查询(重点!!!)

正向查询和反向查询(重点!!!)

正向与方向的概念解释

一对一
正向:author---关联字段在author表里--->authordetail        按字段
反向:authordetail---关联字段在author表里--->author        按表名小写
 查询jason作者的手机号   正向查询
查询地址是 :山东 的作者名字   反向查询
  
一对多
正向:book---关联字段在book表里--->publish        按字段
 反向:publish---关联字段在book表里--->book        按表名小写_set.all() 因为一个出版社对应着多个图书

多对多
 正向:book---关联字段在book表里--->author        按字段
反向:author---关联字段在book表里--->book        按表名小写_set.all() 因为一个作者对应着多个图书

 

基于双下划线的跨表查询(连表查询,就不再2行代码了,而是一行了)

# 一对一
-连表查询
        -一对一双下划线查询
            -正向:按字段,跨表可以在filter,也可以在values中
            -反向:按表名小写,跨表可以在filter,也可以在values中
    # 查询jason作者的手机号   正向查询  跨表的话,按字段
    # ret=Author.objects.filter(name='jason').values('authordetail__phone')
    # 以authordetail作为基表 反向查询,按表名小写  跨表的话,用表名小写
    # ret=AuthorDetail.objects.filter(author__name='jason').values('phone')
    
    # 查询jason这个作者的性别和手机号
    # 正向
    # ret=Author.objects.filter(name='jason').values('sex','authordetail__phone')

    # 查询手机号是13888888的作者性别
    # ret=Author.objects.filter(authordetail__phone='13888888').values('sex')
    # ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex')
    
"""
总结 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可
比如:
    1.查询出版社为北方出版社的所有图书的名字和价格
    res1 = Publish.objects.filter(name='').values('book__name','book__price')
    res2 = Book.objects.filter(publish__name='').values('name','price')
    2.查询北方出版社出版的价格大于19的书
    res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)
"""

 

聚合查询

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}

分组查询

from django.db.models import Avg

res = models.Book.objects.annotate(别名=聚合函数).values(别名,其他内容)
values是获取某个表中的某个字段

 

F与Q查询

F查询就是通过数据库获取某个字段对应的值

from django.db.models import F
models.Book.objects.filter(priice=F(price)

 

Q查询就是修改查询的条件的。

from django.db.models import Q
res = models.Book.objects.filter(title='三国演义',price=444.44)  # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444))  如果用逗号 那么还是and关系
res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))

高级Q用法

q = Q()
q.connector = 'or'  # 修改查询条件的关系   默认是and
q.children.append(('title__contains','三国演义'))  # 往列表中添加筛选条件
q.children.append(('price__gt',444))  # 往列表中添加筛选条件
res = models.Book.objects.filter(q)  # filter支持你直接传q对象  但是默认还是and关系
print(res)

 自定义Char字段

       class MyChar(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                                     

查询优化

only 和 defer


这2个都是查出来是一个列表套对象,但不一样的是,only如果获取的是括号内指定的字段,会直接获取,如果获取的不是指定的字段,那么会频繁的访问数据库。而defer则正好相反,如果获取的是指定的字段,那么会频繁的访问数据库,如果不是指定的字段则是会直接获取。



select_related  和 prefect_related

都是做连表操作的。

括号内都只能放外键字段,并且可以连续用__连外键字段,并且只支持一对多核一对一。
不同处:select_related这个是直接连表,而prefect_related则是现将这个外键字段对应的id值拿到,然后再用这个id值去另外关联的表中找到一一对应的值。

注意:orm中的语句操作,全部都是惰性查询,就是只有在真正需要这个数据的时候,才会去访问数据库,减少数据库的压力

事务

    from django.db import transaction
    
        with transaction.atomic():
            """数据库操作
            在该代码块中书写的操作 同属于一个事务
            """
            models.Book.objects.create()
            models.Publish.objects.create()
            # 添加书籍和出版社 就是同一个事务 要么一起成功要么一起失败
        print('出了 代码块 事务就结束')

 

posted @ 2019-09-18 21:34  帅气逼人23  阅读(188)  评论(0编辑  收藏  举报