DjangoModelQuery详解

django 对于model的查询使用较多,会包含在view中做查询。

当前已经使用的如下:

articles = Article.objects.order_by('-updatedAt')
categories = Category.objects.all()

创建对象

使用save()方法可以进行对象的创建

样例:

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

在我们的程序中使用做slug部分使用了重写save方法,具体可以查看models.py

def save(self, *args, **kwargs):
    self.slug = slugify(self.title)
    super(Article, self).save(*args, **kwargs)

这个例子重写了article的save方法,其中调用uuslug的slugify方法将title的标题字段重写为slug的格式,然后赋值给slug。最后调用父类的save方法来进行保存。

注意这里一定要调用父类的方法进行保存。

更新对象

在django中对象的更新是可以直接使用save进行更新的,save部分字段就可以更新。

查询对象

查询所有对象

# 查询对象并按照时间排序
articles = Article.objects.order_by('-updatedAt')
# 查询所有对象
categories = Category.objects.all()

根据关键字查询

filter(**kwargs) 根据kwargs过滤的内容返回一个QuerySet。

exclude(**kwargs) 根据kwargs排除过滤的内容返回一个QuerySet。

我们在查询Article的时候返回所有的对象,但是我们在设计BaseSchema的时候,使用的是软删除的方式,这种查询方法会把已删除的对象也查询出来,我们需要过滤掉deletedAt的对象。修改views.py

def index(request):
    articles = Article.objects.filter(deletedAt=None).order_by('-updatedAt')
    categories = Category.objects.filter(deletedAt=None)
    context = {
        'articles': articles,
        'categories': categories,
    }
    return render(request, 'blog/blog_image_rs.html', context)

通过这种模式filter我们可以只查deletedAt字段为None的article。

查看query的相应查询语句

经常我们在使用查询语句的时候,希望看一下最终的sql的查询语句是什么。 比较好的方式是在debug的断点中停住查看,这样更方便调试 -w1261

同时我们希望在页面中过只显示publish状态的文章。同样需要添加我们的查询条件

def index(request):
    # articles = Article.objects.order_by('-updatedAt')
    articles = Article.objects.filter(deletedAt=None).filter(status=2).order_by('-updatedAt')
    categories = Category.objects.filter(deletedAt=None)
    context = {
        'articles': articles,
        'categories': categories,
    }
    return render(request, 'blog/blog_image_rs.html', context)

这样就能再次过滤我们的状态为publish的文章

同时在修改deletedAt的时候,也记得将admin中的部分修改。 具体可以参考DjangoAdmin详解

Chaining filters

我们可以在查询中连接使用filter和exclude 来对结果进行过滤。如下所示

articles = Article.objects.filter(deletedAt=None).filter(status=2).order_by('-updatedAt')

filter lookups

在查询方法filter(), exclude() and get()中,我们可以指定更精准的查询方式,这种方式对应到sql的where方法中。

这种查询方式使用格式field__lookuptype=value

查询方式包含以下几个:

exact

An "exact" match。 指定一个精准的匹配。类似 = 的作用

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

匹配

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

iexact

支持大小写不敏感的查询,使用之后可以查到当前大小写的。

Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)
SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;

contains

大小写不敏感的like方式, 使用后可以找到前后包含的内容,同时是大小写不敏感的

Entry.objects.get(headline__contains='Lennon')
SELECT ... WHERE headline LIKE '%Lennon%';

icontains

大小写不敏感的icontains方式

Entry.objects.get(headline__icontains='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%Lennon%';

in

在集合中查询 list, tuple, or queryset

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')

SQL equivalents:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

这种写法可以使用为in查询

SQL如下

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

同时也可以支持对其他外键的支持

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

gt

Greater than.

gte

Greater than or equal to.

lt

Less than.

lte

Less than or equal to.

startswith

Case-sensitive starts-with.

Entry.objects.filter(headline__startswith='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE 'Lennon%';

istartswith

Case-insensitive starts-with.

endswith

Case-sensitive ends-with.

iendswith

Case-insensitive ends-with.

range

Range test (inclusive).

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL equivalent:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

更多可以参考 django官方文档filed-lookups部分

属性查询

join查询,SQL中提供丰富的联表join查询。在django中也可以同关系联表查询的模式。可以使用filter方式进行。

Article.objects.filter(categories__title='Ielts')

可以用于查询所有目录标题为Ielts的Article

多次联表可以使用多个双下划线

复杂的Q查询

前面的filter、exclude可以提供基础的查询模式,更复杂的查询可以使用Q查询来进行

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

可以提供or查询的能力

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

等同于SQL

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

多级查询

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

等同于SQL

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

Last updated

Was this helpful?