【问题标题】:Django ModelAdmin get_object optimizationDjango ModelAdmin get_object 优化
【发布时间】:2017-05-12 13:25:22
【问题描述】:

我在Django ModelAdmin 列表视图中优化了get_queryset

  • .only('field1', 'field2',)
  • .select_related('rel1',)

这些优化与 get_object 更改视图所需的不同:

  • .only('field1', 'field2', 'field3',)
  • .select_related('rel1__rel2', 'rel3',)
  • .prefetch_related(...)

事情是,get_queryset and get_object are coupled:

class BaseModelAdmin(...):

  ...

  def get_object(self, request, object_id, from_field=None):
      """
      Returns an instance matching the field and value provided, the primary
      key is used if no field is provided. Returns ``None`` if no match is
      found or the object_id fails validation.
      """
      queryset = self.get_queryset(request)
      model = queryset.model
      field = model._meta.pk if from_field is None else model._meta.get_field(from_field)
      try:
          object_id = field.to_python(object_id)
          return queryset.get(**{field.name: object_id})
      except (model.DoesNotExist, ValidationError, ValueError):
          return None

我怎样才能覆盖get_queryset 而不必复制/粘贴上面的所有样板?

【问题讨论】:

  • 目前还不清楚您到底想在这里实现什么。与其列出问题的可能解决方案,不如陈述问题本身。您在get_queryset 中的优化究竟是什么?您想在get_object 中应用什么优化?
  • @НазарТопольський 我已经更新了问题

标签: django django-admin


【解决方案1】:

我想出了这个解决方案,这似乎是一个不错的折衷方案:

def get_queryset(self, request):
    queryset = super().get_queryset(request)
    if request.resolver_match.url_name.endswith('_change'):
        # admin change view
        queryset = queryset.only(
            'iso_code',
            *get_translation_fields('name'),
            'official_languages',
            'active',
            'currency_code',
            'currency_symbol',
        )
    else:
        # admin change list
        queryset = queryset.only(
            'iso_code',
            'name',
            'active',
        )
    return queryset

【讨论】:

  • 另一种方法是使用wrapt
【解决方案2】:

您的用例不是很常见,所以我认为没有任何明智的方法可以在不重写get_object 的情况下实现您的需求。我会这样做:

# A parameter with default False value shouldn't screw things up
def get_queryset(request, for_object=False):
    qs = super(YourModelAdmin, self).get_queryset(request)
    if for_object:
        qs = qs.select_related('rel1__rel2', 'rel3')
        qs = .prefetch_related('rel4', 'rel5')
        return qs.only('field1', 'field2', 'field3')
    else:
        qs = qs.select_related('rel1')
        return qs.only('field1', 'field2')

def get_object(self, request, object_id, from_field=None):
    # Don't forget to add new param here
    queryset = self.get_queryset_for_object(request, for_object=True)
    model = queryset.model
    field = model._meta.pk if from_field is None else model._meta.get_field(from_field)
    try:
        object_id = field.to_python(object_id)
        return queryset.get(**{field.name: object_id})
    except (model.DoesNotExist, ValidationError, ValueError):
        return None

【讨论】:

  • 我不会说我的用例不是很常见。对我来说这是优化 101。
  • 我的意思是说get_object 和列表视图的不同查询集并不常见。如果你不同意这个说法,你甚至可以在 code.djangoproject.com 上提出改进票,这样以后会变得更容易一些。
猜你喜欢
  • 2019-03-04
  • 1970-01-01
  • 2020-05-23
  • 2014-03-24
  • 2012-07-21
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多