模型Models
数据模型
模型的字段类型
- CharField(max_length=):字符串类型,参数为长度
- Boolean field():布尔类型
- DateField():日期类型,年月日
- DateTimeField():时间类型,年月日时分秒
- auto_now_add:第一次创建的时候赋值
- auto_now:每次修改时候赋值
- AutoField():自增类型
- IntegerField():整数类型
- FloatField():浮点数类型
- FileField():文件类型
- ImageField(upload_to=)图片类型,存储路径,参数是路径
- 依赖于
pillow
模块 - 设置
MEDIA_ROOT
- 依赖于
- TextField():文本类型
- DecimalField():固定精度小数
- max_digits:总位数
- decimal_places:小数后几位
MEEDIA_ROOT的设置,例如存储用户头像icon,在settings.py中添加其路径:
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/icons')
在模型中定义字段类型和限制为image文件:
class UserModel(models.Model):
username = models.CharField(max_length=32)
# upload_to=后面是根据时间生成的路径,在静态文件文件夹里面
icon = models.ImageField(upload_to="%Y-%M-%D")
当然,我们也可以不用ImageField()
属性,自定义存储的位置,然后将路径存储到数据库中
模型参数
- default:默认值
- null:是否为空,存储有关,创建记录时可以不传值,用NULL填充
- blank:是否为空,校验有关,创建记录时可以为空字符串,不允许前端传空字符串,否则400
- primary_key:主键,有自增属性
- unique:唯一约束,可以有多个null
属性
数据模型的属性分为显性属性和隐形属性
显性属性包括开发主动声明的模型的属性和方法,还有从父类中继承来的属性和方法。
隐性属性是开发这未声明,自动生成的属性,开发者声明了就不自动生成了
例如模型的objects属性,是一个隐性属性,不需要开发者声明,自动生成,直接调用进行查询过滤,是一个manager实例,用来创建管理模型。
重写这个实例,实现对数据库数据的过滤,使返回的结果只包含没有被逻辑删除的结果。首先创建一个新的manager类,继承自Manager,重写他的get_queryset()
方法,实现过滤功能。
class LearnManager(Manager):
# 重写查询结果集,对数据进行过滤
def get_queryset(self):
queryset = super().get_queryset().filter(is_delete=Flase)
return queryset
def create_goods(self, g_name, g_price=10):
goods = self.model()
goods.g_name = g_name
goods.g_price = g_price
goods.save()
return goods
针对数据的逻辑删除,需要在模型中定义一个删除的属性is_delete
,删除是直接操作这个属性,我们在模型中定义这个删除的方法:
class Goods(model.Model):
is_delte = models.BooleanField(default=False)
def delete(self, using=None, keeo_parents=False):
self.is_delete = True
self.save()
# 重新定义objects为我盟的模型管理器的实例
goods_manager = LearnManager()
这样我们的模型就有了一个新的模型管理器goods_manager
在views中使用管理器
# 查询所有没有被逻辑删除的数据
goods = Goods.goods_manager.all()
数据关系
数据之间的管理是认为定义的,分为一对一,一对多,多对多,一对一可以通过数据表中唯一的外键来实现,一对多可以使用不唯一的外键实现,多对对则需要创建一个新的关系表,来表示两个表之间数据的关系
一对一
使用场景,业务拆分时,对现有的表进行拆分,或者对项目扩充,增加字段,直接操作现有表,可能会出现错误,造成无法晚会的损失,创建一个扩展的表是理想的解决方案,可以通过给外键添加唯一约束来实现一对一的关系,例如g_foo = models.ForeignKey(User, unique=True)
,Django里面自带一个OneToOneField属性用来实现一对一的关系映射。
当操作数据库时,删除主表的内容,从表的数据也会被级联删除,删除从表数据,主表不会受影响。谁声明的一对一关系,谁就是从表
我们假定有两张表,一张用户表UserModel,一张用户权限表VipModel,用户表是主表,权限表是从表。声明关系语句为v_user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True)
。SET_NULL可以为空。
一对一中的属性:主表获取从表的值,是隐形属性,获取要用模型名,根据用户表获取最后一个用户在权限表中的数据
user = UserModel.objects.last()
# 对象.关联模型(模型名要小写)获取到一条vip数据
vip = user.vipmodel
根据从表获取主表信息是显性属性,直接按字段名就可以获取。如果要获取第一个vip的用户名,则通过权限表,获取用户表的字段
vip = VipModel.objects.first()
# 对象.字段(字段是vip表中的,获取到用户对象)
user = vip.v_user
一对多
一对多的关系和一对一基本一致,使用ForeignKey来实现,默认删除主表数据,从表的数据会被级联删除,可以设置保护模式,使其不被删除。SET_PROTECT
假定我们有一个人的表,一个爱好的表,人的表是主表,定义模型
# 人
class Person(models.Model):
p_name = models.CharField(max_length=30)
p_age = models.IntegerField(default=1)
# 爱好
class Hobby(models.Model):
h_name = models.CharField(max_length=30)
h_cost = models.FloatField(default=1000)
# 一对多
h_person = models.ForeignKey(Person, on_delete=models.PROTECT)
获取级联数据,Django会自动生成一个从表的模型_set
管理器,获取从表数据通过它来获取
# 从获取主,显性属性, 对象.字段名
hobby = Hobby.objects.last()
person = hobby.h_person # 爱好对应的人
# 主获取从,隐性属性, 对象.关联模型_set [与objects同源,所以用法也是一致]
person = Person.objects.last()
# hobby_set与objects同源,all表示所有数据
hobbies = person.hobby_set.all() # 人对应的爱好
# 按条件获取
hobbies = person.hobby_set.filter(id=2)
多对多
表现出来的是两个数据表之间的映射,通过第三张表来体现,用ManyToManyField
来实现,Django会自动创建第三张表关系表,关系表中会存储两张关联表的id,同样,声明关系的表是从表,并且从表不需要人为干涉。
删除数据时,会自动删除关系表中的级联关系数据
我们以用户和商品的关系,来展示级联数据的获取
class UserModel(models.Model):
u_name = models.CharField(max_length=32)
class Goods(models.Model):
g_name = models.CharField(max_length=64)
g_users = models.ManyToManyField(UserModel)
数据的操作,查询时获取的数据都是复数:
# 数据查询
# 从表获取主表,是显性属性:对象.字段名
goods = Goods.object.last()
user = goods.g_user.all()
# 主表获取从表,是隐形属性:对象.从表_set
user = UserModel.objects.first()
goods = user.Goods_set.all()
# 数据改动
goods = Goods.objects.first()
user = UserModel.objects.last()
user.goods_set.add(goods) # goods_set是自动生成的模型管理器
goods.g_user.remove(user)
goods.g_user.clear() # 清楚所有关系数据
删除模式
在声明级联关系的字段中增加’on_delete=xxx’属性,包含以下几个值
写法例如(多对多的关系中没有on_delete属性)
v_user = models.OneToOneField(UserModel, on_deletr=models.SET_NULL, null=True)
- models.CASECADE:默认模式,默认删除级联数据
- models.DO_NOTHING:删除关联数据,什么都不做
- models.PROTECT:保护模式,存在级联数据时,删除会报异常
- models.SET_XXX
- SET_NULL:主表级联数据被删时置空(需要指定允许为空)
- SET_DEFAULT:主表级联数据被删设为默认值(指定默认值)
- SET():删除时重新指向一个实体对象元素
- SET(value):删除关联的数据设为指定的值
- SET(可执行对象):关联值设置为可执行对象的返回值
模型继承
我们所创建的models模型,本身就是继承自models.Model,同样,我们也可以自己定义一个model作为基础父类,把通用的数据存储在父类的模型中。
如果直接迁移,数据库中也会直接生成父类的表,可以在基础模型中定义一个属性class Meta:
,来抽象化基础模型。
class BaseModel(models.Model):
id = models.IntegerField(primary_key=True, unique=True, autoincrement=True)
class Meta:
abstract = True
定义abstract属性之后,基础模型就不会在数据库中生成映射
模型和库转换
models --> db
迁移模型生成数据表
db --> models
把数据表映射到模型文件中
python manage.py insectdb > models.py
环境转移:
- 导出所有依赖
pip freeze > requirements.txt
- 安装所有依赖
pip install -r requirements.txt