Django基础四之测试环境和ORM查询

目录

1. 搭建测试环境

Django是一个整体,不能单独测试某一个.py文件,要想测试需要搭建测试环境。

1.1 测试环境搭建方法:

  1. 方法一:
  2. 在项目里创建一个py文件,名字随意起。在这个py文件里写:
  3. """
  4. 从manage.py里拷出来前四行有非注释的代码。
  5. import os
  6. import sys
  7. def main():
  8. """Run administrative tasks."""
  9. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day05templates.settings')
  10. # 然后增加两行固定代码:
  11. import django
  12. django.setup()
  13. # 下面是自己写的测试代码:
  14. from templateByValue import models
  15. res=models.Books.objects.all()
  16. print(res)
  17. if __name__ == '__main__':
  18. main()
  19. """
  20. 方法二:
  21. 使用pycharm
  22. pycharm ---> python Console

1.2 使用测试环境对数据库进行CURD

使用ORM向表插入数据时,一定要先插入没有主键的表,否则会报错。如果一定要先操作有主键的表,则要在settings.py里面的DATABASES增加取消主键检查的操作

  1. DATABASES = {
  2. 'default': {
  3. 'ENGINE'--->'django.db.backends.mysql',
  4. 'NAME'--->'orm',
  5. 'USER'--->'root',
  6. 'PASSWORD'--->'123456',
  7. 'HOST'--->'192.168.1.109',
  8. 'PORT'--->'3306',
  9. 'OPTIONS':{
  10. "init_command":"SET foreign_key_checks = 0;", # 取消主键检查
  11. },
  12. }
  13. }

测试环境:

  1. test.py:
  2. import os
  3. import sys
  4. def main():
  5. """Run administrative tasks."""
  6. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day06Library.settings')
  7. import django
  8. django.setup()
  9. from lib01 import models
  10. """1. 增加一条数据"""
  11. res = models.Book.objects.create(title='平凡的世界',price=30.9)
  12. """create 返回值是当前创建的数据对象"""
  13. print(res)
  14. """2. 查询全部"""
  15. res = models.Book.objects.all()
  16. """.query能打印出来对应的SQL语句"""
  17. print(res.query)
  18. """使用filter查询如果没有条件也是打印全部 """
  19. res = models.Book.objects.filter()
  20. """2.1 filter()过滤,返回一个query对象(filter里面可以设置多个参数,是AND的关系) """
  21. res = models.Book.objects.filter(id=1)
  22. """ .get和.filter()一样"""
  23. res = models.Book.objects.get(title='平凡的世界')
  24. """但是get如果没找到,则会报错"""
  25. print(type(gres))
  26. lib01.models.DoesNotExist: Book matching query does not exist.
  27. """"3. 修改"""
  28. """Pk能够自动查找 到当前表的主键字段,我们不需要查看当表主键字段名"""
  29. models.Book.objects.filter(pk=1).update(price=39)
  30. """4. 删除"""
  31. models.Book.objects.filter(pk=1).delete()
  32. """5 firstlast"""
  33. # 拿第一个
  34. res = models.Book.objects.all().first()
  35. print(res)
  36. # 拿最后一个
  37. res = models.Book.objects.all().last()
  38. print(res)
  39. # 还支持切片
  40. res = models.Book.objects.all().first()[0]
  41. """6. 只取指定的字段"""
  42. res = models.Book.objects.all().values('title')
  43. print(res) # 只取title字段
  44. # all()其实可加可不加。
  45. res = models.Book.objects.all().values_list('title')
  46. """values_list获取的结果,类似于列表套元组"""
  47. """
  48. order_by排序: 默认是升序,降序是加个减号(-)
  49. """
  50. res = models.Book.objects.order_by('price')# 升序
  51. res = models.Book.objects.order_by('-price')#降序
  52. """count()计数"""
  53. res = models.Book.objects.count()
  54. """distinct()去重
  55. 去重的前提是数据必须是一模一样,一定不能忽略主键
  56. """
  57. res = models.Book.objects.values('title').distinct()
  58. """ exclude() 排除"""
  59. res = models.Book.objects.exclude(title='平凡的世界')
  60. '''reverse() 反转
  61. reverse需要先排序之后再反转
  62. '''
  63. res = models.Book.objects.order_by('price').reverse()
  64. """exists() query包含数据返回True,否则返回False"""
  65. if __name__ == '__main__':
  66. main()

1.3 返回QuerySet对象的方法

all()

filter()

exclude()

order_by()

reverse()

distinct()

**特殊的QuerySet **

values() 返回可迭代的字典序列

values_list() 返回可迭代的元组序列

1.4 返回具体对象的方法

get()

first()

last()

1.5 返回布尔值的方法

exists()

1.6 返回数字的方法

count()

