【问题标题】:Django get_query_set override is being cachedDjango get_query_set 覆盖被缓存
【发布时间】:2011-05-08 16:20:51
【问题描述】:

我在我的一个模型上动态覆盖了 Django 的 get_query_set 函数。我这样做是为了使用装饰器通过“场景”值强制过滤 Model.objects.all/filter/get 返回的原始查询集。这是装饰器的功能:

# Get the base QuerySet for these models before we modify their
# QuerySet managers. This prevents infinite recursion since the
# get_query_set function doesn't rely on itself to get this base QuerySet.
all_income_objects = Income.objects.all()

# Figure out what scenario the user is using.
current_scenario = Scenario.objects.get(user=request.user, selected=True)

# Modify the imported income class to filter based on the current scenario.
Expense.objects.get_query_set = lambda: all_expense_objects.filter(scenario=current_scenario)

# Call the method that was initially supposed to
# be executed before we were so rudely interrupted.
return view(request, **arguments)

我这样做是为了干燥代码,这样我的所有查询都不会被额外的过滤器弄得乱七八糟。但是,如果场景发生变化,则不会返回任何对象。如果我杀死服务器上的所有 python 进程,则会出现新选择场景的对象。我认为它正在缓存修改后的类,然后当场景发生变化时,它会应用另一个永远不会有意义的过滤器,因为对象一次只能有一个场景。

这不是基于用户的过滤器的问题,因为用户永远不会在我的会话中更改。乘客是否在做一些愚蠢的事情来在请求之间保留类对象?我是否应该放弃这种奇怪的设计模式,只在每个视图的基础上实现这些过滤器?必须有一个 DRYing 过滤器的最佳实践,该实践适用于基于动态事物(例如当前用户)的许多视图。

【问题讨论】:

  • 我没看到装饰器在哪里?

标签: python django filter dry django-queryset


【解决方案1】:

如何为模型创建一个 Manager 对象,该对象将用户作为完成此过滤的参数。我对使用 Django 查询集进行 DRY 的理解是使用模型管理器

#### view code:
def some_view(request):
    expenses = Expense.objects.filter_by_cur_scenario(request.user)

    # add additional filters here, or add to manager via more params
    expenses = expenses.filter(something_else=True)

#### models code:
class ExpenseManager(models.Manager):
    def filter_by_cur_scenario(self, user):
        current_scenario = Scenario.objects.get(user=request.user, selected=True)
        return self.filter(scenario=current_scenario)

class Expense(models.Model):
    objects = ExpenseManager()

另外,对管理器的一个快速警告(可能适用于覆盖 get_query_set):外部关系不会考虑在此级别完成的任何过滤。例如,您覆盖 MyObject.objects.filter() 方法以始终过滤掉已删除的行;带有外键的模型不会使用该过滤器功能(至少据我了解-如果我错了,请有人纠正我)。

【讨论】:

    【解决方案2】:

    我希望无需在其他视图中编写任何代码就可以实现此功能。本质上,在导入类之后,我想对其进行修改,以便无论使用 Expense.objects.get/filter/all 在何处引用它,它都已被过滤。因此,其他任何视图都不需要实现;它是完全透明的。而且,即使在我将其用作 ForeignKey 的情况下,当使用上述 Expense.objects.get/filter/all 检索对象时,它们也会被过滤。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-10
      • 2015-12-29
      • 2020-08-08
      • 2012-11-21
      • 2011-08-17
      • 1970-01-01
      相关资源
      最近更新 更多