from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self): # __unicode__ on Python 2
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self): # __unicode__ on Python 2
return self.headline
保存对象
要更改已存在于数据库的对象然后进行保存,使用save()。
例如:
b5.name = ‘New Name’
b5.save()
存储ForeignKey和ManyToManyField
更新ForeignKey字段和更新普通字段的方法相同:
from blog.models import Blog, Entry
entry = Entry.objects.get(pk=1)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()
更新ManyToManyField,可以使用add()字段:
From blog.models improt Author
Joe = Author.objects.create(name=”Joe”)
entry.authors.add(Joe)
当需要一次添加多个记录时,在add()中将需要添加的字段都加上:
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)
检索对象
检索所有对象
从数据库表中检索对象的最简单方法是获取所有对象:
All_entries = Entry.objects.all()
使用过滤器检索特定的对象
在QuerySet中用all()返回数据库的表中的所有对象。但是通常情况下,我们只需要完整对象集中的一部分。
在这种情况下可以使用下面方法,添加过滤条件:
Filter(**kwargs)返回一个新的QuerySet包含给定查找参数的对象/
Exclude(**kwargs)返回除给定查找参数之外的对象。
例如,需要获得QuerySet2006年的博客条目,使用filter()如下所示:
Entry.objects.filter(pub_date__year=2006)
相当于:
Entry.objects.all().filter(pub_date__year=2006)
组合过滤
例如:
Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
表示为以2005年1月30日和当天发布的“What”开头的数据。
已筛选的QuerySets是唯一的
每当你重新定义一个QuerySet,你就会得到一个新的QuerySet,这个QuerySet和你现在的定义绑定。他可以重复使用或重新定义。
例如:
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.date.today())
q3 = q1.filter(pub_date__gte=datetime.date.today())
Q1为以What开头的数据,q2继承q1在q1基础上排除时间为今天的数据,q3继承q1在q1基础上过滤为时间是今天的。
查询表达式
查询表达式描述可用作更新、创建、过滤、排序、注释或聚合的一部分的值或计算。有很多的内置表达式可以用于查询。表达式可以组合,或在某些情况下进行嵌套,用于更复杂的计算。
支持的算术
Django支持使用Python常量,变量,甚至其他的表达式对查询表达式进行加法,减法,乘法,除法,模运算和运算符运算。
例子:
from django.db.models import F, Count, Value
from django.db.models.functions import Length, Upper
# Find companies that have more employees than chairs.
Company.objects.filter(num_employees__gt=F('num_chairs'))
# Find companies that have at least twice as many employees
# as chairs. Both the querysets below are equivalent.
Company.objects.filter(num_employees__gt=F('num_chairs') * 2)
Company.objects.filter(
num_employees__gt=F('num_chairs') + F('num_chairs'))
# How many chairs are needed for each company to seat all employees?
>>> company = Company.objects.filter(
... num_employees__gt=F('num_chairs')).annotate(
... chairs_needed=F('num_employees') - F('num_chairs')).first()
>>> company.num_employees
120
>>> company.num_chairs
50
>>> company.chairs_needed
70
# Create a new company using expressions.
>>> company = Company.objects.create(name='Google', ticker=Upper(Value('goog')))
# Be sure to refresh it if you need to access the field.
>>> company.refresh_from_db()
>>> company.ticker
'GOOG'
# Annotate models with an aggregated value. Both forms
# below are equivalent.
Company.objects.annotate(num_products=Count('products'))
Company.objects.annotate(num_products=Count(F('products')))
# Aggregates can contain complex computations also
Company.objects.annotate(num_offerings=Count(F('products') + F('services')))
# Expressions can also be used in order_by()
Company.objects.order_by(Length('name').asc())
Company.objects.order_by(Length('name').desc())
F()表达式
一个F()对象来替换Model字段或注释列的值。他可以引用Model字段的值并使用它们执行数据库操作,而不用将数据从数据库中读取道Pyhton内存中。
Django可以使用F()对象来生成对应的SQL语句。
一个简单的例子:
通常情况下我们是这样写的:
Reporter = Reporters.objects.get(name=’Tintin’)
Reporter.stories_filed += 1
Reporter.save()
这样操作后我们将数据库的数据提取到了内存中,并使用Pyhton进行处理/
我们也可以:
From django.db.models import F
Reporter = Reporters.objects.get(name=’Tintin’)
Reporter.stories_filed = F(‘stories_filed’) + 1
Reporter.save()
看起来像一个正常的Python赋值给实例,实际上改是一个描述数据库操作的SQL构造。
当Django遇到F(),它会覆盖标准的Python运算符,然后创建一个封装的SQL表达式;
F()还可以用于QuerySet对象实例update():
Reporter = Reporters.objects.get(name=’Tintin’)
Reporter.update(stories_filed=F(‘stories_filed’) + 1)
使用F()避免竞争条件
F()另一个有用的好处是让数据库(而不是Python)更新字段的值可以避免竞争状况。
如果两个Python线程在上面的第一个示例中执行代码,则一个线程可以在另一个线程从数据库中检索到字段值后检索,增加和保存字段值。第二个线程保存的值将基于原始值; 第一个线程的工作将会丢失。
如果数据库负责更新字段,则该过程更加简单:只有在执行save() 或update()时基于数据库中字段的值更新字段,而不是根据检索实例时的值来更新字段。
聚合
当我们需要检索通过汇总或汇总对象集合而得到的值时使用。
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class Publisher(models.Model):
name = models.CharField(max_length=300)
num_awards = models.IntegerField()
class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
pubdate = models.DateField()
class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
registered_users = models.PositiveIntegerField()
常见的聚合查询(利用上述Model作为原型):
# Total number of books.
>>> Book.objects.count()
2452
# Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73
# Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
# Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}
# Difference between the highest priced book and the average price of all books.
>>> from django.db.models import FloatField
>>> Book.objects.aggregate(
... price_diff=Max('price', output_field=FloatField()) - Avg('price'))
{'price_diff': 46.85}
# All the following queries involve traversing the Book<->Publisher
# foreign key relationship backwards.
# Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs =Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
>>> pubs[0].num_books 73 # The top 5 publishers, in order by number of books. >>> pubs =Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5] >>> pubs[0].num_books 1323 在QuerySet生成聚合 Django提供了两种生成聚合的方法。第一种方法是在整个QuerySet生成总结值。 例如: Book.objects.all() >>>From django.db.models import Avg >>>Book.objects.all().aggregate(Avg(‘price’)) {‘price__avg’: 34.35} All()其实在其中是多余的可以省略; Book.objects.aggregate(Avg(‘price’)) {‘price__avg’:34.35} Aggregate()是QuertSet的一个终端子句,当被调用时,返回一个键-值对的字典。 该名称是聚合值的标识符;该值是计算的聚合。名称是根据字段名称和聚合函数自动生成的。如果您想手动制定聚合值的名称,可以改为如下写法: Book.objects.aggregate(average_price=Avg(‘price’)) {‘average_price’:34.35} 如果需要生成多个聚合,则只需在aggregate()子句中添加其他参数,如: From django.db.models import Avg, Max, Min Book.objects.aggregate(Avg(‘price’), Max(‘price’), Min(‘price’)) {‘price__avg’:34.35, ‘price__max’:Decimal(‘81.20’), ‘price__min’:Decimal(‘12.99’)} 为QuerySet中的每个项目生成聚合 生成汇总值的第二中方法是为a中的每个对象生成一个的QuerySet汇总,例如,如果您正在检索书籍列表,您可能想知道有多少作者对每本书书有多少贡献。每本书都与作者有多对多的关系; 可以使用annotate()子句生成每个对象的摘要。当annotate()描述要计算聚合的每个参数。例如,要用作者数量对书籍进行annotate: # Build an annotated queryset >>> fromdjango.db.models import Count >>> q = Book.objects.annotate(Count('authors')) # Interrogate the first object in the queryset >>> q[0] >>> q[0].authors__count 2 # Interrogate the second object in the queryset >>> q[1] >>> q[1].authors__count 1 与之前的aggregate()一样,注释的名称自动从聚合函数的名称和要聚合的字段名称派生而来。可以在使用annotate时提供别名来更改默认名称: >>> q = Book.objects.annotate(num_authors=Count('authors')) >>> q[0].num_authors 2 >>> q[1].num_authors 1 不同于aggregate(),annotate()不是一个终端子句。Annotate()输出的是一个QuerySet;这个QuerySet可以使用任何其他的QuerySet操作进行修改,包括filter(),order_by()甚至是在此调用annotate()。 连接和聚合¶ 到目前为止,我们已经处理了属于被查询模型的字段的聚合。但是,有时您想要汇总的值将属于与您正在查询的模型相关的模型。 当在集合函数中指定要聚合的字段时,Django将允许您使用在引用过滤器中的相关字段时使用的相同的双下划线表示法。然后Django将处理检索和聚合相关值所需的任何表连接。 例如,要查找每个商店中提供的书籍的价格范围,可以使用注释: >>> from django.db.models import Max, Min >>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price')) 这告诉Django检索Store模型,加入(通过多对多关系)与Book模型,并聚合在书模型的价格字段上以产生最小值和最大值。 该条款适用相同的规则aggregate()。如果您想知道任何商店中可供出售的任何图书的最低和最高价格,则可以使用以下汇总: >>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price')) 加入连锁可以尽可能深。例如,要提取可供出售的任何图书的最年轻作者的年龄,可以发出查询: >>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))下载本文