视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
利用Django对数据库数据进行查询
2025-09-30 22:45:36 责编:小OO
文档
利用Django对数据库数据进行查询

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'))下载本文

显示全文
专题