有效cod的Django模型继承

2024-04-26 15:10:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个Django应用程序,它使用一个抽象基类('Answer'),并根据问题对象所需的答案类型创建不同的答案。(这个项目是作为一个教程开始的)。现在的问题是:

class Question(models.Model):
    ANSWER_TYPE_CHOICES = (
    ('CH', 'Choice'),
    ('SA', 'Short Answer'),
    ('LA', 'Long Answer'),
    ('E3', 'Expert Judgement of Probabilities'),
    ('E4', 'Expert Judgment of Values'),
    ('BS', 'Brainstorms'),
    ('FB', 'Feedback'),
    )
    answer_type = models.CharField(max_length=2,
                               choices=ANSWER_TYPE_CHOICES,
                               default='SA')
    question_text = models.CharField(max_length=200, default="enter a question here")

答案是:

class Answer(models.Model):
"""
Answer is an abstract base class which ensures that question and user are
always defined for every answer
"""
question = models.ForeignKey(Question, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
class Meta:
    abstract = True
    ordering = ['user']

目前,我在Answer中有一个方法(覆盖get\u或\u update\u Answer()),其中包含特定于类型的指令,用于查找正确的表并收集或创建正确类型的对象。你知道吗

    @classmethod
def get_or_update_answer(self, user, question, submitted_value={}, pk_ans=None):
    """
    this replaces get_or_update_answer with appropriate handling for all
    different Answer types. This allows the views answer and page_view to get
    or create answer objects for every question type calling this function.
    """
    if question.answer_type == 'CH':
        if not submitted_value:
            # by default, select the top of a set of radio buttons
            selected_choice = question.choice_set.first()
            answer, _created = Vote.objects.get_or_create(
                user=user,
                question=question,
                defaults={'choice': selected_choice})
        else:
            selected_choice = question.choice_set.get(pk=submitted_value)
            answer = Vote.objects.get(user=user, question=question)
            answer.choice = selected_choice

    elif question.answer_type == 'SA':
        if not submitted_value:
            submitted_value = ""
            answer, _created = Short_Answer.objects.get_or_create(
                user=user,
                question=question,
                defaults={'short_answer': submitted_value})
        else:
            answer = Short_Answer.objects.get(
                user=user,
                question=question)
            answer.short_answer = hashtag_cleaner(submitted_value['short_answer'])
 etc... etc... (similar handling for five more types)

把这些逻辑都放进去型号.py'时,我可以加载页面视图中任意数量问题的用户答案:

    for question in page_question_list:
        answers[question] = Answer.get_or_update_answer(user, question, submitted_value, pk_ans)

我相信有一种更具python风格的方法来设计这段代码——一些我还没有学会使用的东西,但我不确定是什么。类似于接口,这样每个对象类型都可以实现其自己的版本答案。获取或更新答案(),而Python将使用适合该对象的版本。这会让你型号.py“整洁多了。你知道吗


Tags: or对象答案answer类型forgetobjects
2条回答

根据您所展示的内容,您已经掌握了重新实现Visitor pattern的大部分方法,这是处理这种情况的一种非常标准的方法(您有一堆相关的子类,每个子类都需要自己的处理逻辑,并且希望迭代它们的实例并对每个子类进行处理)。你知道吗

我建议看看这个模式是如何工作的,也许可以更明确地实现它。你知道吗

我最近重新讨论了这个问题,用五行或十行代码替换了一行或两百行代码,并认为有一天找到我在这里所做的事情可能会对某些人有用。你知道吗

我遇到的问题有几个要素——第一,需要创建、保存和检索的答案类型很多;第二,GET和POST二分法(以及我的独特解决方案,总是创建一个答案,并将其发送到表单);第三,一些类型有不同的逻辑(头脑风暴可以为每个用户提供多个答案反馈甚至不需要回应——如果它是为用户创建的,那么它已经被呈现出来了。)这些元素可能掩盖了一些消除重复的机会,这使得访问者模式非常合适。你知道吗

元素1和元素2的解决方案

词典问答式映射到相关答案子类的代码在中创建视图.py(因为很难把它放进去型号.py和解决依赖关系):

# views.py: 
ANSWER_CLASS_DICT = {
'CH': Vote,
'SA': Short_Answer,
'LA': Long_Answer,
'E3': EJ_three_field,
'E4': EJ_four_field,
'BS': Brainstorm,
'FB': FB,}

然后我就可以得到我想要的答案类,对于任何问题都是'get\u or \u created':

ANSWER_CLASS_DICT[question.answer_type]

我将其作为参数传递给class方法:

# models.py:
def get_or_update_answer(self, user, question, Cls, submitted_value=None, pk_ans=None):            
    if not submitted_value:
            answer, _created = Cls.objects.get_or_create(user=user, question=question)
    elif isinstance(submitted_value, dict):
            answer, _created = Cls.objects.get_or_create(user=user, question=question)
        for key, value in submitted_value.items():
                setattr(answer, key, value)
    else:
        pass

因此,相同的六行代码处理get\或\ U在提交时创建任何答案\ U value=None(get)或not(submitted\ U value)。你知道吗

元素3的解决方案

元素3的解决方案是将模型扩展为至少三种类型的处理,以便用户重新访问同一问题: “S”-单一,允许他们只记录一个答案,重新审视和修改答案,但决不能给出两个不同的答案。 “T”-跟踪,允许他们每次更新答案,但可以记录他们的答案(例如,研究人员) “M”-多个,允许对一个问题提交多个答案。你知道吗

在所有这些更改之后仍然修复bug,所以我不会发布代码。 下一个功能:复合问题和问题模板,所以人们可以使用管理员屏幕,使自己的答案类型。你知道吗

相关问题 更多 >