django model
django model syntex
字段类型,主要确定以下信息:
- 数据库当中的列类型 (比如: INTEGER, VARCHAR)。
- 渲染表单时使用的默认HTML 部件(例如,, )。
- 最低限度的验证需求,它被用在 Django 管理站点和自动生成的表单中。
字段选项
null : 为True表示将用null 来存储空值
blank:
choice:
default:
help_text:
primary_key:
unique:
字段的自述名
一般情况下自述名放在第一个参数,使用字符串类型。
first_name = models.CharField("person's first name", max_length=30)
默认情况下不加字符串表示和变量名相同
在外键的时候由于要求第一个字段是外键类型名,所以需要加一个verbose_name 参数
poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
关系
多对一关系:
ForeignKey(). ForeignKey 需要一个位置参数:与该模型关联的类。
若要创建一个递归的关联 —— 对象与自己具有多对一的关系 —— 请使用models.ForeignKey('self')。
多对多关系:
多对多关系: ManyToManyField 需要一个位置参数:和该模型关联的类。
在哪个模型中设置 ManyToManyField 并不重要,在两个模型中任选一个即可 —— 不要两个模型都设置。
Django 允许你指定一个中介模型来定义多对多关系。 你可以将其他字段放在中介模型里面。源模型的ManyToManyField 字段将使用through 参数指向中介模型。
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
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)
中介模型有一些限制:
- 中介模型必须有且只有一个外键到源模型(上面例子中的Group),或者你必须使用
ManyToManyField.through_fields
显式指定Django 应该在关系中使用的外键。如果你的模型中存在不止一个外键,并且through_fields没有指定,将会触发一个无效的错误。 对目标模型的外键有相同的限制(上面例子中的 Person)。 - 对于通过中介模型与自己进行多对多关联的模型,允许存在到同一个模型的两个外键,但它们将被作为多对多关联关系的两个(不同的)方面。如果有超过 两个外键,同样你必须像上面一样指定through_fields,否则将引发一个验证错误。
- 使用中介模型定义与自身的多对多关系时,你必须设置 symmetrical=False(详见模型字段参考)。
一对一关系:
OneToOneField要一个位置参数:与模型关联的类。
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
name = models.CharField(max_length=50)
def __str__(self): # __unicode__ on Python 2
return "%s the waiter at %s" % (self.name, self.restaurant)
跨文件模型
可以定义跨文件的模型结构,在顶部import之后就可以在内部进行跨文件的模型内容。
模型的方法
可以在模型上使用自定义的方法来给对象添加底层的功能,Manager 方法用于“表范围”的事务,模型的方法应该着眼于特定的模型实例。
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):
"Returns the person's baby-boomer status."
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):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
full_name = property(_get_full_name)
也可以覆盖部分模型的自定义方法,如__str()__
方法,__unicode()__
方法、get_absolute_url
方法等。
其中__str()__
用于python3中,相当于python2 的 __unicode()__
方法,主要用于覆盖对象的某些打印值。
get_absolute_url()
方法告诉Django 如何计算一个对象的URL。Django 在它的管理站点中使用到这个方法,在其它任何需要计算一个对象的URL 时也将用到。
任何具有唯一标识自己的URL 的对象都应该定义这个方法。
重写预定于的模型方法
还有另外一部分封装数据库行为的模型方法,你可能想要自定义它们。特别是,你将要经常改变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) # Call the "real" save() method.
do_something_else()
这个模型表示了可以在调用save方法的时候做一些其他的事情。
super(Blog, self).save(*args, **kwargs)
这个方法将数据保存到数据库中,
支持执行自定义SQL
在模型方法和模型级别方法中可以执行自订的的SQL,
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
... print(p)
John Smith
Jane Jones
模型继承
自定义的模型类应该继承django.db.models.Model。
需要决定的是继承的模型类是否需要进行数据库持久化
在Django 中有3种风格的继承。
- 通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以你要使用抽象基类。
- 如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承。
- 最后,如果你只是想改变一个模块Python 级别的行为,而不用修改模型的字段,你可以使用代理模型。
抽象基类
将一些共有的信息放进Model的时候,抽象化类是比较有用的。
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)
设置meta类中的abstract属性为True,就实现了模型的抽象化基类
多表继承
使用这种继承方式时,每一个层级下的每个 model 都是一个真正意义上完整的 model。 每个Model 都会拥有一个专属的数据表,都可以创建和查询数据表。
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
可以看到这种模式就是直接继承。
代理继承
有时,你可能只想更改 model 在 Python 层的行为实现。比如:更改默认的 manager ,或是添加一个新方法。
代理继承要做的:为原始模型创建一个代理 。你可以创建,删除,更新代理 model 的实例,而且所有的数据都可以像使用原始 model 一样被保存。 不同之处在于:你可以在代理 model 中改变默认的排序设置和默认的 manager ,更不会对原始 model 产生影响。
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
设置Meta类中 proxy 的值为 True,就完成了对代理 model 的声明。