Restrinja el conjunto de datos `UpdateView` para usuarios autenticados en vistas basadas en clase

Tengo un proyecto de Django en el que extendí al Usuario para que tuviera un Perfil utilizando OneToOneField. Estoy usando CBV UpdateView que permite a los usuarios actualizar su perfil. La URL que visitan para esto es ../profile/ user / update. El problema que tengo es que si un usuario escribe el nombre de otro usuario, puede editar el perfil de otras personas. ¿Cómo puedo restringir UpdateView para que el usuario autenticado solo pueda actualizar su perfil? Estaba intentando hacer algo para asegurarme de que user.get_username == profile.user no tuviera suerte.

Modelos.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}) 

Vistas.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 para la aplicación de perfiles

 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[-_\w]+)/$', login_required(ProfileDetail.as_view()), name='profile-detail'), url(r'^(?P[-_\w]+)/update/$', login_required(ProfileUpdate.as_view()), name='profile-update'), ) 

Profile_update.html

 {% extends "base.html" %} {% load bootstrap %} {% block content %} {% if user.is_authenticated %} 

Update your profile

{% csrf_token %} {{ form|bootstrap }}
{% else %}

You can't update someone elses profile.

{% endif %} {% endblock %}

Qué tal algo como esto:

 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) 

En este ejemplo, el usuario se redirige a LOGIN_URL predeterminado. Pero puedes cambiarlo fácilmente. para redirigir al usuario a su propio perfil.

  • su template.html:

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

Para evitar el acceso a datos no relacionados con el usuario conectado cuando se usa la vista basada en clase (CBV), puede usar el filtrado dynamic y definir el conjunto de queryset en los atributos del model .

Si tiene un book.models con una ForeignKey ( user nombrado aquí) en auth.models.user , puede restringir fácilmente el acceso de esta forma:

 # 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) 

Vea más explicaciones en la documentación sobre CBV – Visualización de subconjuntos de objetos

Especificar model = Publisher es realmente una abreviatura para decir queryset = Publisher.objects.all() . Sin embargo, al utilizar queryset para definir una lista filtrada de objetos, puede ser más específico acerca de los objetos que estarán visibles en la vista.

[…]

En forma práctica, ListView tiene un método get_queryset() que podemos anular. Anteriormente, acaba de devolver el valor del atributo queryset, pero ahora podemos agregar más lógica. La parte clave para hacer que esto funcione es que cuando se llaman vistas basadas en clases, varias cosas útiles se almacenan en self ; así como la solicitud ( self.request ) esto incluye los self.args posicionales ( self.args ) y basados ​​en el nombre ( self.kwargs ) capturados de acuerdo con el URLconf.