阿布云

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

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

阿布云 发表于

p4.png

Model Field Options

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

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

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

  • Field.auto_created
  • Field.concrete
  • Field.hidden
  • Field.is_relation
  • Field.model

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

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

自定义Model Field

不是很懂

可以参考源码。

Relationships

Many-to-one relationships

翻译-一对多关系

Many-to-many relationships

翻译-多对多关系

One-to-one relationships

翻译-一对一关系

Meta 选项

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

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

设置之后,可以通过get_RELATED_order和set_RELATED_order进行获取关联对象的已经拍好序的主键列表或者是自定义设置其顺序。

    我们还可以通过get_next_in_order和get_previous_in_order,可以用于获取一个生成器。

  • ordering,对象默认的顺序,获取一个对象的列表时候使用。
  • permissions,设置创建对象时权限表中额外的权限,注意其是一个二元祖的元祖或者列表。
  • default_permissions,默认为 add,change,delete。
  • proxy,如果为True,则表明这是另外一个模型的子类,这将会作为一个代理模型。
  • required_db_features,
  • required_db_vendor,指定使用哪种数据库。
  • select_on_save,指定使用哪种保存数据的算法。
  • unique_together,用来设置不重复的字段组合。
  • index_together,用来设置带有索引的字段组合,和上面的用法相似。
  • verbose_name,为model创建一个易于理解的名称,单数。
  • verbose_name_plural,和上面不同的是,为复数形式。

模型属性

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

模型方法

创建对象

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

模型加载

Model.from_db和Model.refresh_from_db。

验证对象

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

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

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

保存对象

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

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

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

  • 准备数据库数据。 要求每个字段提供的当前值是能够写入到数据库中的类型。

大部分字段不需要数据准备。简单的数据类型,例如整数和字符串,是可以直接写入的Python 对象。但是,复杂的数据类型通常需要一些改动。

例如,DateField 字段使用Python 的 datetime 对象来保存数据。数据库保存的不是datetime 对象,所以该字段的值必须转换成ISO兼容的日期字符串才能插入到数据库中。

  • 插入数据到数据库中。 将预处理过、准备好的数据组织成一个SQL 语句用于插入数据库。
  • 发出一个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种风格的继承。

  • 通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以你要使用抽象基类。
  • 如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承。继承关系在子model和它的每个父类之间添加一个链接,这是通过自动创建的OneToOneField来实现的。
  • 最后,如果你只是想改变一个模块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方法,如果其不存在数据或者存在多条数据,都会抛出错误,所以要保证只有一条单独的数据。