Джанго, пользовательские менеджеры влияют на метод сохранения?

Я использую Джанго 1.7. У меня есть настраиваемый менеджер по умолчанию, который фильтрует «активное» логическое поле. Согласно документам, он должен быть менеджером по умолчанию для работы со связанными полями (т. е. при доступе к User.story_set отображаются только активные объекты Story). Я сохраняю стандартный менеджер для доступа к администратору и оболочке, но я не могу сохранять изменения в объектах, я размышляю, потому что методы save() в какой-то момент проходят через менеджер по умолчанию.

class Story(models.Model):
    active = models.BooleanField(default=True)
    ....

    objects = ActiveStoryManager()
    full_set = models.Manager()

class ActiveStoryManager(models.Manager):
    def get_query_set(self):
        return super(ActiveStoryManager, self).get_query_set().filter(active=True)
    use_for_related_fields = True

Это хорошо работает для любого публичного использования. Однако в админке и шелле я не могу воздействовать на неактивные объекты, в том числе возвращать их в активное состояние.

story = Story.full_set.get(id=#) будет получать историю с active=False, но после установки active=True я не могу сохранить, получая

django.db.utils.IntegrityError: duplicate key value violates unique constraint "stories_story_pkey" DETAIL: Key (id)=(#) already exists.

Вызов save.(force_update=True) возвращает django.db.utils.DatabaseError: Forced update did not affect any rows.

Таким образом, хотя save() является модельным методом, похоже, что в какой-то момент процесса сохранения он зависит от менеджера по умолчанию.

Обходной путь использует API Queryset, например. Story.full_set.filter(id=#).update(active=True), но это можно использовать только в оболочке и требует ручного ввода каждого изменения, по-прежнему нельзя сохранять неактивные экземпляры в админке.

Любая помощь в этом?


person sybaritic    schedule 23.11.2014    source источник
comment
Или кто-нибудь знает, могу ли я использовать оператор if в get_query_set, чтобы метод сохранения всегда выполнялся независимо? Я просто хочу использовать фильтр для всех запросов на чтение.   -  person sybaritic    schedule 23.11.2014


Ответы (2)


Это невозможно! Как указал inancsevinc, save() вызывает диспетчер по умолчанию. В документах Django упоминается, что get_query_set не следует изменять на менеджерах по умолчанию, и я с грустью выяснил, почему. Надеюсь, что в будущем связанные менеджеры можно будет указывать/контролировать, но пока этот метод мне не подходит. Подтверждено в IRC-чате Django.

Вместо этого я объединяю обычный метод Manager, а также методы моделей для некоторых моделей, чтобы получить эквивалентную функциональность. Также требуется изменить все вызовы related_set в шаблоне, чтобы включить новые методы, так что это боль, но никак иначе.

person sybaritic    schedule 23.11.2014

Чтобы страница администратора работала с другим менеджером, вы можете реализовать get_queryset в вашем классе ModelAdmin.

class StoryAdmin(ModelAdmin):

    def get_queryset(self, request):
        return self.model.full_set.get_queryset()
person inancsevinc    schedule 23.11.2014
comment
Я сделал это, и страница администратора может видеть/читать неактивные строки. Однако любые изменения/обновления приводят к той же ошибке, что и в оболочке. Метод save() не может быть вызван. Я все еще думаю, что save() каким-то образом требует, чтобы менеджер моделей по умолчанию обращался к элементу, но не уверен, почему. - person sybaritic; 23.11.2014
comment
Вы правы, сохранение используется _base_manager, который является объектом по умолчанию. - person inancsevinc; 23.11.2014
comment
Любые другие мысли по этому поводу? Я чувствую, что use_for_related_fields был создан именно для этого случая использования, но кажется странным, что как только вы объявите его, сразу же не будет возможности сохранить неприемлемые объекты. - person sybaritic; 23.11.2014