zhangyaqian

导航

 

21 Jun 18

一、ORM查询练习题

https://www.cnblogs.com/liwenzhou/articles/8337352.html

  1. Django终端打印SQL语句

在Django项目的settings.py文件中,在最后复制粘贴如下代码:

LOGGING = {

    'version': 1,

    'disable_existing_loggers': False,

    'handlers': {

        'console':{

            'level':'DEBUG',

            'class':'logging.StreamHandler',

        },

    },

    'loggers': {

        'django.db.backends': {

            'handlers': ['console'],

            'propagate': True,

            'level':'DEBUG',

        },

    }

}

 

  1. 练习题

脚本.py

import os

 

if __name__ == "__main__":

   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

from app01 import models  

# 要先导入环境,才能导入app01中的models,否则报错

 

    # 查找所有书名里包含番茄的书

    print(models.Book.objects.filter(title__contains='番茄'))

 

    # 查找出版日期是2017年的书

    print(models.Book.objects.filter(publish_date__year=2017))

 

    # 查找出版日期是2017年的书名

    print(models.Book.objects.filter(publish_date__year=2017).values('title'))

 

    # 查找价格大于10元的书

   print(models.Book.objects.filter(price__gt=10))

 

    # 查找价格大于10元的书名和价格

   print(models.Book.objects.filter(price__gt=10).values('title','price'))

 

    # 查找memo字段是空的书

    print(models.Book.objects.filter(memo__isnull=True))

 

    # 查找在北京的出版社

   print(models.Publisher.objects.filter(city='北京'))

 

    # 查找名字以沙河开头的出版社

    print(models.Publisher.objects.filter(name__startswith='沙河'))

 

    # 查找作者名字里面带“小”字的作者

    print(models.Author.objects.filter(name__contains='小'))

 

    # 查找年龄大于30岁的作者

   print(models.Author.objects.filter(age__gt=30))

 

    # 查找手机号是155开头的作者

   print(models.Author.objects.filter(phone__startswith='155'))

 

    # 查找手机号是155开头的作者的姓名和年龄

    print(models.Author.objects.filter(phone__startswith='155').values('name','age'))

 

    # 查找书名是“番茄物语”的书的出版社

    print(models.Book.objects.get(title='番茄物语').publisher)

 

    # 查找书名是“番茄物语”的书的出版社所在的城市

    print(models.Book.objects.get(title='番茄物语').publisher.city)

 

    # 查找书名是“番茄物语”的书的出版社的名称

    print(models.Book.objects.get(title='番茄物语').publisher.name)

 

    # 查找书名是“番茄物语”的书的所有作者

    print(models.Book.objects.filter(title='番茄物语').values('author'))

 

    # 查找书名是“番茄物语”的书的作者的年龄

    print(models.Book.objects.filter(title='番茄物语').values('author__age'))

 

    # 查找书名是“番茄物语”的书的作者的手机号码

    print(models.Book.objects.filter(title='番茄物语').values('author__phone'))

 

    # 查找书名是“番茄物语”的书的作者的地址

    print(models.Book.objects.filter(title='番茄物语').values('author__detail__addr'))

 

    # 查找书名是“番茄物语”的书的作者的邮箱

    print(models.Book.objects.filter(title='番茄物语').values('author__detail__email'))

 

二、ORM连表查询之ForeignKey

import os

 

if __name__ == "__main__":

   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

    from app01 import models  

 

    # 外键的正向查找

    # 基于对象查找(第一本书的出版社名称) (SQL:子查询)

    # first()得到一个对象,通过.属性的方法查找

    print(models.Book.objects.first().publisher.name)

 

    # 基于双下划线的跨表查询(书所关联的第一个出版社名称和所在城市)(SQL:JOIN)

    # 通过FK直接__跨表查询

    print(models.Book.objects.values('publisher__name','publisher__city').first())

    # 练习:查找书名是"番茄物语"的书的出版社的城市

    # 基于对象的查找方式

    print(models.Book.objects.get(title='番茄物语').publisher.city)

    # 基于双下划线的跨表查询

    print(models.Book.objects.filter(title='番茄物语').values('publisher__city'))

    # 外键的反向查找

    # 基于对象查找

    # 没有设置related_name时,first()得到一个对象,用表名_set反向查找

    print(models.Publisher.objects.first().book_set.all())

 

    # 在FK中设置了related_name = 'books'时,用设置的books反向查找 # publisher = models.ForeignKey(to="Publisher", related_name='books')

    print(models.Publisher.objects.first().books.all())

 

    # 在FK中设置了related_query_name = 'bookss'时,用设置的表名_set反向查找 # publisher = models.ForeignKey(to="Publisher",related_query_name="bookss")

    # related_query_name使用频率较小,可能于动态关联(当所关联的表不固定时)

    # print(models.Publisher.objects.first().book_set.all())

 

    # 基于双下划线的跨表查询

    # 没有设置related_name时,用表名反向查找

    # print(models.Publisher.objects.filter(id=1).values('book__title'))

 

    # 在FK中设置了related_name = 'books'时,用设置的books反向查找 # publisher = models.ForeignKey(to="Publisher", related_name='books')

    # print(models.Publisher.objects.filter(id=1).values('books__title'))

 

    # 在FK中设置了related_query_name = 'bookss'时,用设置的bookss反向查找 # publisher = models.ForeignKey(to="Publisher",related_query_name="bookss")

