Skip to main content
 首页 » 编程设计

python之使用 Django 模型继承时如何避免这种冗余

2025年04月02日42lyj

我的 Django 网站中的所有页面都有一个页脚链接“反馈/问题”。如果新人来到该站点并单击该链接,他们应该被引导到一个带有下拉列表的表单,以指示他们是否有反馈与问题以及他们的电子邮件地址和他们的反馈或问题的字段。该页面将有一个简单的标题,所有未经身份验证的用户都会看到。另一方面,如果站点成员登录并通过身份验证,他们应该看到相同的表单但没有电子邮件字段(因为我已经知道他们的电子邮件地址)和包含站点内部导航栏、按钮等的不同的经过身份验证的 header 。

我最初的想法是创建一个抽象类 FeedbackQuestion:

class FeedbackQuestion(models.Model): 
  submission_type = ...  (type, i.e. feedback or question) 
  submission_text = ...  (actual feedback or question) 
  ... 
  class Meta: 
    abstract = True 

然后我将创建两个单独的具体子类:

class AnonFeedbackQuestion(FeedbackQuestion): 
  email = models.EmailField(...) 
  class Meta: 
    db_table = anon_feedback_question 
 
class AuthFeedbackQuestion(FeedbackQuestion): 
  user = models.ForeignKey(User, related_name="user") 
  class Meta: 
    db_table = auth_feedback_question 

这两个类会有自己的模型形式:

class AnonFeedbackQuestionForm(ModelForm): 
  class Meta: 
    model = AnonFeedbackQuestion 
    fields = ['submission_type', 'submission_text', 'email'] 
 
class AuthFeedbackQuestionForm(ModelForm): 
  class Meta: 
    model = AuthFeedbackQuestion 
    fields = ['submission_type', 'submission_text'] 

我预见到的问题是,我必须在显示反馈表的 View 中执行以下操作:

def get_feedback_questions(request, template): 
  if request.method == 'POST': 
    ... 
    if request.user.is_authenticated(): 
      form = AuthFeedbackQuestionForm(request.POST) 
    else: 
      form = AnonFeedbackQuestionForm(request.POST) 
    if form.is_valid(): 
      (process form) 
      ... 
  else: 
    if request.user.is_authenticated(): 
      form = AuthFeedbackQuestionForm(request.POST) 
    else: 
      form = AnonFeedbackQuestionForm(request.POST) 
    ... 
  context = {'form': form} 
  return render(request, template, context) 

必须重复这些 if/then/else block 来确定使用哪种形式似乎相当不雅。有没有更好、更干净的“Django”方法来做到这一点?

谢谢!

请您参考如下方法:

我不会对您的模型进行子类化 - 如果这是一个匿名问题,您可以只在一个模型上包含一个 user 属性以及一个 email 属性 blank=True 和 null=True:

class FeedbackQuestion(models.Model): 
    submission_type = ...  (type, i.e. feedback or question) 
    submission_text = ...  (actual feedback or question) 
    email = models.EmailField(..., blank=True, null=True) 
    user = models.ForeignKey(User, related_name="user", blank=True, null=True) 
    ... 
    class Meta: 
        abstract = True 

通过这种方式,您可以为匿名用户的反馈/问题添加电子邮件,或者如果他们通过身份验证,则添加用户。

然后我会将您的表单合并为一个包括电子邮件字段的表单,但根据用户是否经过身份验证删除电子邮件字段(请参阅 this answer ):

def __init__(self, *args, **kwargs): 
    self.user = kwargs.pop('user', None) 
    super(UserForm, self).__init__(*args, **kwargs) 
    if self.user: 
        # For logged-in users, email field not necessary 
        self.fields.pop('email') 
    else: 
        # Otherwise, the field needs to be required 
        self.fields['email'].required = True 

然后您只需确保在清理表单数据时正确创建用户(例如,确保电子邮件地址未被占用等)