- 通常每个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常用的属性和方法:
- Model.objects:数据库查询的接口,用于返回model instance
- get_absolute_url():生成对象的url,在admin site会使用到
- 重写已定义Model方法,一定要调用基类的该方法,否则会改变默认行为,示例代码:
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()
- 执行自定义sql语句:语法为Manager.raw(raw_query,params=None,translations=None):
#两者效果一样 Person.objects.raw('SELECT * FROM myapp_person') Person.objects.all()
- 定义抽象类:在Meta class中定义abstract=true,抽象类不能创建数据库表,且抽象类中的字段名与其子类中的字段名不能相同。另外Meta class也可以继承
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'
- multi-table 继承:子model与父model间通过隐式的OneToOneField关联,每个model对应单独的表。显示的OneToOneField会占用ForeignKey或ManyToManyField默认的related_name值,如果在子类中还要使用ForeignKey或者ManyToManyField需要显示指定related_name的值
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')
- 关于related_name以及relatd objects:如果在一个model中通过ForeignKey,OneToOneField或者ManyToManyField定义了relationship,relationship的另一端就是related objects.model可以直接访问related model,related model通过related_name可以访问model,related_name默认的名字是modelclassname_set,是一个Manager对象,示例代码:
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
- 抽象类中定义了relationship时,如果要显示指定related_name,则抽象类的多个子类会都包含相同的related_name会导致错误,正确的方式是在related_name中包含‘%(app_label)s’和’%(class)s’,app_label会用app name替换,class用class name替换
- Proxy models:如果需要改变一个model的behavior,如添加新方法,改变默认的manager等,不需要添加新数据时可以使用proxy model.创建,删除,更新model数据都同使用original model一样会被保存。区别是在proxy model中改变默认的ordering,manager等则不会改变original model. original model的所有实例都可以在Proxy model中访问,反之亦然。对于非抽象model类,proxy model只能继承一个model,对于抽象model类,如果抽象类中没有field则可以继承任意多个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 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")