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

Django模型具有不同类型的功能,django,django-models,architecture,Django,Django Models,Architecture,我有一个用例,希望在Django应用程序中为用户捕获各种类型的提醒(由业务逻辑自动生成)。在所有提醒中,属性都是相同的(即所有者,创建者,创建时间,状态,完成时间),并且它们具有相同的界面(即呈现消息(),有效()。但是,有许多类型的提醒,对于这些常见功能,每种提醒都应该有自己的实现细节 由于模型属性永远不会改变,因此使用一个Django模型似乎是有意义的,但我质疑从模型实例到函数的特定实现(如render\u message())的最佳方式 我目前正在考虑在提醒模型上设置一个名为类型的选项字段

我有一个用例,希望在Django应用程序中为用户捕获各种类型的提醒(由业务逻辑自动生成)。在所有提醒中,属性都是相同的(即
所有者
创建者
创建时间
状态
完成时间
),并且它们具有相同的界面(即
呈现消息()
有效()。但是,有许多类型的提醒,对于这些常见功能,每种提醒都应该有自己的实现细节

由于模型属性永远不会改变,因此使用一个Django模型似乎是有意义的,但我质疑从模型实例到函数的特定实现(如
render\u message()
)的最佳方式

我目前正在考虑在
提醒
模型上设置一个名为
类型
选项字段
,它将映射到各种提醒类型的类,然后在
提醒
中有一个助手函数,该函数将根据
self.type
实例化适当的提醒类型类,并调用该类以供参考像
render\u message()
这样的功能


我错过了一条更好的路吗?不确定该模式考虑了什么,也不确定在哪里可以找到与同一接口的各种实现相关联的单个Django模型的类似示例。

如果您想使用模型来存储警报,您的需求将通过以下方式得到很好的满足

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

  • : 不会创建基类表,所有继承的模型都会获取基类的所有字段

  • :

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

  • 使用多表继承时,将创建一个新的数据库表 对于模型的每个子类。这通常是期望的行为, 因为子类需要一个地方来存储任何额外的数据字段 基类上不存在的。然而,有时候,你只是 想要改变模型的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

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

如果您想使用模型存储警报,您的需求将得到很好的满足

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

  • : 不会创建基类表,所有继承的模型都会获取基类的所有字段

  • :

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

  • 使用多表继承时,将创建一个新的数据库表 对于模型的每个子类。这通常是期望的行为, 因为子类需要一个地方来存储任何额外的数据字段 基类上不存在的。然而,有时候,你只是 想要改变模型的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

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

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

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,
        }

这还允许将消息模板标记为可翻译。

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

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,
        }

这也允许将消息模板标记为可翻译的。

您能否举例说明
render\u message
的不同实现?您可以使用
class Meta:abstract=True
甚至
@abc.abstractmethod
,但我从来都不需要这些JavaISM。如果您正在处理一个始终具有render_message()的提醒,只需调用它。如果EatReminder有不同的render_消息,请覆盖它。@AntoinePinsard每个提醒都与项目对象关联。一种提醒类型可能是针对过期的项目,因此render_消息将返回
“到期时间超过x天”
。另一种提醒类型可能适用于在一定天数内未进行任何更新以呈现消息实现的项目