Django框架之ORM操作

一曲冷凌霜 提交于 2019-12-02 19:10:31

ORM操作

ORM常用字段与参数

常用字段类型 常用参数
AutoField primary_key
IntegerField choices
DecimalField max_digits,decimal_places
DateField auto_now,auto_now_add
DateTimeField auto_now,auto_now_add
CharField max_lenght
TextField \
EmailField \
URLField \

choice:为字段设置对应关系

choices = (
    (1,'male'),
    (2,'female'),
    (3,'others')
)   # 创建对应关系
gender = models.IntegerField(choices=choices)   # 将对应关系传给IntegerField

# 获取对应关系的值:数据对象.get_字段名_display()  当没有对应关系的时候 该句式获取到的还是数字
  • 如果存的是不在对应关系表里的数据是也是可以存进去的
  • 如果我们存的是元组范围的话实际上也是以数字存在数据库中

:“”一般无特殊情况不加参数

准备数据

  • models.py

    from django.db import models
    
    # Create your models here.
    
    class Author_info(models.Model):
        phone = models.BigIntegerField()
        addr = models.CharField(max_length=32)
    
        def __str__(self):
            return self.addr
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
        author_info = models.OneToOneField(to="Author_info")
    
        def __str__(self):
            return self.name
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=64)
    
        def __str__(self):
            return self.name
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8, decimal_places=2)
        publish_date = models.DateField(auto_now=True)
    
        publish = models.ForeignKey(to=Publish)
        author = models.ManyToManyField(to="Author")
    
        def __str__(self):
            return self.title
  • 数据库建表

    python manage.py makemigrations
    python manage.py migrate
  • 插入数据(mysql)

    insert  into `app01_author_info`(`id`,`phone`,`addr`) values (1,110,'温州'),(2,120,'温岭'),(3,130,'台州');
    insert  into `app01_author`(`id`,`name`,`age`,`author_info_id`) values (1,'ly',18,1),(2,'zzh',19,3),(3,'wht',20,2);
    insert  into `app01_publish`(`id`,`name`,`addr`) values (1,'东方出版社','东京'),(2,'南方出版社','南京'),(3,'北方出版社','北京');
    insert  into `app01_book`(`id`,`title`,`price`,`publish_date`,`publish_id`) values (1,'三国演义','69.00','2004-07-25',1),(2,'西游记','110.00','1994-07-29',2),(3,'水浒传','80.00','2010-06-26',3),(4,'封神榜','56.00','2000-11-03',1),(6,'西厢记','87.00','2000-07-11',1),(7,'红楼梦','65.00','1996-06-22',3),(10,'鹿鼎记','88.00','2019-10-26',1);
  • 创建测试环境

    import os,django
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
        django.setup()
        from app01 import models

常规查询操作

  • get

    book_obj = models.Book.objects.get(pk=1)   # 获取一个数据表对象
    print(book_obj)   # 三国演义   ## 这是同__str__修改了输出信息
  • filter

    book_obj = models.Book.objects.filter(pk=2)   # 获取一个结果集,Queryset套数据库对象
    print(book_obj)   # <QuerySet [<Book: 西游记>]>
  • all

    book_obj = models.Book.objects.all()   # 获取数据表的所有数据,Queryset套数据库对象
    print(book_obj)   # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
  • first

    book_obj = models.Book.objects.first()   # 取结果集第一个对象
    print(book_obj.first())   # 三国演义
  • last

    book_obj = models.Book.objects.last()   # 取结果集最后一个对象
    print(book_obj.last())   # 鹿鼎记
  • exclude

    book_obj = models.Book.objects.exclude(pk=3)   # 除此之外,除了主键值为3的数据之外都查询出来
    print(book_obj)   # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
  • values

    book_obj = models.Book.objects.all().values("id","title")   # 查询指定字段,Queryset套字典
    print(book_obj)   # <QuerySet [{'id': 1, 'title': '三国演义'}, {'id': 2, 'title': '西游记'}, {'id': 3, 'title': '水浒传'}, {'id': 4, 'title': '封神榜'}, {'id': 6, 'title': '西厢记'}, {'id': 7, 'title': '红楼梦'}, {'id': 10, 'title': '鹿鼎记'}]>
  • values_list

    book_obj = models.Book.objects.all().values("id","title")   # 查询指定字段,Queryset套元组
    print(book_obj)   # <QuerySet [(1, '三国演义'), (2, '西游记'), (3, '水浒传'), (4, '封神榜'), (6, '西厢记'), (7, '红楼梦'), (10, '鹿鼎记')]>
  • count

    count = models.Book.objects.count()   # 统计数据表内的数据条数
    print(count)   # 7
  • distinct

    book_obj = models.Book.objects.all().values("title").distinct()   # 去重,只有当所查字段都一样时才会触发去重的机制
    print(book_obj)   # <QuerySet [{'title': '三国演义'}, {'title': '西游记'}, {'title': '水浒传'}, {'title': '封神榜'}, {'title': '西厢记'}, {'title': '红楼梦'}, {'title': '鹿鼎记'}]>
  • order_by

    book_obj = models.Book.objects.all().order_by("title")   # 排序
    print(book_obj)   # <QuerySet [<Book: 三国演义>, <Book: 封神榜>, <Book: 水浒传>, <Book: 红楼梦>, <Book: 西厢记>, <Book: 西游记>, <Book: 鹿鼎记>]>
  • reverse

    book_obj = models.Book.objects.all().order_by("title").reverse()   # 反转排序的顺序
    print(book_obj)   # <QuerySet [<Book: 鹿鼎记>, <Book: 西游记>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 水浒传>, <Book: 封神榜>, <Book: 三国演义>]>
  • exists

    book_obj = models.Book.objects.filter(title="西游记").exists()   # 查询是否存在
    print(book_obj)   # True
    book_obj = models.Book.objects.filter(title="东游记").exists()
    print(book_obj)   # False

