模型层

建表

  class User(models.Model)
      name = models.CharField(max_length)
      age = models.InterField()
      register_time = models.DateField()  ## models.DateTimeField()
  针对DateField以及DateTimeField,有两个关键参数
  1.auto_now:每次操作数据的时候,该字段会自动将该字段时间更新
  2.auto_now_add:在创建数据的时候会自动将当前创建时间记录下来,之后只要不任伟的修改,就不会改变

数据库迁移

  python manage.py makemigrations
  python manage.py migrate

新增数据

  res = models.User.objects.create(name='lilli',age=18,register_time='2021/1/5')
  user_obj = models.User(name='',age=,register_time)
  user_obj.save()      

删除数据

  pk会自动查找到当前表的主键字段,指代的就是当前表的主键
  res = models.User.objects.filter(pk=2).delete()
  user_obj = models.User.objects.filter(pk=1).first().delete()

修改数据

  get方法返回的就是当前数据对象,但是该方法不推荐使用,一旦数据不存在,该方法会直接报错
  filter不会报错,而会返回一个空
  models.User.objects.filter(pk=4).update()
  user_obj = models.User.objects.get(pk=4)
  user_obj.name = ''

必知比会13条

  1.all()  # 查询所有
  2.filter()  # 带有过滤条件的查询
  3.get()  # 直接拿数据对象,但是条件不存在直接报错
  4.first()  # 拿queryset里面第一个元素
  5.last()  # 拿queryset里面最后一个元素
  6.values() # 可以指定获取的数据字段 select name,age from ...
  res = models.User.objects.values('name','age') # 可以看成列表套字典
  7.values_list() # 可以指定获取的数据字段 
  res = models.User.objects.values_list('name') # 可以看成列表套元组
  res.query # 查看内部封装的sql语句,上述查看sql语句的方式,只能用于queryset对象,只有queryset对象才能够点击query查看内部的sql语句
  8.distinct() # 去重,一定要一摸一样的数据,如果带有主键,那么肯定不一样,查询一定不要忽略主键
  res = models.User.objects.values('name','age').distinct()
  9.order_by()
  models.User.objects.order_by('age') # 默认升序
  models.User.objects.order_by('-age') # 字段前加-,降序
  10.reverse() # 反转的前提是,数据已经排序了
  11.count() # 统计当前数据的个数
  res = models.User.objects.count()
  12.exclude() # 排除什么在外
  res = models.User.objects.exclude(name='lili')
  13.exists() # 判断对象是否存在,返回的是布尔值
  res = models.User.objects.filter(pk=3).exists()

神奇的双下划线查询

  # 查询年龄大于35岁的数据
  res = models.User.objects.filter(age__gt=35)
  # 小于35
  res = models.User.objects.filter(age__lt=35)
  # 大于等于
  res = models.User.objects.filter(age__gte=35)
  # 小于等于
  res = models.User.objects.filter(age__lte=32)
  # 查询年龄18或者32或者40
  res = models.User.objects.filter(age__in=[18,32,40])
  # 年龄在18~40之间
  res = models.User.objects.filter(age__range=[18,40]) # 首尾兼顾
  # 查询出名字里含有n的数据,模糊查询
  res = models.User.objects.filter(name__contains='n')
  # 那么是否区分大小写呢?
  # 默认是区分大小写的
  res = models.User.objects.filter(name__icontains='p') # 忽略大小写
  # 以啥开头,结尾
  res = models.User.objects.filter(name__startwith='j')
  # 查询出注册时间2020年1月份的数据,按照年月日拿数据
  res = models.User.objects.filter(register_time__month='1')
  res = models.User.objects.filter(register_time__year='2020')
  res = models.User.objects.filter(register_time__day='1')

多表操作

  # 一对多的外键增删改查
  ## 增
  1.直接写实际字段 id
  models.Book.object.create(title='三国',price=123.23,publish_id=1)
  2.虚拟字段 对象
  publish_obj = models.Publish.objects.filter(pk=2).first()
  models.Book.objects.create(title='红楼',price=1111.11,publish=publish_obj)
  ## 删,默认级联的
  models.Publish.objects.filter(pk=1).delete()
  ## 修改,也可以传对象或者id
  models.Book.objects.filter(pk=1).update(publish_id=2)

  # 多对多的增删改查(就是在操作第三张关系表)
  ## 如何给书籍添加作者?
  book_obj = models.objects.filter(pk=1).first()
  book_obj.authors # 就类似于已经到了第三张关系表了
  book_obj.authors.add(1) # 给书籍id为1的书籍绑定一个主键值为1的作者
  book_obj.authors.add(2,3) # 可以添加多个对应值
  author_obj = models.objects.filter(pk=1).first()
  book_obj.authors.add(author_obj) # 还可以直接添加对象
  """
  add给第三张关系表添加数据,既可以传对象,也可以传值
  """
  ## 删除
  book_obj.authors.remove(2,3)
  book_obj.authors.remove(author_obj)
  """
  remove既可以传值,也可以传对象,并且也支持多个
  """
  ## 修改(set)
  book_obj.authors.set([1,3]) # 括号内必须为可迭代对象
  book_obj.authors.set([3,])
  book_obj.authors.set([author_obj,author_obj1])
  """
  set即可以传数字,也可以传对象,但必须在可迭代对象内
  先删除,后新增
  """
  ## 清空,在第三张关系表中清空某个书籍与作者的绑定关系
  book_obj.authors.clear()
  """
  clear不需要加任何参数
  """

