-
通常每个model都映射到一张单独的表,自定义model的特点:
- 每个model都是一个继承自django.db.models.Model的class
- 每个model的attribute代表一个表的列值
- model中只包含与表列对应的field
- django会自动生成访问数据库的api
-
示例代码:
from django.db import models class Person(models.Model): #models是module,CharField是class first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
- 自动创建数据库表,表名默认为app name_model name,可以重命名
- 自动添加id字段作为主键,此行为也可以改写,相当于执行了id=models.AutoField(primary_key=true),如果显示指定了其他列为primary key,则不会自动添加id列
- 每个Model都要有一个primary_key=true的field
- 要通过manage.py migrate命令创建数据库表
-
关于字段(field):
- 每个字段都是Field class的子类对象,Field class是抽象类
- django通过field的类型确定表列的类型
- 确定用于显示field的html元素
- 有效性判断
- 字段名不能是python保留字,不能带‘--’
-
common filed arguments包括不限于:
- null:默认是false,如果是true,则在数据库表中存储null值
- blank:默认是false,如果true,则存放空值
- choices:可以作为field值的tuple
- default:field的默认值,可以是一个值也可以是一个callable object
- primary_key:如果是ture,这个field是model的primary key
- db_column:field对应的数据库列名
- db_index:为这个field创建索引
- unique:如果是true,field的值必须是唯一的
- help_text:帮助信息
-
model之间的关系,也是表之间的关系
-
多对一:使用ForeignKey类,可以定义自身对自身的多对一关系
#多对一:ForeignKey类 from django.db import models class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer) # ...
-
对对多:ManyToManyField class,可以定义自身对自身的多对多的关系
#多对多:ManyToManyField class,在Topping或者Pizza中定义均可 from django.db import models class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
-
可以使用intermediate model管理多对多关系,指定其他field,示例代码:
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) #through参数指向的就是intermediate class members = models.ManyToManyField(Person, through='Membership') def __str__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) #可以指定其他field 描述两者之间的关系 date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
-
intermediate class的限制条件:
- 必须包含指向两个关系类的foreignkey
- 自身指向自身的多对多关系,应该设置两个指向同一model的foreignkey
- 自身指向自身的多对多关系,ManyToManyField.symmetrical必须为false
-
可以使用intermediate model管理多对多关系,指定其他field,示例代码:
- 一对一:OneToOneField class,可以定义自身指向自身的一对一关系
-
多对一:使用ForeignKey类,可以定义自身对自身的多对一关系
- 自定义field type:需要继承models.Field
- Meta options:使用class Meta为model定义metadata,django已经定义了很多Meta option字段,如
- ordering:排序字段
- app_label: app name
- db_table:model对应的数据库表名
- abstract指定该类为抽象类
- managed:默认为true,django会为model创建数据库表,为false则不会创建
- proxy:指定proxy model
from django.db import models class Ox(models.Model): horn_length = models.IntegerField() class Meta: #排序字段 ordering = ["horn_length"] verbose_name_plural = "oxen" #指定存放model的database table db_table="myOx"
- Model.objects:数据库查询的接口,用于返回model instance
- get_absolute_url():生成对象的url,在admin site会使用到
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()
#两者效果一样 Person.objects.raw('SELECT * FROM myapp_person') Person.objects.all()
from django.db import models class CommonInfo(models.Model): # ... class Meta: abstract = True ordering = ['name'] class Student(CommonInfo): # django会自定把abstract设为false,所以Student不是抽象类 class Meta(CommonInfo.Meta): db_table = 'student_info'
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) class Supplier(Place): #需要显示指定related_name参数 customers = models.ManyToManyField(Place,related_name='provider')
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): return self.name class Entry(models.Model): #blog 是related object blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() def __str__(self): return self.headline b = Blog.objects.get(id=1) b.entry_set.all() # Returns all Entry objects related to Blog. # b.entry_set is a Manager that returns QuerySets. b.entry_set.filter(headline__contains='Lennon') b.entry_set.count()
-
抽象类中定义了relationship时,如果要显示指定related_name,则抽象类的多个子类会都包含相同的related_name会导致错误,正确的方式是在related_name中包含‘%(app_label)s’和’%(class)s’,app_label会用app name替换,class用class name替换
from django.db import models class Base(models.Model): m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") class Meta: abstract = True class ChildA(Base): pass class ChildB(Base): pass #如果related_name指定了固定名字如"refer",那么m2m.refer无法确定是引用ChildA还是ChildB,如果
#Base类中隐式指定related_name,则不会有错误,ChildA中的related_name默认为childa_set,ChildB中
#related_name默认为childb_set
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 model的方法 proxy = True ordering = ["last_name"] def do_something(self): # ... pass #可以在proxy model中访问original model实例,反之亦然 p = Person.objects.create(first_name="foobar") MyPerson.objects.get(first_name="foobar")