下划线操作

  • __gt

    book_obj = models.Book.objects.filter(pk__gt=3)   # 大于
    print(book_obj)   # <QuerySet [<Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
  • __lt

    book_obj = models.Book.objects.filter(pk__lt=3)   # 小于
    print(book_obj)   # <QuerySet [<Book: 三国演义>, <Book: 西游记>]>
  • __gte

    book_obj = models.Book.objects.filter(pk__gte=3)   # 大于等于
    print(book_obj)   # <QuerySet [<Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
  • __lte

    book_obj = models.Book.objects.filter(pk__lte=3)   # 小于等于
    print(book_obj)   # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 水浒传>]>
  • __in

    book_obj = models.Book.objects.filter(pk__in=[2,3,5])   # 包含
    print(book_obj)   # <QuerySet [<Book: 西游记>, <Book: 水浒传>]>
  • __range

    book_obj = models.Book.objects.filter(pk__range=[2,7])   # 在这个范围
    print(book_obj)   # <QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>]>
  • __contains

    book_obj = models.Book.objects.filter(title__contains="记")   # 包含,区分大小写
    print(book_obj)   # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
  • __icontains

    book_obj = models.Book.objects.filter(title__icontains="记")   # 包含,不区分大小写
    print(book_obj)   # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
  • __startswith

    book_obj = models.Book.objects.filter(title__startswith="红")   # 匹配开头
    print(book_obj)   # <QuerySet [<Book: 红楼梦>]>
  • __endswith

    book_obj = models.Book.objects.filter(title__startswith="记")   # 匹配结尾
    print(book_obj)   # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
  • __year

    book_obj = models.Book.objects.filter(publish_date__year=2019)  # 匹配年份
    print(book_obj)   # <QuerySet [<Book: 鹿鼎记>]>
  • __month

    book_obj = models.Book.objects.filter(publish_date__month=6)   # 匹配月份 
    print(book_obj)   # <QuerySet [<Book: 水浒传>, <Book: 红楼梦>]>

多表操作

  • add

    book_obj = models.Book.objects.filter(pk=2).first()   # 获取书籍对象
    book_obj.author.add(1,2,3)   # 将作者id添加到多对多字段的中间表去
  • set

    book_obj = models.Book.objects.filter(pk=2).first()   # 获取书籍对象
    book_obj.author.set([1,3])   # 传递的为一个可迭代对象,将中间表的记录修改,如果已经存在对应的记录,便不会修改,不存在的会添加,没有对应的就会被删除。
    # 下面这种方法可以删除关于这本书籍的记录
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.author.set([])
  • remove

    book_obj = models.Book.objects.filter(pk=2).first()   # 获取书籍对象
    book_obj.author.remove(1,2)   # 删除对应的记录
  • clear

    book_obj = models.Book.objects.filter(pk=2).first()   # 获取书籍对象
    book_obj.author.clear()   # 删除书籍对应的所有记录

跨表查询

上面已经讲了怎么对多表进行增删改,下面就是对多表查询

跨表查询只需要记住两句话就可以了:

