二 Djano模型层之模型字段选项

字段选项

以下参数是全部字段类型都可用的,而且是可选的

null

如果为True,Django将在数据库中将空值存储为NULL。默认值为False

对于字符串字段,如果设置了null=True意味着“无数据”有两个可能的值,NULL和空字符串,在大多数情况下,我们在数据库中存储无数据的字符串时,不会区分到底是NULL还是空字符串,如果存储了两个值势必会增加操作数据的难度。django的惯例是使用空字符串,所以我们在创建字符串字段(如:CharField、TextField)尽量不要设置null=True。null属性对于字符串字段也并非没有用处,比如这种情况就必须设置null=True,如当CharField同时具有blank=True和unique=True属性是,在这种情况下,需要设置null=True,以便在数据库中使用NULL保存对个对象,从而达到唯一性(NULL!=NULL)

如果希望BooleanField接受null值,请使用NULLBolleanField类来代替

注意:在使用Oracle数据库时,数据库使用NULL来表示空字符串,与null这个属性无关

 blank

如果为True,字段允许为空,默认False

与null不同,null纯粹是数据库范畴,blank是数据验证范畴,如果blank=True,字段可为空,否则为必填字段

choices

它是一个可迭代的结构(如列表、元组),由可迭代的二元元组表示,用来给字段提供选项

每个元组中的第一个元素,是存储在数据库中的值;第二个元素是使人容易理解的描述。 比如:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
)

一般来说,最好给每个值定义一个合适名字的常量,然后再在模型类内部定义choices:

from django.db import models

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    YEAR_IN_SCHOOL_CHOICES = (
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
    )
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

    def is_upperclass(self):
        return self.year_in_school in (self.JUNIOR, self.SENIOR)

这样做的好处是使得choices更容易被引用,例如, Student.SOPHOMORE 可以在任何引入Student 模型的位置生效

你也可以归类choices:

MEDIA_CHOICES = (
    ('Audio', (
            ('vinyl', 'Vinyl'),
            ('cd', 'CD'),
        )
    ),
    ('Video', (
            ('vhs', 'VHS Tape'),
            ('dvd', 'DVD'),
        )
    ),
    ('unknown', 'Unknown'),
)

对于有choices属性的模型字段, Django 使用get_FOO_display()方法来获取当前字段值的易于理解的名称

注意:choices可以是任何可迭代的对象 , 不是必须是列表或者元组。 这一点使你可以动态的构建choices。 但是如果你发现你自己搞不定动态的choices,你最好还是使用ForeignKey来构建一个合适的数据库表。choices更适合那些变动不多的静态数据。

除非blank=Falsedefault一起在字段中被设置,否则,可选择菜单将会有"---------" 的标签。 要重写这个行为, 需要加入一个包含None的元组到 choices里面; 例如 (None, 'Your String For Display'),对于字符串字段也可以用一个空字符串代替None

db_index

如果True,将为该字段创建一个数据库索引。

db_column

用来表示数据库中该字段的列名称。 如果未指定,那么Django将会使用字段名作为列名.

default

字段的默认值,可以是一个值或一个不可变对象,如果非要用个字典(可变对象)做默认值,可以这样操作:

def contact_default():
    return {"email": "to1@example.com"}

contact_info = JSONField("ContactInfo", default=contact_default)

匿名函数不能用于default的字段选项

默认值会在新实例创建并且没有给该字段提供值时使用。 如果字段为主键且值为None时,将会使用默认值

editable

如果设置为false,将不会出现在admin和modelForm中,默认为True

error_messages

error_messages 参数能够让你重写抛出的默认错误信息。 通过关键字,在字典中匹配你要重写的错误信息。

error_messages 的 key 值包括 unique, unique_for_date, invalid, blank, null, 和 invalid_choice

help_text

 对字段的帮助说明,会显示在表单中,注意在自动生成的表单中,这个值不会进行HTML转义,如果需要使用HTML标签渲染,应该在help_text中包含html:

help_text="Please use the following format: <em>YYYY-MM-DD</em>."

primary_key

 如果为true,则该字段会成为模型的主键字段

如果没有指定该字段,django会自动添加一个AutoField字段来充当主键

主键字段时只读的。如果你改变了一个已经存在的对象的主键,会创建一个新的对象,而不是覆盖旧的

unique

 如果为true,该字段值再表中必须是唯一的

此选项对除ManyToMany和OneToOneField之外的所有字段有效

当设置了unique为true后,你不再需要设置db_index,因为unique本身就以为着一个索引的创建

unique_for_date 

 当它设置为一个DeteField或DateTimeField字段的名称时,表示该字段的值相对于unique_for_date指定的字段的日期值是唯一的

 当设置为DateTimeField字段名称时,只会考虑其日期部分,

unique_for_year    unique_for_month

类似于unique_for_date,只不过是要求字段对于月份、年份是唯一的

verbose_name

 一个字段的可读性更高的名称,如果没有给定自述名,dango将会根据字段名称,将下划线转换为空格自动创建它

validators

指示该字段验证时要执行的validator列表

字段类型

AutoField

