向Django mod动态添加属性

2024-10-01 09:28:19 发布

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

我有一个Django模型,其中有很多字段可以选择。所以我不得不写很多类的“is_nusomething”属性来检查实例值是否等于某个choice值。大致如下:

class MyModel(models.Model):
    some_choicefield = models.IntegerField(choices=SOME_CHOICES)

    @property
    def is_some_value(self):
        return self.some_choicefield == SOME_CHOICES.SOME_CHOICE_VALUE

    # a lot of these...

在我的实例中,我用大量的多余的方法来自动执行这些检查。 代码如下(我假设有一个“normalize”函数,它使所选的标签成为可用的函数名):

^{pr2}$

现在,这是可行的,但我觉得还有更好的方法。可能在类创建时(使用元类或在新的方法中)?你对此有什么想法/建议吗?在


Tags: django实例方法函数模型self属性is
3条回答

好吧,我不知道如何用你的方式来做,但在这种情况下,我认为方法是简单地创建一个新的模型,在那里你保留你的选择,并将字段改为ForeignKey。这更易于编码和管理。在

您可以在Django docs: Models: Relationships中找到许多基本级别的信息。在那里,有许多链接可以在各种主题上展开。除此之外,我相信这只需要一点想象力,也许一开始就需要试错。在

我遇到了一个类似的问题,我需要在运行时编写大量的属性,以便在更改模型字段时提供向后兼容性。有两种标准的处理方法-

  1. 第一种方法是在模型中使用自定义元类,它继承自模型的默认元类。在
  2. 第二,是使用类修饰符。类装饰器有时为元类提供了一种简单的替代方法,除非您必须在创建类之前做些什么,在这种情况下,您必须使用元类。在

我打赌你知道Django字段中提供的选项将自动具有显示功能。在

假设您有一个定义如下的字段:

category = models.SmallIntegerField(choices=CHOICES)

您只需调用一个名为get_category_display()的函数来访问显示值。以下是此功能的Django源代码:

https://github.com/django/django/blob/baff4dd37dabfef1ff939513fa45124382b57bf8/django/db/models/base.py#L962

https://github.com/django/django/blob/baff4dd37dabfef1ff939513fa45124382b57bf8/django/db/models/fields/init.py#L704

所以我们可以按照这个方法来实现我们的dynamically set property目标。在

这是我的设想,与你的有点不同,但到最后都是一样的:

我有两个类,CourseLesson,类Lesson有一个ForeignKey字段Course,我想向类cached_course添加一个属性名Lesson,该类将首先从缓存中获取{},如果缓存未命中,则回退到数据库:

下面是一个典型的解决方案:

^{pr2}$

原来我有这么多ForeignKey字段要缓存,所以下面的代码与Django get_FIELD_display特性类似:

from django.db import models
from django.utils.functional import curry


class CachedForeignKeyField(models.ForeignKey):

    def contribute_to_class(self, cls, name, **kwargs):
        super(models.ForeignKey, self).contribute_to_class(cls, name, **kwargs)
        setattr(cls, "cached_%s" % self.name,
                property(curry(cls._cached_FIELD, field=self)))


class BaseModel(models.Model):

    def _cached_FIELD(self, field):
        value = getattr(self, field.attname)
        Model = field.related_model
        return cache.get_model(Model, pk=value)

    class Meta:
        abstract = True


class Course(BaseModel):
    # some fields


class Lesson(BaseModel):
    course = CachedForeignKeyField(Course)

通过定制CachedForeignKeyField,并用_cached_FIELD方法覆盖contribute_to_class方法以及BaseModel类,每个CachedForeignKeyField将自动相应地具有一个cached_FIELD属性。在

太好了,太棒了!在

相关问题 更多 >