django進階-查詢(適合GET4以上人群閱讀)


前言: 下篇博客寫關於bootstrap...

一、如何在腳本測試django

 1 from django.db import models
 2 
 3 class Blog(models.Model):
 4     name = models.CharField(max_length=100)
 5     tagline = models.TextField()
 6 
 7     def __str__(self):              # __unicode__ on Python 2
 8         return self.name
 9 
10 class Author(models.Model):
11     name = models.CharField(max_length=50)
12     email = models.EmailField()
13 
14     def __str__(self):              # __unicode__ on Python 2
15         return self.name
16 
17 class Entry(models.Model):
18     blog = models.ForeignKey(Blog)
19     headline = models.CharField(max_length=255)
20     body_text = models.TextField()
21     pub_date = models.DateField()
22     mod_date = models.DateField()
23     authors = models.ManyToManyField(Author)
24     n_comments = models.IntegerField()
25     n_pingbacks = models.IntegerField()
26     rating = models.IntegerField()
27 
28     def __str__(self):              # __unicode__ on Python 2
29         return self.headline
View Code

一般往django添加一條數據庫,我們會在cmd 下導入django環境后進行測試。
那如何在.py腳本下運行測試呢?

1 import os 2 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day18.settings") 3 
4 import django 5 django.setup()   #導入django環境
6 
7 from blog import models 8 
9 entry=models.Entry.objects.get(pk=1)
10 print(entry)

輸出: 屌炸天。

 

二、處理帶外鍵關聯或多對多關聯的對象

創建

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

This performs an INSERT SQL statement behind the scenes. Django doesn’t hit the database until you explicitly call save().
The save() method has no return value.

ForeignKey的關聯

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

ManyToManyField關聯

>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)

添加多個ManyToMany對象

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

 

三、查詢

 1 all_entries = Entry.objects.all() #查詢所有
 2 Entry.objects.filter(pub_date__year=2006) #查詢所有pub_date為2006年的紀錄
 3 Entry.objects.all().filter(pub_date__year=2006) #與上面那句一樣
 4 >>> Entry.objects.filter(   #鏈式查詢
 5 ...     headline__startswith='What'
 6 ... ).exclude(  7 ...     pub_date__gte=datetime.date.today()  8 ... ).filter(  9 ...     pub_date__gte=datetime(2005, 1, 30) 10 ... ) 11 
12 one_entry = Entry.objects.get(pk=1) #單條查詢
13 
14 Entry.objects.all()[:5] #查詢前5條
15 Entry.objects.all()[5:10] #你猜
16 
17 Entry.objects.order_by('headline')[0] #按headline排序取第一條
18 
19 Entry.objects.filter(pub_date__lte='2006-01-01') #相當於sql語句SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
20 
21 Entry.objects.get(headline__exact="Cat bites dog") #相當於SELECT ... WHERE headline = 'Cat bites dog';
22 Blog.objects.get(name__iexact="beatles blog") #與上面相同,只是大小寫不敏感
23 
24 Entry.objects.get(headline__contains='Lennon') #相當 於SELECT ... WHERE headline LIKE '%Lennon%';

 

四、對同一表內不同的字段進行對比查詢-F

對同一表內不同的字段進行對比查詢,In the examples given so far, we have constructed filters that compare the value of a model field with a constant. But what if you want to compare the value of a model field with another field on the same model?

Django provides F expressions to allow such comparisons. Instances of F() act as a reference to a model field within a query. These references can then be used in query filters to compare the values of two different fields on the same model instance.

For example, to find a list of all blog entries that have had more comments than pingbacks, we construct an F() object to reference the pingback count, and use that F() object in the query: gt表示大於,lt表示小於,gte表示大於等於。

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

示例:

 1 import os  2 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day18.settings")  3 
 4 import django  5 django.setup()#導入django環境
 6 
 7 from blog import models  8 
 9 from django.db.models import F 10 
11 objs = models.Entry.objects.filter(n_comments__gt=F('n_pingbacks')) 12 #相當於原生sql語句:selectn_comments,n_pingbacksfromEntry
13 #where n_comments<n_pingbacks
14 
15 print(objs)

輸出: <QuerySet [<Entry: 屌炸天>, <Entry: qqqq>]>

 

Django supports the use of addition, subtraction, multiplication, division, modulo, and power arithmetic with F() objects, both with constants and with other F() objects. To find all the blog entries with more than twice as many comments as pingbacks, we modify the query:

>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

To find all the entries where the rating of the entry is less than the sum of the pingback count and comment count, we would issue the query:

>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

For date and date/time fields, you can add or subtract a timedelta object. The following would return all entries that were modified more than 3 days after they were published:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

  

五、Caching and QuerySets

Each QuerySet(查詢集合) contains a cache to minimize(最小化) database access. Understanding how it works will allow you to write the most efficient code.