一个根据实际ID自动增长的IntegerField,通常不需要直接使用它

BigAutoField

一个64位整数,类似于AutoField

BigIntegerField

一个64位整数,非常像IntegerField,这个字段默认的表单组件是一个TextInput

BinaryField

一个用来存储二进制码的Field,只支持bytes赋值

这个Field的功能很有限,不大可能在一个二进制数据上进行查询数据,在ModelForm中也不太可能使用BinaryField

你可能想使用数据库来存储你的文件,但是%99的情况下这都是一个不好的设计

BooleanField

表示true/false的字段,默认的表单组件是CheckboxInput

如果需要设置为null值,应该使用NullBooleanField来代替BooleanField

如果没有指定default,该字段的默认值是None

CharField

一个用来存储各种长度的字符串的地方,默认的表单组件是TextInput,该字段必须接受一个额外参数:max_length,该参数将在数据库层和Django表单验证中起作用,用来限定长度

如果是巨大的文本类型,可用TextField

DateField

一个用来表示日期的字段,使用python的datetime.date实例来表示日期,默认的表单组件是TextInput,有几个额外的参数:

auto_now:每次保存对象时,自动设置该字段为当前时间,注意:只用调用了modle.save()是该子段的值才会自动更新,当以其他方式更新字段(如QuerySet.update())时,该字段不会更新

auto_now_add:当对象第一次被创建时自动设置为当前时间,即使在创建对象时为此字段设置了一个值,也将被忽略。若是要让此字段在创建时可以为该字段提供一个值,如下能实现:

  • 对于DateFielddefault=date.today    # datetime.date.today()
  • 对于DateTimeFielddefault=timezone.now    #django.utils.timezone.now()

注意:default、auto_now、auto_now_add这些设置都是互斥的

在目前的实现中,设置了auto_now、auto_now_add为True时,django会自动为该字段设置editable=False和blank=True

DateTimeField

同DateField

DecimalField 

 一个表示浮点数的字段,用python中Decimal的一个实例来表示该字段的值,有两个必须的参数

  1.  max_digits:该浮点数的总位数,包括小数点前后的位数
  2. decimal_places:小数点后的位数

 EmialField

 相当于CharField,用来检查输入的email地址是否合法,使用EmailValidator来验证输入的合法性

 FileField

 用于上传文件的字段,不支持primary_key参数

 FloatField

 表示一个浮点数,使用python的float实例来表示

IntegerField 

 表示一个整数,localizeFalseTextInput时,该字段的默认表单小部件是NumberInput

 NullBooleanField

 类似BooleanField, 但是允许 NULL 作为一个选项. 使用该字段代替null=TrueBooleanField字段此字段的默认表单widget为NullBooleanSelect

 PositivIntegerField

 类似IntegerField,但值必须是正数或0

SmallIntegerField

类似IntegerField,该值范围视数据库而定,一版对django而言,该值在-32768到32767之间对于所有支持的数据库都是安全的

TextField

表示大文本字段,默认表单组件是Textarea

 TimeField

 表示时间的字段,默认表单组件TextInput使用python datetime.time的实例来表示该字段值,接受与DateField相同的自动填充选项

关联关系字段 

 ForignKeyField

 多对一关系,两个必填参数,模型相关类和on_delete选项

如果需要创建递归关联关系,一个对象与自身具有多对一的关系,使用 ‘self’字符串左右模型相关的类

如果需要关联到一个还未创建的模型,你可以使用模型的名字而不用 模型对象本身(使用场景:模型继承),子类化模型时,将会在子类所在模块查找相对应的模型相关类:

#products/models.py

from django.db import models

class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)

    class Meta:
        abstract = True
#production/models.py

from django.db import models
from products.models import AbstractCar

class Manufacturer(models.Model):
    pass

class Car(AbstractCar):
    pass

# Car.manufacturer将指向这里的`production.Manufacturer`。

  若要引用其他应用中的模型,可以使用app_label.modelname来应用,如下:

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'production.Manufacturer',
        on_delete=models.CASCADE,
    )

  这称为懒惰关系的引用,在解决两个应用之间循环导入时很有用

ForignKey会自动创建数据库索引,可以通过db_Index=False来取消

数据库表示

Django会在字段名上添加“_id”来创建数据库的列名称,也可以通过db_column来修改,但是,除非你编写自定义SQL,否则不要修改数据库列名称。

参数

on_delete 

当删除由ForignKey引用的对象时,Djanog将模拟由on_delete参数指定的SQL约束行为

  1. SET_NULL():表示外键关联到的表的数据被删除时,外键字段置为空。models.ForeignKey(AuthModel, null=True, blank=True, on_delete=models.SET_NULL)
  2. CASCADE:级联删除,一并删除包含ForignKey的对象
  3. PROTECT:会抛出protectedError,阻止被引用对象的删除,
  4. SET_DEFAULT():删除引用对象后,将设置的默认值左右该外键值
  5. SET():引用表数据删除后,将传递给SET()的值作为外键值,如果传入了一个可调用对象,则为调用后的结果
  6. DO_NOTHING:不采取任何动作

  limit_choices_to

  当ForignKey字段被admin或ModelForm渲染时,为该字段选项设置条件类过滤选项。它可以是字典、Q对象,或者一个返回字典或Q对象的可调用对象,如:  

  

