You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF考勤系统开发:如何获取AttendanceSlot ID并关联保存Attendance

问题分析与解决方案

你的代码存在几个关键问题,导致无法正确关联AttendanceSlot和Attendance:

  1. get_queryset 方法返回单个AttendanceSlot实例,违反了DRF中该方法必须返回QuerySet的要求,会导致列表查询功能异常。
  2. perform_create 中传递的user参数多余,你的Attendance模型没有对应字段。
  3. slot_id的传递逻辑可以优化,通过URL参数自动关联更符合需求,避免前端随意指定slot。

修正后的代码

models.py(可选优化:规范外键字段名,建议去掉后缀_id)

from django.db import models
from django.utils.translation import gettext_lazy as _

class AttendanceSlot(models.Model):
    department = models.ForeignKey("students.Department", verbose_name=_("department"), on_delete=models.CASCADE)
    course = models.ForeignKey("students.Course", verbose_name=_("course"), related_name='courses', on_delete=models.CASCADE)
    lecturer = models.ForeignKey("lecturers.Lecturer", on_delete=models.CASCADE)
    date = models.DateField(_("attendance date"), auto_now=False, auto_now_add=True)
    start_time = models.TimeField(_("start time"), auto_now=False, auto_now_add=False)
    end_time = models.TimeField(auto_now=False, auto_now_add=False)
    longitude = models.CharField(_("longitude"), max_length=50)
    latitude = models.CharField(_("latitude"), max_length=50)
    radius = models.CharField(_("radius"), max_length=50)

    def __str__(self):
        return f'{self.course.course_code}'

class Attendance(models.Model):
    slot = models.ForeignKey("attendance.AttendanceSlot", verbose_name=_("attendance slot"), on_delete=models.CASCADE)
    student = models.ForeignKey("students.Student", on_delete=models.CASCADE)
    performance = models.CharField(max_length=50)

serializers.py(设置slot为只读,从URL获取;学生根据需求选择是否只读)

如果学生是当前登录用户(需确保User与Student为一对一关联):

from rest_framework import serializers
from .models import Attendance

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ['student', 'slot', 'performance']
        read_only_fields = ['student', 'slot']

如果需要前端传递学生ID:

from rest_framework import serializers
from .models import Attendance

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ['student', 'slot', 'performance']
        read_only_fields = ['slot']

views.py(修正查询集逻辑,正确关联slot)

from rest_framework.generics import ListCreateAPIView
from django.shortcuts import get_object_or_404
from .models import Attendance, AttendanceSlot
from .serializers import AttendanceSerializer

class Attendance(ListCreateAPIView):
    queryset = Attendance.objects.all()
    serializer_class = AttendanceSerializer

    def get_queryset(self):
        # 返回当前URL指定slot下的所有考勤记录
        slot_id = self.kwargs['pk']
        return Attendance.objects.filter(slot_id=slot_id)

    def perform_create(self, serializer):
        # 获取URL对应的AttendanceSlot实例,不存在则返回404
        slot = get_object_or_404(AttendanceSlot, id=self.kwargs['pk'])
        
        # 处理学生关联:如果是当前登录用户
        student = self.request.user.student  # 需确保User模型与Student模型有OneToOneField关联
        
        # 保存考勤记录,关联slot和student
        serializer.save(slot=slot, student=student)

urls.py(保持不变)

from django.urls import path
from . import views

path('<int:pk>/', views.Attendance.as_view(), name='attendance'),

关键说明

  • 使用get_object_or_404替代get,避免slot不存在时抛出500错误,返回更友好的404响应。
  • 规范外键字段名后,代码可读性更强,Django会自动在数据库中生成带_id后缀的字段(如slot对应slot_id)。
  • 如果学生不是通过登录用户获取,只需去掉serializer.save中的student参数,让前端传递合法的student ID即可。

内容的提问来源于stack exchange,提问作者bello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:45:41