Django кэшируется переопределение get_query_set - PullRequest
0 голосов
/ 11 ноября 2010

Я переопределяю функцию get_query_set в Django на одной из моих моделей динамически.Я делаю это для принудительной фильтрации исходного набора запросов, возвращенного 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, которые применяются ко многим представлениям, основанным на чем-то динамическом, например, текущем пользователе.

Ответы [ 2 ]

0 голосов
/ 12 ноября 2010

Я надеялся, что эта реализация произойдет без необходимости что-либо кодировать в других представлениях.По сути, после того, как класс импортирован, я хочу изменить его так, чтобы независимо от того, где на него ссылаются, используя Expense.objects.get / filter / all, он уже отфильтрован.В результате не требуется реализация ни для одного из других представлений;это полностью прозрачно.И даже в тех случаях, когда я использую его как ForeignKey, когда объект извлекается с использованием вышеупомянутого Expense.objects.get / filter / all, они также будут фильтроваться.

0 голосов
/ 11 ноября 2010

Как насчет создания объекта Manager для модели, который принимает пользователя в качестве аргумента при выполнении этой фильтрации.Я понимаю, что DRY с наборами запросов Django - это использование Model Manager

#### 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 (), чтобы всегда отфильтровывать удаленные строки;Модель с иностранным ключом к этому не будет использовать эту функцию фильтра (по крайней мере из того, что я понимаю - кто-то, пожалуйста, поправьте меня, если я ошибаюсь).

...