外键关联的优缺点
优点:插入修改数据时,会自动查询关联表,如果数据不合法,就不能修改,保证数据不会错乱,不会出现脏数据。
缺点:每次校验会消耗资源,数据量大会很慢,其实可以通过程序控制脏数据不被录入。
公司一般建立外键,但是不会有约束。
on_delete参数
CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
SET(): 放一个函数内存地址,关联字段删除时,执行这个函数。
class BookModel(models.Model):
"""
图书
"""
book_name = models.CharField(max_length=100, verbose_name='书名')
# 表示外键关联到作者表,当作者表删除了该条数据,图书表中不删除,仅仅是把外键置空
author = models.ForeignKey(AuthModel, null=True, blank=True, on_delete=models.SET_NULL)
price = models.FloatField(verbose_name='价格')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
ManyToMany参数(through,db_constraint)
class Book(models.Model):
name=models.CharField(max_length=20)
authors=models.ManyToMany('Author',through='Score')
class Author(models.Model):
name=models.CharField(max_length=20)
class Score(models.Model):
book=models.ForeignKey('Book')
author=models.ForeignKey('Author')
socre=models.IntegerField()
如果ManyToMany没有指定through参数,django会自动创建第三张表,通过authors.add()、.remove()、.set()、.clear()
对第三张关系表进行操作。但是第三张表的扩展性很差,不能给第三张表添加字段。
而如果不写ManyToMany字段,那么我们可以通过Score来执行一些操作,但是此时book和author表已经没有直接的联系了,查询起来很繁琐。
在ManyToMany中指定through参数(authors=models.ManyToMany('Author',through='Score')
),既有了扩展性,也方便使用ORM的跨表查询。
db_constraint
db_constraint=False,这个就是保留跨表查询的便利(双下划线跨表查询),但是不用约束字段了,一般公司都用false,这样就省的报错,因为没有了约束(Field字段对象,既约束,又建立表与表之间的关系)
如果使用两个表之间存在关联,首先db_constraint=False 把关联切断,但保留连表查询的功能,其次要设置null=True, blank=True,注意on_delete=models.SET_NULL 一定要置空,这样删了不会影响其他关联的表。
related_name
反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’。
related_query_name
反向查询操作时,使用的连接前缀,用于替换表名。
Meta类主要字段如:
db_table
:ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。
index_together
: 联合索引。
unique_together
:联合唯一索引。
ordering
:指定默认按什么字段排序。只有设置了该属性,我们查询到的结果才可以被reverse()。
课程分类接口
serializers.py
class CourseCategorySerializer(serializers.ModelSerializer):
class Meta:
model = CourseCategory
fields = ['id', 'name']
views.py
# 课程分类接口
class CourseCategoryView(GenericViewSet, ListMixinView):
queryset = CourseCategory.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseCategorySerializer
课程接口
serializers.py
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = [
'id',
'name',
'course_img',
'price',
'students',
'pub_sections',
'sections',
'brief',
'attachment_path',
'period',
'course_type_name',
'level_name',
'status_name',
'section_list',
'teacher_info',
]
views.py
# 所有课程接口
class CourseView(GenericViewSet, ListMixinView, RetrieveModelMixin):
queryset = Course.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseSerializer
models.py
class Course(BaseModel):
"""课程"""
course_type = (
(0, '付费'),
(1, 'VIP专享'),
(2, '学位课程')
)
level_choices = (
(0, '初级'),
(1, '中级'),
(2, '高级'),
)
status_choices = (
(0, '上线'),
(1, '下线'),
(2, '预上线'),
)
name = models.CharField(max_length=128, verbose_name="课程名称")
# blank 后台管理录入可以为空,null 存到数据库字段可以为空
course_img = models.ImageField(upload_to="courses", max_length=255, verbose_name="封面图片", blank=True, null=True)
course_type = models.SmallIntegerField(choices=course_type, default=0, verbose_name="付费类型")
# TextField 大文本, 存html
brief = models.TextField(max_length=2048, verbose_name="详情介绍", null=True, blank=True)
level = models.SmallIntegerField(choices=level_choices, default=0, verbose_name="难度等级")
pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)
period = models.IntegerField(verbose_name="建议学习周期(day)", default=7)
attachment_path = models.FileField(upload_to="attachment", max_length=128, verbose_name="课件路径", blank=True,
null=True)
status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="课程状态")
# 优化字段
students = models.IntegerField(verbose_name="学习人数", default=0)
sections = models.IntegerField(verbose_name="总课时数量", default=0)
pub_sections = models.IntegerField(verbose_name="课时更新数量", default=0)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价", default=0)
teacher = models.ForeignKey("Teacher", on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="授课老师",
db_constraint=False)
course_category = models.ForeignKey("CourseCategory", on_delete=models.SET_NULL, db_constraint=False, null=True,
blank=True, verbose_name="课程分类")
class Meta:
db_table = "luffy_course"
verbose_name = "课程"
verbose_name_plural = "课程"
def __str__(self):
return "%s" % self.name
@property
def course_type_name(self):
return self.get_course_type_display()
@property
def level_name(self):
return self.get_level_display()
@property
def status_name(self):
return self.get_status_display()
@property
def teacher_info(self):
from django.conf import settings
image = settings.HOST_URL + '/media/' + self.teacher.image.name
return {
'id': self.id,
'name': self.teacher.name,
'role': self.teacher.role_name,
'title': self.teacher.title,
'signature': self.teacher.signature,
'image': image,
'brief': self.teacher.brief,
}
@property
def section_list(self):
res_list = []
# 先查出课程章节 课程 =》课程章节 反向
chapters_qs = self.coursechapters.all()
for chapter_obj in chapters_qs:
# chapter_obj是章节对象 章节 =》课时 反向
sections_qs = chapter_obj.coursesections.all()
for sections_obj in sections_qs:
res_list.append({
'id': sections_obj.id,
'name': sections_obj.name,
'section_type_name': sections_obj.section_type_name,
'section_link': sections_obj.section_link,
'duration': sections_obj.duration,
'free_trail': sections_obj.free_trail,
})
if len(res_list) > 3:
return res_list
return res_list
方式一:在序列化中定义一个字段,SerializerMethodField的对象,在写一个get_字段的方法,这个方法返回什么,序列化类就序列化什么。
CourseSerializer序列化类中
teacher = serializers.SerializerMethodField()
def get_teacher(self, obj):
image = settings.HOST_URL + '/media/' + obj.teacher.image.name
return {
'id': obj.id
'name': obj.teacher.name,
'role': obj.teacher.role_name,
'title': obj.teacher.title,
'signature': obj.teacher.signature,
'image': image,
'brief': obj.teacher.brief,
}
section_list = serializers.SerializerMethodField()
def get_section_list(self, course_obj):
res_list = []
# 先查出课程章节 课程 =》课程章节 反向
chapters_qs = course_obj.coursechapters.all()
for chapter_obj in chapters_qs:
# chapter_obj是章节对象 章节 =》课时 反向
sections_qs = chapter_obj.coursesections.all()
for sections_obj in sections_qs:
res_list.append({
'id': sections_obj.id
'name': sections_obj.name,
'section_type_name': sections_obj.section_type_name,
'section_link': sections_obj.section_link,
'duration': sections_obj.duration,
'free_trail': sections_obj.free_trail,
})
if len(res_list) > 3:
return res_list
return res_list
方式二:在模型类中写函数,函数返回什么,序列化类就能序列化什么。
models.py
# 获取choice字段真正的值
@property
def course_type_name(self):
return self.get_course_type_display()
@property
def level_name(self):
return self.get_level_display()
@property
def status_name(self):
return self.get_status_display()
@property
def teacher_info(self):
from django.conf import settings
image = settings.HOST_URL + '/media/' + self.teacher.image.name
return {
'id': self.id,
'name': self.teacher.name,
'role': self.teacher.role_name,
'title': self.teacher.title,
'signature': self.teacher.signature,
'image': image,
'brief': self.teacher.brief,
}
@property
def section_list(self):
res_list = []
# 先查出课程章节 课程 =》课程章节 反向
chapters_qs = self.coursechapters.all()
for chapter_obj in chapters_qs:
# chapter_obj是章节对象 章节 =》课时 反向
sections_qs = chapter_obj.coursesections.all()
for sections_obj in sections_qs:
res_list.append({
'id': sections_obj.id,
'name': sections_obj.name,
'section_type_name': sections_obj.section_type_name,
'section_link': sections_obj.section_link,
'duration': sections_obj.duration,
'free_trail': sections_obj.free_trail,
})
if len(res_list) > 3:
return res_list
return res_list
方式三:返回哪个模型表的字段,就重写一个这个模型表的序列化类,再在查询的序列化类中指定返回字段为模型表的序列化类即可。
class TeacherSerializer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = ['id', 'name', 'role_name', 'title', 'signature', 'image', 'brief']
class CourseSerializer(serializers.ModelSerializer):
teacher = TeacherSerializer()
class Meta:
model = Course
fields = [
'id',
'name',
'course_img',
'price',
'students',
'pub_sections',
'sections',
'brief',
'attachment_path',
'period',
'course_type_name',
'level_name',
'status_name',
'teacher',
'section_list',
]
查询所有章节接口带按课程id过滤功能
serializers.py
class CourseChapterSerializer(serializers.ModelSerializer):
class Meta:
model = CourseChapter
fields = [
'id',
'name',
'chapter',
'summary',
'pub_date',
'course_info',
]
views.py
# 所有章节接口
class CourseChapterView(GenericViewSet, ListMixinView, RetrieveModelMixin):
queryset = CourseChapter.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = CourseChapterSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['course']