阿布云

你所需要的,不仅仅是一个好用的代理。

Django的模型和数据库以及一点总结(三)

阿布云 发表于

p1.png

另外一些查询字段:

  • exact:精确匹配,通常我们查询时使用的字段都包含了exact,只不过Dangjo都默认帮你处理好了;
  • iexact:匹配,忽略大小写;
  • contains,icontains:包含和忽略大小写的包含;
  • startswith,endswith,istartswith,iendswith:以某字符串开头和其忽略大小写的情况;
  • pk:和主键的作用一样,任何查询类型都可以与pk 结合来完成一个模型上对主键的查询;

F表达式

F() 返回的实例用作查询内部对模型字段的引用,Django支持对对象使用加法、减法、乘法、除法、取模以及幂计算等算术操作.

Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)  # n_pingbacks为一个字段

当面对多值查询的时候,需要注意使用filter,一种是同时满足条件,另一种是至少满足条件。

缓存和查询集

为了避免查询的内容不一致,可以先将查询集进行缓存;但是如果访问查询集中不存在的部分,那么后面的部分查询集将不会保存。

使用Q对象

如果使用Q对象,那么其必须位于所有关键字参数的前面。

Poll.objects.get(

    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),

    question__startswith='Who')

删除对象

注意,delete() 是唯一没有在管理器 上暴露出来的查询集方法。这是一个安全机制来防止你意外地请求Entry.objects.delete(),而删除所有 的条目。如果你确实想删除所有的对象,你必须明确地请求一个完全的查询集:

update

update() 方法会立即执行并返回查询匹配的行数。如果你想保存查询集中的每个条目并确保每个实例的save() 方法都被调用,你不需要使用任何特殊的函数来处理。只需要迭代它们并调用save():

for item in my_queryset:

    item.save()

聚合

常用的字段包括:

  • Avg:平均值;
  • Count:返回对应expression的个数;
  • Max:返回expression的最大值;
  • Min:返回expression的最小值;
  • StdDev:标准差;
  • Variance:方差;

annotate() 和 values() 字句的顺序

和使用 filter() 子句一样,作用于某个查询的annotate() 和 values() 子句的使用顺序是非常重要的。如果values() 子句在 annotate() 之前,就会根据 values() 子句产生的分组来计算注解。

但是,如果 annotate() 子句在 values()子句之前,就会根据整个查询集生成注解。在这种情况下,values() 子句只能限制输出的字段范围。

Author.objects.annotate(average_rating=Avg('book__rating'))  # 根据作家id进行分组Author.objects.values('name').annotate(average_rating=Avg('book__rating'))  # 根据作家名字进行分组

默认排序交换或order_by()

如果在 Meta 中指定了排序方式,那么在annotate的时候则会将默认的排序方式也作为一个分组项,所以要将其默认排序方式进行清空,做法如下:

Item.objects.values("data").annotate(Count("id")).order_by()

搜索

Managers

自定义管理器和模型继承

可以继承自models.Manger,从而自定义管理器。需要注意的是,如果使用自定义的管理器对象,Django会将遇到的第一位当成默认的管理器。可以在Meta中指定base_manager_name,这样就不用自己去写创建的代码。

Django如何处理:

  • 定义在非抽象基类中的管理器是不会被子类继承的。如果你想从一个非抽象基类中重用管理器,只能在子类中重定义管理器。 这是因为这种管理器与定义它的模型绑定得非常紧密,所以继承它们经常会导致异常的结果(特别是默认管理器运行的时候)。 因此,它们不应继承给子类。
  • 定义在抽象基类中的管理器总是被子类继承的,是按 Python 的命名解析顺序解析的(首先是子类中的命名覆盖所有的,然后是第一个父类的,以此类推)。
  • 如果类当中显示定义了默认管理器,Django 就会以此做为默认管理器;否则就会从第一个抽象基类中继承默认管理器; 如果没有显式声明默认管理器,那么 Django 就会自动添加默认管理器。

注意在抽象模型上面定义一个自定义管理器的时候,不能调用任何使用这个抽象模型的方法,需要通过子管理器来使用。比如,这样就是错的:

AbstractBase.objects.do_something()

Django 为自定义管理器的开发者提供了一种方式:无论开发的管理器类是不是默认的管理器,它都应该可以用做自动管理器。 可以通过在管理器类中设置 use_for_related_fields属性来做到这点。

class MyManager(models.Manager):

    use_for_related_fields = True  # 注意是在管理器中进行定义

但是需要注意的是,不要在这种类型的管理器子类中过滤掉任何结果,一个原因是自动管理器是用来访问关联模型的对象。 在这种情况下,Django 必须要能看到相关模型的所有对象,所以才能根据关联关系得到任何数据 ;如果过滤掉了数据,那么会使得它所在的管理器不适于用做自动管理器。

原生SQL语句的查询

有两种方式,分别是使用ORM提供的函数或者不用ORM,但要注意的是,需要防止SQL注入。

使用raw

for p in Person.objects.raw('SELECT * FROM myapp_person'):

    print(p)

这里的myapp_person,Django会去从指定的myapp中找到对应的模型。

也可以通过字典的方式来传递参数,使用函数的参数params可以完全防止SQL注入攻击,不要使用字符串的连接。:

name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}

Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

当对其的结果进行数量的限制时,直接对数据库进行操作,这样可以稍微提升效率。