DRF考勤系统开发:如何获取AttendanceSlot ID并关联保存Attendance
问题分析与解决方案
你的代码存在几个关键问题,导致无法正确关联AttendanceSlot和Attendance:
get_queryset方法返回单个AttendanceSlot实例,违反了DRF中该方法必须返回QuerySet的要求,会导致列表查询功能异常。perform_create中传递的user参数多余,你的Attendance模型没有对应字段。- 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
相关产品推荐
相关产品推荐