正反向(非常重要)

  """
  正向:看外键字段在谁那儿,有谁开始查询,就是正向,外键字段如果不再我这,那么有我查你,就是反向
  """

多表查询

  """
  正向查询按字段
  反向查询按表名小写
	_set
	...
  """
  # 子查询(基于对象的跨表查询)
  查询书籍主键为1的出版社
  book_obj = models.Book.objects.filter(pl=1).first()
  书查出版社,正向
  publish_obj = book_obj.publish
  publish_obj.name

  查询书籍主键为1的作者,正向
  book_obj.authors # app01.Author.None
  book_obj.authors.all() # 拿到作者对象

  查询作者jason的电话号码,正向
  author_obj.author_detail.phone
  """
  在书写ORM语句的时候和写sql一样,不要一次写完,一步一步来
  正向查询结果如果为多个的时候需要加.all(),拿对象
  """

  查询东方出版社出版的书,反向
  publish_obj
  publish_obj.book_set.all() # 拿到出版社对应的所有的相关的书

  查询作者是jason写过的书,反向
  author_obj
  author_obj.book_set.all() # 拿到作者对应的相关的所有的书

  查询手机号为110的作者姓名
  author_detail_obj.author() # 直接拿到对应的作者
  """
  反向查询
  当你的查询结果可以有多个的时候,必须加_set.all()
  只有一个的时候,不需要加
  """

联表查询(基于双下划线的跨表查询)

  # 正向
  查询jason的手机号,正向
  res = models.Author.objects.filter(name='jason').values('author_detail__phone')
  查询书籍主键为1的出版社名称和书的名称,正向
  res = models.Book.objects.filter(pk=1).values('title','publish__name')
  查询书籍主键为1的作者姓名
  res = models.Book.objects.filter(pk=1).values('author__name')
  # 反向                            
  models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__name')  拿作者姓名是jsaon的作者详情
  models.Publish.objects.filter(book__id=1).values('name','book__title')
  models.Author.objects.filter(book_id=1).values('name')
  # 查询书籍主键是1的作者的手机号
  models.Book.objects.filter(pk=1).values('author__author_detail__phone')
  """
  只要掌握了正反向的概念,以及双下划线,你就可以无限制跨表查询
  """

聚合函数的使用

  先导入,只要和数据库相关的都在django.db.models里面,或者django.db
  如果不想聚合,需要aggregate
  from django.db.models import Max,Min,Sum,Count,Avg
  models.Book.objects.aggregate(Avg('price'))
  models.Book.objects.aggregate(Max('price'),Min('price'))

分组查询

  关键字:annotate
  """
  Mysql分组之后,默认只能获取到分组的依据,组内其他字段都无法直接截取了,严格模式 ONLY_FULL_GROUP
  """
  """
  ORM分组,关键字annotate
  """
  统计每一本书的作者个数 ------->按书来分组
  models.Book.objects.annotate() # models后面点什么就是按照什么分组
  models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')

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

  统计不止一个作者的图书
  models.Book.objects.annotate(author_num = Count('author')).filter('author_num'__gt=1).values('title','author_num')
  """
  只要你的ORM语句得出的结果还是一个queryset对象
  那么他就可以继续无限制的点queryset对象封装的方法
  """
  查询每个作者出的书的总价格
  models.Author.objects.annotate(sum_price = Sum('book__price')).values('name','sum_price')

  """
  如何按照指定的字段分组?
  models.Book.objects.values('price').annotate()
  如果查询分组查询报错的情况,你需要修改数据库严格模式,ONLY_FULL_GROUPBY
  """

F与Q查询

  F的功能可以帮助你直接获取列表中某个字段对应的数据
  for循环取值的意思吗
  查询卖出数量大于库存数量的书籍
  from django.db.models import F
  models.Book.objects.filter(maichu__gt=F('kucun'))

  将所有书的价格提升50块
  models.Book.objects.filter(price = F('price') + 50)

  将所有书的名称后面加上爆款两个字
  """
  在操作字符类型的数据的时候,F不能够直接做到字符串的拼接
  """
  from django.db.models.functions import Concat
  from django.db.models import Value
  models.Book.object.update(title=Concat(F('title'),Value('爆款')))


  # Q的功能可以
  查询卖出数大于100或者价格小于600的书籍
  from django.db.models import Q
  models.Book.objects.filter(Q(maichu__ge=100|price__lt=600)) # Q包裹,逗号分隔还是and关系;|是or关系;~是非关系
  """
  filter括号内多个参数是and关系
  """
  # Q的高阶用法,能够将查询条件的左边也变成字符串的形式
  q = Q()
  q.connector = 'or' # 将方式由and改成or
  q.children.append(('maichu__gt',100))
  q.children.append(('price__lt',600))
  models.Book.objects.filter(q) # 默认还是and关系     