1. 从外键所在的表查询用字段名(使用Django建表)
2. 从费外键所在的表查询使用表名小写
    第二条这里还需要分两种情况,多值和单值
    1. 单值直接加表名小写
    2. 多值需要表名小写并加上_set_all

查询方法也有两个方式:

  1. 通过对象查询(基于子查询)
  2. 通过双下划綫查询(基于连表查询)

表间数据自己随便填

用例:

  • 查询作者是gredae的手机号码(一对一)

    • 对象查询

      author = models.Author.objects.filter(name="gredae").first()   # 获取作者对象
      phone = author.author_info.phone   # 从作者表跨到作者详情表获取phone
      print(phone)   # 110
    • 双下划綫查询

      author_info_obj = models.Author_info.objects.filter(author__name="gredae").first()   # 获取作者详情表,条件是作者名字
      print(author_info_obj.phone)   # 110
  • 查询东方出版社出版过得书(一对多)

    • 对象查询

      publish_obj = models.Publish.objects.filter(name="东方出版社").first()   # 获取出版社对象
      print(publish_obj.book_set.all())   # 通过出版社跨到书籍表,通过all()将所有是东方出版社出版的书全部查询出来
    • 双下划綫查询

      book_ls = models.Book.objects.filter(publish__name="东方出版社")   # 直接获取所有是东方出版社出版的书
      print(book_ls)   # <QuerySet [<Book: 三国演义>, <Book: 封神榜>, <Book: 西厢记>, <Book: 鹿鼎记>]>
  • 查询水浒传的作者名字(多对多)

    • 对象查询

      book_obj = models.Book.objects.filter(title="水浒传").first()   # 获取书籍对象
      for author_obj in book_obj.author.all():    # 通过书籍对象查询作者
          print(author_obj.name)    # gredae  zzh
    • 双下划綫查询

      author_ls = models.Author.objects.filter(book__title="水浒传")   # 直接可以获取作者对象
      for author_obj in author_ls:   # 循环打印作者名字
          print(author_obj.name)

聚合查询

聚合函数:Max,Min,Sum,Count,Avg

  • Max

    price_max = models.Book.objects.aggregate(Max("price"))
    print(price_max)   # {'price__max': Decimal('110.00')}
  • Min

    price_min = models.Book.objects.aggregate(Min("price"))
    print(price_min)   # {'price__min': Decimal('56.00')}
  • Sum

    price_sum = models.Book.objects.aggregate(Sum("price"))
    print(price_sum)   # {'price__sum': Decimal('555.00')}
  • Count

    price_count = models.Book.objects.aggregate(Count("price"))
    print(price_count)   # {'price__count': 7}
  • Avg

    price_avg = models.Book.objects.aggregate(Avg("price"))
    print(price_avg)   # {'price__avg': 79.285714}

分组查询

关键字:annotate

  • 统计每本书作者数

    book_author_count = models.Book.objects.annotate(count_author = Count("author")).values("count_author")
    print(book_author_count)   # <QuerySet [{'count_author': 2}, {'count_author': 2}, {'count_author': 2}, {'count_author': 1}, {'count_author': 1}, {'count_author': 1}, {'count_author': 3}]>
  • 统计出版社最便宜的书

    publish_book_price_min = models.Publish.objects.annotate(min_price_book = Min("book__price")).values("min_price_book")
    print(publish_book_price_min)   # <QuerySet [{'min_price_book': Decimal('56.00')}, {'min_price_book': Decimal('110.00')}, {'min_price_book': Decimal('65.00')}]>

F与Q查询

  • F查询

    快到双十一了需要为所有的书籍提价10%

    models.Book.objects.all().update(price=F("price")*1.1)   为所以的书籍提价10%
  • Q查询

    我们知道filter的关系是and关系,我们很多时候需要or关系,所以就有了Q查询。

    res = models.Book.objects.filter(Q(price__lt=60)|Q(price__gt=100))   # 价格小于60或价格大于100

数据库查询优化

  • only和defer
    • only:会将括号内的数据放到对象中,点该字段不需要再从数据库中查询,如果是不在括号内就会频繁的从数据库中拿去数据
    • defer:不会将括号内的数据放到对象中,其他字段已经查询完毕,只要点了括号内的就会频繁从数据库中查询数据
  • select_related和prefetch_related
    • select_related:会自动连表,将连表后的数据放到对象中,并且括号内的只能是外键,并且多对多字段不能放
    • prefetch_related:类似于子查询,只能放外键字段,并且多对多字段不能放

ORM中的事务

from django.db import transaction
with transaction.atomic():
    # 在该代码块中所写的orm语句 同属于一个事务
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!