一、 一对一关系: 实名认证表
一对一关系: models.OneToOneField
主表的数据是相对重要的(UserEntity), 从表 需要 主动声明关系(RealProfile)
对象获取: 从表获取主表数据, 直接使用字段, 对象.字段名.属性名; 主表获取从表数据: 隐性的, 对象.模型名.属性名
1.1 声明一对一关系
class RealProfile(models.Model):
# 声明一对一的关联关系 OneToOneField
user = models.OneToOneField(UserEntity, verbose_name='账号', on_delete=models.CASCADE)
real_name = models.CharField(max_length=20, verbose_name='真实姓名')
id_number = models.CharField(max_length=18, verbose_name='证件号')
id_type = models.IntegerField(choices=((0, '身份证'), (1, '护照'), (2, '驾驶证')), verbose_name='证件类型')
image1 = models.ImageField(verbose_name='正面照片', upload_to='user/real')
image2 = models.ImageField(verbose_name='反面照片', upload_to='user/real')
class Meta:
db_table = 't_real_profile'
verbose_name = '实名认证'
verbose_name_plural = verbose_name
class RealProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'real_name', 'id_number', 'id_type')
admin.site.register(RealProfile, RealProfileAdmin)
1.2 从表获取主表的数据、 主表获取从表的数据
>>> from mainapp.models import UserEntity, RealProfile
>>> u1 = RealProfile.objects.filter(real_name='李哪吒').first()
>>> u1.user.phone # 从表访问主表数据
'15577778888'
>>> login_u1 = UserEntity.objects.get(pk=1)
>>> login_u1.realprofile.id_number # 主表访问从表数据, 模型类的全小写
'3900110011'
1.3 级联关系
on_delete=models.CASCADE 级联删除/ models.SET_NULL级联关系设置为null
class CartEntity(models.Model):
user = models.OneToOneField(UserEntity, verbose_name='账号', on_delete=models.CASCADE)
no = models.CharField(primary_key=True, max_length=10, verbose_name='购物车编号')
class Meta:
db_table = 't_cart'
verbose_name = verbose_name_plural = '购物车表'
def __str__(self):
return self.user.name + "(" + self.no + ")"
class CartEntityAdmin(admin.ModelAdmin):
list_display = ('user', 'no')
admin.site.register(CartEntity, CartEntityAdmin)
二、 一对多关系: 声明购物车与水果的关系表
一对多关系: 使用ForeignKey关系实现; models.ForeignKey
对象获取: 从表获取主表数据, 字段属性
主表获取从表数据: 对象.模型名_set; 结果是数据集合, Manager类型, 支持filter,exclude,all,last,first等方法
2.1 定义一对多关系
class FruitCartEntity(models.Model): cart = models.ForeignKey(CartEntity, on_delete=models.CASCADE, verbose_name='购物车') fruit = models.ForeignKey(FruitEntity, on_delete=models.CASCADE, verbose_name='水果') cnt = models.IntegerField(verbose_name='数量', default=1)
@property def price(self): return round(self.cnt * self.fruit.price, 2) # 显式单个商品的合计
class Meta: db_table = 't_fruit_cart' verbose_name = verbose_name_plural = '购物车详情表' def __str__(self): return self.fruit.name + ':' + self.cart.no
class FruitCartEntityAdmin(admin.ModelAdmin):
list_display = ('cart', 'fruit', 'cnt', 'price')
admin.site.register(FruitCartEntity, FruitCartEntityAdmin)
2.2 展示计算属性的verbose_name名称
2.2.1 属性方法def price(self) 在后台显示时没有verbose_name, 如何解决
list_display = ('cart', 'fruit', 'cnt', 'price', 'fruit.price') # 使用fruit.price报错
ERRORS:
<class 'mainapp.admin.FruitCartEntityAdmin'>: (admin.E108) The value of 'list_display[4]' ref
ers to 'fruit.price', which is not a callable, an attribute of 'FruitCartEntityAdmin', or an
attribute or method on 'mainapp.FruitCartEntity'.
2.2.2 解决办法: 显示字段可以引用关系实体对象的属性
class FruitCartEntity(models.Model):
@property
def price(self):
return round(self.cnt * self.fruit.price, 2)
@property
def price_v(self):
return self.fruit.price
class FruitCartEntityAdmin(admin.ModelAdmin):
list_display = ('cart', 'fruit', 'cnt', 'price_v_title', 'price_title')
def price_title(self, obj):
return obj.price
def price_v_title(self, obj):
return obj.price_v
price_title.short_description = '小计'
price_v_title.short_description = '单价'
2.3 主表 读取 从表数据
>>> from mainapp.models import UserEntity
>>> login_u = UserEntity.objects.get(pk=1)
# UserEntity 与 CartEntity 是一对一关系, CartEntity 与 FruitCartEntity是 一对多关系
>>> login_u.cartentity.fruitcartentity_set
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>
.RelatedManager object at 0x0000006F5513C4F0>
>>> login_u.cartentity.fruitcartentity_set.all()
<QuerySet [<FruitCartEntity: 苹果:CT001>, <FruitCartEntity: 神仙果:CT001>]>
2.4 一对多关系案例: 一个种类对应多种水果
class FruitEntity(models.Model):
# category = models.ForeignKey(CategoryEntity, on_delete=models.CASCADE)
category = models.ForeignKey(CategoryEntity, related_name='fruits',
to_field='id', on_delete=models.CASCADE)
>>> from mainapp.models import CategoryEntity >>> f1.category.name '南方水果' >>> c1 = f1.category >>> c1.fruitentity_set <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager. <locals>.RelatedManager object at 0x000000C8C826E370> >>> cat1 = CategoryEntity.objects.get(pk=1) >>> cat1.name '热带水果' >>> cat1.fruits.values() <QuerySet [{'id': 1, 'name': '火龙果', 'price': 11.50, 'source': '泰国', 'category_id': 1}, {'id': 3, 'name': '神仙果', 'price': 395.59, 'source': '非洲', 'category_id': 1}, {'id': 4, 'name': '荔枝', 'price': 10.78, 'source': '福州', 'category_id': 1}]>
>>> cat1.fruits.values_list() <QuerySet [(1, '火龙果', 11.50, '泰国', 1), (3, '神仙果', 395.59, '非洲', 1),(4, '荔枝', 10.78, '福州', 1)]>
三、 多对多关系
使用第三方表建立多对多关系
3.1 定义多对多关系: 用户收藏商品
class FruitEntity(models.Model):
# 默认情况下, 反向引用的名称是当前类的名称(小写)_set,可以通过 related_name 来指定;
# db_table='t_collect' 使用第三张表建立 fruit 和user 的多对多关系
users = models.ManyToManyField(UserEntity, db_table='t_collect',
related_name='fruits', verbose_name='收藏用户列表',
blank=True, null=True)
准备数据
>>> from mainapp.models import UserEntity, FruitEntity
>>> FruitEntity.objects.get(pk=1)
<FruitEntity: 火龙果>
>>> FruitEntity.objects.get(pk=2)
<FruitEntity: 苹果>
>>> u1 = UserEntity.objects.get(pk=1)
>>> u1.name
'哪吒'
>>> u2 = UserEntity.objects.get(pk=2)
>>> u2.name
'宋江'
>>> f1 = FruitEntity.objects.get(pk=2)
>>> f1.name
'苹果'
3.2 多对多关系的CRUD操作
### 给用户u1/u2 添加水果
>>> u1.fruits.add(FruitEntity.objects.get(pk=1))
>>> u1.fruits.add(FruitEntity.objects.get(pk=2))
>>> u2.fruits.add(FruitEntity.objects.get(pk=2))
### 查找水果f1 有哪些用户收藏, 查询用户的信息
>>> f1.users.all()
<QuerySet [<UserEntity: 哪吒>, <UserEntity: 宋江>]>
>>> f1.users.values_list()
<QuerySet [(1, '哪吒', 3, '15577778888'), (2, '宋江', 47, '15566660000')]>
>>> f1.users.values()
<QuerySet [{'id': 1, 'name': '哪吒', 'age': 3, 'phone': '15577778888'},
{'id': 2, 'name': '宋江', 'age': 47, 'phone': '15566660000'}]>
### 查询用户收藏了 哪些水果
>>> u1.fruits.values()
<QuerySet [{'id': 1, 'name': '火龙果', 'price': 11.508304793776945, 'source': '泰国', 'category_id': 1},
{'id': 2, 'name': '苹果', 'price': 2.013953338910966, 'source': '烟台', 'category_id': 2}]>
### 用户取消收藏的水果
>>> u1.fruits.remove(FruitEntity.objects.get(pk=1))
>>> u1.fruits.values()
<QuerySet [{'id': 2, 'name': '苹果', 'price': 2.013953338910966, 'source': '烟台', 'category_id': 2}]>
3.3 多对多关系案例: 水果与标签
3.3.1 定义标签类
class TagEntity(models.Model):
name = models.CharField(max_length=50, unique=True, verbose_name='标签名')
order_num = models.IntegerField(default=1, verbose_name='序号')
class Meta:
db_table = 't_tag'
verbose_name = verbose_name_plural = '标签管理'
ordering = ['-order_num']
def __str__(self):
return self.name
3.3.2 定义多对多关系
class FruitEntity(models.Model):
tags = models.ManyToManyField(TagEntity, db_table='t_fruit_tags',
related_name='tag_fruits', verbose_name='所有标签')
3.3.3 多对多关系的CRUD操作
### pk=1的水果 添加 两个标签
>>> FruitEntity.objects.get(pk=1).tags.add(TagEntity.objects.get(pk=1)) >>> FruitEntity.objects.get(pk=1).tags.add(TagEntity.objects.get(pk=2))
### pk=1的标签对应的水果 >>> TagEntity.objects.get(pk=1).tag_fruits.values() <QuerySet [{'id': 1, 'name': '火龙果', 'price': 11.50, 'source': '泰国', 'category_id': 1}]>
### pk=1的水果 包含的标签 >>> FruitEntity.objects.get(pk=1).tags.values() <QuerySet [{'id': 1, 'name': '会员半价', 'order_num': 1}, {'id': 2, 'name': '七天包退', 'order_num': 1}]> ### pk=2的水果 包含的标签 >>> FruitEntity.objects.get(pk=2).tags.values() <QuerySet []>
四、模型类的对象继承
将父模型抽象; 父模型的字段会复制在子模型中
4.1 基础类
class BaseModel(models.Model):
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True, null=True)
update_time = models.DateTimeField(verbose_name='更新时间', auto_now=True, null=True)
class Meta:
abstract = True # 抽象的模型类, 不会创建表
4.2 定义OrderModel, 继承BaseModel
class OrderModel(BaseModel): id = models.CharField(max_length=20, primary_key=True, verbose_name='订单号') title = models.CharField(max_length=100, verbose_name='订单名称') price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='金额')
pay_type = models.IntegerField(choices=((0, '余额'),(1,'银行卡'),(2, '微信支付'), (3, '支付宝')), verbose_name='支付方式', default=0) order_status = models.IntegerField(choices=((0, '待支付'), (1, '已支付'), (2, '待收货'), (3, '已收货'), (4, '完成'), (5, '取消')), verbose_name='订单状态', default=0) receiver = models.CharField(max_length=20, verbose_name='收货人姓名') receiver_phone = models.CharField(max_length=11, verbose_name='收货人手机号') receiver_addr = models.CharField(max_length=100, verbose_name='收货地址') class Meta: db_table = 't_order' verbose_name = '订单表' verbose_name_plural = verbose_name def __str__(self): return self.title
4.3 编写orderapp/admin.py
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'price', 'pay_type', 'order_status', 'create_time')
fields = ('id', 'title', 'price')
list_filter = ('order_status', )
admin.site.register(OrderModel, OrderAdmin)
五、 模型类的自关联