• Django 模型和数据库 总结


    模型和数据库

    模型

    首先我们在创建一个model的时候,这个类都是继承自 django.db.models.Model,

    各种Model Field类型

    1. AutoField,自动增长的IntegerField,如果不指定,则默认添加。
    2. IntegerField/BigIntegerField/PositiveSmallIntegerField/SmallIntegerField:都是类似的,只是数字的范围不同。
    3. BinaryField/DecimalField:二进制和十进制。
    4. BooleanField,如果没有指定default的话,默认为None
    5. CharField,**必须**接收另外一个参数 max_length
    6. DateField,使用Python的datetime.date实例表示的日期。

      需要注意的是,auto_now用于每次保存对象的时候,自动设置该字段为当前时间;auto_now_add则用于第一次被创建时自动设置该字段为当前时间,这些选项还有default之间相互违背的,所以不要同时使用任意多个。这些选项默认保存的是 django.utils.timezone.datetime 里面的now,所以如果想要进行特殊的保存,需要自己重写save函数。
    7. EmailField,基于CharField,使用EmailValidator来验证输入和合法性。

    8. FileField,上传文件,字段的选项不支持primary_key和unique。

      需要在settting文件里面,需要添加MEDIA_ROOT用来提供文件上传的根路径,而参数upload则提供文件具体的位置。
      当你删除了该model,文件需要你自己手动去删除。
    9. ImageField,继承自FileField,同时还添加了图像的验证。

    10. NullBooleanField,和之前BooleanField不同的是,它除了允许True或者False,还允许Null=True,也就是为null。

    11. TextField,适用于大文本字段,如果设定了max_length属性,那么其只会对组件进行一个内容显示的限制,但是不会对数据库存在限制。

    12. TimeField,和Python中的datetime.time一样,参数则和DateField相同。

    13. URLField,继承自CharField,但是同样添加了URL的验证。

    除了上面的Fields,还有关系Field:

    1. ForeignKey,对应的是一对多的关系,可以指定关联删除-**on_delete=models.CASCADE**,如果要关联的对象还没有定义好,可以使用其名字。
      1. limit_choices_to,可以限制关联返回的内容。
      2. related_name,可以让关联的对象反查到源对象,如果不想创建反向关联,则设置为"+"即可。需要注意的是,如果没有使用该Field,那么想要使用反向关联,则需要**foo_set**,foo为关联对象的小写名称,如果使用了该Field,则可以直接使用自己定义的名称。
      3. related_query_name,和上面的作用类似,同样可以反向查询,两者只需要设置一个即可。
      4. to_field,指定关联对象的字段名称,默认情况下为对方的主键。
      5. db_constraint,控制是否在数据库中为这个外键创建约束,默认为True。
      6. on_delete,可以实现CASCADE,级联删除;PROTECT,防止被引用对象删除,抛出ProtectedError;SET_NULL,将其设置成null;

    SET_DEFAULT,设置成默认值;SET,可以传递值,同时还可以传递可调用对象;DO_NOTHING,不采取任何动作。

    1. ManyToManyField,对应的是多对多的关系。
      1. symmetrical,只用在自己对自己进行关联的时候。比如说Friend,你的朋友是我,我的朋友是你。
      2. through,如果不想要Django自动创建的多对多的关系表,可以通过指定through指定自己定义的中介表。
      3. through_fields,在上面的基础上指定中间模型的**哪些字段**来建立是多对多关联。
      4. db_table,设定多对多关系表的名称。
      5. db_constraint,同上。
      6. swappable,
    2. OneToOneField,对应的是一对一的关系,其可以直接返回关系另一边的对象,最主要的用途是作为扩展自另外一个模型的主键。比如多表继承就是利用这样的原理,通过对子模型添加一个隐式的一对一关联关系到父亲模型实现的。

      如果你没有指定其的related_name参数,那么Django将使用当前模型的小写名称作为默认值。
      如果访问相应的对象不存在的话,则会抛出ObjectDoesNotExist的异常。
      当设置**parent_link**为True时,??

    Model Field Options

    下面这些选项都是可选择的,非固定要求。

    1. Field.null,注意在CharField或者TextField里避免使用null,因为其存储的值是空字符串而不是NULL。
    2. Field.blank,和上面的不同,其限制的是组件,而上面限制的是数据库。
    3. Field.choices,由可迭代的二元祖来组成,其中元祖里面第一个元素是存储在数据中的值,第二个则是元素更加详细的描述,界面上显示的是后者。,数据库存储的是前者。
    4. Field.db_column,数据库中用来表示字段的名称,如果没有提供,则默认使用filed的名称。
    5. Field.db_index,如果为True,则为该字段创建索引。
    6. Field.db_tablespace,表空间,如果该字段已经创建了索引,那么数据库表空间的名称将作为该字段的索引名。注意,部分数据库不支持表空间。
    7. Field.db_default,指定一个默认值,它可以是一个值或者可调用对象,注意的是,其不可以是一个可变对象,因为会指向同一个引用。
    8. Field.editable,如果为false,则不可编辑,那么admin和其它model则忽略掉这个字段。
    9. Field.error_messages,能够重写默认抛出的错误信息。
    10. Field.help_text,将会作为提示信息显示在表单中。
    11. Field.primary_key,这意味着null=False和unique=True,所以一个对象只能拥有一个主键。
    12. Field.unique,当设定为True时,不需要再设定db_index,因为其本身就是一个索引的创建。注意的是,ManyToManyField和OneToOneField和FileField以外的其它类型都可以使用这个字段(????)。
    13. Field.unique_for_date/Field.unique_for_month/Field.unique_for_year/Field,设置对应的时间是唯一的。
    14. Field.validators,指定验证器。
    15. ForeignKey、ManyToManyField和OneToOneField需要通过Field.verbose_name才能自定义设置字段名,其它均可以每个字段类型都可在第一个参数上自定义设置字段的字段名。

    每个字段实例都包含几个允许内省其行为的属性,自定义模型字段需要实行这些标志。

    1. Field.auto_created
    2. Field.concrete
    3. Field.hidden
    4. Field.is_relation
    5. Field.model

    上面是普通Field的属性,下面是关系Field的属性:

    1. Field.many_to_many,多对多关系;
    2. Field.many_to_one,多对一关系,例如ForeignKey;
    3. Field.one_to_many,一对多关系,例如GenericRelation或者ForeignKey的反向;
    4. Field.one_to_one,一对一关系;
    5. Field.related_model,指向字段涉及的模型;

    自定义Model Field

    不是很懂

    可以参考源码。

    Relationships

    Many-to-one relationships

    翻译-一对多关系

    Many-to-many relationships

    翻译-多对多关系

    One-to-one relationships

    翻译-一对一关系

    Meta 选项

    所有的选项都不是必须的。

    1. abstract,如果声明为True,则表明这是一个抽象基类。
    2. app_label,如果定义在application之外,则需要指明它是那个applicaition的,也可以通过其属性自定义格式。
    3. base_manager_name,指定managers的名字。
    4. db_table,指定数据库表格的名字。
    5. db_tablespace,指定表格空间,如果数据库不支持则忽略。
    6. default_manger_name,指定manager的名字。
    7. default_related_name,指定反向关联的模型的名称,需要注意的是,这个名称应该是唯一的,建议命名中包含app和model名字以避免冲突,%(app_label)s和%(model_name)s
    8. get_latest_by,指定model中某个可排序的字段的名称,这样当通过managers去调用lates函数的时候会返回根据排序的最新的结果。
    9. managed,是否指明Django为当前模型创建和删除数据库表,True或者False。
    10. order_with_respect_to,通常用在关联对象上面,指定某个字段,使其在父对象中有序。

          设置之后,可以通过get_RELATED_order和set_RELATED_order进行获取关联对象的已经拍好序的主键列表或者是自定义设置其顺序。
          我们还可以通过get_next_in_order和get_previous_in_order,可以用于获取一个生成器。
    11. ordering,对象默认的顺序,获取一个对象的列表时候使用。

    12. permissions,设置创建对象时权限表中额外的权限,注意其是一个二元祖的元祖或者列表。

    13. default_permissions,默认为 add,change,delete。

    14. proxy,如果为True,则表明这是另外一个模型的子类,这将会作为一个代理模型。

    15. required_db_features,

    16. required_db_vendor,指定使用哪种数据库。

    17. select_on_save,指定使用哪种保存数据的算法。

    18. unique_together,用来设置不重复的字段组合。

    19. index_together,用来设置带有索引的字段组合,和上面的用法相似。

    20. verbose_name,为model创建一个易于理解的名称,单数。

    21. verbose_name_plural,和上面不同的是,为复数形式。

    模型属性

    如果没有自定义Manager,则默认的名称为objects;Managers只能通过模型类来访问,而不能通过模型实例来访问。

    模型方法

    创建对象

    在封装一些操作的时候,可以在model中添加一个类方法,或者在自定义管理器中添加一个方法(推荐)。

    模型加载

    Model.from_db和Model.refresh_from_db。

    验证对象

    验证一个模型涉及这三个步骤:

    1. 验证模型的字段 —— Model.clean_fields()
    2. 验证模型的完整性 —— Model.clean()
    3. 验证模型的唯一性 —— Model.validate_unique()

    当调用full_clean()的时候,上面三个方法都会按顺序执行。如果验证失败,则会抛出ValidationError

    保存对象

    保存对象需要经过下面的步骤:

    1. 发出一个pre-save 信号。 发送一个django.db.models.signals.pre_save 信号,以允许监听该信号的函数完成一些自定义的动作。
    2. 预处理数据。 如果需要,对对象的每个字段进行自动转换。

      大部分字段不需要预处理 —— 字段的数据将保持原样。预处理只用于具有特殊行为的字段。例如,如果你的模型具有一个auto_now=True 的DateField,那么预处理阶段将修改对象中的数据以确保该日期字段包含当前的时间戳。(我们的文档还没有所有具有这种“特殊行为”字段的一个列表。)
    3. 准备数据库数据。 要求每个字段提供的当前值是能够写入到数据库中的类型。

      大部分字段不需要数据准备。简单的数据类型,例如整数和字符串,是可以直接写入的Python 对象。但是,复杂的数据类型通常需要一些改动。
      例如,DateField 字段使用Python 的 datetime 对象来保存数据。数据库保存的不是datetime 对象,所以该字段的值必须转换成ISO兼容的日期字符串才能插入到数据库中。
    4. 插入数据到数据库中。 将预处理过、准备好的数据组织成一个SQL 语句用于插入数据库。

    5. 发出一个post-save 信号。 发送一个django.db.models.signals.post_save 信号,以允许监听听信号的函数完成一些自定义的动作。

    关于Django是怎么知道UPDATE还是INSERT?

    • 如果对象的主键属性为一个求值为True 的值(例如,非None 值或非空字符串),Django 将执行UPDATE。
    • 如果对象的主键属性没有设置或者UPDATE 没有更新任何记录,Django 将执行INSERT。

    当然你也可以通过指定save的参数,强制进行INSERT或者UPDATE。

    在执行完create动作之后,需要将其创建的对象调用save进行保存。

    更新对象

    可以通过F表达式可以避免竞争条件而且更快,而不是通过对对象赋一个新值。

    删除对象

    通过Model.delete方法。

    Pickling对象

    pickle是Python自带的用于对象序列化的。

    Model.__str__

    用来返回一个更易读的字符串。

    Model.__eq__

    为了让具有相同主键的相同实类的实例是相等的。

    Model.__hash__

    基于实例主键的值。

    Model.get_absolute_url

    告诉Django如何计算对象的标准URL。需要注意的是,get_absolute_url() 返回的字符串必须只包含ASCII 字符(URI 规范RFC 2396 的要求),并且如需要必须要URL-encoded。

    其它

    Model.get_FOO_display,对于每个具有choices 的字段,每个对象将具有一个get_FOO_display() 方法,其中FOO 为该字段的名称。

    Model.get_next_by_FOO和Model.get_previous_by_FOO。

    Model.DoesNotExist,通常发生在找不到对象的时候则报出这个错。

    模型继承

    在Django 中有3种风格的继承。

    1. 通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以你要使用抽象基类。
    2. 如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承。继承关系在子model和它的每个父类之间添加一个链接,这是通过自动创建的OneToOneField来实现的。
    3. 最后,如果你只是想改变一个模块Python 级别的行为,而不用修改模型的字段,你可以使用代理模型。

    抽象基类

    基类并不会创建任何的数据库,继承自其的子model才会创建包括基类的数据库。

    多表继承

    因为是隐藏的创建了一对一的关系,其反向关联名字是默认的,如果你还存在和父model的一对多或者多对多的关系,那么你必须指定它们的related_name,否则它们都用默认的就会发生冲突。

    代表模型

    有时,你可能只想更改 model 在 Python 层的行为实现。比如:更改默认的 manager ,或是添加一个新方法。

    为原始模型创建一个代理 。你可以创建,删除,更新代理 model 的实例,而且所有的数据都可以像使用原始 model 一样被保存。 不同之处在于:你可以在代理 model 中改变默认的排序设置和默认的 manager ,更不会对原始 model 产生影响

    多重模型

    一般来说,你并不需要继承多个父类。多重继承主要对“mix-in”类有用:向每个继承mix-in的类添加一个特定的、额外的字段或者方法。你应该尝试将你的继承关系保持得尽可能简洁和直接,这样你就不必费很大力气来弄清楚某段特定的信息来自哪里。

    不允许重写字段。普通的 Python 类继承允许子类覆盖父类的任何属性。 但在 Django 中,重写 Field实例是不允许的(至少现在还不行)。如果基类中有一个 author字段,你就不能在子类中创建任何名为 author的字段。

    查询

    关联对象参考

    就像 remove() 方法一样,clear()只能在 null=True的ForeignKey上被调用,也可以接受bulk关键词参数。

    注意,对于所有类型的关联字段,add()、create()、remove()和clear()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

    获取对象

    每个模型至少拥有一个管理器,其默认命名为objects。

    链式过滤

    查询集的筛选结果还是查询集,所以可以将筛选结果链接在一起,表示一个链式过滤:

    Entry.objects.filter(headline__startswith='What')
    .exclude(pub_date__gte=datetime.date.today())
    .filter(pub_date__gte=datetime(2005, 1, 30))
    

    需要注意的是,查询集是懒惰的,只有在请求其的时候才会去访问数据库。

    使用get

    注意使用get方法,如果其不存在数据或者存在多条数据,都会抛出错误,所以要保证只有一条单独的数据。

    另外一些查询字段:

    • 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:标准差;
    • Sum:和;
    • 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如何处理:

    1. 定义在非抽象基类中的管理器是不会被子类继承的。如果你想从一个非抽象基类中重用管理器,只能在子类中重定义管理器。 这是因为这种管理器与定义它的模型绑定得非常紧密,所以继承它们经常会导致异常的结果(特别是默认管理器运行的时候)。 因此,它们不应继承给子类。
    2. 定义在抽象基类中的管理器总是被子类继承的,是按 Python 的命名解析顺序解析的(首先是子类中的命名覆盖所有的,然后是第一个父类的,以此类推)。
    3. 如果类当中显示定义了默认管理器,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)
    

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

    使用原生orm

    如果你需要直接访问数据库,则格式如下:

    from django.db import connection
    def my_custom_sql(self):
        cursor = connection.cursor()
        cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
        cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
        row = cursor.fetchone()
        return row
    

    延迟加载

    注意延迟加载的问题,在每次访问的时候,会从加载中返回指定内容并且指向下一个。

    数据库事务

    管理事务

    使用默认的管理事务

    Django中提供了一种默认的方式,只需要在Settting中将ATOMIC_REQUESTS设置为True,其原理就是将把每一个请求用事务包装起来,在调用一个view里面的方法之前Django先创建一个事务,如果发出的响应没有问题,Django就会提交这个事务。如果在view这里产生一个异常,Django就会回滚这次事务。

    但是,这也存在一个效率问题,对每个视图开启一个事务是有所耗费的。其对性能的影响依赖于应用程序对数据库的查询语句效率和数据库当前的锁竞争情况。

    如果想要阻止视图运行一个事务,则可以在view上使用non_atomic_requests装饰器,那么对应的view则不会执行一个事务。

    from django.db import transaction
    @transaction.non_atomic_requests(using='other')
    def my_other_view(request):
        do_stuff_on_the_other_database()
    

    自定义管理事务

    通过atomic(using=None, savepoint=True)装饰器对具体的view进行管理事务,它也可以作为上下文管理器。

    from django.db import transaction
    @transaction.atomic
    def viewfunc(request):
        # This code executes inside a transaction.
        do_stuff()
    def viewfunc(request):
        # This code executes in autocommit mode (Django's default).
        do_stuff()
        with transaction.atomic():
            # This code executes inside a transaction.
            do_more_stuff()
    

    在底层,Django的事务管理代码:

    • 当进入到最外层的 atomic 代码块时会打开一个事务;
    • 当进入到内层atomic代码块时会创建一个保存点;
    • 当退出内部块时会释放或回滚保存点;
    • 当退出外部块时提交或回退事物。

    同样的存在一个性能的考虑,所有打开的事务会对数据库带来性能成本。要尽量减少这种开销,尽量保持您的交易尽可能短。 在Django的请求/响应周期,如果你使用 atomic()来执行长运行的进程,这尤其重要。

    使用原生的api

    具体参考

    数据库访问优化

    在模版中使用with标签

    {% with total=business.employees.count %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    

    在数据库中操作而不是在Python中操作

    • 在最基础的层面上,使用过滤器和返现过滤器对数据库进行过滤;
    • 使用**F表达式**在相同模型中基于其它字段进行过滤;
    • 使用数据库中的aggregate和annotate;

    用唯一的被索引的列来当作检索的对象

    比如,上面的就快过于下面,因为id被数据库索引,而且是唯一的:

    entry = Entry.objects.get(id=10)
    entry = Entry.object.get(headline="News Item Title")
    

    一次性检索需要的东西

    通过使用select_relatedprefetch_related,前者限于单值关系 - 外键和一对一关系,后者允许它预取多对多和多对一对象。它们都可以实现对数据的缓存。

    获取你想要的

    使用QuerySet.values()和values_list()

    当你仅仅想要一个带有值的字典或者列表,并不需要使用ORM模型对象时,可以适当使用values()。对于在模板代码中替换模型对象,这样会非常有用 —— 只要字典中带有的属性和模板中使用的一致,就没问题。

    使用QuerySet.defer()和only()

    如果一些数据库的列你并不需要(或者大多数情况下并不需要),使用defer()和only()来避免加载它们。注意如果你确实要用到它们,ORM会在另外的查询之中获取它们。如果你不能够合理地使用这些函数,不如不用。

    另外,当建立起一个带有延迟字段的模型时,要意识到一些(小的、额外的)消耗会在Django内部产生。不要不分析数据库就盲目使用延迟字段,因为数据库必须从磁盘中读取大多数非text和VARCHAR数据,在结果中作为单独的一行,即使其中的列很少。 defer()和only()方法在你可以避免加载大量文本数据,或者可能要花大量时间处理而返回给Python的字段时,特别有帮助。像往常一样,应该先写出个大概,之后再优化。

    使用QuerySet.count()

    如果你想要获取大小,不要使用 len(queryset)

    使用QuerySet.exists()

    如果你想要知道是否存在至少一个结果,不要使用if queryset

    不要过度使用count和exists

    如果前面已经将某个数据进行了缓存,如果再使用count或者exist则会造成额外的查询。比如下面的情况就是比较好的使用方法。

    {% if display_inbox %}
      {% with emails=user.emails.all %}
        {% if emails %}
          <p>You have {{ emails|length }} email(s)</p>
          {% for email in emails %}
            <p>{{ email.body }}</p>
          {% endfor %}
        {% else %}
          <p>No messages today.</p>
        {% endif %}
      {% endwith %}
    {% endif %}
    

    使用QuerySet.update()和delete()

    通过QuerySet.update()使用批量的SQL UPDATE语句,而不是获取大量对象,设置一些值再单独保存。与此相似,在可能的地方使用批量deletes。

    但是要注意,这些批量的更新方法不会在单独的实例上面调用save()或者delete()方法,意思是任何你向这些方法添加的自定义行为都不会被执行,包括由普通数据库对象的信号驱动的任何方法。

    直接使用外键的值

    如果你仅仅需要外键当中的一个值,要使用对象上你已经取得的外键的值,而不是获取整个关联对象再得到它的主键。例如,执行:

    entry.blog_id # 正确
    entry.blog.id # 不好
    

    没有需要就不需要进行排序

    排序并不是没有代价的;每个需要排序的字段都是数据库必须执行的操作。如果一个模型具有默认的顺序(Meta.ordering),并且你并不需要它,通过在查询集上无参调用order_by() 来移除它。

    向你的数据库添加索引可能有助于提升排序性能。

    整体插入

    创建对象时,尽可能使用bulk_create()来减少SQL查询的数量。或者是在ManyToManyFields上。

    Entry.objects.bulk_create([
        Entry(headline="Python 3.0 Released"),
        Entry(headline="Python 3.1 Planned")
    ])
    my_band.members.add(me, my_friend)
  • 相关阅读:
    ubuntu下安装eclipse
    UTC时间、GMT时间、本地时间、Unix时间戳
    [转]mysql使用关键字作为列名的处理方式
    mysql日期格式化
    ssh远程登陆看不到用户名和主机名
    ssh以root用户远程登录失败
    PowerBI发布到网页
    视图是否有主键的问题
    select count(*)和select count(1)
    PPT产品的重要性
  • 原文地址:https://www.cnblogs.com/George1994/p/7073967.html
Copyright © 2020-2023  润新知