实操学习——题目的管理

news2024/9/21 21:17:39

实操学习——题目的管理

  • 一、基础配置
  • 二、权限控制
  • 三、分页
    • 1. PageNumberPagination分页器
    • 2. LimitOffsetPagination分页器
    • 3.总结
  • 四、题目操作模块
    • 1. 考试
    • 2. 题目练习——顺序刷题
    • 3. 模拟考试
  • 补充:前端调用接口写法

本文主要讲解题目的管理案例
1.题目的基本增删改查
2.题目的权限控制
3.题目的搜索

在这里插入图片描述

一、基础配置

  1. 创建一个名为work的app
    在这里插入图片描述

  2. 将work注册到settings.py
    在这里插入图片描述

  3. 在models.py中创建模型

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' #定义生成的mysql表名
        verbose_name = '标签'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name #重写__str__方法,返回标签名,这样在Topic模型中的label 字段显示为正常的标签名,而不是object

# 题目表
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)
    description = models.TextField(verbose_name='题目描述', 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:
        ordering = ['-update_time'] #可以在元信息中定义排序方式,倒序排序
        db_table = 'topic'
        verbose_name = '题目'
        verbose_name_plural = verbose_name

这里要导入自己创建的ModelSetMixin,代码如下:

from django.db import models


class DateTimeModelMixin(models.Model):
    """创建和修改时间模型拓展类"""
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        abstract = True  # 指定该类为抽象模型类,迁移映射的时候就不会创建对应的表,只是用于封装拓展


class IsDeleteModelMixin(models.Model):
    """逻辑删除模型拓展类"""
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    def delete(self, using=None, keep_parents=False):
        # 逻辑删除
        self.is_delete = True
        self.save()

    class Meta:
        abstract = True


class ModelSetMixin(DateTimeModelMixin, IsDeleteModelMixin):
    """模型拓展整合类"""

    class Meta:
        abstract = True

  1. 编写序列化器serializers.py
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *

# 有对应的模型可以直接继承ModelSerializer
class LabelSerializer(ModelSerializer):
	#新增字段,查询时将username 也显示出来
    username = serializers.CharField(source='user.username', read_only=True)

    class Meta:
        model = Label
        fields = '__all__'

        extra_kwargs = {
        	#将user设置为只写,查询时隐藏不显示user这个字段
            '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']

  1. 编写views.py视图函数
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 rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *

class LabelViewSet(ModelViewSet):
    queryset = Label.objects.all()
    serializer_class = LabelSerializer

class TopicViewSet(ModelViewSet):
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer

  1. 编写路由urls.py
from rest_framework.routers import DefaultRouter

from .views import *

urlpatterns = []
router = DefaultRouter()
router.register('label', LabelViewSet)
router.register('topics', TopicViewSet)
urlpatterns += router.urls

7.配置总路由urls.py
在这里插入图片描述
8.启动测试
在这里插入图片描述

二、权限控制

  • 标签权限分析:

标签的权限:
创建:老师及以上
查看:登录可查看
修改:老师及以上
删除:超级管理员

设置最低基本权限:选择这个事物操作的最低权限,将最低权限定义为视图类的权限。最基础的就是登录。

  1. 修改视图views.py,增加权限
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 rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *

class LabelViewSet(ModelViewSet):
	# 设置基础权限:该视图必须登录才能访问
    permission_classes = [IsAuthenticated]
    queryset = Label.objects.all()
    serializer_class = LabelSerializer
	
	#重写create方法
	@wrap_permisssion(TeacherPermission) #定义只有老师权限才可以创建
	@auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)
    
    #重写create方法,操作的用户必须是当前登陆的用户
	@wrap_permisssion(ActiveUserPermission)
	@auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)
    
    #重写destroy方法,必须为超级管理员权限
    @wrap_permisssion(RootPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)
  1. 在permission.py中增加超级管理员的权限类RootPermission,以及其他权限如下。
from functools import update_wrapper

from django.contrib.auth.models import Group
from rest_framework.permissions import BasePermission 


class TeacherPermission(BasePermission):
    def has_permission(self, request, view):
        user = request.user  # 当前请求的用户信息
        # 判断身份,查询用户在不在老师这个分组里面
        group = Group.objects.filter(name='老师').first()
        user_groups = user.groups.all()
        return user.is_superuser or group in user_groups


