Django之模型层&ORM操作

一. 单表查询:

         1.在模型层创建模型表:

from django.db import models

# Create your models here.
# 单表查询表
class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    register_time = models.DateField()

       2.连接MySQL,创建表 (具体操作见https://www.cnblogs.com/sima-3/p/10987276.html)

       3.在test.py中进行单表查询测试, 首先配置环境:

from django.test import TestCase

# Create your tests here.
import os


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

        a.新增数据:

方式一:对象的create方法添加记录

user_obj=models.User.objects.create(name='jason',age='18',register_time='2019-6-12')
print(user_obj.name)

方式二:对象的save方法添加记录

from datetime import datetime
ctime=datetime.now()
user_obj=models.User(name='egon',age='18',register_time=ctime)
user_obj.save()
print(user_obj.register_time)

         b.修改数据:

方式一:数据对象更新记录

user_obj=models.User.objects.filter(name='jason').last()
user_obj.name='kevin'
user_obj.age='18'
user_obj.save()

方式二:queryset对象的update方法更新记录

user_list=models.User.objects.filter(pk=6)
user_list.update(name='tank')

       c.删除数据:

方式一:数据对象删除记录

user_obj=models.User.objects.filter(name='jason')[0]
user_obj.delete()

 方式二:queryset对象删除记录

user_list=models.User.objects.filter(age='18')
user_list.delete()

      d.查询数据:

     # < 1 > all(): 查询所有结果

    # < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
    # res = models.User.objects.filter(name='jason',age=17)
    # filter内可以放多个限制条件但是需要注意的是多个条件之间是and关系
    # print(res)

    # < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
(源码就去搂一眼~诠释为何只能是一个对象)
# 不推荐使用 # < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 # res = models.User.objects.exclude(name='jason') # print(res) # < 5 > order_by(*field): 对查询结果排序('-id') / ('price') # res = models.User.objects.order_by('age') # 默认是升序 # res = models.User.objects.order_by('-age') # 可以在排序的字段前面加一个减号就是降序 # res = models.User.objects.order_by('name') # res = models.User.objects.order_by('-name') # print(res) # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向 # res = models.User.objects.order_by('age').reverse() # print(res) # < 7 > count(): 返回数据库中匹配查询(QuerySet) 的对象数量。 # res = models.User.objects.count() # res = models.User.objects.all().count() # print(res) # < 8 > first(): 返回第一条记录 # res = models.User.objects.all().first() # res = models.User.objects.all()[0] # 不支持负数的索引取值 # print(res) # < 9 > last(): 返回最后一条记录 # res = models.User.objects.all().last() # print(res) # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False # res = models.User.objects.all().exists() # res1 = models.User.objects.filter(name='jason',age=3).exists() # print(res,res1) # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 # res = models.User.objects.values('name') # 列表套字典 # res = models.User.objects.values('name','age') # 列表套字典 # print(res) # < 12 > values_list(*field): 它与values() 非常相似,它返回的是一个元组序列,values返回的是一个字典序列 # res = models.User.objects.values_list('name','age') # 列表套元祖 # print(res) # < 13 > distinct(): 从返回结果中剔除重复纪录 去重的对象必须是完全相同的数据才能去重 # res = models.User.objects.values('name','age').distinct() # print(res)

          e.神奇的双下划线查询 (基于queryset对象操作):

  查询年轻大于44岁的用户
    # res = models.User.objects.filter(age__gt=44)
    # print(res)
   
  查询年轻小于44岁的用户
    # res = models.User.objects.filter(age__lt=44)
    # print(res)
   
  查询年轻大于等于44岁的用户
    # res = models.User.objects.filter(age__gte=44)
    # print(res)
    
 查询年轻小于等于44岁的用户
    # res = models.User.objects.filter(age__lte=44)
    # print(res)

 查询年龄是44或者22或者73的用户
    # res = models.User.objects.filter(age__in=[44,22,73])
    # print(res)

 查询年龄在22到44范围内
    # res = models.User.objects.filter(age__range=[22,44])
    # print(res)

 查询年份
    # res = models.Book.objects.filter(publish_date__year=2019)
    # print(res)

 查询名字中包含字母n的用户  sqlite数据库演示不出来大小写的情况!!!
    # res = models.Author.objects.filter(name__contains='n')
    区分大小写
    # res = models.Author.objects.filter(name__icontains='n')
    不分大小写
  # print(res)

 查询名字以j开头的用户
    # res = models.User.objects.filter(name__startswith='j')
    # print(res)
 
查询名字以n结尾的用户
    # res = models.User.objects.filter(name__endswith='n')
    # print(res)

二.多表查询:

      1.在模型层创建模型表:

# 多表查询表
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_add=True)
    # 外键关系
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')  # 虚拟字段, 信号字段

    def __str__(self):
        return '书籍对象的名字:%s'%self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.EmailField()  # 对应就是varchar类型

    def __str__(self):
        return '出版社对象的名字:%s'%self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authordetail = models.OneToOneField(to='AuthorDetail')

    def __str__(self):
        return  '作者对象的名字:%s'%self.name


