Редактировать запись перед удалением. Django DeleteView - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть следующие модели:

class Category(models.Model):
    ....
    posts = models.PositiveIntegerField(_('numero post'), default=0)
    ....

class Post(models.Model):
    ....
    categories = models.ManyToManyField(Category, blank=True, verbose_name=_('categorie'))
    ....

поле Category.posts подсчитывает количество сообщений, относящихся к его собственной категории. Я увеличиваю счетчик до CreateView следующим образом:

class CreatePostView(LoginRequiredMixin, CreateView):
    model = Post
    ...

    def form_valid(self, form, **kwargs):
        ...
        categories = self.object.categories.all()
        for category in categories:
            category.posts = category.posts + 1
            category.save()

        self.object.save()
        return super(CreatePostView, self).form_valid(form)

Когда я удаляю запись в блоге, мне нужно уменьшить счетчик при удалении Post. Я пытался сделать так:

class DeletePostView(LoginRequiredMixin, DeleteView):
    model = Post
    ...

    def form_valid(self, form, **kwargs):
        ...
        categories = post.categories.all()
        for category in categories:
            if (category.posts - 1) > 0:
                category.posts = category.posts - 1
                category.save()
        return post

Но это не работает, потому что запись удаляется до того, как этот метод вызывается.

Как я могу сделать эту операцию до того, как запись будет удалена? Или есть встроенный способ получить количество связанных записей от Category?

1 Ответ

0 голосов
/ 04 ноября 2018

Для DeleteView нет form_valid, поскольку DeleteView не имеет формы.

Что мы можем сделать, это добавить некоторую логику в функцию .delete(..), которая является функцией, удаляющей объект. DeleteView реализует это как:

def delete(self, request, *args, **kwargs):
    """
    Call the delete() method on the fetched object and then redirect to the
    success URL.
    """
    self.object = self.get_object()
    success_url = self.get_success_url()
    self.object.delete()
    return HttpResponseRedirect(success_url)

Таким образом, мы можем реализовать это как:

from django.db.models import F

class DeletePostView(LoginRequiredMixin, DeleteView):

    model = Post
    # ...

    def <b>delete</b>(self, *args, **kwargs):
        self.object = self.get_object()
        <b>self.object.post.categories.all().update(posts=F('posts')-1)</b>
        return super(DeletePostView, self).delete(*args, **kwargs)

Выше будет обновлять категории в "навалом", уменьшая поле posts. Здесь может достичь нуля (что невозможно в данном коде).

Если вы хотите предотвратить это, мы можем использовать Greatest [Django-doc] , чтобы избежать этого:

from django.db.models import F, Value
from django.db.models.functions import Greatest

class DeletePostView(LoginRequiredMixin, DeleteView):

    model = Post
    # ...

    def <b>delete</b>(self, *args, **kwargs):
        <b>self.object.post.categories.all().update(posts=Greatest(F('posts')-1, Value(1)))</b>
        return super(DeletePostView, self).delete(*args, **kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...