【问题标题】:Django Models and Admin InlinesDjango 模型和管理内联
【发布时间】:2023-07-07 09:14:01
【问题描述】:

我正在尝试设置一组带有单独答案的问题,每个用户都可以回答。 为了实现这种功能,我构建了以下模型:

models.py:

class Question(models.Model):
  question = models.TextField(null=False)

class PossibleAnswer(models.Model):
  question=models.ForeignKey(Question, related_name="possible_answer")
  answer = models.CharField(max_length=200)

class Answer(models.Model):
  question = models.ForeignKey(Question)
  user = models.ForeignKey(User)
  real_answer = models.ForeignKey(PossibleAnswer, related_name="real_answer")

最初,管理界面就足够了,可以解决这些问题。它应该在“每个问题”的基础上可见,因此“问题”应该显示它允许的答案以及用户可以给出的答案:

admin.py:

class AnswerInline(admin.TabularInline): 
  model = Answer

class PossibleAnswerInline(admin.TabularInline):
  model = PossibleAnswer   

class QuestionAdmin(admin.ModelAdmin):
  inlines = [PossibleAnswerInline, AnswerInline]

admin.site.register(Question, QuestionAdmin)

一切都很好,直到我保存答案,这会产生一个 IntegrityError。我相信这与对象之间的依赖关系有关?

我无法解决的第二项:为了将 real_answer 的选择限制为实际选项(与问题相关),我在 forms.py 中定义了以下内容:

class AnswerForm(ModelForm):
  class Meta:
    model = Answer

  def __init__(self, *args, **kwargs):  
    super(AnswerForm, self).__init__(*args, **kwargs)  
    choices = self.instance.question.possible_answer.all()
    self.fields["real_answer"].choices = choices

并在 admin.py 中使用如下:

class AnswerInline(admin.TabularInline): 
  model = Answer
  form = AnswerForm

当我运行它时,self.instance.question.possible_answer.all() 总是会引发 DoesNotExist

任何指针都非常感谢。

最好的,

安德烈亚斯

【问题讨论】:

    标签: django django-models django-forms django-admin


    【解决方案1】:

    AnswerForm被初始化时,它的实例属性并不总是有与之相关的问题对象,所以每当你从表单中引用self.instance.question时,如果没有DoesNotExist异常就会抛出一个附加到表单答案对象的问题实例。

    在您的表单 init 方法中尝试此代码:

    choices = []
    if self.instance.pk
        questions = Question.objects.filter(answer=self.instance)
        if questions.exist():
            choices = questions.get().possibleanswer_set.all()
    

    【讨论】:

    • 很好的方法,它几乎可以工作。当 django admin 显示表单时,有没有办法限制选项呢?在已经存在的答案中,它有效,但在底部的新行中无效。
    • 应该有,是的,请参阅 Django 的管理(可能还有表单)文档。
    • 不应该也在 AnswerForm 中吗?
    【解决方案2】:

    我主要以@GonzaloDelgado 的回答为基础,但我不认为他的代码是最佳的。最好使用try...except 块。

    from django.core.exceptions import ObjectDoesNotExist
    ...
    def __init__(self, *args, **kwargs):
        super(AnswerForm, self).__init__(*args, **kwargs)
    
        if self.instance.pk:
            try:
                self.fields['real_answer'].queryset = self.question.possibleanswer_set.all()
            except ObjectDoesNotExist:
                pass
    

    【讨论】:

    • 不是这样的。该编辑将(并且应该)被拒绝,因为它是“根本性的变化:此编辑在原始帖子中更改太多;帖子的原始含义或意图将丢失。”
    • 抱歉,我没想到重构我的代码(使其“最佳”)会失去我回答的意义或意图。
    • 除了最初的问题,这里如何调用 __init__(...) ?当尝试在具有 answer = Answer(question=q, user=request.user) 的视图中实例化 AnswerForm 时,a = AnswerPublicForm(instance=answer) 实际上会显示所有答案选项(就像管理员一样)
    • 那是因为 self.instance.pk 有一个值是有条件的,直到 Answer 至少被保存一次。现在想想,这实际上可能不是必需的,所以请尝试删除if self.instance.pk: 位。
    • 最后的努力,实际的question 属性可能会强制需要保存以查找自身。您可以尝试使用self.instance.question_id 来过滤PossibleAnswer