1.7 范围查找(双下划线查询)

  1. 1. 价格大于30的书籍:
  2. res = models.Book.objects.filter(price__gt=30)
  3. __gt 大于
  4. 2. 价格小于30的书籍:
  5. res = models.Book.objects.filter(price__lt=30)
  6. __lt小于
  7. 3. 价格大于等于30的书籍:
  8. res = models.Book.objects.filter(price__gte=30)
  9. __gte 大于等于
  10. 4. 价格小于等于30的书籍:
  11. res = models.Book.objects.filter(price__lte=30)
  12. __lte小于等于
  13. 5, 价格要么是10元,要么是20,要么是30
  14. res = models.Book.objects.filter(price__in=[10,20,30])
  15. """
  16. Python时面的数字类型精确度不高,很多时候会使用字符串存储数字类型,特别是小数,用的时候再从字符串转成小数
  17. """
  18. 6, 价格在10元到30元之间的
  19. res = models.Book.objects.filter(price__range=(10,30))
  20. 7, 查询书名包含字母a的书籍
  21. res = models.Book.objects.filter(title__contains='a')
  22. # 上面是区分大小写,如果忽略大小写:
  23. res = models.Book.objects.filter(title__icontains='a')
  24. 8, 以什么开头, 结尾:
  25. # 开头:
  26. res = models.Book.objects.filter(title__startswith='a')
  27. # 结尾:
  28. res = models.Book.objects.filter(title__endswith='a')
  29. 9 查询出版日期是2000年的书籍:
  30. res = models.Book.objects.filter(publish_time__year=2000)
  31. 10 查询出版日期是8月的书籍:
  32. res = models.Book.objects.filter(publish_time__month=8)

1.8 外键字段操作

  1. 外键字段
  2. # 直接传主键值
  3. """
  4. models.Book.objects.create(title='聊斋',price=666.98,publish_id=1)
  5. models.Book.objects.create(title='聊斋志异2',price=666.98,publish_id=2)
  6. """
  7. # 传数据对象
  8. """
  9. publish_obj = models.Publish.objects.filter(pk=1).first()
  10. models.Book.objects.create(title='神雕侠侣', price=234.56, publish=publish_obj)
  11. models.Book.objects.filter(pk=1).update(publish_id=2)
  12. models.Book.objects.filter(pk=3).update(publish=publish_obj)
  13. """
  14. 多对多外键字段
  15. # 增
  16. """
  17. book_obj = models.Book.objects.filter(pk=1).first()
  18. # 主键值
  19. book_obj.authors.add(1) # 去第三张关系表中 与作者主键为1的绑定关系
  20. # 作者对象
  21. author_obj = models.Author.objects.filter(pk=2).first()
  22. book_obj.authors.add(author_obj)
  23. # 括号内支持传多个参数
  24. book_obj.authors.add(1,2)
  25. author_obj1 = models.Author.objects.filter(pk=1).first()
  26. author_obj2 = models.Author.objects.filter(pk=2).first()
  27. book_obj.authors.add(author_obj1,author_obj2)
  28. # 改
  29. book_obj.authors.set([1,])
  30. book_obj.authors.set((1,2))
  31. book_obj.authors.set([author_obj1, ])
  32. book_obj.authors.set([author_obj1,author_obj2 ])
  33. # 删
  34. book_obj.authors.remove(1)
  35. book_obj.authors.remove(1,2)
  36. book_obj.authors.remove(author_obj1,author_obj2)
  37. # 清空
  38. book_obj.authors.clear() # 去第三张关系表中删除所有改书籍对应的记录
  39. """

总结:

  1. add()
  2. remove()
  3. 括号内既可以传数字也可以传对象 逗号隔开即可
  4. set()
  5. 括号内必须传递可迭代对象 可迭代对象内既可以传数字也可以传对象 支持多个
  6. clear()
  7. 清空操作 无需传值

2. 跨表查询

2.1 正向查询和反向查询

  1. 正向查询:
  2. 外键字段在谁哪,谁查另外的表就是正向
  3. 例如: 表和出版社表,外键在书表上,要查一本书对应的出版社就是正向查询
  4. 反正查询:
  5. 表中没有外键,它要去查是反向
  6. 例如: 作者表和作者详情表,作者表中只有id和作者姓名,作者详情表里有作者的电话,地址等。作者表中有外键。用作者的电话查对应的作者就是反射查询
  7. 查询技巧:
  8. 正向查询按外键字段
  9. 反向查询按表名小写加_set(如何出现:应用名.表名.None 则再加.all())
  10. 先查询出一个对象,然后基于对象再去找

