模型是关于您的数据的惟一,明确的信息来源,它包含您正在存储的数据的重要字段和行为。一般,每一个模型映射到单个数据库表。html
每一个模型都是一个子类的python类django.db.models.Model前端
模型的每一个属性表示一个数据字段python
综上所述,Django为您提供了一个自动生成的数据库访问API。git
简单实例:在app下的models中建立person类:正则表达式
class person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
first_name和last_name是模型的命名字段,每一个字段都被指定为一个类属性,而且每一个属性映射到一个数据表的列上,上面的person模型会建立一个以下的SQL数据库表语句:数据库
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
其中表的名称以APP名为表的前缀命名myapp_person,Django自动从模型类的名称和包含它的应用程序中派生出数据库表的名称,模型的数据库表格名称是经过将模型的“应用标签”(您使用的名称)与模型的类名称加在一块儿并在它们之间加下划线来构造的。要修改它请使用模型meta元数据选项db_table来指定表名django
模型会自动添加一个自增加的主键字段浏览器
使用模型:要使用模型,须要在项目的setting.py文件中修改INSTALLED_APPS设置,来添加应用程序名,而后迁移数据。服务器
INSTALLED_APPS = [ 'myapp', ] #python manage.py makemigrations #python manage.py migrate
模型中最重要的部分,字段在python中表现为一个类属性,体现了数据库中的一个列app
在命名时请避免使用python关键字,django内置模型API名字,防止命名冲突;字段名中不能有两个以上下划线,由于两个下划线是Django的查询语法
(1)字段类型:
模型中的每一个字段都是相应Field类的实例,它们都位于django.db.models中,Django使用字段类型来肯定列类型,呈现表单字段时使用默认的HTML,Django管理员和自动生成的表单中使用的最小验证要求。
经常使用的Django字段类型:
AutoField() :一个自动增长的整数类型字段。一般你不须要本身编写它,Django会自动帮你添加字段:id = models.AutoField(primary_key=True)
,这是一个自增字段,从1开始计数。若是你非要本身设置主键,那么请务必将字段设置为primary_key=True
。Django在一个模型中只容许有一个自增字段,而且该字段必须为主键
BigAutoField():和AutoField差很少,不一样之处在于它是64位整数类型自增字段,数字范围更大,从1到9223372036854775807
BigIntegerField:64位整数字段(看清楚,非自增),相似IntegerField ,-9223372036854775808 到9223372036854775807。在Django的模板表单里体现为一个textinput标签
BinaryField:二进制数据类型。使用受限,少用
BooleanField:布尔值类型。默认值是None。在HTML表单中体现为CheckboxInput标签。若是要接收null值,请使用NullBooleanField
CharField:字符串类型。必须接收一个max_length参数,表示字符串长度不能超过该值。默认的表单标签是input text。最经常使用的filed
CommaSeparatedIntegerField:逗号分隔的整数类型。必须接收一个max_length参数。经常使用于表示较大的金额数目,例如1,000,000元
DateField:class DateField(auto_now=False, auto_now_add=False, **options)
日期类型。一个Python中的datetime.date的实例。在HTML中表现为TextInput标签。在admin后台中,Django会帮你自动添加一个JS的日历表和一个“Today”快捷方式,以及附加的日期合法性验证。两个重要参数:(参数互斥,不能共存) auto_now
:每当对象被保存时将字段设为当前日期,经常使用于保存最后修改时间。auto_now_add
:每当对象被建立时,设为当前日期,经常使用于保存建立日期(注意,它是不可修改的)。设置上面两个参数就至关于给field添加了editable=False
和blank=True
属性。若是想具备修改属性,请用default参数。例子:pub_time = models.DateField(auto_now_add=True)
,自动添加发布时间。
DateTimeField:日期时间类型。Python的datetime.datetime的实例。与DateField相比就是多了小时、分和秒的显示,其它功能、参数、用法、默认值等等都同样
DecimalField:固定精度的十进制小数。至关于Python的Decimal实例,必须提供两个指定的参数!参数max_digits
:最大的位数,必须大于或等于小数点位数 。decimal_places
:小数点位数,精度。 当localize=False
时,它在HTML表现为NumberInput标签,不然是text类型。例子:储存最大不超过999,带有2位小数位精度的数,定义以下:models.DecimalField(..., max_digits=5, decimal_places=2)
DurationField:持续时间类型。存储必定期间的时间长度。相似Python中的timedelta。在不一样的数据库实现中有不一样的表示方法。经常使用于进行时间之间的加减运算。可是当心了,这里有坑,PostgreSQL等数据库之间有兼容性问题
EmailField:邮箱类型,默认max_length最大长度254位。使用这个字段的好处是,可使用DJango内置的EmailValidator进行邮箱地址合法性验证
FileField:class FileField(upload_to=None, max_length=100, **options)
上传文件类型,它不能设置为主键,默认状况下,该字段在HTML中表现为一个ClearableFileInput标签,在数据库内,咱们实际保存的是一个字符串类型,默认最大长度100,可用经过max_length参数自定义,真实的文件是保存在服务器的文件系统内的,最重要的参数upload_to用于设置上传地址的目录和文件名,以下示例:
class MyModel(models.Model): # 文件被传至`MEDIA_ROOT/uploads`目录,MEDIA_ROOT由你在settings文件中设置 upload = models.FileField(upload_to='uploads/') # 或者 # 被传到`MEDIA_ROOT/uploads/2015/01/30`目录,增长了一个时间划分 upload = models.FileField(upload_to='uploads/%Y/%m/%d/')
FilePathField:文件路径类型
class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]
一种用来保存文件路径信息的字段,在数据表内以字符串的形式存在,默认最大长度100,能够经过max_length参数设置,它包含有如下参数:
path:必须指定的参数,表示一个系统绝对路径
match:可选参数,一个正则表达式,用于过滤文件名,只匹配基本文件名,不匹配路径
recursive:可选参数,只能是True或者False,默认为False,决定是否包含子目录,也就是是否递归的意思
allow_files:可选参数,只能是True或者False,默认为True,决定是否应该将文件名包括在内,它和allow_folders其中,必须有一个为True
allow_folders:可选参数,只能是True或者False,默认为False,决定是否应该将目录名包括在内
FloatField:浮点数类型,参考整数类型
ImageFiedl:图像类型;用于保存图像文件的字段。其基本用法和特性与FileField同样,只不过多了两个属性height和width。默认状况下,该字段在HTML中表现为一个ClearableFileInput标签。在数据库内,咱们实际保存的是一个字符串类型,默认最大长度100,能够经过max_length参数自定义。真实的图片是保存在服务器的文件系统内的。
height_field
参数:保存有图片高度信息的模型字段名。 width_field
参数:保存有图片宽度信息的模型字段名。
使用Django的ImageField须要提早安装pillow模块,pip install pillow便可
使用FileField或者ImageField字段的步骤:
(1)在settings文件中,配置MEDIA_ROOT做为上传文件在服务器中的基础路径,为了性能考虑,这些文件不会被存储在数据库中,在配置个MEDIA_URL做为公用URL,指向上传文件的基本路径,请确保Web服务器的用户帐号对该目录具备写入权限
(2)添加FileField或者ImageField字段到模型中,定义好upload_to参数,文件最总会放在MEDIA_ROOT目录的'upload_to‘子目录中
(3)全部真正被保存在数据库中的只是指向上传文件路径的字符串而已,可用经过url属性,在Djang的模块中方便的访问这些文件;列如:一个ImageField字段名为mug_shot,那么在Django模块的HTML文件中,可用使用{{ object.mug_shot.url }}来获取该文件,其中的object用具体的对象名称代替
(4)能够经过name和size属性,获取文件的名称和大小信息
IntegerField:整数类型,最经常使用的字段之一,取值范围-2147483648到2147483647。在HTML中表现为NumberInput标签。
GenericIPAddressField:
class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options)[source]
,IPV4或者IPV6地址,字符串形式,例如192.0.2.30
或者2a02:42fe::4
在HTML中表现为TextInput标签。参数protocol
默认值为‘both’,可选‘IPv4’或者‘IPv6’,表示你的IP地址类型
NullBooleanField:相似布尔字段,只不过额外容许NULL
做为选项之一
PositiveIntegerField:正整数字段,包含0,最大2147483647
PositiveSmallIntegerField:较小的正整数字段,从0到32767
SlugField:slug是一个新闻行业的术语。一个slug就是一个某种东西的简短标签,包含字母、数字、下划线或者链接线,一般用于URLs中。能够设置max_length参数,默认为50
SmallIntegerField:小整数,包含-32768到32767
TextField:大量文本内容,在HTML中表现为Textarea标签,最经常使用的字段类型之一!若是你为它设置一个max_length参数,那么在前端页面中会受到输入字符数量限制,然而在模型和数据库层面却不受影响。只有CharField才能同时做用于二者
TimeField:时间字段,Python中datetime.time的实例。接收同DateField同样的参数,只做用于小时、分和秒
URLField:一个用于保存URL地址的字符串类型,默认最大长度200
UUIDField:用于保存通用惟一识别码(Universally Unique Identifier)的字段。使用Python的UUID类。在PostgreSQL数据库中保存为uuid类型,其它数据库中为char(32)。这个字段是自增主键的最佳替代品
数据库没法本身生成uuid,所以须要以下使用default参数:
import uuid # Python的内置模块 from django.db import models class MyUUIDModel(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # 其它字段
(2)字段参数
每一个字段都有一组特定于字段的参数,下面列出通用参数为可选的:
null:
若是True
,Django将像NULL
数据库中那样存储空值。默认是False
。
blank:
若是True
,该字段被容许为空;默认是False
。和Null参数不一样的是,null是纯数据库层面的,而blank是验证相关的,它与表单验证是否容许输入框内为空有关,与数据库无关,因此要当心一个null为False,blank为True的字段接收到一个空值可能会出bug或异常
choices:
一个二维元组可迭代的对象(例如,一个列表或元组),用做该字段的选择,用于页面上的选择框标签,第一个元素表示存在数据库内真实的值,第二个元素表示页面上显示的具体内容,在浏览器页面上将显示第二个元素的值:
YEAR_IN_SCHOOL_CHOICES = ( ('FR', 'Freshman'), ('SO', 'Sophomore'), ('JR', 'Junior'), ('SR', 'Senior'), )
db_column:该参数用于定义当前字段在数据表内的列名,若是未指定,Django将使用字段名做为列名
db_index:该参数接收布尔值,若是为True,数据库将为该字段建立索引
db_tablespace:用于字段索引的数据库表空间的名字,前提是当前字段设置了索引,默认值为工程的DEFAULT_INDEX_TABLESPACE设置,若是使用的数据库不支持表空间,该参数会被忽略
default:
字段的默认值。这能够是一个值或一个可调用的对象。若是可调用,则每次建立新对象时都会调用它。设置的默认值不能是一个可变对象,好比列表,集合等,lambda匿名函数也不可用于default的调用对象,由于匿名函数不能被migrations序列化,注意:在某种缘由不明的状况下将default设置为None,可能引起intergyerror:not null constraint failed,即非空约束失败异常,致使python manage.py migrate失败,此时可将None改成Fasle或其余值,只要不是None就行。
editable:若是设为false那么当前字段将不会在admin后台或者其余的ModelForm表单中显示,同时还会被模型验证功能跳过,参数默认值为True
error_messages:用于自定义错误信息,参数接收字典类型的值,字典的键能够是null,blank,invalid,invalid_choice,unique和unique_for_date其中的一个。
help_text:
用窗体小部件显示额外的“帮助”文本。即便您的字段未用于表单,对于文档也颇有用。
primary_key:
若是True
,这个字段是模型的主键。若是您没有primary_key=True
为模型中的任何字段指定,Django会自动添加一个 AutoField自增字段,名为'id',并设置为主键,也就是id = models.AutoField(primary_key=True),若是你为某个字段设置了primary_key=True,则当前字段变为主键,并关闭Django自动生成id主键的功能;primary_key=True隐含null=False和unique=True的意思,一个模型中只能由一个主键字段,另外主键字段不可修改,若是给某个对象的主键赋个新值其实是建立一个新对象,并不会修改原来的对象
unique:
若是为True
,该字段在整个表格中必须是惟一的,注意:对于ManyToManyField和OneToOneField关系类型,该参数无效;当unique=True时,db_index参数无需设置,由于unqiue隐含了索引
unique_for_date:日期惟一,若是由一个title字段,并设置了参数unique_for_date="pub_date",那么django将不容许由两个模型对象具有一样的title和pub_date,有点相似联合约束。
unique_for_month:月份惟一
unique_for_year:年份惟一
verbose_name:为字段设置一我的类可读的,更加直观的别名,对于每一个字段类型,除了ForeignKey、ManyToManyField和OneToOneField这三个特殊的关系类型,其第一可选位置参数都是verbose_name,若是没指定这个参数,Django会利用字段的属性名自动建立它,并将下划线转换为空格
#下面列子的verbose_naem是“person'sfirst name" first_name = models.CharField("person's first name", max_length=30) #下面例子的verbose_name是”first name" first_name = models.CharField(max_length=30) #因为外键、多对多和一对一字段,第一个参数须要用来指定关联的模型,所以必须用关键参数verbose_name来明确指定 poll = models.ForeignKey( Poll, on_delete=models.CASCADE, verbose_name="the related poll", ) #另外,你无须大写verbose_name的首字母,Djang自动为你完成这项工做
validators:运行在该字段上的验证器的列表
默认状况下,Django为每一个模型提供如下字段:
id = models.AutoField(primary_key=True)
这是一个自动递增的主键;若是你想指定一个自定义主键,只需primary_key=True
在其中一个字段上指定 。若是Django看到你已经明确设置Field.primary_key
,它不会添加自动 id
列。
每一个模型只须要一个字段primary_key=True
(显式声明或自动添加)
每一个字段类型除了ForeignKey
, ManyToManyField
和 OneToOneField
,都有一个可选的第一个位置参数 - 一个详细名称。若是没有给出详细名称,Django将使用该字段的属性名称自动建立它,并将下划线转换为空格。
first_name = models.CharField("person's first name", max_length=30)
上面的例子中详细名称为:“person's first name”
first_name = models.CharField(max_length=30)
若是第一个位置参数不制定详细名则使用字段属性名来建立它,上面的例子详细名为“first name"
还可用在字段中使用verbose_name选项来指定字段名
关系数据库的强大之处在于相互关联表。Django提供了定义三种最多见类型的数据库关系的方法:多对一,多对多和一对一。
要定义多对一关系,请使用django.db.models.ForeignKey
。您能够像使用其余Field
类型同样使用它,多对一的关系一般被称为外键,外键字段类的定义以下:
class ForeignKey(to,no_delete,**options)
多对一的关系,须要两个位置参数,第一个为关联的模型,另外一个是no_delete选项models.ForeignKey('self',no_delete=models.CASCADE) :
当一张表中建立一行数据时,有一个单选的下拉框且可用被重复选择
ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要进行关联的表名 to_field=None, # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 related_name=None, # 反向操做时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做时,使用的链接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在数据库中建立外键约束 parent_link=False # 在Admin中是否显示关联数据
例如如下实例:在一篇博客文章中引用多个用户可选择。
#下面以建立一个对应多用户的博客文章模型为例来讲明:
from django.db import models from django.utils import timezone class User(models.Model): username = models.CharField(max_length=150,verbose_name="用户名") password = models.CharField(max_length=300,verbose_name="密码") age = models.IntegerField(verbose_name="年龄") def __str__(self): return self.username class articel(models.Model): title = models.CharField(max_length=300,verbose_name="博客标题") author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="做者") #做者将对应User表中的多个用户,提供下拉菜单可选择用户 body = models.TextField(verbose_name="文章内容") publish = models.DateTimeField(default=timezone.now,verbose_name="发表时间") class Meta: ordering = ["-publish"] def __str__(self): return self.title
若是要关联的模型对象在另一个app中,假设user模型在blog这个app中,要在当前app模型中关联,以下设置:
class articel(models.Model): author = models.ForeignKey( 'blog.user', #app之间关联 on_delete=models.CASCADE, )
若是要建立一个递归的外键,也就是本身关联本身的外键,使用下面的方法:
models.ForeignKey('self',on_delete=models.CASCADE)
外键还有一些重要的参数:on_delete当一个被外键关联的对象被删除时,Django将模仿on_delete参数定义的SQL约束执行相应的操做,好比有一个可为空的外键,而且你想让它在关联的对象被删除时,自动设为null,可以下定义:
user = models.ForeignKey( User, models.SET_NULL, blank=True, null=True, )
该参数可选的值都内置在django.db.models中,包括:
CASCADE:模拟SQL语言中的ON DELETE CASCADE约束,将定义有外键的模型对象同时删除,该操做为当前django版本的默认操做
PROTECT:阻止上面的删除操做,可是弹出ProtectedError异常
SET_NULL:将外键字段设为Null,只用当字段设置了Null=True时,方可以使用该值
SET_DEFAULT:将外键字段设为默认值。只有当字段设置了default参数时,方可以使用
DO_NOTHING:什么也不作
SET():设置为一个传递给SET()的值或者一个回调函数的返回值;注意大小写
要定义多对多关系,请使用 ManyToManyField
。您能够像使用其余Field
类型同样使用它 :将其做为模型的类属性包含在内。
ManyToManyField
须要一个位置参数:与模型相关的类。
ManyToManyField(RelatedField) to, # 要进行关联的表名 related_name=None, # 反向操做时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做时,使用的链接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否建立反向操做的字段 # 作以下操做时,不一样的symmetrical会有不一样的可选字段 models.BB.objects.filter(...) # 可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定义第三张表时,使用字段用于指定关系表 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段作多对多关系表 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) db_constraint=True, # 是否在数据库中建立外键约束 db_table=None, # 默认建立第三张表时,数据库中表的名称
#以上面的例子为例再增长一个评论的类模型,并关联到博客表中,它是一个可用多选的下拉框。
class comment(models.Model): user = models.ForeignKey(User,on_delete=models.CASCADE) date = models.DateTimeField(default=timezone.now) body = models.TextField() class articel(models.Model): title = models.CharField(max_length=300,verbose_name="博客标题") author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="做者") body = models.TextField(verbose_name="文章内容") publish = models.DateTimeField(default=timezone.now,verbose_name="发表时间") comment = models.ManyToManyField(comment,verbose_name="评论") #在每一篇文章中针对多个评论,即为多对多的关系 class Meta: ordering = ["-publish"] def __str__(self): return self.title
对于ManyToManyField字段,Django采用的是第三张中间表的方式,经过这第三张表,来关联ManyToMany的双方,下面经过具体的列子来详细解析:
首先创建一个简单的多对多关系模型:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person) def __str__(self): return self.name
在Group模型中,经过members字段,以ManyToMany方式与Person模型创建多对多关系,咱们在数据库中能够看到三张表,以app名为前缀,如app01则三张表名为:app01_group、app01_person、app01_group_members
其中app01_group_memebers是对应关系表,它会生成自身id列,group的id列和person相对应的id列,此中间表是经过id的关联进行映射的。
自定义中间表:
通常状况,普通的多对多已经够用,无需本身建立第三张关系表,可是某些状况可能更复杂一点,好比若是你想保存某我的加入某个分组的时间呢?想保存进组的缘由呢?
Django提供了一个through参数,用于指定中间模型,你能够将相似进组时间,邀请缘由等其余字段都放在这个中间模型内:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person,through='Membership') #指定中间表 def __str__(self): return self.name #自定中间表 class Membership(models.Model): person = models.ForeignKey(Person,on_delete=models.CASCADE) #经过外键关联模型 group = models.ForeignKey(Group,on_delete=models.CASCADE) date_joined = models.DateField() #添加自定义字段 invite_reason = models.CharField(max_length=100)
要定义一对一的关系,请使用 OneToOneField
。您能够像使用其余Field
类型同样使用它 :将其做为模型的类属性包含在内。
当对象以某种方式“扩展”另外一个对象时,这对于对象的主键很是有用。
OneToOneField
须要一个位置参数:与模型相关的类。
OneToOneField(ForeignKey) to, # 要进行关联的表名 to_field=None # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 ###### 对于一对一 ###### # 1. 一对一其实就是 一对多 + 惟一索引 # 2.当两个类之间有继承关系时,默认会建立一个一对一字段 # 以下会在A表中额外增长一个c_ptr_id列且惟一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1)
一对一:在建立表中一行数据时,有一个单选的下拉框,下拉框中的内容被用过一次就消失了。
class User(models.Model): username = models.CharField(max_length=150,verbose_name="用户名") password = models.CharField(max_length=300,verbose_name="密码") age = models.IntegerField(verbose_name="年龄") def __str__(self): return self.username class User_extend(models.Model): User = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) #将用户信息扩展到此表 address = models.CharField(max_length=300,null=True,blank=True,verbose_name="住址") education = models.CharField(max_length=30,null=True,blank=True,verbose_name="学历")
将模型与另外一个应用程序中的模型相关联彻底能够。为此,请在定义模型的文件顶部导入相关模型。而后,只需在须要的地方引用其余模型类。
from django.db import models from geography.models import ZipCode class Restaurant(models.Model): # ... zip_code = models.ForeignKey( ZipCode, on_delete=models.SET_NULL, blank=True, null=True, )
Django对模型字段名称只有两个限制:
(1)字段名称不能是Python保留字,由于这会致使Python语法错误
(2)因为Django查询查找语法的工做方式,字段名称不能在一行中包含多个下划线
模型源数据Meta是数据库类可选的附加属性,如排序(ordering),数据库表名(db_table),可读的数据类名称(verbose_name)
下面列出可用的Meta选项:
abstract = True :定义模型为抽象基类,抽象模型自己不实际生成数据表,而是做为其余模型的父类,被继承使用
app_label = 'myapp' :声明模型属于哪一个应用,如定义了模型的app没有在INSTALLED_APPS中注册,则必须经过此元选项声明它属于哪一个app
base_manager_name :用于模型的管理器名称
db_table = ‘db_name' :指定模型使用的数据库名称
db_tablespace:自定义数据库表空间的名称,默认值是工程DEFAULT_TABLESPACE设置
default_manager_name:自定义模型的_default_manager管理器的名字
ordering = ['order_date'] :指定对象的默认排序,可对指定排序规则
verbose_name = “blog” :指定对象的可读名称
verbose_name_plural:指定模型对象的复数名,在使用中文时,若是不指定该参数,那么默认的复数名是verbose_name加上‘s'
label:前面介绍的元数据都是可修改和设置的,但还有两个只读的元数据,label就是其中之一,app_label.object_name,例如'polls.Question'
class blog(models.Model): pass class Meta: ordering = ['-publish'] verbose_name = "博客"
模型的最重要的属性是 Manager
。它是经过它向Django模型提供数据库查询操做的接口,用于 从数据库中检索实例。若是Manager
未定义自定义,则默认名称为 objects
。管理者只能经过模型类访问,而不能访问模型实例。
from blog.models import User_extend date = User_extend.objects.all()
Django中的模型继承以与Python中的普通类继承彻底不一样的方式完成,但基本思想在一开始就很常见。那就是它的基类django.db.models.Model
必须是它的子类。
django中有三种可能的继承方法:
1.定义一个抽象基类,它不单独使用;用来给子类继承使用
2.若是要建立现有模型的子类,而且但愿在数据库中为每一个模型定义一个表,那么最好使用多个表的继承
3.若是要在有python级别修改模型的行为而不以任何方式修改模型的字段,则可用使用代理模型
(1)抽象基类
当想要将一些公共信息放入许多其余模型时,抽象基类会派上用场,在数据模型的Meta类中定义abstract=True,则此模型不会建立任何数据库表,当它用做其余模型的基类时,其字段将添加到子类的字段中。
class CommonInfo(models.Model): name = models.CharField(max_length=100) age = models.PositiveIntegerField() class Meta: abstract = True class Student(CommonInfo): home_group = models.CharField(max_length=30) #该Student模型将会继承name和age字段和自身的home_group组成,该CommonInfo模型不能用做普通的django模型,它是一个抽象类,它不生成数据库表,而且没法直接实例化或保存,从抽象类继承的字段可用使用其余字段或值覆盖,也可用使用删除None
Meta继承:
当建立抽象基类时,Django使您在基类中声明的任何Meta内部类可用做属性,若是子类没有声明它本身的Meta类,它将继承父类的Meta,若是子类想要扩展父类的Meta类,它能够将其子类化。
from django.db import models class CommonInfo(models.Model): # ... class Meta: abstract = True ordering = ['name'] class Student(CommonInfo): # ... class Meta(CommonInfo.Meta): db_table = 'student_info' #Student子类会继承父类中的Meta内部的属性
十一、多表继承
多表继承中父类和子类都是独立自主功能完整,可正常使用的模型,都由本身的数据库表,内部隐含了一个一对一的关系,以下:
from django.db import models class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __str__(self): return "{}-{}".format(self.name,self.address) class Restaurant(Place): serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) def __str__(self): return "{}-{}-{}-{}".format(self.name,self.address,self.serves_hot_dogs,self.serves_pizza) #Restaurant继承Place后会有name和address字段,它会在内部字段中建立一个一对一的主键关系来将父类中的字段数据映射到自身数据表上 operations = [ migrations.CreateModel( name='Place', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=50)), ('address', models.CharField(max_length=80)), ], ), migrations.CreateModel( name='Restaurant', fields=[ ('place_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='app01.Place')), ('serves_hot_dogs', models.BooleanField(default=False)), ('serves_pizza', models.BooleanField(default=False)), ], bases=('app01.place',), ), ]
如在Restaurant数据表中写入数据,而继承字段数据实际是写入父类数据表中的,它的内部机制实际隐含一个OneToOne字段,并设置parent_link=True来映射表字段,咱们也能够经过这种方法来自定义
Meta和多表继承:
在多表继承的状况下,因为父类和子类都在数据库内有物理存在的表,父类的Meta类会对子类形成不肯定的影响,所以,Django在这种状况下关闭了子类继承父类的Meta功能,这点和抽象类的继承有所不一样
可是,还有两个Meta元数据库特殊点,那就是ordering和get_latest_by,这两个参数是会被继承的,所以若是在多变继承中,你不想让你的子类继承父类的撒谎给你吗两个参数,就必须在子类中重写
class ChildModel(ParentModel): ... class Meta: ordering = [] #删除父类的排序影响