class AuthorDetail(models.Model):
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

     五张表如下图所示(多对多会新增一张表):

   

   先在author, authordetail, publish三张表中填写记录,book, book_author两张表暂不填:

           其各表关系如下:

                    book ---------  publish            一对多关系

                    book ---------  author             多对多关系  ------- 产生 book_author

                    author--------- authordetail    一对一关系

   

   publish 表记录:

               

   author  表记录:

           

   authordetail 表记录:

           

    2.一对多字段的增删改查:

            a.在book表中添加记录:

        

# 方式一:数据对象的create方法添加记录
book_obj=models.Book.objects.create(title='孙子兵法',price='66.88',publish_id=3)
print(book_obj.title)

# 方式二:数据对象的save方法添加记录
book_obj=models.Book(title='三国志',price='33.66',publish_id=4)
book_obj.save()
print(book_obj.title)

#除了用publish_id关联book表,还可传publish对象publish_obj,因为book表中有publish字段
publish_obj=models.Publish.objects.filter(pk=4).first()
book_obj=models.Book.objects.create(title='洛神赋',price='98.89',publish=publish_obj)

         添加记录后:

     

           b.在book表中修改记录:

# 方式一:数据对象更新记录

book_obj=models.Book.objects.filter(pk=4).first()
book_obj.title='厚黑学'
book_obj.publish_id=2
book_obj.save()
print(book_obj.title)


# 方式二:queryset对象的update方法更新记录

book_list=models.Book.objects.filter(pk=6)
publish_obj=models.Publish.objects.filter(pk=4).first()
book_list.update(title='红楼梦',publish=publish_obj)
print(book_list)

        修改记录后:

    

      c.在book表中删除记录:

# 方式一:数据对象删除记录
book_obj=models.Book.objects.filter(pk=4)[0]
book_obj.delete()

 # 方式二:queryset对象的update方法删除记录
book_list=models.Book.objects.filter(pk=6)
book_list.delete()
如果删除出版社,相应的书也会被删除(级联删除)

            删除记录后:

    

    2.多对多字段的增删改查:

        a.在book_authors表中添加记录:

             

          给书籍绑定与作者之间的关系:

 
    # 添加关系 add支持传数字或对象,并且都可以传多个
    # 方式一:直接添加authors_id
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.add(4)
    book_obj.authors.add(2,3)

    # 方式二: 添加authors对象
    author_obj = models.Author.objects.filter(pk=2).first()
    author_obj1 = models.Author.objects.filter(pk=3).first()
    book_obj = models.Book.objects.filter(pk=5).first()
    book_obj.authors.add(author_obj,author_obj1)

        绑定之后:

      

     b.在book_authors表中更新记录:

    修改书籍与作者的关系  set()  set传的必须是可迭代对象!!!
    book_obj = models.Book.objects.filter(pk=3).first()
    # 可以传数字和对象,并且支持传多个
    book_obj.authors.set((2,))
    # book_obj.authors.set((1,2,3))
   
    author_list = models.Author.objects.all()     #[{},{},...],包含所有的作者对象,主键id=2,3,4,5
    book_obj = models.Book.objects.filter(pk=5).first()
    book_obj.authors.set(author_list)

        修改之后:

         

   c.在book_authors表中删除记录:

         删除书籍与作者的绑定关系: 需要将queryset打散:

    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.remove(2)
    # book_obj.authors.remove(4,3)

    # author_obj = models.Author.objects.all().first()
    # book_obj.authors.remove(author_obj)
    book_obj = models.Book.objects.filter(pk=5).first()
    author_list = models.Author.objects.all()
    book_obj.authors.remove(*author_list)

        正好将所有记录都删完了 !!!

   补充: 清空  clear()  清空的是当前这个表记录中id为3的book对应的所有绑定关系
# book_obj = models.Book.objects.filter(pk=3).first()
    # 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() 因为一个作者对应着多个图书
  
  

# 连续跨表
    # 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号

# 总结:基于对象的查询都是子查询,这里可以用django配置文件自动打印sql语句的配置做演示


1.基于对象的表查询
      a. 正向:

# 一对多
# 查询书籍是三国志的出版社邮箱
book_obj = models.Book.objects.filter(title='三国志').first()
print(book_obj.publish.email)

# 多对多
# 查询书籍是山海经的作者的姓名
book_obj = models.Book.objects.filter(title='山海经').first()
print(book_obj.authors)  # app01.Author.None,多对多必须用all查询
print(book_obj.authors.all())  # <QuerySet [<Author: 作者对象的名字:jason>]>

# 一对一
# 查询作者为jason电话号码
user_obj = models.Author.objects.filter(name='jason').first()
print(user_obj.authordetail.phone)

      b.反向:

    # 一对多字段的反向查询
    # 查询出版社是江苏日报出版社出版的书籍
    publish_obj = models.Publish.objects.filter(name='江苏日报').first()
    print(publish_obj.book_set)  # app01.Book.None
    print(publish_obj.book_set.all())
    #<QuerySet [<Book: 书籍对象的名字:三国志>, <Book: 书籍对象的名字:洛神赋>]>

    