2.2 基于对于的跨表查询(子查询)

  1. 正向查询:
  2. 1.查询《三重门》书籍对应的出版社名称
  3. book_obj = models.Book.objects.filter(b_name='三重门').first().publish
  4. res = book_obj.publish.p_name
  5. print(res)
  6. 2.查询《三重门》对应的作者
  7. book_obj = models.Book.objects.filter(b_name='三重门').first()
  8. res = book_obj.authors.first()
  9. print(res.a_name)
  10. 3.查询余华的地址
  11. author_obj = models.Author.objects.filter(a_name='余华').first()
  12. res = author_obj.authorDetail.a_address
  13. print(res)
  14. # 反向查询:
  15. 4.查询作家出版社出版过的书籍
  16. publish_obj = models.Publish.objects.filter(p_name='作家出版社').first()
  17. res = publish_obj.book_set.all()
  18. print(res)
  19. 5.查询莫言写过的书
  20. author_obj = models.Author.objects.filter(a_name='莫言').first()
  21. res = author_obj.book_set.all()
  22. print(res)
  23. 6.查询电话是0536123456的作者姓名
  24. author_obj = models.AuthorDetail.objects.filter(a_phone='0536123456').first()
  25. res = author_obj.author.a_name
  26. print(res)

2.3 双下划线跨表查询(连表查询)

  1. 正向查询:
  2. 1.查询《十三步书籍》对应的出版社名称
  3. res=models.Book.objects.filter(b_name='十三步').values('publish__p_name')
  4. print(res)
  5. 2.查询《活着》对应的作者和年龄
  6. res = models.Book.objects.filter(b_name='活着').values('authors__a_name','authors__a_age')
  7. print(res)
  8. 3.查询韩寒的地址
  9. res = models.Author.objects.filter(a_name='韩寒').values("authorDetail__a_address")
  10. print(res)
  11. 正向查询:
  12. 4.查询《许三观卖血记》书籍对应的出版社名称(不用model.BOOK)
  13. res = models.Publish.objects.filter(book__b_name='许三观卖血记').values("p_name")
  14. print(res)
  15. 5.查询《红高粱家族》对应的作者和年龄(不用model.BOOK)
  16. res = models.Author.objects.filter(book__b_name='红高粱家族').values('a_name','a_age')
  17. print(res)
  18. 6.查询莫言的地址(不用作者表)
  19. res = models.AuthorDetail.objects.filter(author__a_name='莫言').values("a_address")
  20. print(res)
  21. 7.查询《像少年啦飞驰》对应的作者的电话和地址
  22. res = models.Author.objects.filter(book__b_name='像少年啦飞驰').values('authorDetail__a_address','authorDetail__a_phone')
  23. print(res)
  24. 8. 查询价格为 50,25.5,或19.9的所有书籍和出版社名称 res=models.Book.objects.filter(b_price__in=(50,25.5,19.9)).values('b_name','publish__p_name')
  25. print(res)
  26. 9. 查询"作家出版社"出版的图书按价格从高到低排序
  27. res = models.Publish.objects.filter(p_name='作家出版社').values('book__b_name', 'book__b_price').order_by('-book__b_price')
  28. print(res)

3. 聚合查询

聚合函数

  1. sum()
  2. max()
  3. min()
  4. count()
  5. avg()

聚合函数的使用

  1. 1. 计算全部图书的平均价格
  2. from django.db.models import Sum, Max, Min, Avg, Count
  3. res = models.Book.objects.all().aggregate(Avg('b_price'))
  4. print(res)
  5. 2. 全部图书中价格最高的:
  6. from django.db.models import Sum, Max, Min, Avg, Count
  7. res = models.Book.objects.all().aggregate(Max('b_price'))
  8. print(res)
  9. 3. 全部图书中价格总价格:
  10. from django.db.models import Sum, Max, Min, Avg, Count
  11. res = models.Book.objects.all().aggregate(Sum('b_price'))
  12. print(res)
  13. 3. 全部图书中价格最低的:
  14. from django.db.models import Sum, Max, Min, Avg, Count
  15. res = models.Book.objects.all().aggregate(Min('b_price'))
  16. print(res)
  17. 4. 全部图书的数量:
  18. from django.db.models import Sum, Max, Min, Avg, Count
  19. res = models.Book.objects.all().aggregate(Count('b_price'))
  20. print(res)
  21. 5. 韩寒出版图书的总价格:
  22. from django.db.models import Sum, Max, Min, Avg, Count
  23. res = models.Author.objects.filter(a_name='韩寒').values('book__b_price').aggregate(Sum('book__b_price'))
  24. print(res)
  25. 6.作家出版社中出版的价格最高的图书
  26. from django.db.models import Sum, Max, Min, Avg, Count
  27. res = models.Publish.objects.filter(p_name='作家出版社').values('book__b_name').aggregate(Max('book__b_price'))
  28. print(res)
  29. 7. 聚合函数结果重命名:
  30. res = models.Book.objects.all().aggregate(boo_sum = Sum('b_price'))
  31. print(res)
  32. 也可以把多个聚合函数放在一起:
  33. 计算图书的总价格和平均价格
  34. res = models.Book.objects.all().aggregate(boo_sum = Sum('b_price'),book_avg =Avg('b_price'))
  35. print(res)

4. F查询和Q查询

4.1 F查询

