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

Django模型中基于所属Exam题量设置Question的order字段默认值

动态设置Question的order字段默认值(对应Exam已有题数+1)

问题原因

你之前尝试的default=Question.objects.filter(exam=self.exam).count() + 1无法生效,是因为模型字段定义时,default参数在类加载阶段执行,此时还没有模型实例,self并不存在,根本无法获取当前关联的exam对象。

可行解决方案

1. 重写模型的save方法(推荐)

这是最直接的方式,覆盖所有创建场景(代码创建、后台创建、API创建等):

修改你的Question模型,添加/修改save方法:

from django.db import transaction

class Question(models.Model):
    # 保留原有字段定义...

    def save(self, *args, **kwargs):
        # 仅当order未设置或为默认值0时,自动计算顺序
        if not self.order or self.order == 0:
            # 用事务+select_for_update避免并发场景下的order重复问题
            with transaction.atomic():
                # 锁定关联的Exam对象,确保count()的准确性
                exam = Exam.objects.select_for_update().get(pk=self.exam.pk)
                self.order = exam.questions.count() + 1
        super().save(*args, **kwargs)

    # 保留原有Meta和__str__方法...

说明:

  • 利用模型实例的self.exam关联对象,通过related_name='questions'直接获取对应考试的试题数量
  • 加入transaction.atomic()和select_for_update()是为了避免多进程同时创建试题时,出现count()重复导致order冲突的问题(因为你的Meta里设置了unique_together=['exam', 'order'],冲突会触发数据库错误)
  • 如果你的场景并发量极低,也可以简化掉事务部分,直接用self.exam.questions.count() + 1

2. 使用pre_save信号

如果不想修改模型的save方法,可以通过Django的信号机制在保存前设置order:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.db import transaction
from .models import Question

@receiver(pre_save, sender=Question)
def auto_set_question_order(sender, instance, **kwargs):
    if not instance.order or instance.order == 0:
        with transaction.atomic():
            exam = Exam.objects.select_for_update().get(pk=instance.exam.pk)
            instance.order = exam.questions.count() + 1

注意:要确保信号被正确加载,需要在你的app的apps.py中添加:

from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'

    def ready(self):
        import your_app_name.signals  # 导入信号文件,假设信号放在signals.py中

3. 在Django Admin中处理(仅后台创建场景)

如果只需要在后台Admin创建试题时自动设置order,可以重写Admin类的save_model方法:

from django.contrib import admin
from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        if not obj.order or obj.order == 0:
            obj.order = obj.exam.questions.count() + 1
        super().save_model(request, obj, form, change)

admin.site.register(Question, QuestionAdmin)

验证方式

创建同一Exam下的试题时,如果不手动填写order字段,系统会自动设置为当前已有试题数量+1;手动设置order值时,会优先使用手动输入的值,符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:35:14