staff_member = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    limit_choices_to={'is_staff': True},
)

  这将使得ModelForm对应的字段只列出User的is_staff=True的成员

 related_name

  • 这个名称用于让关联对象反查到源对象。它还是releated_query_name的默认值(关联模型进行反向过滤时使用的名称)
  • 如果未指定该属性,默认情况下使用FOO_set来反查原模型,FOO是源模型的小写名称
  • 如果不想创建一个反向关联,将该属性设置为“+”,此时关联模型不能反向查找到源模型

related_query_name

 用于目标模型的反向过滤。如果未设置该属性和related_name 则默认为模型名称,如果该属性未设置,设置了related_name ,则使用related_name,如果该属性设置了值,则使用该属性值:

# Declare the ForeignKey with related_query_name
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")

to_field

 关联到的关联对象的字段名称,默认使用关联对象的主键列。如果要关联到其他字段,那个字段应该具有unique=True

ManyToManyField

 多对多关联关系,要求一个关键字参数,与该模型关联的类

数据库表示

 在幕后,Django创建一个中间表来表示多对多关系。默认情况下该中间表的名称使用多对多字段名称和多对多字段所在表的名称组成。你也可以使用db_table选项提供中间表的名称

 参数

 related_name  related_query_name  limit_choices_to

 与ForignKeyField一样,注意:ManyToManyField 对于使用through 参数自定义中间表的limit_choices_to 不生效

 through

 Django 会自动创建一个表来管理多对多关系。 不过,如果你希望手动指定中介表,可以使用through 选项来指定Django 模型来表示你想要使用的中介表。

 这个选项最常见的使用场景是当你想要关联更多的数据到关联关系的时候。

 

如果你没有显式指定through 的模型,仍然会有一个隐式的through 模型类,你可以用它来直接访问对应的表示关联关系的数据库表。 它由三个字段来链接模型。

如果源模型和目标不同,则生成以下字段:

    • id:关系的主键。
    • <containing_model>_id:声明了ManyToManyField的模型的id
    • <other_model>_id: 被ManyToManyField所指向的模型的id

如果ManyToManyField 的源模型和目标模型相同,则生成以下字段:

    • id:关系的主键。
    • from_<model>_id:源模型实例的id
    • to_<model>_id:目标模型实例的id

 through_fields

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(
        Person,
        through='Membership',
        through_fields=('group', 'person'),
    )

class Membership(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    inviter = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        related_name="membership_invites",
    )
    invite_reason = models.CharField(max_length=64)

上文示例中Membership 有两个外键指向Person (person 和inviter),这使得关联关系含混不清并让Django 不知道使用哪一个。

在这种情况下,必须使用through_fields 明确指定Django 应该使用哪些外键

through_fields 接收一个二元组('field1', 'field2'),其中field1 为指向定义ManyToManyField 字段的模型的外键名称(本例中为group),field2 为指向目标模型的外键的名称(本例中为person).

db_table 

默认情况下,关联表的名称使用多对多字段的名称和包含这张表的模型的名称以及Hash值生成,如:memberShip_person_3c1f5.若要想要手动指定表的名称,可以使用db_table关键字参数指定.

 OneToOneField

 一对一关系,相当于在ForignKey上设置了unique=True

当一个模型要扩展时,这很有用。例如多表继承是通过将一个隐式一对一关系添加到模型中来实现的

需要一个参数,与该模型关联的类

 

 字段API参考

 Field

 是一个抽象类,用来代表数据库中的一列,具有以下属性

 db_type:返回该字段在数据库中的类型,例如你自定义了一个时间类型,那么对应在MySQL中就是datetime类型。

 rel_db_type:返回字段的Field类型,如:ForeignKeyFieldOneToOneField

 

有三种主要情况,Django需要与数据库后端字段交互:

    • 当它查询数据库(Python值 转为 数据库后端值)
    • 当它从数据库加载数据(数据库后端值 转为 Python值)
    • 当它保存到数据库(Python值 转为 数据库后端值)

   get_prep_value():将python值转换为数据库查询参数值

   get_db_prep_value():将查询值转换为数据库值

   from_db_value():将数据库值转换为python值,它与get_prep_value作用相反

 get_db_prep_save():在保存数据库是会调用此方法,默认实现是返回get_db_prep_value()

 prep_save():在get_db_pre-save前调用

 to_python():将一个值转换为正确的python对象。是value_to_string的反向操作会在clean中调用

 value_to_string():将obj转换为字符串,用于序列化字段的值。字段经常会接收不同类型的值,这时就需要序列化。

 字段的属性

 auto_create:布尔标识,指示字段时否时自动创建

 concreate:布尔标志,指示字段是否具有与其相关联的数据列

 model:返回定义字段的模型类,如果在模型类的超类上定义了字段,则返回超类

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-04-19 15:12  持&恒  阅读(836)  评论(2编辑  收藏  举报