F查询就是取出某个字段对应的值

  1. # 找出阅读书比评论数高的书籍
  2. from django.db.models import F
  3. res = models.Book.objects.filter(read_number__gt=F('commit_number'))
  4. print(res)
  5. # 给每本书的价格都加1元
  6. from django.db.models import F
  7. res = models.Book.objects.all().update(b_price=F("b_price")+1)
  8. print(res)

4.2 Q查询

Q查询就是构造出 与&或|非~

默认情况下在filter()里面的关系为and 与的关系,要想表示或和非就要用Q查询

  1. # 查询书名为<活着>或价格大于40的书籍
  2. from django.db.models import Q
  3. res = models.Book.objects.filter(Q(b_name='活着')|Q(b_price__gt=40))
  4. print(res)
  5. # 查询书名不是<活着>的书籍
  6. from django.db.models import Q
  7. res=models.Book.objects.filter(~Q(b_name='活着'))
  8. print(res)

4.3 查看原生SQL

  1. 1. Queryset对象.query()
  2. 2. settings.py里面配置日志打印:
  3. settings.py:
  4. LOGGING = {
  5. 'version': 1,
  6. 'disable_existing_loggers': False,
  7. 'handlers': {
  8. 'console':{
  9. 'level':'DEBUG',
  10. 'class':'logging.StreamHandler',
  11. },
  12. },
  13. 'loggers': {
  14. 'django.db.backends': {
  15. 'handlers': ['console'],
  16. 'propagate': True,
  17. 'level':'DEBUG',
  18. },
  19. }
  20. }

5. 聚合分组

  1. 1. 查询每个出版社id,以及它所出版书的平均价格:
  2. 原生SQL
  3. SELECT publish_id,AVG(b_price) from lib01_book GROUP BY publish_id;
  4. ORM实现:
  5. """
  6. annotate()内写聚合函数
  7. values 在前,表示 group by 的字段
  8. values 在后,表示取字段
  9. filter 在前, 表示 where条件
  10. filter 在后,表示having
  11. from django.db.models import Sum, Max, Min, Avg, Count
  12. res = models.Book.objects.all().values('publish_id').annotate(price_avg = Avg('b_price')).values('publish_id','price_avg')
  13. print(res.query)
  14. """
  15. 2. 查询出版社id大于1的出版社ID,以及所出书的平均价格
  16. 原生SQL
  17. """
  18. select publish_id, avg(b_price) from lib01_book where publish_id >1 GROUP BY publish_id;
  19. """
  20. ORM实现:
  21. """
  22. from django.db.models import Sum, Max, Min, Avg, Count res=models.Book.objects.filter(publish_id__gt=1).values('publish_id').annotate(price_avg=Avg('b_price')).values('publish_id', 'price_avg')
  23. print(res)
  24. """
  25. 3. 查询出版社id大于1的出版社ID,以及所出书的平均价格大于30
  26. 原生SQL
  27. """
  28. select publish_id, avg(b_price) as price_avg from lib01_book where publish_id >1 GROUP BY publish_id having price_avg>30 ;
  29. """
  30. ORM实现:
  31. """
  32. from django.db.models import Sum, Max, Min, Avg, Count res=models.Book.objects.filter(publish_id__gt=1).values('publish_id').annotate(price_avg=Avg('b_price')).filter(price_avg__gt=30).values('publish_id', 'price_avg')
  33. print(res)
  34. """
  35. 4,查询每个出版社的名字和出版的书籍数量
  36. 原生SQL:
  37. """
  38. select p_name, count(b.b_name) from lib01_publish p, lib01_book b where p.id=b.publish_id group by p.id ;
  39. """
  40. ORM:
  41. """
  42. 联表操作最后以group by的表作为基表
  43. from django.db.models import Sum, Max, Min, Avg, Count
  44. res = models.Publish.objects.values('id').annotate(num=Count('book__id')).values('p_name','num')
  45. print(res.query)
  46. 如果基表是group by的表,可以不写values
  47. models.Publish.objects.annotate(num=Count('book__id')).values('p_name','num')
  48. """
  49. 5. 查询每个作者出版过书籍的最高价格,打印作者名和最高价格
  50. 原生SQL:
  51. """
  52. select a.a_name, max(b.b_price) from lib01_author a, lib01_book b, lib01_book_authors ba where b.id=ba.book_id and a.id = ba.author_id group by a.a_name;
  53. """
  54. ORM:
  55. """
  56. from django.db.models import Sum, Max, Min, Avg, Count
  57. res = models.Author.objects.annotate(price_max=Max('book__b_price')).values('a_name', 'price_max')
  58. print(res)
  59. """
  60. 6. 查询每个书籍的名称,以及对应的作者个数
  61. 原生SQL:
  62. """
  63. select a.b_name, count(b.a_name) from lib01_book a, lib01_author b, lib01_book_authors c where a.id=c.book_id and b.id= c.author_id group by a.b_name;
  64. """
  65. ORM:
  66. """
  67. from django.db.models import Sum, Max, Min, Avg, Count res=models.Book.objects.values('b_name').annotate(author_count=Count('authors__id')).values('b_name', 'author_count')
  68. print(res)
  69. """
  70. 7. 统计价格大于25书籍和作者
  71. 原生SQL:
  72. """
  73. select a.b_name, c.a_name from lib01_book a inner join lib01_book_authors b on a.id=b.book_id inner join lib01_author c on c.id=b.author_id where a.b_price >25;
  74. """
  75. ORM
  76. """
  77. res = models.Book.objects.filter(b_price__gt=25).values('b_name','authors__a_name')
  78. print(res.query)
  79. """

