一个Model通常是一个python的django.db.models.Model类的子类,对应于一个数据库表。Model中的每一个属性表示一个数据库字段。
定义模型后需要将app的名称写入manage.py的INSTALLED_APPS中,这样才能使用模型。
基本的Model创建已经在前面说过,运行manage.py migrate,Django会在数据库中自动创建一个appname_modelname这样的表,并且自动添加一个自增的id字段(可以手动覆盖)。
字段类型
每个字段都是一个适当的Field类的实例,字段类型决定了数据库表列类型、HTML中表单的input类型。
AutoField,自增的整型,通常是id,用于主键
BigAutoField,类似于AutoField,从1到9223372036854775807
BigIntegerField,64位整型,类似于整型,从-9223372036854775808到9223372036854775807,对应于HTML的TextInput
BinatyField,存储原生二进制数据,只支持bytes的赋值,这种字段不能做值的过滤查询也不能在ModelForm中使用。
BooleanField,表示true/false,默认的HTML表单中是CheckboxInput,如果需要接收null值,应用NullBooleanField,如果没有定义Field.default,默认值是None。
CharField,字符串类型,对于大量文字,使用TextField,HTML表单中默认对应的是TextInput。该类有一个额外的参数max_length,表示字段的字符数。
CommaSeparatedIntegerField,用逗号分隔的整型,需要max_length参数。在1.9版本以后,可以用带有"validate_comma_separated_integer_list"检验的CharField来代替。
DateField,日期类型通过datetime.date实例来表示,有一些可选参数:
DateField.auto_now=True,在调用Model.save()时(QuerySet.update()无用,但可以手动指定更新的值)自动将字段设置为当前时间,常用于last-modified时间戳,总是使用当前日期,不仅是一个可以覆盖的默认值。
DateField.auto_now_add=True,在对象首次创建时自动将字段设置为当前时间,总是使用当前日期,不仅是一个可以覆盖的默认值,创建时手动设置字段值会被忽略。如果想要修改字段,需要设置default=date.today(DateField,使用datetime.date.today()),default=timezone.now(DateTimeField,使用django.utils.timezone.now())。HTML中默认对应的是TextInput,
注意:设置上述两个属性为True则会自动设置editable=False,blank=True;总是使用创建或更新时默认的时区,如果需要自定义,则需要重载save()或调用自定义函数,而不能使用这两个属性,或者可以使用DateTimeField来代替,在显示时处理时区问题。
DateTimeField,日期和时间,在python中用datetime.datetime实例表示,参数同DateField,默认的HTML表单类型是TextInput。
DecimalField,指定精度的十进制数,使用python中的Decimal实例来表示,HTML表单中当localize=Flase时对应NumberInput,否则为TextInput。有两个必须的参数:
DecimalField.max_digits,指定允许的最大位数,必须大于等于decimal_places。
DecimalField.decimal_places,存储数字的小数位数。
例:
models.DecimalField(..,max_digits=5,decimal_places=2)即最大到999.99的两位小数
EmailField,略
FileField,上传文件的字段,不支持作为主键。默认对应的HTML表单中是ClearableFileInput。有两个可选参数:
FileField.upload_to,用于设置上传目录和文件名,值被传到Storage.save()中。如果指定了一个字符串值,可以包含strftime()格式化,会用上传时的日期时间来代替,例:(使用文件系统则会添加到MEDIA_ROOT之后)
upload=models.FileField(upload_to='/uploads/') # MEDIA_ROOT/uploads
upload=models.FileField(upload_to='/upload_to/%Y/%m/%d/') # MEDIA_ROOT/uploads/2016/01/30
upload_to可以像函数一样调用,用来获取上传路径和文件名,需要两个参数:instance(定义FileField的model实例),filename(一开始定义的文件名,最终可能使用也可能不用),例:
FileField.storage,存储对象,用于处理文件的存储和恢复。def user_directory_path(instance,filename): return 'user_{0}/{1}'.format(instance.user.id,filename) class MyModel(models.Model): upload=models.FileField(upload_to=user_directory_path)
关于FileField和ImageField以及FieldFile有时间再说明。
FilePathField,略
FloatField,浮点数,python中为float的实例。当localize=Flase,对应于HTML表单中的NumberInput,否则为TextInput。(FloatField使用float类型,DecimalField使用Decimal类型)
ImageField,是FileField的子类,另外有height和width两个属性。需要引入Pillow库,在数据库中以varchar保存,最长100个字符,可以用max_length参数指定最大长度。有两个可选参数:
ImageField.height_field,指定保存高度的字段名,每次模型实例被保存时高度值都会自动存入。
ImageField.width_field,指定保存宽度的字段名,每次模型实例被保存时宽度值都会自动存入。
IntegerField,整型,从-2147483648到2147483647,当localize=Flase时对应的HTML表单中用NumberInput,否则用TextInput。
GenericIPAddressField,略
NullBooleanField,类似BooleanField,但允许NULL,等同于BooleanField带上null=True。HTML表单中对应NullBooleanSelect。
PositiveIntegerField,类似于IntegerField,0~2147483647。
PositiveSmallIntegerField,类似于PositiveIntegerField,0~32767.
SlugField,常用于url,略。
SmallIntegerField,类似于IntegerField,-32768~32767。
TextField,大量文字的字段,在HTML表单中对应TextArea。
TimeField,表示时间,python中使用datetime.time实例,可以自动转换为DateField。HTML表单中默认对应TextInput。
URLField,用于URL的CharField子类。HTML表单中默认对应TextInput。可选参数max_length,默认200。
UUIDField,略。
关系字段
ForeignKey,表示多对一的关系,需要两个参数:该模型对应关联的类和on_delete选项。
一个对象可以与自己产生多对一关系用于创建递归的关系。
models.ForeignKey('self',on_delete=models.CASCADE)
如果需要对一个还未定义的model创建关系,可以使用模型的名称而不是模型对象。例:
from django.db import models
class Car(models.Model):
manufacturer=models.ForeignKey('Manufacturer',on_delete=models.CASCADE,)
...
class Manufacturer(models.Model):
pass
在抽象model上定义的关系会在模型子类化为一个具体模型时处理,并且不再关联到抽象模型的app_label。例:
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 AbstractCar(models.Model):
pass
class Car(AbstractCar):
pass
要引用另一个应用中定义的模型,需要使用application标签名显式指定模型,这种方式叫做lazy relationship,在循环引用中很有用。
class Car(models.Model):
manufacturer=models.ForeignKey('production.Manufacturer',on_delete=models.CASCADE,)
数据索引会自动在外键上创建,可以设置db_index=Flase来disable它。
实际上Django会创建后缀为_id的列(可以指定db_column来显式修改)。
参数:
ForeignKey.on_delete,指定当外键引用的对象删除时SQL约束的行为:
models.CASCADE,级联删除
models.PROJECT,抛出ProjectedError
models.SET_NULL,设置外键为null(只有当null=True)
models.SET_DEFAULT,设置为默认值
models.SET(),要设置的值传入SET函数
models.DO_NOTHING,不做任何操作,但如果数据库强制,会导致IntegrityError,除非手动加上ON DELETE约束
ForeignKey.limit_choices_to,当使用ModelForm时限制取值。可选的值一般是一个字典或Q对象或返回字典或Q对象的函数。例:
staff_member=models.ForeignKey(User,on_delete=models.CASCADE,limit_choices_to={‘is_staff’:True},)
ForeignKey.related_name,用于从关联对象反向关联的关系名称。是related_query_name的默认值。当定义抽象模型时,必须设置该值。如果希望不创建反向关系,设置为'+',或以'+'结尾。def limit_pub_date_choices(): return {'pub_date__lte':datetime.date.utcnow()} limit_choices_to=limit_pub_date_choices # 每次一个新的表单实例化时都会调用,也可能在一个模型被验证时
ForeignKey.related_query_name,用于逆向的目标模型的名称,如果设置了默认值是related_name或default_related_name,否则默认为模型的
ForeignKey.to_field,被关联对象上关系存在的字段,默认是被关联对象的主键,自定义的话则需该字段为unique=True
ForeignKey.db_constraint,控制约束是否在数据库中对该外键创建。默认为True,如果设置为Flase则意味着有错误的遗留数据或碎片化数据库。这时访问被关联的对象会抛出DoesNotExist异常。
ForeignKey.swappable,略。
ManyToManyField
ManyToManyField表示多对多的关系,要求一个参数:模型相关联的类,类似于ForeignKey,包含了recursive和lazy关系。不支持validators,可以为null。
关联的对象可以使用RelatedManager来添加、移除或创建。
数据库中创建一个中间的join表来表示多对多关系,默认情况下,表名就是两个表名的拼接,由于部分数据库不支持超过一定长度的名称,会自动转换为64个字符和一个唯一的hash,可以使用db_table来指定表名。
参数:
ManyToManyField.related_name,类似于ForeignKey.related_name
ManyToManyField.related_query_name,类似于ForeignKey.related_query_name
ManyToManyField.limit_choices_to,类似于ForeignKey.limit_choices_to,如果对ManyToManyField使用through参数指定一个自定义的中间表,则参数无效
ManyToManyField.symmetrical,只用在对于自身的ManyToManyField定义,比如:
Django处理这种模型时,不会添加一个person_set属性到Person类,而是认为是相互的。如果不希望对自身的多对多关系,设置symmetrical=False,强制Django添加逆向关系的描述符。from django.db import models class Person(models.Model): friends=models.ManyToManyField("self")
ManyToManyField.through,Django会自动生成一个表来管理多对多的关系,如果想手动指定中间表,可以使用这个参数。最常见的用法是想添加额外的数据到多对多的关系中。through模型类有三个字段:
id:关系的主键
<containing_model>_id:声明ManyToManyField模型的id
<other_model>_id:ManyToManyField指向的模型的id
如果ManyToManyField指向相同的模型,会生成以下字段:
id:关系的主键
from_<model>_id:源实例的id
to_<model>_id:目标模型实例的id
ManyToManyField.through_fields,只有指定自定义中间表时才使用。Django通常决定使用中间表哪些字段来自动生成一个多对多关系。例:
这里的person和inviter都是对应Person的外键,这时就需要through_fields来显式指定(''fiele1,'field2'),field1是外键指向的ManyToManyField定义在的模型的名称,field2是外键的目标模型的名称。当一个中间模型有超过一个指向任何在多对多关系中的模型的外键时,必须指定through_fields,这也适用于递归关系,即使用一个中间表且有多于两个指向该模型的外键,或者你想要显式指定Django应该使用哪两个。递归关系使用的中间表往往定义为non-symmerical,即symmetrical=False,因此就有了源和目标的概念,这时field1是源,field2是目标。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) member=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)
ManyToManyField.db_table,创建用于存储多对多数据的表名。如果没有提供Django会猜想一个默认的名称:定义关系的模型的表和字段名。
ManyToManyField.db_constraint,控制是否约束在数据库中创建,类似于ForeignKey.db_constraint
ManyToManyField.swappable,略
OneToOneField
OneToOneField表示一对一关系,类似于带有unique=True的ForeignKey,但关系的逆向端直接返回一个对象。这常用于主键“扩展”了另一个模型时。多表继承就是通过添加一个显式的从子模型到父模型的一对一关系来实现的。需要一个参数:模型关联的类。类似于ForeignKey,包括了所有关于递归和惰性关系的选项。
如果不指定related_name参数,Django会使用小写的当前模型名称作为默认值。
例:
from django.conf import settings
from django.db import models
class MySpecialUser(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
supervisor = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='supervisor_of',
)
>>> user = User.objects.get(pk=1)
>>> hasattr(user, 'myspecialuser')
True
>>> hasattr(user, 'supervisor_of')
True
如果关联表不存在entry,当访问逆向关系时会抛出DoesNotExist异常。
>>> user.supervisor_of
Traceback (most recent call last):
...
DoesNotExist: User matching query does not exist.
并且OneToOneField接收所有ForeignKey的额外参数,另外有一个参数:
OneToOneField.parent_link,在从另一个具体模型继承的model中使用时且为True时,表明这个字段应用作父类的link back。
字段选项
每一个字段都有一个特定的特殊参数集,也有一个公共的参数集:
null,True表示可以存储NULL值,默认为False
blank,True表示允许字段为空,默认为False。null是数据库相关的,blank是验证相关的,当一个字段blank=True,表单验证才允许空值进入。
choices,一个2元组的‘iterable’,默认的表单为一个select box。例:
YEAR_IN_SCHOOL_CHOICES=(('FR','Freshman'),('SO','Sophomore'),('JR','Junior'),('SR','Senior'),('GR','Graduate'))
每个元组中的第一个值会存储在数据库中,第二个值会显示在默认的表单控件中或者为ModelChoiceField。给定一个模型实例,choices field显示的值需要使用get_FOO_display()来访问。例如:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
default,默认值,可以是一个值也可以是一个函数,如果为函数则会在每次一个新的对象创建时调用。
help_text,常用于显示表单的帮助文字。
primary_key,True表示为模型的主键。如果不为任何字段指定该参数,则自动添加一个IntegerField来表示主键。主键字段为只读的,如果试图改变一个已存在对象的主键值,将会创建一个新的对象。
unique,True表示字段值在表中必须唯一。
参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/models/
https://docs.djangoproject.com/en/1.11/ref/models/fields/#model-field-types
https://docs.djangoproject.com/en/1.11/ref/models/fields/#common-model-field-options