如何为Django模型字段创建别名?

14

我的Django模型有一个名为'updatedOn'的datetime字段,我需要在这个模型上使用一个库函数来计算一些统计信息,但是该函数假定datetime字段名称为'time',以下是该函数如何使用datetime:

c = qset.filter(time__year=tt.year, time__month=tt.month, time__day=tt.day).count();

不修改库代码,我如何创建一个别名 'time',来引用 'updatedOn' 字段,以便我可以使用该函数?

4个回答

7

这个旧的Django片段在Django 1.11之前对我有用。正如@Jaberwocky所评论的,virtual_onlyDjango 2.0中被删除。

然而,弃用警告表明,该字段已被弃用,推荐使用private_only, 尽管以上链接中没有提到这一点。

class AliasField(models.Field):
    # def contribute_to_class(self, cls, name, virtual_only=False):
    #       '''
    #           virtual_only is deprecated in favor of private_only
    #       '''
    #     super(AliasField, self).contribute_to_class(cls, name, virtual_only=True)
    #     setattr(cls, name, self)

    def contribute_to_class(self, cls, name, private_only=False):
        '''
            virtual_only is deprecated in favor of private_only
        '''
        super(AliasField, self).contribute_to_class(cls, name, private_only=True)
        setattr(cls, name, self)

    def __get__(self, instance, instance_type=None):
        return getattr(instance, self.db_column)


class Order(models.Model):
    """
    The main order model
    """
    number = AliasField(db_column='id')

2
做好准备。Django 2.0 摒弃了 virtual_only。 - addohm
@Jaberwocky 哇,谢谢,那就是旧片段的问题! - raratiru
在2.0版本中,你可以大多数情况下复制粘贴文档中的示例代码并且它们会正常工作(不像1.11版本)。我就是这样做的,并对用户模型添加了一些字段,同时将id分配为UUID4。我使用了源文件模板并进行了修剪和样式化。整个过程非常快速和无痛。 - addohm
@Jaberwocky,我发现了一个弃用消息,它说“virtual_only”已被“private_only”取代。由于某种原因,在“已删除功能”部分中这并不清楚。我已经相应地更新了答案。 - raratiru

6

我并没有深入研究,但直觉告诉我以下几种方式可能会帮助你开始:

自定义管理器

使用修改过的get_queryset方法的自定义管理器,在过滤time时查找updatedOn

自定义字段类型

可能可以创建一个自定义字段类型,该字段类型仅作为对另一个字段的引用。

修改模型._meta.fields

模型对象的_meta.fields似乎包含了该对象中的字段列表。也许你可以尝试添加一些名为time的虚拟字段,它引用了updatedOn字段。


3
在你的模型中为字段创建一个属性:
class MyModel(moels.Model):
    updated_on = models.DateTimeField()

    def _get_time(self):
        return self.updated_on
    time = property(_get_time)

6
该属性可用于查询数值,但不能在 qset.filter(time__year=tt.year...) 中使用。 - NeoWang
啊,那真烦人 :-( - hellsgate
这也可以内联写成 time = property(lambda self: self.updated_on) - Vladimir Osintsev

2

在miikkas的建议下,我使用model.Manager提出了以下解决方案,可以在查询uuid时检索id字段。数据库创建时,ID是一个用于十六进制字符串的varchar字段,并且我正在添加一个顺序整数ID字段,以便可以使用Django的auth模块(这需要ID)。我希望逐步完成此操作,因此这个方法很“hacky”。

if DEVELOPMENT['merging_to_sequential_ids_incomplete']:
    class ModelManager(models.Manager):
        def get(self, *args, **kwargs):
            if 'uuid' in kwargs:
                kwargs['id'] = kwargs.pop('uuid')
            return super(ModelManager, self).get(*args, **kwargs)

class Model(models.Model):
    if DEVELOPMENT['merging_to_sequential_ids_incomplete']:
        print >>sys.stderr, 'WARNING: uuid now a synonym to id'
        id = models.CharField(max_length = 32,
            primary_key = True, default = uuid_string)
        objects = ModelManager()  # for Client.objects.get(uuid=...)
        uuid = property(lambda self: self.id)  # for client.uuid
    else:
        id = models.AutoField(primary_key = True)
        uuid = models.CharField(max_length = 32, ...

现在我可以:

cd myapp && ../djangopython manage.py shell
WARNING: uuid now a synonym to id
setting up special admin settings
Python 2.7.8 (default, Nov 18 2014, 16:29:10) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from myapp.models import *
>>> Client.objects.get(uuid=u'18b86bd7b58e4c0186f7654045ce81d9')
<Client: jc@example.net>
>>> _.uuid
u'18b86bd7b58e4c0186f7654045ce81d9'

filter可以用相同的方式进行。

也许这可以帮助指导其他人寻找一种使用Django模型字段的“别名”或“同义词”的方法。但我不认为这会对OP有所帮助。自定义字段类型可能是更好的通用方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接