【问题标题】:send request from signal从信号发送请求
【发布时间】:2022-12-09 00:59:22
【问题描述】:

我有一个考试模型,无论何时创建实例,都会创建考试中指定数量的问题模型实例(使用 post_save 信号)。另外,我有一个 Go 代码,每当发送请求时,它都会填写问题模型的 3 个字段。我的问题是如何在信号部分发送这个请求。

代码如下:

模型.py:

class Exam(models.Model):
    title = models.CharField(max_length=255)
    subject = models.CharField(max_length=255, default='')
    organizer = models.CharField(max_length=255, default='...')
    description = models.TextField(max_length=1000)
    created_at = models.DateTimeField(auto_now_add=True)
    duration = models.DurationField()
    number_of_questions = models.PositiveSmallIntegerField()
    order = models.IntegerField(default=0)

    def __str__(self):
        return self.title


class ExamQuestion(models.Model):
    exam = models.ForeignKey('ExamApply', on_delete=models.CASCADE)
    question_template = models.ForeignKey(QuestionTemplate, on_delete=models.CASCADE)
    text = models.TextField(max_length=5000, null=True, blank=True)
    question_params = models.JSONField(null=True, blank=True)
    answer_choices = models.JSONField(null=True, blank=True)
    answer_given = models.JSONField(default=dict, null=True, blank=True)
    correct_answer = models.JSONField(null=True, blank=True)
    data = models.JSONField(null=True, blank=True)
    is_correct = models.BooleanField(null=True)
    order = models.IntegerField(null=True, blank=True)

    def __str__(self):
        return str(self.id)


class ExamApply(models.Model):
    class Status(models.TextChoices):
        CREATED = 'CR', 'Created'
        STARTED = 'ST', 'Started'
        FINISHED = 'FN', 'Finished'

    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    exam = models.ForeignKey(Exam, on_delete=models.CASCADE)
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()
    status = models.CharField(max_length=2, choices=Status.choices, default=Status.CREATED)

    def get_score(self):
        score = ExamQuestion.objects.filter(exam=self, answer_given=F('correct_answer')).count()
        return score

信号.py:

@receiver(post_save, sender=ExamApply)
def create_examapply_examquestion(sender, instance, created, **kwargs):
    if created:
        for _ in range(instance.exam.number_of_questions):
            ExamQuestion.objects.create(exam=instance)
            id = ExamQuestion.objects.all().last().id
            return redirect('/question/' + str(id) + '/')    #doesnt work

@receiver(post_save, sender=ExamApply)
def save_examapply_examquestion(sender, instance, created, **kwargs):
    instance.exam.save()

网址.py与我想要的部分相关:

urlpatterns = [
    path('questions/<int:pk>/', UpdateQuestionAPI.as_view()),
]

意见.py:

class UpdateQuestionAPI(generics.RetrieveUpdateDestroyAPIView):
    queryset =  ExamQuestion.objects.all()
    serializer_class = IntegrateQuestionSerializer
    lookup_field = 'pk'

    def get(self, request, *args, **kwargs):
        question = ExamQuestion.objects.filter(pk=kwargs['pk'])
        serializer = ExamQuestionSerializer(question, many=True)
        return Response(serializer.data)

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=True)

        if serializer.is_valid():
            serializer.save()
            return Response({"message": "updated successfully"})

        else:
            return Response({"message": "failed", "details": serializer.errors})

序列化程序.py:

class IntegrateQuestionSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExamQuestion
        fields = ['question_params', 'answer_choices', 'correct_answer',]


class ExamQuestionSerializer(serializers.ModelSerializer):
    title = serializers.SerializerMethodField()

    class Meta:
        model = ExamQuestion
        fields = ['title']

    def get_title(self, obj):
        return obj.exam.exam.title

我有使用重定向(到更新视图)的想法,但它不起作用。

【问题讨论】:

    标签: django django-rest-framework request signals


    【解决方案1】:

    首先,在信号部分使用请求是没有意义的。 这段代码与model和orm相关,不负责request部分。这就是视图工作。

    您使用的信号与ExamApply模型的创建有关。您发布的视图不会创建 ExamApply,因此根本不会调用它。 正如您所知,通常会避免信号,因为它们会导致代码复杂。引用documentation信号看似松散耦合,但它们会很快导致代码难以理解、调整和调试。在可能的情况下,您应该选择直接调用处理代码,而不是通过信号进行调度。

    在这里,您的信号中有多个问题,循环中有一个 return,它将在第一次迭代后停止循环。然后你返回一个HttpResponse(以redirect的形式)但是你不在视图中所以它没有意义。

    目前尚不清楚您想做什么,因为您发布的视图和序列化程序与 ExamApply 的创建无关,据我所知您可以做什么(其中之一):

    1. 覆盖ExamApplysave方法来创建问题。
    2. 或者在创建ExamApply的视图中处理问题的创建

      例如:

      def save(self, *args, **kwargs):
          if not self.pk:
              # not self.pk means a creation.
              for _ in range(self.exam.number_of_questions):
                  question = ExamQuestion.objects.create(exam=self.exam)
                  # You might want to link question to user / exam apply here?
                  self.exam.question_set.add(question)
          super().save(*args, **kwargs)
      

      在您的ExamApply 创建视图或序列化程序中,您可能想要返回问题 ID,如果您使用 DRF,这样做很简单:https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield 但是您可能希望将问题链接到ExamApply 和/或用户,而不仅仅是Exam

      在旁注中,为了将来,如果您需要创建的对象 ID,您应该使用

      question = ExamQuestion.objects.create(exam=instance)
      question.id
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-27
      • 1970-01-01
      • 2011-03-10
      • 2018-05-14
      • 2019-09-14
      • 1970-01-01
      相关资源
      最近更新 更多