【问题标题】:Django 2.2 Cannot figure out how to authorize user to edit or delete blog post if user created that blog post如果用户创建了博客文章,Django 2.2 无法弄清楚如何授权用户编辑或删除博客文章
【发布时间】:2019-12-03 22:19:52
【问题描述】:

所以这是我第三次问这个问题了。我不知道如何只允许创建特定博客文章的用户编辑或删除该文章。所以这个博客就像任何其他博客一样。所有用户都可以查看所有其他用户的博客文章。要创建博客文章,用户必须已经使用帐户登录。编辑和删除博客文章也是如此。但是,我不知道如何根据用户是否是创建博客文章的人来检查用户是否可以编辑或删除博客文章。我正在输入这个问题,因为没有人回答我之前发布的问题。下面是模型、视图和用于更新/编辑博客文章的 html 的三个文件。一旦我弄清楚编辑,我就可以弄清楚删除。我知道 Django 会自动创建添加、更改、删​​除权限。不幸的是,即使该用户已经登录,更改和删除权限总是返回 false。我已经坚持了好几天了。已经超过 3 天了 15 多个小时。

博客/models.py

from django.db import models
from django.conf import settings
from django.utils import timezone
from django.db.models import Q

User = settings.AUTH_USER_MODEL

class BlogPostQuerySet(models.QuerySet):
    def published(self):
        now = timezone.now()
        return self.filter(publish_date__lte=now)

    def search(self, query):
        lookup = (
            Q(title__icontains=query) |
            Q(content__icontains=query) |
            Q(slug__icontains=query) |
            Q(user__first_name__icontains=query) |
            Q(user__last_name__icontains=query) |
            Q(user__username__icontains=query) |
            Q(user__email__icontains=query) |
            Q(image__icontains=query)
        )
        return self.filter(lookup)

class BlogPostManager(models.Manager):
    def get_queryset(self):
        return BlogPostQuerySet(self.model, using=self._db)

    def published(self):
        return self.get_queryset().published()

    def search(self, query=None):
        if query is None:
            return self.get_queryset().none()
        return self.get_queryset().published().search(query)

class BlogPost(models.Model): # blogpost_set -> queryset
    user = models.ForeignKey(User, default=1, null=True, on_delete=models.SET_NULL)
    image = models.ImageField(upload_to='image/', blank=True, null=True)
    title = models.CharField(max_length=120)
    slug = models.SlugField(unique=True) # Example: "hello world" -> hello-world
    content = models.TextField(null=True, blank=True)
    publish_date = models.DateTimeField(auto_now=False, auto_now_add=False, null=True, blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    objects = BlogPostManager()

    class Meta:
        ordering = ['-publish_date','-updated','-timestamp']
        permission = (
            ("can_change_blogpost", "Can change BlogPost"),        
        )

    def get_absolute_url(self):
        return f"/blog/{self.slug}"

    def get_edit_url(self):
        return f"{self.get_absolute_url()}/edit"

    def get_delete_url(self):
        return f"{self.get_absolute_url()}/delete"

blog/views.py

from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404
from .models import BlogPost
from .forms import BlogPostModelForm
from django.contrib.auth.models import User


def blog_post_list_view(request):
    qs = BlogPost.objects.all().published() # queryset -> list of python objects
    if request.user.is_authenticated:
        my_qs = BlogPost.objects.filter(user=request.user)
        qs = (qs | my_qs).distinct()
    context = {'object_list':qs}
    return render(request, 'blog/list.html', context)

@login_required
def blog_post_create_view(request):
    form = BlogPostModelForm(request.POST or None, request.FILES or None)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.user = request.user
        obj.save()
        form = BlogPostModelForm()
    context = {'form':form}
    return render(request, 'blog/form.html', context)

def blog_post_detail_view(request, slug):
    obj = get_object_or_404(BlogPost, slug=slug)
    context = {'object':obj}
    return render(request, 'blog/detail.html', context)

@login_required
def blog_post_update_view(request, slug):
    obj = get_object_or_404(BlogPost, slug=slug)
    form = BlogPostModelForm(request.POST or None, instance=obj)
    if form.is_valid():
        form.save()
    context = {
            "form":form,
            "title":f"Update {obj.title}",
    }
    return render(request, 'blog/update.html', context)

@login_required
def blog_post_delete_view(request, slug):
    obj = get_object_or_404(BlogPost, slug=slug)
    if request.method == "POST":
        obj.delete()
    context = {'object':obj}
    return render(request, 'blog/delete.html', context)

blog/templates/blog/update.html

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'blog/style.css' %}">
    <title>New Blog post</title>
</head>
<body>
    <div class="parallax5" align="center">
        <h1 class="a">UPDATE your Blog page</h1><br>
        <h1>Perms</h1><br>
        {{ perms.blog.change_blogpost }}<br>
        {% if perms.blog.change_blogpost %}
        <form style="background-color:grey;" method="POST" action=".">
            <p>Please only post blogs that are in good taste. You can 
            update your blog below.</p>
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit">Update Blog</button>
        </form><br>
        {% else %}
            <p style="background-color:red;color:white;">You do not have permission to update this blog post</p>
        {% endif %}
        <a style="background-color:white;font-size:50px;" href="{% url 'list' %}">I'm done!<br>Go back to blog list</a>
    </div>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

到目前为止我已经尝试过什么... 一切!你的名字,我已经(很可能)知道你在说什么。我太累了,太生气了,连我尝试过的所有事情的大清单都没有。请有人帮忙!

【问题讨论】:

  • Django 的默认权限是为表级访问而设计的,所以我不会将这些权限用于行级。在您的编辑和删除视图中,我会使用obj = get_object_or_404(BlogPost, slug=slug, user=request.user),因此如果用户没有创建博客文章,他们会得到 404。

标签: python django


【解决方案1】:

我的网站确实具有您所要求的完全相同的行为,但实现方式却截然不同。

删除后视图如下所示:

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Post
    success_url = '/market'

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

发布更新视图:

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

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

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

要使此代码正常工作,您还需要导入这些:

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import ( ListView, DetailView, CreateView, UpdateView, DeleteView)

我知道,只是向您展示我的代码库可能不会直接帮助您,但它可能会给您一些想法,请告诉我。保持坚强,我知道有时会令人沮丧,但你会做到的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多