我在我的一个模型上动态地覆盖了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过滤器必须有一个最佳实践,它适用于基于动态内容的许多视图,如当前用户。
答案 0 :(得分:0)
如何为模型创建Manager对象,该对象将用户作为完成此过滤的参数。我对DRY w / Django查询集的理解是使用模型管理器
#### 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()方法以始终过滤掉已删除的行;一个带有外键的模型将不会使用该过滤功能(至少根据我的理解 - 如果我错了,请有人纠正我。)
答案 1 :(得分:0)
我希望无需在其他视图中编写任何代码即可实现此实现。本质上,在导入类之后,我想修改它,以便无论使用Expense.objects.get / filter / all引用它,它都已被过滤。因此,任何其他视图都不需要实现;它是完全透明的。而且,即使在我将其用作ForeignKey的情况下,当使用上述Expense.objects.get / filter / all检索对象时,它们也将被过滤。