In a newly created QuerySet, the cache is empty. The first time a QuerySet is evaluated(評估) – and, hence, a database query happens – Django saves the query results in the QuerySet’s cache and returns the results that have been explicitly(明確地) requested (e.g., the next element, if the QuerySet is being iterated over迭代). Subsequent(后來的) evaluations of the QuerySet reuse(重用) the cached results.

如果QuerySet迭代,后續評估的QuerySet重用緩存的結果。

Keep this caching behavior in mind, because it may bite you if you don’t use your QuerySets correctly. For example, the following will create two QuerySets, evaluate them, and throw them away:

>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])

That means the same database query will be executed twice, effectively doubling your database load. Also, there’s a possibility the two lists may not include the same database records, because an Entry may have been added or deleted in the split second between the two requests.

To avoid this problem, simply save the QuerySet and reuse it:

>>> queryset = Entry.objects.all()                  #為節省資源,只取了很少的部分數據
>>> print([p.headline for p in queryset]) # Evaluate the query set.真正循環時才取出來
>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.已經取出了緩存中了,這句代碼不用再去數據庫中取

 

When QuerySets are not cached

Querysets do not always cache their results. When evaluating only part of the queryset, the cache is checked, but if it is not populated then the items returned by the subsequent query are not cached. Specifically, this means that limiting the queryset using an array slice or an index will not populate the cache.

For example, repeatedly getting a certain index in a queryset object will query the database each time:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again  再去數據庫中查詢,用不到緩存

However, if the entire queryset has already been evaluated, the cache will be checked instead:

>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database 從數據庫取數據后遍歷
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache 不用再去數據庫中查詢,到緩存查詢,更快

  

六、復雜查詢-Q

Complex lookups with Q objects(復雜查詢)

Keyword argument queries – in filter(), etc. – are “AND”ed together. If you need to execute more complex queries (for example, queries with OR statements), you can use Q objects.

A Q object (django.db.models.Q) is an object used to encapsulate(封裝) a collection of keyword arguments. These keyword arguments are specified as in “Field lookups” above.
For example, this Q object encapsulates a single LIKE query:

from django.db.models import Q
Q(question__startswith='What')

Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it yields a new Q object.

For example, this statement yields a single Q object that represents the “OR” of two "question__startswith" queries:

Q(question__startswith='Who') | Q(question__startswith='What')

This is equivalent to(相當於) the following SQL WHERE clause:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

You can compose statements of arbitrary(任意的) complexity by combining Q objects with the & and | operators and use parenthetical grouping. Also, Q objects can be negated(否定) using the ~ operator, allowing for combined lookups that combine both a normal query and a negated (NOT) query:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Each lookup function that takes keyword-arguments (e.g. filter(), exclude(), get()) can also be passed one or more Q objects as positional (not-named) arguments. If you provide multiple Q object arguments to a lookup function, the arguments will be “AND”ed together(下面的逗號表示and). For example:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

... roughly translates into the SQL(轉化為SQL語句如下):

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

示例:

 1 import os  2 os.environ.setdefault("DJANGO_SETTINGS_MODULE","day18.settings")  3 
 4 import django  5 django.setup()#導入django環境
 6 
 7 from blog import models  8 from django.db.models import F,Q  9 
10 objs=models.Entry.objects.filter(Q(n_comments__gt=F('n_pingbacks')), Q(pub_date__gt="2017-3-18")) 11 
12 print(objs)

輸出: <QuerySet [<Entry: 屌炸天>]>

 

if a Q object is provided, it must precede the definition of any keyword arguments(Q語句要放前面). For example:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

... would be a valid query, equivalent to the previous example; but:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

... would not be valid.

 

七、批量自增

在原有數據的基礎上批量自增

Calls to update(調用更新) can also use F expressions to update one field based on the value of another field in the model. This is especially useful for incrementing counters based upon their current value. For example, to increment the pingback count for every entry in the blog:

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

However, unlike F() objects in filter and exclude clauses, you can’t introduce joins when you use F() objects in an update – you can only reference fields local to the model being updated. If you attempt to introduce a join with an F() object, a FieldErrorwill be raised:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))

只能用原有字段F('n_pingbacks') + 1)進行更新,比如Entry的字段n_pingbacks;
若想找到與Entry外鍵關聯blog的name,再更新到headline. 是不行的。eg: headline=F('blog__name')

 

八、反向關聯

表結構參考上篇博客: django進階-3

1 from app01 import models as book_models 2 pub_obj = book_models.Publisher.objects.last() 3 print(pub_obj) 4 #反向關聯 書類中與出版社多對多關聯,但這種關聯是雙向的,所以可以根據出版社找出書的集合
5 # book_set中book為書的表名出版社反向關聯book數據庫中書的表是小字的
6 print(pub_obj.book_set.select_related())

輸出:

<惠來出版社>
<QuerySet [<Book: <跟zcl學python <惠來出版社>>>, <Book: <新書A <惠來出版社>>>, <Book: <新書A <惠來出版社>>>, <Book: <新書A <惠來出版社>>>, <Book: <zcl_python <惠來出版社>>>, <Book: <hello world <惠來出版社>>>]>
View Code