# print(models.Publisher.objects.filter(id=1).values('bookss__title'))

 

总结:

  1. 正向查找之对象查找(跨表):obj.关联字段.字段
  2. 正向查找之字段查找(跨表):关联字段__字段
  3. 反向操作之对象查找:obj.表名_set;如果设置了related_name=abc, 用obj.abc
  4. 方向操作之字段查找:表名__字段; 如果设置了related_name=abc, 用abc__字段,如果设置了related_query_name=def, 用def__字段
  5. 表名_set只有在反向+对象查找+没有设置related_name时使用

 

 

三、ORM连表查询之ManyToManyField

"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。存在于下面两种情况:外键关系的反向查询and多对多关联关系

简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

 

import os

 

if __name__ == "__main__":

    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

    from app01 import models  # 要先导入环境,才能导入app01中的models,否则报错

 

    #1. create:a. 创建了一个新的作者,b. 将新创建的作者和第一本书做关联

    ret = models.Book.objects.first().author.create(name='author11',age=18,phone='12345678901',detail_id=5)

    # author的detail字段为OneToOne,不能和已用的重复

   print(models.Book.objects.first().author.all().values('name'))

 

    #2. set:用set设置值,必须放在一个列表中

    print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 8}]>

    models.Book.objects.first().author.set([2,3])  

# 用set设置值,必须放在一个列表中

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 2}, {'id': 3}]>

 

    #3. add: 用add添加值,不需放在列表中,只要把所要添加的值用,隔开即可;或*[a,b]

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 2}, {'id': 3}]>

    models.Book.objects.first().author.add(1,4)  # 用add添加值,不需放在列表中,只要把所要添加的值用,隔开即可

    models.Book.objects.first().author.add(*[1, 4])

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]>

 

    #4. remove: 同add, 不需放在列表中,只要把所要添加的值用,隔开即可

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]>

    models.Book.objects.first().author.remove(3,4)  # 同add, 不需放在列表中,只要把所要添加的值用,隔开即可

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 1}, {'id': 2}]>

 

    #5. clear: 清空

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet [{'id': 1}, {'id': 2}]>

    models.Book.objects.first().author.clear()

   print(models.Book.objects.first().author.all().values('id'))  # <QuerySet []>

 

    #6. all: 查询所有

print(models.Book.objects.first().author.all())  # <QuerySet [<Author: author1小>, <Author: author4>]>

 

# 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

# 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

# 对于手动创建第三张关联表的情况,可以使用all(),但不能使用add()、create()、remove()和clear(),set()

 

四、聚合查询和分组查询

import os

 

if __name__ == "__main__":

   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

    from app01 import models

 

    # aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。

    from django.db.models import Avg, Sum, Max, Min, Count

 

    # 查询所有书的总价格

   print(models.Book.objects.all().aggregate(Avg("price")))  # {'price__avg': 36.25}

    # 如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

   print(models.Book.objects.aggregate(sum_price=Sum('price')))  # {'sum_price': Decimal('145.00')}

    # 如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。print(models.Book.objects.aggregate(sum_price=Sum('price'),min_price=Min('price'),max_price=Max('price')))  # {'sum_price': Decimal('145.00'), 'min_price': Decimal('10.00'), 'max_price': Decimal('100.00')}

 

    # 求每一本书的作者个数

print(models.Book.objects.annotate(c=Count('author')).values('title','c'))  # <QuerySet [{'title': 'book1', 'c': 2}, {'title': 'book2', 'c': 0}, {'title': 'book3', 'c': 0}, {'title': '番茄物语', 'c': 2}]>

# 按照什么分组就models.什么;以什么分组就annotate(什么)

   

    # 求部门的平均薪资         

    models.Employee.objects.values("dept").annotate(salary_avg=Avg("salary")).values("dept", "salary_avg")

    # annotate()前的是分组的依据(以Employee表中的dept字段分组);annotate()相当于新建了一个column(salary_avg)

    

    # 统计出每个出版社买的最便宜的书的价格

print(models.Publisher.objects.annotate(min=Min('book__price')).values('name','min'))  # <QuerySet [{'name': 'publisher1', 'min': Decimal('10.00')}, {'name': '沙河出版社', 'min': Decimal('100.00')}, {'name': 'publisher3', 'min': Decimal('20.00')}, {'name': 'publisher4', 'min': Decimal('15.00')}]>

# 如果为该FK设置related_name='books'

   print(models.Publisher.objects.annotate(min=Min('books__price')).values('name', 'min'))  

 

    # 统计不止一个作者的图书 (书作者的数量大于1)

   print(models.Book.objects.annotate(c=Count('author')).filter(c__gt=1))  # <QuerySet [<Book: book1>, <Book: 番茄物语>]>

 

    # 按照书作者的数量做排序

   print(models.Book.objects.annotate(c=Count('author')).order_by('c'))  # <QuerySet [<Book: book2>, <Book: book3>, <Book: book1>, <Book: 番茄物语>]>

 

    # 查询各个作者出的书的总价格

   print(models.Author.objects.annotate(sum=Sum('book__price')).values('name','sum'))  # <QuerySet [{'name': 'author1小', 'sum': Decimal('25.00')}, {'name': 'author4', 'sum': Decimal('10.00')}, {'name': 'author2', 'sum': Decimal('15.00')}, {'name': 'author3', 'sum': None}]>

 

五、不使用ManyToManyField,通过手动创建第三张表,关联两个外键

model.py

from django.db import models

 

class Book(models.Model):

    title = models.CharField(max_length=32)

 

class Author(models.Model):

    name = models.CharField(max_length=32)

 

# 自己创建第三张表,分别通过外键关联书和作者

class Author2Book(models.Model):

    author = models.ForeignKey(to="Author")

    book = models.ForeignKey(to="Book")

    class Meta:

            unique_together = ("author", "book")  # 联合唯一

脚本.py

import os

 

if __name__ == "__main__":

   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

    from app03 import models

    # 基于对象查找

   print(models.Book.objects.first().author2book_set.all().values('author__name'))

 # <QuerySet [{'author__name': 'a1'}, {'author__name': 'a2'}]>

         # 基于双下划线的跨表查询

print(models.Book.objects.filter(id=1).values('author2book__author__name'))  

#. <QuerySet [{'author2book__author__name': 'a1'}, {'author2book__author__name': 'a2'}]>

    

first_book=models.Book.objects.first()

# 直接通过操作第三张表建立关系

    models.Author2Book.objects.create(book=first_book,author_id=3)

# 直接通过操作第三张表删除关系

       models.Author2Book.objects.filter(book=first_book).delete()

 

六、自己创建第三张表,并通过ManyToManyField指定关联(中介者模型)

# ManyToManyField建在哪张表中:根据业务逻辑;如果经常由Author表查Book,推荐将ManyToManyField加在Author表中;如果经常由Book表查Author,推荐将ManyToManyField加到Book表中。

models.py

from django.db import models

 

class Book(models.Model):

    title = models.CharField(max_length=32, verbose_name="书名")

 

# 自己创建第三张表,并通过ManyToManyField指定关联

class Author(models.Model):

    name = models.CharField(max_length=32, verbose_name="作者姓名")

    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))

    # through_fields接受一个2元组('field1','field2'):

    # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。

 

class Author2Book(models.Model):

    author = models.ForeignKey(to="Author")

    book = models.ForeignKey(to="Book")

    class Meta:

            unique_together = ("author", "book")

 

脚本.py

import os

 

if __name__ == "__main__":

   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day68_yq.settings")

    import django

    django.setup()

 

    from app04 import models

    # 基于对象查找

        print(models.Book.objects.first().author2book_set.all().values('author__name'))  

#. <QuerySet [{'author__name': 'a1'}]>

#基于双下划线的跨表查询

   print(models.Book.objects.filter(id=1).values('author__name'))  

# <QuerySet [{'author__name': 'a1'}]>

 

    first_book=models.Book.objects.first()

# 直接通过操作第三张表建立关系

 

   models.Author2Book.objects.create(book=first_book,author_id=2)

# 直接通过操作第三张表删除关系

        models.Author2Book.objects.filter(book=first_book,author_id=2).delete()

 

七、其他

models.Employee2.objects.all()  《==》 select * from employee2;

models.Employee2.objects.values("name")  《==》 select name from employee2;

posted on 2018-06-21 17:31  zhangyaqian  阅读(127)  评论(0编辑  收藏  举报