Django是一个免费且开源的Python Web框架,它采用了MVC(Model-View-Controller)的软件架构模式,用于构建高效、安全、可扩展的 Web 应用程序。Django提供了大量的构建 Web 应用程序所需的功能,例如表单处理、认证、管理后台、数据库 ORM、URL路由等等,使得开发人员可以专注于业务逻辑的实现,大大提高了开发效率。同时,Django还具有高度的安全性和可维护性,因此广泛地应用于各种规模的 Web 项目中,包括知名的网站和应用程序,如Instagram、Pinterest、Mozilla等等。
这是一个单独的板块,新建app,在settings里进行注册
先上模型
from django.contrib.auth.models import User
from django.db import models
from utils.modelsMixin import ModelSetMixin
# Create your models here.
class Label(models.Model):
name = models.CharField(max_length=30, verbose_name='标签名', unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'label'
verbose_name = '标签'
verbose_name_plural = verbose_name
class Topic(ModelSetMixin):
TYPE_CHOICES = (
(0, '单选题'),
(1, '多选题'),
(2, '判断题'),
(3, '填空题'),
(4, '问答题'),
)
subject = models.TextField(verbose_name='题干')
type = models.IntegerField(verbose_name='类型', choices=TYPE_CHOICES)
score = models.FloatField(verbose_name='分值', default=1.0, null=True, blank=True)
answer = models.TextField(verbose_name='答案')
label = models.ForeignKey(Label, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'topic'
verbose_name = '题目'
verbose_name_plural = verbose_name
Label 模型类有两个字段:name 和 user。name 是一个 CharField,表示标签名,最大长度为 30,且必须唯一。user 是一个 ForeignKey,表示标签所属的用户,当用户被删除时,与之关联的标签也会被删除。 Topic 模型类有七个字段:subject、type、score、answer、label、user 和 created_time。subject 是一个 TextField,表示题干。type 是一个 IntegerField,表示题目类型,有五种选择。score 是一个 FloatField,表示分值,默认为 1.0,可以为空。answer 是一个 TextField,表示答案。label 是一个 ForeignKey,表示题目所属的标签,当标签被删除时,与之关联的题目也会被删除。user 是一个 ForeignKey,表示题目所属的用户,当用户被删除时,与之关联的题目也会被删除。created_time 是一个 DateTimeField,表示题目创建时间,使用了一个自定义的 Mixin 类 ModelSetMixin 来自动设置创建时间和更新时间。 这些模型类的 Meta 类中定义了数据库表名、verbose_name 和 verbose_name_plural。
编写序列化器,先将所有字段进行返回
from rest_framework.serializers import ModelSerializer
from work.models import *
class LabelSerializer(ModelSerializer):
class Meta:
model = Label
fields = '__all__'
在视图里增加必要的权限,可以新建py文件定义权限装饰器,用于区分老师和学生。区别在于答案的显示与否。在这里用于调用。调用@action可以自动生成路由。
其中分页器采用limit分页器。用于指定跳转。
from random import sample
from django.db.models import Q
from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from utils.permission import *
from work.serializers import *
from rest_framework.pagination import LimitOffsetPagination
class TopicPaginationLimitOffset(LimitOffsetPagination):
default_limit = 3
max_limit = 100
class LabelViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Label.objects.all()
serializer_class = LabelSerializer
@wrap_permission(TeacherPermission)
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
@wrap_permission(ActiveUserPermission)
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
@wrap_permission(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
class TopicViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
# pagination_class = TopicPaginationPageNumber
pagination_class = TopicPaginationLimitOffset
def get_queryset(self):
if self.action in ['practice', 'random']:
return Topic.objects.filter(Q(is_delete=False) & ~Q(label__name__contains='试卷'))
return self.queryset
def get_serializer(self, *args, **kwargs):
if self.action in ['exam', 'random']:
return TopicStudentSerializer(*args, **kwargs)
return self.serializer_class(*args, **kwargs)
@wrap_permission(TeacherPermission)
def list(self, request, *args, **kwargs):#查多个
return ModelViewSet.list(self, request, *args, **kwargs)\
@wrap_permission(TeacherPermission)
def retrieve(self, request, *args, **kwargs):#查单一
return ModelViewSet.retrieve(self, request, *args, **kwargs)
@wrap_permission(TeacherPermission)
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
@wrap_permission(ActiveUserPermission)
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
@wrap_permission(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
@action(methods=['get'], detail=False)
def practice(self, request):
return ModelViewSet.list(self, request)
@action(methods=['get'], detail=True)
def exam(self, request, pk):
#获取指定标签,指定试卷
labels = Label.objects.filter(id=pk, name__contains='试卷').first()
#判断有没有这个试卷,没有返回404
if not labels:
return Response(status=HTTP_404_NOT_FOUND)
#有,则获取这个试卷的所有题目,不包含答案,通过管理器,题目_ser
topics = labels.topic_set.filter(is_delete=False)
serializer = self.get_serializer(topics, many=True)
return Response(serializer.data)
@action(methods=['get'], detail=False)
def random(self, request):
#获取随机刷题个数
try:
size = int(request.query_params.get('size', 3))
except ValueError:
return Response(status=HTTP_400_BAD_REQUEST)
#获取查寻集,随机抽取指定个数
pool = list(self.get_queryset())
#判断要获取的随机题目个数是否超过题目总数,如果操作,则会给出提示
if len(pool) < size:
return Response({'detail':'超出题目个数:题目总数为: %s' % len(pool)}, status=HTTP_400_BAD_REQUEST)
#序列化进行返回
serializer = self.get_serializer(sample(pool, size), many=True)
return Response(serializer.data)
优化序列化器
from rest_framework.serializers import *
from rest_framework import serializers
from work.models import *
class LabelSerializer(ModelSerializer):
username = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Label
fields = '__all__'
extra_kwargs = {
'user': {'required': False, 'write_only': True}
}
class TopicSerializer(ModelSerializer):
label_name = serializers.CharField(source='label.name', read_only=True)
user_name = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Topic
exclude = ['is_delete']
class TopicStudentSerializer(ModelSerializer):
label_name = serializers.CharField(source='label.name', read_only=True)
user_name = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Topic
exclude = ['is_delete', 'answer']
这段代码是用于序列化 Django 模型的,使用了 Django REST framework 库中的 serializers 模块。其中包含了三个序列化器:
1. LabelSerializer:用于序列化 Label 模型,将其转换为 JSON 格式。其中,username 字段是通过 user 模型中的 username 字段来获取的,且只读。extra_kwargs 中的设置表示 user 字段不是必须的,且只能在写入时使用。
2. TopicSerializer:用于序列化 Topic 模型,将其转换为 JSON 格式。其中,label_name 和 user_name 字段是通过 label 和 user 模型中的 name 和 username 字段来获取的,且只读。exclude 中的设置表示排除 is_delete 字段。
3. TopicStudentSerializer:与 TopicSerializer 类似,但是排除了 answer 字段。
采用路由器
from rest_framework.routers import DefaultRouter
from work.views import *
urlpatterns = []
router = DefaultRouter()
router.register('label', LabelViewSet),
router.register('topics', TopicViewSet),
urlpatterns += router.urls
它自带测试页面,输入IP+接口进行测试。一切正常。OK