6. 事务

Django 默认的事务行为是自动提交。

  1. 测试test.py:
  2. import os
  3. def main():
  4. """Run administrative tasks."""
  5. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day06Library.settings')
  6. import django
  7. django.setup()
  8. from lib01 import models
  9. res = models.Book.objects.filter(pk=3).first()
  10. print(res.b_name, res.b_price)
  11. from django.db import transaction
  12. try:
  13. with transaction.atomic(): # 开启事务
  14. models.Book.objects.filter(pk=3).update(b_price=50)
  15. res = models.Book.objects.filter(pk=3).first()
  16. print(res.b_name, res.b_price)
  17. raise Exception("Error")
  18. # 其实如果开启了事务,那么只要报错这个事务就会回滚,使用try....except只是不让程序报错退出
  19. except Exception as e:
  20. print("回滚")
  21. transaction.rollback() # 事务回滚
  22. print("回滚成功")
  23. res = models.Book.objects.filter(pk=3).first()
  24. print(res.b_name, res.b_price)
  25. if __name__ == '__main__':
  26. main()
  27. 开启事务:
  28. 使用装饰器
  29. from django.db import transaction
  30. @transaction.atomic
  31. def viewfunc(request):
  32. # This code executes inside a transaction.
  33. do_stuff()
  34. 使用上下文件管理
  35. from django.db import transaction
  36. def viewfunc(request):
  37. # This code executes in autocommit mode (Django's default).
  38. do_stuff()
  39. with transaction.atomic():
  40. # This code executes inside a transaction.
  41. do_more_stuff()

Django事务详情

7. choices参数

  1. 例如一张表要存储学生成绩,'A''优秀''B''良好','C''及格','D''不及格',如果查询为A则打印优秀,查询D打印不及格。
  2. 方法一:
  3. 查询出来后自己写代码判断输出。】
  4. 方法二:
  5. 1. 在数据库里创建表时使用choices参数
  6. models.py创建表:
  7. class Score(models.Model):
  8. score_choices = (
  9. ('A', '优秀'),
  10. ('B', '良好'),
  11. ('C', '及格'),
  12. ('D', '不及格'),
  13. )
  14. name = models.CharField(max_length=128)
  15. score = models.CharField(max_length=12,choices=score_choices)
  16. 2.插入数据
  17. 3.查询:
  18. res = models.Score.objects.filter(pk=1).first()
  19. print(res.name, res.score)
  20. # 结果为: Z A
  21. res = models.Score.objects.filter(pk=1).first()
  22. print(res.name, res.get_score_display())
  23. # 结果为: Z 优秀

总结:

1.传值:

  1. 对于choices参数,数据类型该怎么选?
  2. 判断依据是:小元组里面第一个参数的数据类型

2.取值:

  1. 固定语法结构取值:get_字段名_display()
  2. 如果查询出来的数据不再choices范围内,会显示原始数据。

8. 常用字段

