【问题标题】:Edit record before delete. Django DeleteView删除前编辑记录。 Django 删除视图
【发布时间】:2019-04-08 06:35:31
【问题描述】:

我有以下型号:

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获取相关记录的数量?

【问题讨论】:

  • category.posts 在这里做什么?通过这个你可以防止它达到零?
  • 怎么看,category.postsPositiveIntegerField 可以小于0
  • 但现在它永远不会变为零或负值。因此,如果最后一个帖子被删除,那么它仍然会有 1。

标签: python django django-models django-forms django-views


【解决方案1】:

在 4.0 版中,您将收到警告 DeleteViewCustomDeleteWarning: DeleteView uses FormMixin to handle POST requests。因此,YourDeleteView.delete() 处理程序中的任何自定义删除逻辑都应移至 form_valid()。所以,继续在 form_valid 中实现你的逻辑

【讨论】:

    【解决方案2】:

    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 delete(self, *args, **kwargs):
            self.object = self.get_object()
            self.object.post.categories.all().update(posts=F('posts')-1)
            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 delete(self, *args, **kwargs):
            self.object.post.categories.all().update(posts=Greatest(F('posts')-1, Value(1)))
            return super(DeletePostView, self).delete(*args, **kwargs)

    【讨论】:

    • 我收到以下错误:ValueError: "<Post: Post 1>" needs to have a value for field "id" before this many-to-many relationship can be used.
    • 但是有没有内置方法来获取与每个Category相关的Post的数量?
    • @masaterofnothing:我打错了。以下通常应该可以工作。
    • @masaterofnothing:是的,但是在这里缓存它可能是有意义的,如果你想相当快地获得每个类别的帖子数量。
    • 请问,你能解释一下如何获取相关帖子的数量吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 2020-11-20
    • 1970-01-01
    相关资源
    最近更新 更多