【问题标题】:How to create an alias for Django Model field?如何为 Django 模型字段创建别名?
【发布时间】:2013-09-29 21:31:24
【问题描述】:

我的 Django 模型有一个名为“updatedOn”的日期时间字段,我需要在这个模型上使用一个库函数来计算一些统计信息,但该函数假定日期时间字段名称为“时间”,这是该函数的使用方式日期时间:

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

在不接触库代码的情况下,如何创建别名'time'来引用'updatedOn'字段,以便我可以使用该功能?

【问题讨论】:

    标签: python database django


    【解决方案1】:

    我没有对此进行过深入研究,但凭直觉,以下一些方法可能会帮助您入门。

    自定义管理器

    custom manager 带有修改后的 get_queryset 方法,用于在过滤 time 时查找 updatedOn

    自定义字段类型

    也许可以创建一个custom field type,它只作为对另一个字段的引用。

    破解模型._meta.fields

    模型对象的_meta.fields 似乎包含该对象中的字段列表。也许您可以尝试添加某种名为time 的虚拟字段,它指的是updatedOn 字段。

    【讨论】:

      【解决方案2】:

      这个老 Django Snippet 为我工作,直到 Django 1.11。正如@Jaberwocky 评论的那样,virtual_onlyDjango 2.0 中被删除

      但是,deprecation warning 读取到此字段已弃用 in favor of 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')
      

      【讨论】:

      • 振作起来。 Django 2.0 摆脱了 virtual_only。
      • @Jaberwocky 哇,谢谢,这是旧的 sn-ps 的问题!
      • 没问题。作为记录,在 2.0 中,您主要可以复制\粘贴文档示例,它们会起作用(与 1.11 不同)。我这样做并进行了一些小的调整以向用户模型添加字段,并为 id 分配 UUID4。我使用了源文件模板并对它们进行了修剪\样式化。它非常快速且无痛。
      • @Jaberwocky 我发现了弃用消息,上面写着virtual_only 被删除以支持private_only。由于某种原因,这在“已删除的功能”部分中不清楚。我已经相应地更新了答案。
      【解决方案3】:

      为模型中的字段创建一个属性:

      class MyModel(moels.Model):
          updated_on = models.DateTimeField()
      
          def _get_time(self):
              return self.updated_on
          time = property(_get_time)
      

      【讨论】:

      • 该属性可用于查询值,但不能在qset.filter(time__year=tt.year...)中使用。
      • 啊,这很烦人:-(
      【解决方案4】:

      按照 miikkas 的建议 remodel.Manager,我想出了以下方法,它适用于通过查询 uuid 来检索 id 字段的更简单的情况。该数据库是使用 ID 为用于十六进制字符串的 varchar 字段创建的,并且我正在改进一个顺序整数 ID 字段,因此我可以使用需要它的 Django 的身份验证模块。我想分步执行此操作,因此是 hack。

      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。自定义字段类型可能是更好的通用方法。

      【讨论】:

        猜你喜欢
        • 2016-11-04
        • 1970-01-01
        • 1970-01-01
        • 2017-12-28
        • 2013-07-05
        • 2018-07-12
        • 1970-01-01
        • 1970-01-01
        • 2023-03-04
        相关资源
        最近更新 更多