8.1 常用字段

  1. AutoField(Field)
  2. int自增列,必须填入参数 primary_key=True
  3. BigAutoField(AutoField)
  4. bigint自增列,必须填入参数 primary_key=True
  5. model中如果没有自增列,则自动会创建一个列名为id的列
  6. IntegerField
  7. 一个整数类型(有符号的),范围在 -2147483648 to 2147483647
  8. SmallIntegerField(IntegerField):
  9. 小整数 -32768 32767
  10. PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
  11. 正小整数 0 32767
  12. PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
  13. - 正整数 0 2147483647
  14. BigIntegerField(IntegerField):
  15. 长整型(有符号的) -9223372036854775808 9223372036854775807
  16. BooleanField(Field)
  17. 布尔值类型
  18. NullBooleanField(Field):
  19. 可以为空的布尔值
  20. CharField(Field)
  21. 字符类型
  22. 必须提供max_length参数, max_length表示字符长度
  23. TextField(Field)
  24. 文本类型
  25. EmailField(CharField):
  26. 字符串类型(Email),Django Admin以及ModelForm中提供验证机制
  27. IPAddressField(Field)
  28. 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
  29. GenericIPAddressField(Field)
  30. 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4Ipv6
  31. 参数:
  32. protocol,用于指定Ipv4Ipv6 'both',"ipv4","ipv6"
  33. unpack_ipv4 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
  34. URLField(CharField)
  35. 字符串类型,Django Admin以及ModelForm中提供验证 URL
  36. SlugField(CharField)
  37. 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
  38. CommaSeparatedIntegerField(CharField)
  39. 字符串类型,格式必须为逗号分割的数字
  40. UUIDField(Field)
  41. 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
  42. FilePathField(Field)
  43. 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
  44. 参数:
  45. path, 文件夹路径
  46. match=None, 正则匹配
  47. recursive=False, 递归下面的文件夹
  48. allow_files=True, 允许文件
  49. allow_folders=False, 允许文件夹
  50. FileField(Field)
  51. 字符串,路径保存在数据库,文件上传到指定目录
  52. 参数:
  53. upload_to = "" 上传文件的保存路径
  54. storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
  55. ImageField(FileField)
  56. 字符串,路径保存在数据库,文件上传到指定目录
  57. 参数:
  58. upload_to = "" 上传文件的保存路径
  59. storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
  60. width_field=None, 上传图片的高度保存的数据库字段名(字符串)
  61. height_field=None 上传图片的宽度保存的数据库字段名(字符串)
  62. DurationField(Field)
  63. 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
  64. FloatField(Field)
  65. 浮点型
  66. DecimalField(Field)
  67. 10进制小数
  68. 参数:
  69. max_digits,小数总长度
  70. decimal_places,小数位长度
  71. BinaryField(Field)
  72. 二进制类型
  73. DateField
  74. 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
  75. DateTimeField
  76. 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例

8.2 ORM与MySQL中对应关系

  1. 'AutoField' ---> 'integer AUTO_INCREMENT',
  2. 'BigAutoField' ---> 'bigint AUTO_INCREMENT',
  3. 'BinaryField' ---> 'longblob',
  4. 'BooleanField' ---> 'bool',
  5. 'CharField' ---> 'varchar(%(max_length)s)',
  6. 'CommaSeparatedIntegerField'--->'varchar(%(max_length)s)',
  7. 'DateField' ---> 'date',
  8. 'DateTimeField' ---> 'datetime',
  9. 'DecimalField' ---> 'numeric(%(max_digits)s, %(decimal_places)s)',
  10. 'DurationField' ---> 'bigint',
  11. 'FileField' ---> 'varchar(%(max_length)s)',
  12. 'FilePathField' ---> 'varchar(%(max_length)s)',
  13. 'FloatField' ---> 'double precision',
  14. 'IntegerField' ---> 'integer',
  15. 'BigIntegerField'--->'bigint',
  16. 'IPAddressField'---> 'char(15)',
  17. 'GenericIPAddressField'--->'char(39)',
  18. 'NullBooleanField'---> 'bool',
  19. 'OneToOneField' ---> 'integer',
  20. 'PositiveIntegerField'---> 'integer UNSIGNED',
  21. 'PositiveSmallIntegerField'---> 'smallint UNSIGNED',
  22. 'SlugField' ---> 'varchar(%(max_length)s)',
  23. 'SmallIntegerField'---> 'smallint',
  24. 'TextField' ---> 'longtext',
  25. 'TimeField' ---> 'time',
  26. 'UUIDField' ---> 'char(32)',

8.3 关系字段

8.3.1 ForeignKey

  1. 外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 ‘一对多’中’多’的一方。
  2. ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
  3. to 设置要关联的表
  4. to_field 设置要关联的表的字段
  5. related_name 反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’。
  6. 例如要查某个作者写了哪些书:
  7. models.Author.objects.filter(name='xx').book_set.all()
  8. 当在ForeignKey字段中添加了参数 related_name 后,
  9. class Book(models.Model):
  10. name = models.CharField(max_length=32)
  11. Author = models.ForeignKey(to="author", related_name="book_author")
  12. 再查某个作者的书籍是:
  13. models.Author.objects.filter(name='xx').book__author.all()
  14. related_query_name 反向查询操作时,使用的连接前缀,用于替换表名。
  15. on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。(1.x版本中不用写,2.x 3.x版本必须指定)
  16. """
  17. models.CASCADE
  18.   删除关联数据,与之关联也删除
  19.   models.DO_NOTHING
  20.   删除关联数据,什么都不做
  21.   models.PROTECT
  22.   删除关联数据,引发错误ProtectedError
  23.   models.SET_NULL
  24.   删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
  25.   models.SET_DEFAULT
  26.   删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
  27.   models.SET
  28.   删除关联数据,
  29.   a. 与之关联的值设置为指定值,设置:models.SET(值)
  30.   b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
  31. """
  32. db_constraint 是否在数据库中创建外键约束,默认为True

8.3.2 OneToOneField

  1. 一对一字段。
  2. 一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。例如作者表和作者详情表。
  3. to 设置要关联的表。
  4. to_field 设置要关联的字段。
  5. on_delete ForeignKey字段。

