【问题标题】:How to automatically update a field depending on the user who changed it in Django?如何根据在 Django 中更改字段的用户自动更新字段?
【发布时间】:2020-05-07 20:42:13
【问题描述】:

上下文:

在页面的博客部分,任何注册用户都可以发布,但所有来自非超级用户帐户的帖子都必须在我注册模型的管理页面上得到管理员的批准。 这按预期工作。

我的问题:

如果博客帖子被超级用户更新,我该如何做到这一点(无论什么样的更改都无关紧要,例如:当管理员打开一个帖子并在帖子正文中添加更多文本时,或删除文本的某些部分,因为它看起来是恶意的或伪造的),它被自动批准(批准的字段然后设置为 TRUE)? 我已经考虑在模型中添加一个名为 changed_by 的字段,并将其初始设置为 null。

代码:

博客/models.py

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse


class BlogPost(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    approved = models.BooleanField(default=False)
    changed_by = models.ForeignKey(User, default=None) # I am planning to use this but how?

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blogPost-detail', kwargs={'pk': self.pk})

博客/admin.py

from django.contrib import admin
from .models import BlogPost


def approve_multiple_posts(modeladmin, request, queryset):
    for blogPost in queryset:
        if blogPost.approved:
            blogPost.approved = False
        else:
            blogPost.approved = True
        blogPost.save()


approve_multiple_posts.short_description = 'Change approval status'


class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'date_posted', 'approved']
    actions = [approve_multiple_posts, ]


admin.site.register(BlogPost, PostAdmin)

blog/views.py

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from .models import BlogPost
from django.views.generic import (
    ListView,
    DetailView,
    CreateView,
    UpdateView,
    DeleteView
)


def blog(request):
    context = {
        'blogPosts': BlogPost.objects.all()
    }
    return render(request, 'blog/blog.html', context)


class PostListView(ListView):
    model = BlogPost
    template_name = 'blog/blog.html'
    context_object_name = 'blogPosts'
    ordering = ['-date_posted']
    paginate_by = 5

    def get_queryset(self):
        return BlogPost.objects.filter(approved=True).order_by('-date_posted')


class UserPostListView(ListView):
    model = BlogPost
    template_name = 'blog/user_blogPosts.html'
    context_object_name = 'blogPosts'
    paginate_by = 5

    def get_queryset(self):
        user = get_object_or_404(User, username=self.kwargs.get('username'))
        return BlogPost.objects.filter(author=user, approved=True).order_by('-date_posted')


class PostDetailView(DetailView):
    model = BlogPost


class PostCreateView(LoginRequiredMixin, CreateView):
    model = BlogPost
    fields = ['title', 'content']

    def form_valid(self, form):
        form.instance.author = self.request.user
        if self.request.user.is_superuser:
            form.instance.approved = True
        return super().form_valid(form)


class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = BlogPost
    fields = ['title', 'content']

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def test_func(self):
        blog_post = self.get_object()
        if self.request.user == blog_post.author:
            return True
        return False


class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = BlogPost
    success_url = '/blog'

    def test_func(self):
        blog_post = self.get_object()
        if self.request.user == blog_post.author:
            return True
        return False

如果您有任何帮助/建议,我将不胜感激!谢谢

【问题讨论】:

  • 超级用户会使用管理员还是您的PostUpdateView
  • 管理员。不是我写的@GregKaleka 的PostUpdateView

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


【解决方案1】:

在您的PostAdmin 类中,您可以覆盖一个名为save_model (Django docs) 的方法。试试这样的:

class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'date_posted', 'approved']
    actions = [approve_multiple_posts, ]

    def save_model(self, request, obj, form, change):
        important_fields = ['title', 'content']  # modify save if these fields changed
        if any(x in important_fields for x in form.changed_data):
            obj.approved = request.user.is_superuser
        super().save_model(request, obj, form, change)

这将使approved 仅当用户是超级用户时为真,否则将设置为假。

【讨论】:

  • 一种有效的方法......但......我认为save_model 每次保存在管理员中都会被调用,即使没有对模型进行任何更改。因此,为了满足上述用例,您需要检查 BlogPost 实例的内容或标题是否已更改,然后再将其设置为已批准。
  • 好点@Chris - 我编辑了我的答案以检查form.changed_data
  • 谢谢!这解决了我的问题!但我可以请你再解释一下吗?尤其是 if 块中的第一条语句。
  • 当然 - if 语句只是 if 'title' in form.changed_data or 'content' in form.changed_data 的 DRY 版本。那么obj.approved = request.user.is_superuser 等价于if request.user.is_superuser: obj.approved = True else: obj.approved = False。请注意,obj 是正在保存的 Post 对象。有意义吗?
猜你喜欢
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
相关资源
最近更新 更多