django中如何开启事务

  """
  事务:acid(原子性、一致性、隔离性、持久性)
  """
  # 如何简单的开启事务
  from django.db import transaction
  with transaction.atomic():
	# sql语句
    # 在with内书写代码块内书写的所有ORM操作都属于统一个事务

ORM常用字段及参数

  AutoField:主键字段,primary_key=True必须指定
  CharField:字符串,verbose_name(字段注释),max_length(字段长度)
  IntegerField:int
  DecimalField:max_digits,decimal_places
  EmailField:varchar(254)
  DateField:auto_now(每次修改数据的时候都会更新),auto_now_add(只在创建的时候记录,之后不会修改了)

  BoolenaField:布尔值类型
  """
  改字段传布尔值,数据库里面存0或1
  """

  TextField:文本类型
  """
  该字段可以用来存大段内容(文章、博客……),没有字数限制
  """

  FileField:文件类型(字符类型)
  """
  upload_to='/data' 给该字段传一个文件对象,会自动将文件保存到/data目录下,然后将路径保存到路径中 
  """

  # 更多字段
  参考博客
  Dominic-Ji
  # django除了提供了很多字段类型之外,还支持自定义字段
  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({})'.format(self.max_length)
	
  myfield = MyCharField(max_length=10)

  # 参数
  unique = True
  ForeignKey(unique = True) ==== OneToOneField() # 在用ORM创建的时候会有一个提示信息
  db_index = True # 代表为此字段设置索引
  to_field = '' # 设置需要关联的字段,默认不写就是关联另外一张的主键字段
  on_delete # 级联行为

数据库查询优化(only与defer,select_related与prefetch_related)

  only与defer
  """
  ORM语句的特点:
惰性查询:如果仅仅只是书写了ORM语句,后面根本没有用到该语句所查询出来的参数,那么ORM会自动识别,只有使用到了才会走数据库
  """
  # 书籍表中所有书的名字
  orm + for循环
  # 想实现获取一个只有title字段的数据对象
  res = models.Book.objects.only('title') # 拿到的是对象
  for i in res:
      i.title # 点only括号内的字段,不会走数据库
      i.price # 点其余的字段,会重新走数据库查询;而all不需要


  res = models.Book.objects.defer('title') # 拿到的数据对象
  for i in res:
      i.price # 点其余的字段,不走数据库
      i.title # 点括号内的字段,走数据库
  """
  defer括号内的字段不再查询出来的对象里面
  only查询出来的对象里面只有括号内的字段
  """

  select_related与prefetch_related:与跨表操作有关
  res = models.Book.objects.all()
  for i in res:
      i.publish.name # 每循环一次,就要走一次数据库

  res = models.Book.objects.select_related('publish') # INNER JOIN
  """
  select_related会将book与publish连接起来,然后一次性将大表里面的所有数据全部封装给查询出来的对象
  这个时候无论是点击book表里的数据还是publish的数据都无需走数据库查询了

  select_related(只能放外键字段,一对一,一对多) 多对多关系不行
  """
  models.Book.objects.prefetch_related('publish') # 子查询
  """
  该方法内部原理就是子查询,然后将查询出来的结果封装给对象
  """

choice参数

  # 数据库设计的时候常用
  """
  针对某个可以列举完全的可能性字段,我们应该如可存储

  只要某个字段的可能性是可以列举完全的,那么一般情况下都会采用choices参数
  """
  比如:
  gender_choices = (
  (1,'男'),
      (2,'女')
  )
  gender = models.IntegerField(choices=gender_choices)
  """
  该字段存的还是数字,但是如果存的数字在gender_choices中,可以简单获取真正的内容
  存的时候,没有列举出来的数字也能存
  取的时候,
  只要是choices的字段,如果想要获取对应信息,get_xxx_display(),固定写法
  """
  # 这个参数使用场景非常多

多对多三种创建方式

  # 全自动:利用ORM自动帮我们创建第三张表
  models.ManyToManyField(to='')
  """
  优点:代码不需要写,方便,还支持ORM提到操作第三张关系表的方法
  不足之出:第三张关系表的扩展性极差(无法额外添加字段……)
  """
  # 纯手动
  自己创建第三张表,自己创建外键字段,自己关联相关表
  """
  优点:自定义关系,扩展性好
  不足之处:需要写的代码较多,不能够使用ORM提供的简单的方法
  """
  # 半自动
  # 还是需要手动创建表,外键字段
  # 并且,还需要再基表中,添加
  models.ManyToManyField(to='',through='第三张表',through_fields=('book','author'))
  """
  through_fields字段先后顺序
判断的本质:
	通过第三张表查询对应的表,需要用到哪个字段,就把哪个字段放在前面
	
  可以使用ORM的正反向查询,但是没法使用add,set,remove,clear这四个方法
  """
posted @ 2021-01-10 10:16  浮生一夜不知秋  阅读(61)  评论(0编辑  收藏  举报