反向關聯默認在django admin是看不到的!

 

九、聚合查詢

示例models

 1 from django.db import models
 2 
 3 class Author(models.Model):
 4     name = models.CharField(max_length=100)
 5     age = models.IntegerField()
 6 
 7 class Publisher(models.Model):
 8     name = models.CharField(max_length=300)
 9     num_awards = models.IntegerField()
10 
11 class Book(models.Model):
12     name = models.CharField(max_length=300)
13     pages = models.IntegerField()
14     price = models.DecimalField(max_digits=10, decimal_places=2)
15     rating = models.FloatField()
16     authors = models.ManyToManyField(Author)
17     publisher = models.ForeignKey(Publisher)
18     pubdate = models.DateField()
19 
20 class Store(models.Model):
21     name = models.CharField(max_length=300)
22     books = models.ManyToManyField(Book)
23     registered_users = models.PositiveIntegerField()
View Code

常用聚合場景需求

 1 # Total number of books.
 2 >>> Book.objects.count()  3 
 4 # Total number of books with publisher=BaloneyPress
 5 >>> Book.objects.filter(publisher__name='BaloneyPress').count()  6 
 7 # Average price across all books.
 8 >>> from django.db.models import Avg  9 >>> Book.objects.all().aggregate(Avg('price')) 10 {'price__avg': 34.35} 11 
12 # Max price across all books.
13 >>> from django.db.models import Max 14 >>> Book.objects.all().aggregate(Max('price')) 15 {'price__max': Decimal('81.20')} 16 
17 # Cost per page
18 >>> Book.objects.all().aggregate( 19 ...    price_per_page=Sum(F('price')/F('pages'), output_field=FloatField())) 20 {'price_per_page': 0.4470664529184653} 21 
22 # All the following queries involve traversing the Book<->Publisher
23 # foreign key relationship backwards.
24 
25 # Each publisher, each with a count of books as a "num_books" attribute.
26 >>> from django.db.models import Count 27 >>> pubs = Publisher.objects.annotate(num_books=Count('book')) 28 >>> pubs 29 [<Publisher BaloneyPress>, <Publisher SalamiPress>, ...] 30 >>> pubs[0].num_books 31 
32 # The top 5 publishers, in order by number of books.
33 >>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5] 34 >>> pubs[0].num_books

示例-1: 統計每個出版社出了多少本書

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day18.settings")

import django
django.setup()   #導入django環境

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

#統計每個出版社出了多少本書
pub_objs = book_models.Publisher.objects.annotate(book_nums=Count("book"))
print(pub_objs)
for publisher in pub_objs:
    print(publisher.book_nums)

輸出:

<QuerySet [<Publisher: <清華出版社>>, <Publisher: <惠來出版社>>]>
8
6
View Code

根據輸出可知,清華出版社出版了8本書,惠來出版社出版了6本書。

 

示例-2: 統計某日期共出版了多少本書

print(models.Entry.objects.values()[0])  #字典形式
print(models.Entry.objects.values_list())  #元組形式

print("----------->>>")
print(book_models.Book.objects.values_list("publish_date"))
print("----------->>>")
#統計某日期共出版了多少本書
print(book_models.Book.objects.values_list("publish_date").annotate(Count("publish_date")))
#基本表內字段的分類聚合

輸出:

{'blog_id': 1, 'headline': '屌炸天', 'rating': 4, 'body_text': '一個屌絲自櫓的日子', 'pub_date': datetime.date(2017, 3, 19), 'id': 1, 'n_comments': 6, 'mod_date': datetime.date(2017, 3, 19), 'n_pingbacks': 6}
<QuerySet [(1, 1, '屌炸天', '一個屌絲自櫓的日子', datetime.date(2017, 3, 19), datetime.date(2017, 3, 19), 6, 6, 4), (2, 2, '學py的日子', '學py的日子不如自櫓', datetime.date(2017, 3, 19), datetime.date(2017, 3, 19), 1, 3, 1), (3, 2, 'qqqq', 'wqertyuio', datetime.date(2017, 3, 8), datetime.date(2017, 3, 19), 6, 5, 7)]>
----------->>>
<QuerySet [(datetime.date(2017, 3, 14),), (datetime.date(2017, 3, 14),), (datetime.date(2017, 3, 1),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 18),), (datetime.date(2017, 3, 2),), (datetime.date(2017, 3, 14),), (datetime.date(2017, 3, 19),)]>
----------->>>
<QuerySet [(datetime.date(2017, 3, 1), 1), (datetime.date(2017, 3, 2), 1), (datetime.date(2017, 3, 14), 3), (datetime.date(2017, 3, 18), 8), (datetime.date(2017, 3, 19), 1)]>
View Code

根據結果可知: 3月1號出版了1本書……3月18號出版了8本書。

 

參考博客: http://www.cnblogs.com/alex3714/articles/5512568.html (他寫得絕逼沒我好哈哈)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM