在基于类的视图中限制经过身份验证的用户的“UpdateView”数据集

时间:2015-03-02 00:16:22

标签: python django django-views

我有一个Django项目,我将用户扩展为使用OneToOneField获取配置文件。我正在使用CBV UpdateView,它允许用户更新他们的个人资料。他们访问的网址是../profile/user/update。我遇到的问题是,如果用户键入其他用户名,他们可以编辑其他人员个人资料。如何限制UpdateView,以便经过身份验证的用户只能更新其配置文件。我试图做一些事情以确保user.get_username == profile.user但没有运气。

Models.py

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.core.urlresolvers import reverse

class Profile(models.Model):
    # This field is required.
    SYSTEM_CHOICES = (
        ('Xbox', 'Xbox'),
        ('PS4', 'PS4'),
    )
    system = models.CharField(max_length=5,
                                    choices=SYSTEM_CHOICES,
                                      default='Xbox')
    user = models.OneToOneField(User)
    slug = models.SlugField(max_length=50)
    gamertag = models.CharField("Gamertag", max_length=50, blank=True)
    f_name = models.CharField("First Name", max_length=50, blank=True)
    l_name = models.CharField("Last Name", max_length=50, blank=True)
    twitter = models.CharField("Twitter Handle", max_length=50, blank=True)
    video = models.CharField("YouTube URL", max_length=50, default='JhBAc6DYiys', help_text="Only the extension!", blank=True)
    mugshot = models.ImageField(upload_to='mugshot', blank=True)

    def __unicode__(self):
            return u'%s' % (self.user)

    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.create(user=instance, slug=instance)

    post_save.connect(create_user_profile, sender=User)

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

Views.py

from django.shortcuts import render
from django.views.generic import DetailView
from django.views.generic.edit import UpdateView
from django.views.generic.list import ListView

from profiles.models import Profile


class ProfileDetail(DetailView):

    model = Profile

    def get_context_data(self, **kwargs):
        context = super(ProfileDetail, self).get_context_data(**kwargs)
        return context

class ProfileList(ListView):
    model = Profile
    queryset = Profile.objects.all()[:3]

    def get_context_data(self, **kwargs):
        context = super(ProfileList, self).get_context_data(**kwargs)
        return context

class ProfileUpdate(UpdateView):
    model = Profile
    fields = ['gamertag', 'system', 'f_name', 'l_name', 'twitter', 'video', 'mugshot']
    template_name_suffix = '_update'

    def get_context_data(self, **kwargs):
        context = super(ProfileUpdate, self).get_context_data(**kwargs)
        return context

Admin.py

from django.contrib import admin
from models import Profile

class ProfileAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('user',), }

admin.site.register(Profile, ProfileAdmin)

适用于个人资料应用的Urls.py

from django.conf.urls import patterns, url
from django.contrib.auth.decorators import login_required
from profiles.views import ProfileDetail, ProfileUpdate

urlpatterns = patterns('',
    url(r'^(?P<slug>[-_\w]+)/$', login_required(ProfileDetail.as_view()), name='profile-detail'),
    url(r'^(?P<slug>[-_\w]+)/update/$', login_required(ProfileUpdate.as_view()), name='profile-update'),
)

Profile_update.html

{% extends "base.html" %} {% load bootstrap %}

{% block content %}

{% if user.is_authenticated %}

  <h1>Update your profile</h1>

  <div class="col-sm-4 col-sm-offset-4">
    <div class="alert alert-info alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
      </button>
      <strong>Heads up!</strong> Other users can find you easier if you have a completed profile.
    </div>
    <form enctype="multipart/form-data" method="post" action="">{% csrf_token %}
      {{ form|bootstrap }}
      <input class="btn btn-default" type="submit" value="Update" />
    </form>
  </div>


{% else %}
<h1>You can't update someone elses profile.</h1>
{% endif %}

{% endblock %}

3 个答案:

答案 0 :(得分:5)

这样的事情怎么样:

from django.contrib.auth.views import redirect_to_login


class ProfileUpdate(UpdateView):
    [...]

    def user_passes_test(self, request):
        if request.user.is_authenticated():
            self.object = self.get_object()
            return self.object.user == request.user
        return False

    def dispatch(self, request, *args, **kwargs):
        if not self.user_passes_test(request):
            return redirect_to_login(request.get_full_path())
        return super(ProfileUpdate, self).dispatch(
            request, *args, **kwargs)

在此示例中,用户被重定向到默认LOGIN_URL。但你可以很容易地改变它。将用户重定向到他们自己的个人资料。

答案 1 :(得分:1)

  • your template.html:
{% if request.user.is_authenticated and profile.user == request.user %}
your form
{% else %}
u cannot edit that profile - its not yours...
{% endif %}

答案 2 :(得分:1)

为避免在使用基于类的视图(CBV)时访问与连接的用户无关的数据,可以使用动态过滤并在其中定义queryset model个属性。

如果您在book.models上有一个ForeignKey(在这里命名为user)上的auth.models.user,则可以轻松地限制访问权限,例如:

# views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from books.models import Book

class BookList(LoginRequiredMixin, ListView):

    def get_queryset(self):
        return Book.objects.filter(user=self.request.user)

请参阅有关CBV - Viewing subsets of objects的文档的更多说明

  

指定model = Publisher实际上只是说queryset = Publisher.objects.all()的简写。但是,通过使用queryset定义对象的过滤列表,您可以更详细地了解将在视图中可见的对象。

     

[…]

     

很方便地,ListView有一个get_queryset()方法可以覆盖。以前,它只是返回queryset属性的值,但是现在我们可以添加更多逻辑。   进行这项工作的关键部分是,当调用基于类的视图时,各种有用的东西都存储在self上。以及请求(self.request)包括根据URLconf捕获的位置(self.args)和基于名称的(self.kwargs)自变量。