首先,要理解这句话:模型是你的数据的唯一的、权威的信息源。它包含你所存储数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表
基础:每个模型都是django.db.models.Model的一个python子类
模型的每个属性都表示为数据库中的一个字段
django提供一套自动生成的用于数据库访问的API,下一章总结
1、第一个例子
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name和last_name是模型的两个字段。每个字段都被指定成一个类属性,每个属性映射到一个数据库的列
(1)上面的代码会创建一个名为myapp_person的表,这个表名是根据模型中的元数据自动生成的,也可以重写为别的名称。
(2)id字段是自动添加的,但这个行为可以被重写
2、使用上面创建好的模型
定义好这些模型之后,然后就需要告诉django使用这些模型。这就需要修改配置文件中的INSTALLED_APPS设置,在其中添加models.py所在应用的名称
注意:当在INSTALLED_APPS中添加新的应用名时,请确保运行命令manage.py migrate,可以事先使用manage.py makemigrations给应用生成迁移脚本
3、字段
对于一个模型来说,最重要的和不可或缺的是列出该模型在数据库中定义的字段。字段由models类属性指定。要注意选择的字段名称不要和模型API冲突,比如clean\save\delete
eg:
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
4、字段类型
模型中的每个字段都是Field子类的某个实例。Django根据字段类的类型确定以下信息:
---------数据库当中的列类型(比如:INTEGER,VARCHAR)
---------渲染表单时使用的默认HTML部件(例如,<input type="text">)
---------最低限度的验证需求,它被用在django管理站点和自动生成的表单中
django自带数十种内置的字段类型;完整字段类型列表下下章整理,当然如果内置的满足不了要求,可以编写自定义的模型字段
5、字段选项
每个字段有一些特有的参数,详见模型字段参考。例如,CharField(和它的派生类)需要max_length参数来指定VARCHAR数据库字段的大小
最常用的介绍如下;
null:如果为True,Django将用NULL来在数据库中存储空值。默认值是False。
blank:如果为True,该字段允许不填,默认为False
注意:这与null不同。null纯粹是数据库范畴,指的是数据库中字段内容是否允许为空,而blank是表单数据输入验证范畴的。如果一个字段的blank=True,表单的验证允许该字段是空值。如果字段的blank=False,该字段就是必填的。
choices:由二项元组构成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。如果设置了choices,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices中的选项。
例如:
YEAR_IN_SCHOOL_CHOICES = (
(‘FR‘:‘Freshman‘),
(‘SO‘,‘Sophomore‘),
(‘JR‘,‘Junior‘),
(‘SR‘,‘Senior‘),
(‘GR‘,‘Graduate‘),
)
每一个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或ModelChoiceField中用作显示的内容。在一个给定的model类的实例中,想得到某个chlices字段的显示值,就调用get_FOO_disolay方法(这里的FOO就是choices字段的名称)
eg:
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.sace()
>>>p.shirt_size
‘L‘
>>>p.get_shirt_size_display()
‘Large‘
default:字段的默认值。可以是一个值或者可调用对象。如果可调用,每有新对象被创建它都会被调用
help_text:表单部件额外显示的帮助内容。即使字段不在表单中使用,它对生成文档也很有用
primary_key:如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,django就会自动添加一个IntegerField字段作为主键,所以除非你想覆盖默认的主键行为,否则没必要设置任何一个字段的primary_key=true.
eg:
unique:如果该值设置为True,这个数据字段在整张表中必须是唯一的
5、自增主键字段
默认情况下,django会给每个模型添加下面这个字段:
id = models.AutoField(promary_key=True)
这是一个自增主键字段,如果你想要指定一个自定义主键字段,只要在某个字段上指定primary_key=True。如果django看到你显示的设置了Field.primary_key,就不会自动添加id列,每个模型只能有一个字段指定primary_key=True(无论是显式声明还是自动添加)。
6、字段的自述名
7、关系
关系数据库的威力体现在表之间的相互关联。django提供了三种最常见的数据库关系:多对一,多对多,一对一
多对一关系:django使用django.db.models.ForeignKey定义多对一关系。和使用其他字段类型一样:在模型当中把它作为一个类属性包含进来
ForeignKey需要一个位置参数:与该模型关联的类。
比如,一辆汽车(Car)有一个制造商(Manufacturer)--但是一个制造商生产很多汽车,每一辆汽车只能有一个制造商--定义如下:
多对多关系,ManyToManyField用来定义多对多关系,用法和其他Field字段类型一样,在模型中作为一个类属性包含进来。ManyToManyField需要一个位置参数:和该模型关联的类
多对多关系中的其他字段:处理类似搭配pizza和topping这样简单的多对多关系时,使用标准的ManyToManyField就可以了。但是,有时你可能需要关联数据到两个模型之间的关系上
例如,有这样一个应用,它记录音乐家所属的音乐小组。我们可以用ManyToManyField表示小组和成员之间的多对多关系。但是,有时,可能想知道更多成员关系的细节,比如成员是何时加入小组的
对于上述情况,django允许你指定一个中介魔心来定义多对多关系。你可以将其他字段放在中介模型里面。源模型的ManytoManyField字段将使用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)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
在设置中介模型时,要显示的指定外键并关联到多对多关系涉及的模型。这个显示声明定义两个模型之间是如何关联的。
一对一关系
8、跨文件的模型
访问其他应用的模型是非常容易的。在文件顶部你定义模型的地方,导入相关的模型来实现它。然后,无论在哪里需要的话,都可以引用它。例如:
from django.db import models
from geography.models import ZipCode
class Restaurant(models.Model):
zip_code = models.ForeignKey(ZipCode)
9、字段命名的限制
(1)字段的名称不能是python保留的关键字,因为这将导致一个python语法错误
(2)由于Django查询语法的工作方式,字段名称中连续的下划线不能超过一个
10、自定义字段类型
(1)使用内部的class Meta定义模型的元数据,例如:
from django.db import models
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
模型元数据是“任何不适字段的数据”,比如排序选项(ordering),数据库表名(db_table)或者人类可读的单复数名称(verbose_name和verbose_name_plural)。在模型中添加class Meta是完全可选的,所有选项都不是必须的。
11、模型的属性
objects:模型最重要的属性是Manager。它是Django模型进行数据库查询操作的借口,并用于从数据库获取实例。如果没有自定义Manager,则默认的名称为objects。Managers只能通过模型类访问,而不能通过模型实例访问。
12、模型的方法
可以在模型上定义自定义的方法来给你的对象添加自定义的底层功能。Manager方法用于“”表范围“”的事务,模型的方法应该着眼于特定的模型实例,这是一个非常有价值的技术,让业务逻辑位于同一个地方--模型中
eg:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
def baby_boomer_status(self):
import datetime
if self.birth_date<datetime.date(1945,8,1):
return "Pre-boomer"
elif self.birth_date<datetime.date(1965,1,1):
return "Baby boomer"
else:
return "Post-boomer"
def _get_full_name(self):
return ‘%s %s‘%(self.first_name,self.last_name)
full_name = property(_get_full_name)
13、重写预定义的模型方法
还有另外一部分封装数据库行为的模型方法,可能想要自定义他们。特别是,你将要经常改变save()和delete()的工作方式。可以自由覆盖这些方法(和其他任何模型方法)来改变他们的行为
覆盖内建模型方法的一个典型的使用场景是,你想在保存一个对象时做一些其他的事情。例如
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self,*args,**kwargs):
do_something()
super(Blog,self).save(*args,**kwargs)
do_something_else()
14、模型继承
Django中的模型继承与pytohn中普通类继承方式几乎完全相同,但是自定义的模型类应该继承django.db.models.Model
你唯一需要作出的决定就是你是想让父模型具有它们自己的数据库表,还是让父模型支持有一些共同的信息而这些信息只有在子模型中才能看到。
在Dajngo中有3中风格的继承
(1)、通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以需要使用抽象基类
(2)、如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承
(3)、最后,如果你只是想改变一个模块pytohn级别的行为,而不用修改模型的字段,可以使用代理模型
15、抽象基类
当你想将一些共有信息放进其他一些model的时候,抽象化类是十分有用的。你编写完基类之后,在Meta类中设置abstract=True,这个模型就不会被用来创建任何数据表。取而代之的是,当它被用来作为一个其他model的基类时,它的字段将被加入那些子类中。如果抽象基类和它的子类有相同的字段名,那么见鬼出现error(并且django将跑出一个exception)
eg:
from django.db import models
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=5)