8.3.3 ManyToManyField

  1. 用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系
  2. to 设置要关联的表
  3. related_name ForeignKey字段。
  4. related_query_name ForeignKey字段。
  5. symmetrical 仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True
  6. through 在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。
  7. 但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名。
  8. through_fields 设置关联的字段。
  9. db_table 默认创建第三张表时,数据库中表的名称。

9. 多对多关系中第三张表的创建方式

9.1 自行创建第三张表

  1. class Book(models.Model):
  2. title = models.CharField(max_length=32, verbose_name="书名")
  3. class Author(models.Model):
  4. name = models.CharField(max_length=32, verbose_name="作者姓名")
  5. # 自己创建第三张表,分别通过外键关联书和作者
  6. class Book2Author(models.Model):
  7. book = models.ForeignKey(to="Book")
  8. author = models.ForeignKey(to="Author")
  9. class Meta:
  10. unique_together = ("book","author" )

9.2 通过ManyToManyField自动创建第三张表

  1. 之前一直使用的方法
  2. class Book(models.Model):
  3. title = models.CharField(max_length=32, verbose_name="书名")
  4. Authors = models.ManyToManyField(to="Author", related_name="book2authors")
  5. # 通过ORM自带的ManyToManyField自动创建第三张表
  6. class Author(models.Model):
  7. name = models.CharField(max_length=32, verbose_name="作者姓名")

9.3 设置ManyTomanyField并指定自行创建的第三张表

  1. # 自己创建第三张表,并通过ManyToManyField指定关联
  2. class Book(models.Model):
  3. title = models.CharField(max_length=32, verbose_name="书名")
  4. authors = models.ManyToManyField(to="Author", through="Book2Author", through_fields=("book", "author"))
  5. # through_fields接受一个2元组('field1','field2'):
  6. # 其中field1是定义ManyToManyField的模型外键的名(book),field2是关联目标模型(author)的外键名。
  7. class Author(models.Model):
  8. name = models.CharField(max_length=32, verbose_name="作者姓名")
  9. class Book2Author(models.Model):
  10. book = models.ForeignKey(to="Book")
  11. author = models.ForeignKey(to="Author")
  12. class Meta:
  13. unique_together = ("book","author" )

注意:

当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。

但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

10. META

ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息

  1. 字段
  2. db_table
  3. ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。
  4. 例如:
  5. class book(models.Model):
  6. title = models.CharField(max_length=32)
  7. class Meta:
  8. db_table = "自己设置表名"
  9. index_together
  10. 联合索引。
  11. unique_together
  12. 联合唯一索引。
  13. ordering
  14. 指定默认按什么字段排序。只有设置了该属性,查询到的结果才可以被reverse()。
  15. # 后台管理admin中显示的表名称
  16. verbose_name='自己设置'

11. ORM中执行原生SQL

Django 允许你用两种方式执行原生 SQL 查询:你可以使用 .raw() 来 执行原生查询并返回模型实例,或者完全不用模型层 直接执行自定义 SQL。

11.1 使用.raw()执行原生SQL

  1. res = models.Book.objects.raw('select * from lib01_book')
  2. print(res)
  3. for i in res:
  4. print(i.b_name,i.b_price)
  5. # 结果:
  6. <RawQuerySet: select * from lib01_book>
  7. 红高粱家族 25.50
  8. 十三步 50.00
  9. 三重门 25.00
  10. 像少年啦飞驰 19.90
  11. 活着 29.50
  12. 许三观卖血记 28.20
  13. # 将参数传给 raw()
  14. 可以使用 raw() params 参数:
  15. bookName="三重门"
  16. res=models.Book.objects.raw('select * from lib01_book where b_name = %s', [bookName])
  17. for i in res:
  18. print(i.b_name,i.b_price)
  19. # 结果:
  20. 三重门 25.00
  21. params 是一个参数字典。你将用一个列表替换查询字符串中 %s 占位符,或用字典替换 %(key)s 占位符(key 被字典 key 替换),不论你使用哪个数据库引擎。这些占位符会被 params 参数的值替换。

11.2 执行自定义 SQL

.raw()无法满足需求:你可能要执行不明确映射至模型的查询语句,或者就是直接执行 UPDATEINSERTDELETE 语句。可以直接访问数据库,完全绕过模型层。

对象 django.db.connection 代表默认数据库连接。要使用这个数据库连接,调用 connection.cursor() 来获取一个指针对象。然后,调用 cursor.execute(sql, [params]) 来执行该 SQL 和 cursor.fetchone(),或 cursor.fetchall() 获取结果数据。

  1. from django.db import connection
  2. with connection.cursor() as cursor:
  3. cursor.execute("SELECT b_name, b_price FROM lib01_book WHERE b_name = %s", ["三重门"])
  4. row = cursor.fetchone()
  5. print(row)
  6. 若你同时使用 不止一个数据库,你可以使用 django.db.connections 获取指定数据库的连接(和指针)。 django.db.connections 是一个类字典对象,它允许你通过连接别名获取指定连接:
  7. with connections['my_db_alias'].cursor() as cursor:
  8. 示例:
  9. from django.db import connections
  10. with connections['user'].cursor() as cursor:
  11. cursor.execute("SELECT * FROM lib01_book")
  12. # row = cursor.fetchone()
  13. row = cursor.fetchall()
  14. connections['my_db_alias'] : 本例中使用'user',这是在settings.pyDATABASES中设置的