class ActiveUserPermission(BasePermission):
    def has_permission(self, request, view):
        # 操作的用户必须是当前登陆的用户
        user = request.user
        return user.id == int(view.kwargs['pk'])

#超级管理员权限类
class RootPermission(BasePermission):
    def has_permission(self, request, view):
        user = request.user
        return user.is_superuser


# 更改权限装饰器
def wrap_permisssion(*permissions, validate_permisssion=True):
    def decorator(func):
        def wrapper(self, request, *args, **kwargs):
            self.permission_classes = permissions
            if validate_permisssion:
                self.check_permissions(request)
            return func(self, request, *args, **kwargs)

        return update_wrapper(wrapper, func)

    return decorator

#创建时自动原则对应的用户,而不是所有用户都能选择
def auto_user(func):
    def wrapper(self, request, *args, **kwargs):
        request.POST._mutable = True  # 让请求参数可以被修改,固定写法
        request.data['user'] = request.user.id #将user改为当前登录用户的id

        return func(self, request, *args, **kwargs) #返回原本函数执行的结果,即创建

    return wrapper

  • 题目操作权限分析

题目的权限:
创建:老师及以上
修改:自己
查看:
自带的查询包括答案,权限是老师
查询需要增加额外的接口,没有答案,权限是登录即可。防止被爬虫
删除:超级管理员

  1. 定义一个学生使用的序列化器TopicStudentSerializer,只能看到题目,无法查看到答案
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *

# 有对应的模型可以直接继承ModelSerializer
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'] #过滤掉答案
  1. 修改视图views.py,增加权限
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 rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *

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']: #判断当前的操作是否是exam或者random接口操作
            return TopicStudentSerializer(*args, **kwargs) #是的话返回学生使用的序列化器,不包含答案
        return self.serializer_class(*args, **kwargs) #不是的话直接返回serializer_class 
	
	#重写查所有,只有老师可以查看带答案的数据
    @wrap_permisssion(TeacherPermission)
    def list(self, request, *args, **kwargs):
        return ModelViewSet.list(self, request, *args, **kwargs)
        
	#重写查单一,只有老师可以查看带答案的数据
    @wrap_permisssion(TeacherPermission)
    def retrieve(self, request, *args, **kwargs):
        return ModelViewSet.retrieve(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(ActiveUserPermission)
    @auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(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)
        # 有,则获取这个试卷的所有题目,不包含答案
        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)

三、分页

为什么要考虑到分页查询,这里我们假设数据库中有10万条题目,如果发起查询题目的请求,需要返回10万条数据,如果某个用户只需要练习20道题目,速度肯定会很慢,并且资源损耗严重。这时候就要考虑到使用分页。下面介绍DRF中使用的两种分页器

1. PageNumberPagination分页器

  1. 在views.py视图中定义分页器类
from rest_framework.pagination import PageNumberPagination
class TopicPaginationPageNumber(PageNumberPagination):
    page_size = 3  # 默认每页多少条,如果不传size,默认3条
    #page_size_param  = 'page' #定义传入页数的参数,默认为page
    page_size_query_param = 'size'  # 规定哪个参数为分页大小参数,参数可以自己定义,这里定义为size,则前端传入参数size = 10,每页展示10条,但是不会超过设置的最大每页条数100
    max_page_size = 100  # 最大每页多少条
  1. 在题目的视图类TopicViewSet中增加该分页属性
class TopicViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer
	#分页器
    pagination_class = TopicPaginationPageNumber
  1. 发送查询请求。
    解释:
    使用分页器查询后,显示如下:
    count:总数
    next:下一页网址
    previous:上一页网址
    results:返回查询的结果集合
    如果需要指定返回条数,在前端传入size参数,指定每页展示条数
    在这里插入图片描述

2. LimitOffsetPagination分页器

  1. 在views.py视图中定义分页器类
from rest_framework.pagination import LimitOffsetPagination
class TopicPaginationLimitOffset(LimitOffsetPagination):
    default_limit = 3  # 默认每页多少条
    #limit_query_param = 'limit' #默认每页展示条数的参数为limit
    #offset_query_param = 'offset' #默认的偏移的参数为offset
    max_limit = 100  # 最大每页多少条


  1. 在题目的视图类TopicViewSet中增加该分页属性
class TopicViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer
	#分页器
    pagination_class = TopicPaginationLimitOffset
  • 发送查询请求。
    返回的数据结构跟PageNumberPagination一样,只是网址中传入的参数区别
    在这里插入图片描述

3.总结

  • 使用PageNumberPagination的场景:
    固定点击下一页,再点击下一页
  • 使用LimitOffsetPagination的场景:
    固定点击下一页,再点击下一页。也可以实现跳转到指定题目,从指定题目开始。

四、题目操作模块

代码参考附件一

1. 考试

没有答案,需要提交答题结果,老师后台审核

  1. 在标签模型里可以添加试卷名标签
    在这里插入图片描述
  2. 在TopicViewSet视图中添加exam接口并将exam接口添加到重写 的get_serializer中,返回没有答案的数据。接口测试可以拿到数据
    在这里插入图片描述

2. 题目练习——顺序刷题

有答案,程序自动判定结果,也可以直接看答案

  1. 在TopicViewSet视图中添加practice接口,并重写queryset方法:修改使用’practice’接口时需要返回的数据集,不能查看到标签名包含试卷的题目,只能做练习题

3. 模拟考试

随机获取指定题目

  1. 在TopicViewSet视图中添加random接口,并在get_queryset和get_serializer中添加random接口
  2. 访问接口测试
    在这里插入图片描述

附件一:topic的视图函数

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 rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *


# class TopicPaginationPageNumber(PageNumberPagination):
#     page_size = 3  # 默认每页多少条
#     page_size_query_param = 'size'  # 规定哪个参数为分页大小参数 size = 10
#     max_page_size = 100  # 最大每页多少条

class TopicPaginationLimitOffset(LimitOffsetPagination):
    default_limit = 3  # 默认每页多少条
    max_limit = 100  # 最大每页多少条


class LabelViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Label.objects.all()
    serializer_class = LabelSerializer

    @wrap_permisssion(TeacherPermission)
    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(ActiveUserPermission)
    @auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(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
	
	#重写queryset方法:修改使用'practice', 'random'接口时需要返回的数据集
    def get_queryset(self):
        if self.action in ['practice', 'random']:
            return Topic.objects.filter(Q(is_delete=False) & ~Q(label__name__contains='试卷')) #~Q(label__name__contains='试卷')标签名不包含”试卷“的数据
        return self.queryset
	
	#重写serializer方法:修改使用'exam', 'random'接口时调用的序列化器
    def get_serializer(self, *args, **kwargs):
        if self.action in ['exam', 'random']:
            return TopicStudentSerializer(*args, **kwargs)
        return self.serializer_class(*args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def list(self, request, *args, **kwargs):
        return ModelViewSet.list(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def retrieve(self, request, *args, **kwargs):
        return ModelViewSet.retrieve(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(ActiveUserPermission)
    @auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(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)

    #传入标签的id
    @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)
        # 有,则获取这个试卷的所有题目,不包含答案
        #.topic_set管理器获取到所有题目
        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:
        	#request.query_params.get获取get请求传入的参数写法
        	#没传入size,默认为3条
            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)

        # 序列化,返回
        #sample(pool, size)从pool中随机取size个数据进行序列化
        serializer = self.get_serializer(sample(pool, size), many=True)
        return Response(serializer.data)


补充:前端调用接口写法

在这里插入图片描述
前端完整代码:

<template>
    <div class="demo-collapse" v-loading="loading">
        <div>
            <div style="margin: 15px 0px">
                <el-input v-model="search" placeholder="请输入你要搜索内容" class="input-with-select">
                    <template #prepend>
                        <el-select v-model="select" placeholder="请选择" style="width: 110px">
                            <el-option label="题目内容" value="1"></el-option>
                        </el-select>
                    </template>
                    <template #append>
                        <el-button @click="searchfunc">
                            <el-icon>
                                <Search />
                            </el-icon>
                        </el-button>
                    </template>
                </el-input>
            </div>
            <div class="start">
                从第
                <el-input-number v-model="offset" :min="1" :max="topics.data.count" @change="get_topics" />题开始
            </div>
        </div>

        <el-collapse v-model="activeNames" v-infinite-scroll="load" infinite-scroll-disabled="disabled">
            <el-collapse-item v-for="(topic, index) in topics.data.results" :name="index" :key="topic.id">
                <template #title>
                    <span>{{ index + offset }}、</span>
                    <span v-html="topic.subject"></span>
                    <el-tag>{{ topic.label_name }}</el-tag>
                    <el-tag>{{ TYPE_CHOICES[topic.type] }}</el-tag>
                </template>
                <div v-html="topic.description"></div>
                <el-form :inline="true" class="demo-form-inline work">
                    <el-form-item label="作答">
                        <el-input v-model="topic.work_answer" placeholder="请填写你的答案"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="onSubmit(index)">提交</el-button>
                    </el-form-item>
                    <span v-if="topic.flag">{{ topic.flag }}、正确答案:{{ topic.answer }}</span>
                </el-form>
            </el-collapse-item>
            <el-empty :image-size="20" v-if="!topics.data.next" description="暂无更多题目"></el-empty>
        </el-collapse>
    </div>
</template>

<script>
import axios from 'axios'
import { reactive, ref } from 'vue-demi'
import { ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons'

export default {
    name: 'exercise',
    components: {
        Search
    },
    setup() {
        let loading = ref(true)
        let activeNames = ref([0])
        let search = ref('')
        let select = ref('1')
        const TYPE_CHOICES = ['单选题', '多选题', '判断题', '填空题', '问答题']

        let disabled = ref(false)

        let topics = reactive({
            data: {
                count: 0,
                next: null,
                previous: null,
                results: [
                    {
                        answer: "B",
                        create_time: "2021-11-19T20:25:56.885565",
                        description: "A、x = y = z = 1  \r<br/>B、x = (y = z + 1)\r<br/>C、x, y = y, x\r<br/>D、x  +=  y",
                        id: 1,
                        label: 1,
                        label_name: "python基础",
                        score: 1,
                        subject: "下列哪个语句在Python中是非法的",
                        type: 0,
                        update_time: "2021-11-19T20:25:56.885594",
                        user: 1,
                        user_name: "一个",
                    }
                ]
            }
        })

        let offset = ref(1)

        function get_topics(offset) {
            loading.value = true
            axios.get('/api/work/topics/practice/', {
                params: {
                    offset: offset - 1,
                    limit: 10
                },
                headers: {
                    'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
                }
            }).then(
                response => {
                    let results = []
                    response.data.results.forEach(e => {
                        e.description = e.description.replace(/\n/g, '<br/><br/>')
                        e.work_answer = ''
                        e.flag = null
                        results.push(e)
                    });
                    response.data.results = results
                    console.log(results)
                    topics.data = response.data
                    loading.value = false
                    disabled.value = false
                },
                error => {
                    console.log('请求失败', error.message)
                }
            )
        }
        get_topics(offset.value)
        function onSubmit(index) {
            let topic = topics.data.results[index]
            if (topic.answer.toUpperCase() == topic.work_answer.toUpperCase()) {
                topic.flag = '回答正确'
                ElMessage.success(topic.flag)
            } else {
                topic.flag = '回答错误'
                ElMessage.error(topic.flag)
            }
        }
        const load = () => {
            if (topics.data.next != null) {
                loading.value = true
                disabled.value = true
                let url = topics.data.next.replace('http://127.0.0.1:8000/', '/api/')
                axios.get(url, {
                    headers: {
                        'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
                    }
                }).then(
                    response => {
                        let results = []
                        response.data.results.forEach(e => {
                            e.description = e.description.replace(/\n/g, '<br/><br/>')
                            e.work_answer = ''
                            e.flag = null
                            results.push(e)
                        });
                        response.data.results = topics.data.results.concat(results);
                        topics.data = response.data
                        console.log(response.data)
                        loading.value = false
                        if (response.data.next == null) {
                            disabled.value = true
                        } else {
                            disabled.value = false
                        }
                    },
                    error => {
                        console.log('请求失败', error.message)
                    }
                )
            }
        }

        function searchfunc() {
            disabled.value = false
            axios.get('/api/work/topics/search/', {
                params: {
                    subject: search.value,
                },
                headers: {
                    'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
                }
            }).then(
                response => {
                    let results = []
                    response.data.results.forEach(e => {
                        e.description = e.description.replace(/\n/g, '<br/><br/>')
                        e.work_answer = ''
                        e.flag = null
                        results.push(e)
                    });
                    response.data.results = results
                    console.log(results)
                    topics.data = response.data
                    loading.value = false
                },
                error => {
                    console.log('请求失败', error.message)
                }
            )
        }
        return { topics, TYPE_CHOICES, loading, onSubmit, activeNames, offset, get_topics, load, disabled, search, select, searchfunc }
    }
}
</script>

<style scoped>
.el-tag {
    margin-left: 20px;
}

.work {
    margin-top: 20px;
}

.start {
    margin-bottom: 20px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2153332.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FastAPI 的隐藏宝石:自动生成 TypeScript 客户端

在现代 Web 开发中&#xff0c;前后端分离已成为标准做法。这种架构允许前端和后端独立开发和扩展&#xff0c;但同时也带来了如何高效交互的问题。FastAPI&#xff0c;作为一个新兴的 Python Web 框架&#xff0c;提供了一个优雅的解决方案&#xff1a;自动生成客户端代码。本…

必知!5大AI生成模型

大数据文摘授权转载自数据分析及应用 随着Sora、diffusion等模型的大热&#xff0c;深度生成模型再次成为了研究的焦点。这类模型&#xff0c;作为强大的机器学习工具&#xff0c;能够从输入数据中学习其潜在的分布&#xff0c;并生成与训练数据高度相似的新样本。其应用领域广…

【IDEA】使用IDEA连接MySQL数据库并自动生成MySQL的建表SQL语句

前言&#xff1a; 在软件开发过程中&#xff0c;数据库的设计与实现是至关重要的一环。IntelliJ IDEA作为一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的数据库工具&#xff0c;使得连接MySQL数据库并自动生成建表SQL语句变得简单快捷。本文将详细…

ansible远程自动化运维、常用模块详解

一、ansible是基于python开发的配置管理和应用部署工具&#xff1b;也是自动化运维的重要工具&#xff1b;可以批量配置、部署、管理上千台主机&#xff1b;只需要在一台主机配置ansible就可以完成其它主机的操作。 1.操作模式&#xff1a; 模块化操作&#xff0c;命令行执行…

竹云赋能“中国·贵州”全省统一移动应用平台建设,打造政务服务“新引擎”

近日&#xff0c;2024中国国际大数据产业博览会在贵州贵阳圆满落幕。会上&#xff0c;由贵州省政府办公厅牵头建设的“中国贵州”全省统一移动应用平台正式发布&#xff0c;聚焦民生办事、政务公开、政民互动、扁平高效、数据赋能五大模块&#xff0c;旨在打造公平普惠的服务平…

解决Python Debug没有反应的问题

应该有伙伴和我一样&#xff0c;用的2024版本的VS code&#xff0c;但是用到的python解释器是3.6.x&#xff0c;或者是更旧版本的Python. 想要进行Debug就会在扩展里面安装 一般安装就会安装最新版本&#xff0c;但是debug时又没有反应&#xff0c;其主要原因是Python的版本与…

基于Springboot的助学金管理系统设计与实现

文未可获取一份本项目的java源码和数据库参考。 一、研究背景 利用计算机来实现助学金管理系统&#xff0c;已经成为一种趋势&#xff0c;相比传统的手工管理方式&#xff0c;利用软件进行助学金管理系统&#xff0c;有着执行快&#xff0c;可行性高、容量存储大&#xff0c;…

前端入门:HTML+CSS

引言: 前端三大件:HTML、CSS、JS,每一个部分都很重要,我听过比较形象的比喻就是HTML(HYPER TEXT MARKUP LANGUAGE)相当于骨架,而CSS就是装饰渲染,JS则是动作功能实现。 之前的文章我已经讲过HTML,这篇文章我将讲解HTML和CSS的案例。 网页开发: 我开发出来的网页如…

DAMODEL——Llama3.1的部署与使用指南

Llama3.1的部署与使用指南 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大模型&#xff08;LLM&#xff09;是基于深度学习算法训练而成的重要工具&#xff0c;应用范围包括自然语言理解和生成。随着技术的发展&#xff0c;开源的LLM不断涌现&#xff0c;涵盖了…

数字人直播带货火了,只要有了这个工具,就可以打造数字人,建议新手小白赶紧尝试!

经济下行&#xff0c;普通人应该尽早认清一个事实&#xff0c;没有一技之长&#xff0c;没有核心竞争力&#xff0c;即便是打工皇帝&#xff0c;年入百万也只是浮云。 一定要保证主业的稳定&#xff0c;再探索新的机会&#xff0c;要多从”1-10"&#xff0c;而不是反复”…

初中数学证明集锦之三角形内角和

导言 非常喜欢数学那套&#xff0c;由简单到复杂&#xff0c;逐层递进的证明之美。 既证了&#xff0c;而且明了 &#x1f603; 让人不得不信服&#xff01; 由人教版教材看到的三角形内角和180度的证明法&#xff0c;觉得现在课本不单传播了知识&#xff0c;而且点睛数学之…

简单多状态dp第二弹 leetcode -删除并获得点数 -粉刷房子

740. 删除并获得点数 删除并获得点数 分析: 使用动态规划解决 这道题依旧是 打家劫舍I 问题的变型。 我们注意到题目描述&#xff0c;选择 x 数字的时候&#xff0c; x - 1 与 x 1 是不能被选择的。像不像 打家劫舍 问题中&#xff0c;选择 i 位置的金额之后&#xff0c;就不…

【网络】高级IO——LT和ET

在上一篇的学习中&#xff0c;我们已经简单的使用了epoll的三个接口&#xff0c;但是仅仅了解那些东西是完全不够的&#xff01;&#xff01;接下来我们将更深入的学习epoll 1.epoll的两种工作模式——LT和ET 下面来举一个例子帮助大家理解ET和LT模式的区别&#xff08;送快递…

【HTTP】请求“报头”,Referer 和 Cookie

Referer 描述了当前这个页面是从哪里来的&#xff08;从哪个页面跳转过来的&#xff09; 浏览器中&#xff0c;直接输入 URL/点击收藏夹打开的网页&#xff0c;此时是没有 referer。当你在 sogou 页面进行搜索时&#xff0c;新进入的网页就会有 referer 有一个非常典型的用…

深度学习-图像处理篇1.3pytorch神经网络例子

batch:一批图像数量 官方例子 #model import torch.nn as nn import torch.nn.functional as Fclass LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv1 nn.Conv2d(3,16,5)self.pool1 nn.MaxPool2d(2, 2)self.conv2 nn.Conv2d(16, 32, 5)self.…

Python 找到给定点集的简单闭合路径(Find Simple Closed Path for a given set of points)

给定一组点&#xff0c;将这些点连接起来而不相交 例子&#xff1a; 输入&#xff1a;points[] {(0, 3), (1, 1), (2, 2), (4, 4), (0, 0), (1, 2), (3, 1}, {3, 3}}; 输出&#xff1a;按以下顺序连接点将 不造成任何交叉 {(0, 0), (3, …

将sqlite3移植到开发板上

1、下载c源码 sqlite官网下载C源码&#xff1a;SQLite Download Page 点击第二个链接下载 2、解压 1、将下载好的c源码&#xff0c;放在linux下&#xff0c; 2、解压压缩包&#xff1a;tar -zxvf sqlite-autoconf-3460100 新建一个用存放 编译出来的文件&#xff1a; mkd…

Web开发:使用C#创建、安装、调试和卸载服务以及要注意的写法

目录 一、创建服务 1.创建项目&#xff08;.NET Framework&#xff09; 2.重命名 3.编写逻辑代码 二、安装服务 1.方案一&#xff1a;利用VS2022安装文件的配置 选择添加安装程序 安装文件的介绍及配置 ​编辑​ 重新编译 工具安装 2.方案二&#xff1a;编写bat脚本安…

Excel match 函数使用方法,和 index 函数是绝配

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f50e; 在处理Excel数据时&#xff0c;我们经常需要找出特定数据在列表或数组中的位置。MATCH函数正是为此设计的&#xff0c;它可以返回一个值在指定数组中的相对位置。今天&#xff0c;我们将详细介绍MATCH函数的使…

MySQL基础(13)- MySQL数据类型

目录 一、数据类型概述 1.MySQL中的数据类型 二、整型 1.数据类型可选属性 2.使用建议 三、浮点数、定点数、位类型 1.类型介绍 2.浮点类型 3.定点数类型 4.位类型 四、日期时间类型 1.YEAR 2.DATE 3.TIME 4.DATETIME 5.TIMESTAMP 6.TIMESTAMP和DATETIME的区别…