Django模型具有不同类型的功能

时间:2016-11-15 21:22:46

标签: django django-models architecture

我有一个用例,我希望在Django应用程序中捕获用户的各种类型的提醒(由业务逻辑自动生成)。在所有提醒中,属性都相同(即ownercreatorcreation_timestatuscompletion_time)并且它们具有相同的界面(即{ {1}},render_message())。但是,有许多类型的提醒,每个提醒都应该有这些常用功能的实现细节。

由于模型属性永远不会改变,似乎只有单个Django模型才有意义,但后来我质疑从模型实例到is_valid()等函数的特定实现的最佳方法。

我目前正考虑在名为render_message()的{​​{1}}模型上设置ChoiceField,该模型将映射到各种提醒类型类,然后在{{1}内设置辅助函数将基于Reminder实例化相应的提醒类型类,并将其调用为type等功能。

我错过了更好的方法吗?不确定这个模式是考虑什么,或者在哪里寻找具有与同一接口的各种实现相关联的单个Django模型的类似示例。

2 个答案:

答案 0 :(得分:2)

如果您想使用模型存储提醒,Django proxy models可以很好地满足您的要求。

在高层次上,Django有三种继承:

  • Abstract Base Class
      

    未创建基类表,并且所有继承的模型都获取基类的所有字段

  • Multi-table inheritance

      

    Django支持的第二种模型继承是每种类型   层次结构中的模型本身就是一个模型。每个型号   对应于自己的数据库表,可以查询和创建   个别。继承关系引入了之间的联系   儿童模型及其每个父母(通过自动创建   OneToOneField)。

  • Proxy Models

      

    使用多表继承时,会创建一个新的数据库表   对于模型的每个子类。这通常是理想的行为,   因为子类需要一个地方来存储任何其他数据字段   基类上没有的。但是,有时你只是   想要改变模型的Python行为 - 也许是为了改变   默认管理器,或添加新方法。

         

    这就是代理模型继承的用途:为。创建代理   原始模型。您可以创建,删除和更新实例   代理模型和所有数据将被保存,就像您使用的一样   原始(非代理)模型。不同之处在于你可以改变   诸如默认模型排序或默认管理器之类的东西   代理,无需改变原件。

示例:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

class AlienPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        pass

很酷的是,它可以帮助您创建不同的管理界面,即使对象存储在同一个表中:) reference

答案 1 :(得分:0)

您可以将逻辑的自定义部分存储到数据库中。

class Reminder:

    message_template = forms.TextField()

    def render_message(self):
        render_message_dict = self.get_render_message_dict()
        return self.message_template.format(**render_message_dict)

    def get_render_message_dict(self):
        return {
            'project_name': self.project_name,
            'due_for_days': (date.today() - self.due_date).days,
            'updated_for_days': (date.today() - self.last_updated.date()).days,
        }

所以你设置:

reminder_a.message_template = '{project_name} is over due by {due_for_days} days'
reminder_b.message_template = '{project_name} hasn't been updated in {updated_for_days} days'

如果您有一组给定的消息模板,您也可以使用选择字段:

class Reminder:

    MESSAGE_TEMPLATE_CHOICES = [
        (1, _("{project_name} is over due by {due_for_days} days")),
        (2, _("{project_name} hasn't been updated in {updated_for_days} days")),
    ]

    message_template = forms.PositiveSmallIntegerField(
        choices=MESSAGE_TEMPLATE_CHOICES)

    def render_message(self):
        render_message_dict = self.get_render_message_dict()
        return self.message_template.format(**render_message_dict)

    def get_render_message_dict(self):
        return {
            'project_name': self.project_name,
            'due_for_days': (date.today() - self.due_date).days,
            'updated_for_days': (date.today() - self.last_updated.date()).days,
        }

这也可以将消息模板标记为可翻译。