# 多对多字段的反向查询 # 查询作者jason写过的所有的书 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set) # app01.Book.None print(author_obj.book_set.all()) # < QuerySet[ < Book: 书籍对象的名字:山海经 >, < Book: 书籍对象的名字:三国志 >] >

# 一对一字段的反向查询,一对一不用加_set,直接可跨表拿到name字段的值 # 查询作者电话号码是456的作者姓名 authordetail_obj = models.AuthorDetail.objects.filter(phone=456).first() print(authordetail_obj.author.name)

2.基于双下滑线的查询:

      a.正向:

    # 查询书籍为洛神赋的出版社地址
    res = models.Book.objects.filter(title='洛神赋').values('publish__addr','title')
    print(res)
    # < QuerySet[{'publish__addr': '江苏', 'title': '洛神赋'}] >
   
# 查询书籍为山海经的作者的姓名 res = models.Book.objects.filter(title='山海经').values("authors__name",'title') print(res) # < QuerySet[{'authors__name': 'jason', 'title': '山海经'}] >
# 查询作者为jason的家乡 res = models.Author.objects.filter(name='jason').values('authordetail__addr') print(res) # < QuerySet[{'authordetail__addr': '东京'}] >

        b.反向:

    # 查询人民日报出版社出版的书名
    res = models.Publish.objects.filter(name='人民日报').values('book__title')
    print(res)
    # < QuerySet[{'book__title': '山海经'}] >
    
    
    # 查询电话号码为789的作者姓名
    res = models.AuthorDetail.objects.filter(phone=789).values('author__name')
    print(res)
    # < QuerySet[{'author__name': 'tank'}] >
    
    # 查询作者为jason的写的书的名字
    res = models.Author.objects.filter(name='jason').values('book__title')
    print(res)
    # < QuerySet[{'book__title': '山海经'}, {'book__title': '三国志'}] >

       c.跨三张表查询:

    # 查询书籍为三国志的作者的电话号码
    res = models.Book.objects.filter(title='三国志').values('authors__authordetail__phone')
    print(res)
    # < QuerySet[{'authors__authordetail__phone': '123'}] >

      d.同一问题不同角度查询:

    # 查询jason作者的手机号
    # 正向
    res = models.Author.objects.filter(name='jason').values('authordetail__phone')
    print(res)
    # < QuerySet[{'authordetail__phone': '123'}] >
    # 反向
    res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
    print(res)
    # < QuerySet[{'phone': '123'}] >

   

    # 查询出版社为新华日报出版社的所有图书的名字和价格
    # 正向
    res = models.Publish.objects.filter(name='新华日报').values('book__title','book__price')
    print(res)
    # < QuerySet[{'book__title': '战国策', 'book__price': Decimal('86.66')}] >
    # 反向
    res = models.Book.objects.filter(publish__name='新华日报').values('title','price')
    print(res)
    # < QuerySet[{'title': '战国策', 'price': Decimal('86.66')}] >
    # 查询人民日报出版社出版的价格大于10的书
    # 正向
    res = models.Publish.objects.filter(name="人民日报",book__price__gt=10).values('book__title','book__price')
    print(res)
    # < QuerySet[{'book__title': '山海经', 'book__price': Decimal('18.88')}] >
    # 反向
    res = models.Book.objects.filter(price__gt=10,publish__name='人民日报').values('title','price')
    print(res)
    # < QuerySet[{'title': '山海经', 'price': Decimal('18.88')}] >

四.聚合查询  aggregate

 from django.db.models import Max,Min,Count,Sum,Avg
    # 查询所有书籍的作者个数
    res = models.Book.objects.aggregate(count_num=Count('authors'))
    print(res)
    # {'count_num': 3}
    # 查询所有出版社出版的书的平均价格
    res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
    print(res)  # {'avg_price': 59.5225}
    # 统计江苏日报出版社出版的书籍的个数
    res = models.Publish.objects.filter(name='江苏日报').aggregate(count_num=Count('book__id'))
    print(res)
    # {'count_num': 2}

五.分组查询 (group_by)   annotate

  # 统计每个出版社出版的书的平均价格
    res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
    print(res)
    # < QuerySet[{'name': '人民日报', 'avg_price': 18.88}, {'name': '新华日报', 'avg_price': 86.66},
    # {'name': '江苏日报', 'avg_price': 66.275}, {'name': '上海日报', 'avg_price': None}] >

   

# 统计每一本书的作者个数 res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num') print(res) # < QuerySet[{'title': '山海经', 'count_num': 1}, {'title': '战国策', 'count_num': 0}, # {'title': '三国志', 'count_num': 1}, {'title': '洛神赋', 'count_num': 1}] >

# 统计出每个出版社卖的最便宜的书的价格 res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') print(res) # 查询每个作者出的书的总价格 res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') print(res) # <QuerySet [{'name': 'jason', 'sum_price': Decimal('52.54')}, {'name': 'kevin', 'sum_price': Decimal('98.89')}, # {'name': 'egon', 'sum_price': None}, {'name': 'tank', 'sum_price': None}]>

    

   

       

猜你喜欢

转载自www.cnblogs.com/sima-3/p/11013499.html