Django基础四之测试环境和ORM查询的更多相关文章

  1. day 68 Django基础四之模板系统

      Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关 ...

  2. day 54 Django基础四之模板系统

    Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关于模 ...

  3. python django基础四 ORM简介

    ORM,全称是object relation mapping.翻译过来,就是对象关系映射. 主要来学习MySQL操作,MySQL是一个软件.它的优点:1.免费 2.开源 pymysql,就是Mysql ...

  4. Django基础四(model和数据库)

    上一篇博文学习了Django的form和template.到目前为止,我们所涉及的内容都是怎么利用Django在浏览器页面上显示内容.WEB开发除了数据的显示之外,还有数据的存储,本文的内容就是如何在 ...

  5. python第一百零五天 ---Django 基础 路由系统 URL 模板语言 ORM 操作

    一 路由系统 URL 1 url(r'^index/',views.index) url(r'^home/', views.Home.as_view()) 2 url(r'^detail-(\d+). ...

  6. Django基础四之模板系统

    一 语法   模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使 ...

  7. 04.Django基础四之模板系统

    一 语法 模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使用:{ ...

  8. Django基础四<二>(OneToMany和 ManyToMany,ModelForm)

    上一篇博文是关于setting.py文件数据库的配置以及model与数据库表关系,实现了通过操作BlogUser,把BlogUser的信息存入后台数据库中.实际开发中有许多东西是相互联系的,除了数据的 ...

  9. Django基础(四)

    Django-4 知识预览 分页器(paginator) COOKIE 与 SESSION Django的用户认证 FORM 回到顶部 分页器(paginator) 分页器的使用 1 2 3 4 5 ...

随机推荐

  1. 学习JDBC遇到的一些问题

    1. 数据库版本与驱动对应问题 参考官方文档:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-versions.html 具体详情还需 ...

  2. java 监听redis事件

    第一步:利用RDM等redis连接工具查看相应事件,然后去网上搜索 一下,会有redis各种事件的说明,选择契合业务的事件: 第二步:创建监听处理类: 1 package com.lechuang.a ...

  3. js实现用按钮控制网页滚动、以及固定导航栏效果

    实现效果如下: 页面内有三个按钮,分别控制页面向上.向下移动,以及暂停,并设置有导航栏,在滚动到某一位置时显示.且当用户主动控制鼠标滑轮时,滚动效果自动关闭.本页面只是演示如何实现,进行了简单的布局, ...

  4. Docker入门的亿点点学习

    前段时间花了些时间学习了亿点点docker,也算是入门了吧,顺便记了一下笔记拿出来分享给想要接触docker的兄弟们. 没有服务器的兄嘚可以去腾讯云或者阿里云领取免费的试用产品嗷,如果已经领取过了,又 ...

  5. Feign实现文件上传下载

    Feign框架对于文件上传消息体格式并没有做原生支持,需要集成模块feign-form来实现. 独立使用Feign 添加模块依赖: <!-- Feign框架核心 --> <depen ...

  6. Java多态、向上转型、向下转型知识分享(讲解全面)

    多态(方法的多态.对象的多态) 方法的多态 重写的多态(重要):子类继承父类,因此子类拥有父类属性和方法,如果子类重写父类方法,那么父类调用该方法的时候就会检查子类是否重写该方法,子类重写了就调用子类 ...

  7. Redis 源码简洁剖析 12 - 一条命令的处理过程

    命令的处理过程 Redis server 和一个客户端建立连接后,会在事件驱动框架中注册可读事件--客户端的命令请求.命令处理对应 4 个阶段: 命令读取:对应 readQueryFromClient ...

  8. 10、Linux基础--find、正则、文本过滤器grep

    笔记 1.晨考 1.每个月的3号.5号和15号,而且这天是星期六时执行 00 00 3,5,15 * 6 2.每天的3点到15点,每隔3分钟执行一次 */3 3-15 * * * 3.每周六早上2点半 ...

  9. ansible手动添加模块

    文章目录 安装ansible 验证ansible版本 定义ansible配置文件路径 为ansible添加模块 由于使用pip安装的ansible,自带的模块会比较少,有的模块会不存在,需要自己手动添 ...

  10. 如何使用 Rancher Desktop 访问 Traefik Proxy 仪表板

    Adrian Goins 最近举办了关于如何使用 K3s 和 Traefik 保护和控制边缘的 Kubernetes 大师班,演示了如何访问 K3s 的 Traefik Proxy 仪表板,可以通过以 ...