How to stop one User to update profile of another user in class based view in Django - django-views

Hello friends i need suggestion.In my app i want a user to update his own profile, but from the url if logged in user put profile/"other-user-id" then he can update other users profile. how to restrict one user to update another user profile. Below is my Code
views.py
#method_decorator(login_required(login_url='login'), name="dispatch")
class ProfileUpdate(UpdateView):
model = User
form_class = ProfileUpdateForm
template_name = 'app/profile.html'
success_url = '/'
extra_context = {"active": "btn-primary"}
urls.py
path('profile/<int:pk>', views.ProfileUpdate.as_view(), name='profile'),

Related

how do I make sure a particular user is the one logged in?

so I have some code which creates a user but how do I make sure every url that the user goes to will be in his/her own user session such that request.user will be the user I created?
def liked(request):
try:
sp = Spotify(auth_manager=oauth)
liked = sp.current_user_saved_tracks(limit=30)['items']
spotify_user = sp.current_user()
user__ , created =
User.objects.get_or_create(username=spotify_user['uri'],
first_name=spotify_user["display_name"])
userprofile = UserProfile.objects.get_or_create(user=user__)[0]
i have other views i want only accessible to the user created or gotten from the get_or_create, i reckon I'd have to use the #login_required decorator but then again I do not know what constitutes this "login" with respect to the user I created. How do I do ensure that user is the logged in user?
Django's default MIDDLEWARE takes care of this for you.
In every request object or self.request there is a user object.
Django checks the session via the cookie that the browser sends with every request, and puts the user object in the current request.
An example in a Class based view:
class ExampleView(TemplateView):
template = 'example.html'
def get_context_data(self, **kwargs):
context = super(ExampleView, self).get_context_data(**kwargs)
user = self.request.user
users_data = ExampleData.objects.filter(user=user)
Once a user is logged in, every other page is put into the session. Just log that user in first.
If you want to check if the user is logged in
In class based views;
if self.request.user.is_authenticated
In function based view
if request.user.is_authenticated
Ok as i understand you need to limit some users to access some pages and not for others .. i suggest to use permissions way
add permission to any Model you Have Like this
then when you create your special user do this to assign this permission to him like that : myuser.user_permissions.add('can_view_all_clients', 'another_perm', ...)
For Function Based Views :
from django.contrib.auth.decorators import permission_required
#permission_required("YourModel.can_view_all_clients")
def your_special_view(request):
return 'your view'
For Class Based View :
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import DetailView
class ModelDetailView(PermissionRequiredMixin, DetailView):
template_name = "model_detail.html"
model = Model
permission_required = "can_view_all_clients"

How To Properly Customize Django LoginView

I am trying to figure out how to customize the django LoginView based on whether or not it's the user's first time logging on for the day. I have my LoginView currently set up so that it defaults to the LOGIN_REDIRECT_URL = "book:author" in my settings.py file. This works flawlessly. When a user logins in and is successfully authenticated, they are redirected to "book:author" as I would expect.
What I'm trying to do is if this is the first time the user has logged in for the day, direct them to one URL, and if it's any other login iteration for the day, redirect them to a different URL. I have read about various methods on how to do this, to use messaging as opposed to conditional URL redirect to using the NEXT parameter and I'm trying to figure out which is the best and most secure and proper way of going about this.
Here is my default LoginView...( Nothing fancy )
class LoginView(LoginView):
template_name = 'registration/login.html'
form_class = AuthenticationForm
And then it redirects based on my settings.py file definition...
LOGIN_REDIRECT_URL = "book:author"
What is the best way to redirect for first login of the day to different URL?
Thanks in advance for any suggestions.
I found this SO answer Django -- Conditional Login Redirect and it seems to be what I'm looking for. Are there any downsides to using the example at the bottom?
And how to do with a LoginView as opposed to the function based example?
To answer your question, let me suppose you have a client model, in a way, similar to this model, and we'll need a helper models that stores the user's logins:
models.py:
from django.db import models
from django.contrib.auth.models import User
class Client(models.Model):
"""
This client model is pointing to django's User model
You can use your custom user model using AbstractBaseUser or whatever.
And if you're using django's User model directly, this class is not required
"""
user = models.OneToOneField(
User,
on_delete=models.DO_NOTHING,
verbose_name='User',
related_name='cli', # related name manager if needed
null=False,
blank=False,
)
def __str__(self):
return '{}'.format(self.user.username)
class ClientLogins(models.Model):
"""
This is a helper model table that stores the logins dates of the client
"""
client = models.ForeignKey(
Client,
verbose_name='Client',
on_delete=models.DO_NOTHING
)
date = models.DateTimeField(verbose_name="Date login")
def __str__(self):
return '{}'.format(self.client)
Then your form:
forms.py:
class LoginForm(forms.ModelForm):
'''Simple login form'''
class Meta:
model = User
fields = ('username', 'password')
And finally, your login behaviour should be treated in the views classes/functions.
views.py:
from datetime import timedelta
from django.utils import timezone
from MY_APP import models, forms
class LoginUser(LoginView):
template_name = 'login.html' # your template
from_class = forms.LoginForm # your form
def get_success_url(self):
'''Here the part where you can implement your login logic'''
now = timezone.now()
# Get current day date object
# like: 12/02/2019 00:00:00
today = now.replace(minute=0).replace(second=0).replace(microsecond=0)
# Get the client from the user object
client = self.request.user.cli
# Get all the user today's logins and count them
client_logins = models.ClientLogins.objects.filter(
client=client,
date__gte=today,
date__lte=today + timedelta(days=1)
).count()
if client_logins < 1: # Or: if not client_logins:
# create a login tracker record
models.ClientLogins.objects.create(
client=client,
date=now # Store the date where the user logged in the website
)
return reverse_lazy('FIRST_LOGIN_REDIRECT_URL')
# Or redirect to: settings.LOGIN_REDIRECT_URL
return super().get_success_url()
And for more informations, this is the core code of LoginView, like this you can know the MRO list and what you can override to have your desired behaviour.

Requested user profile present at two urls

For logged-in user the profile url is
path('profile/', profile, name='profile'),
For profile views the url is
re_path(r'^profile/(?P<pk>\d+)/$',UserProfileView,name='my_profile'),
But when we try to access the logged-in user by '/profile/user_pk' then it was conflicting one profile present at two urls
views.py
#login_required
def profile(request):
args={'user':request.user}
return render(request,'account/profile.html',args)
def UserProfileView(request,pk):
if pk==request.user.pk:
raise(Http404)
else:
user = get_object_or_404(User,pk=pk)
return render(request,'account/profile.html',{'user':user})
something like if requested pk is same as profile pk then it raises Http else show other profile but now working still showing all profile as it was showing.

Django Class Based Views Profile view, can't distinguish between user logged in and user being modified in a template

I'm trying to create a user dashboard, and the first thing I'm implementing is the user profile. All the profiles are meant to be public, and I want to add an Edit button if the user is visiting their own profile. My problem is that when I go onto someone's page, it replaces the user variable with the user I'm seeing the profile of.
My url:
url(r'^profile/(?P<pk>\d+)$',
views.ProfileView.as_view(),
name='profile'),
I created a view:
from django.contrib.auth import get_user_model()
from django.views.generic.detail import DetailView
class ProfileView(DetailView):
model = get_user_model()
template_name = 'accounts/profile.html'
And in my template:
{% if user == object %}user and object are the same{% endif %}
I am seeing user and object are the same when the current user is on their own profile, but it also works when the current user is seeing another profile. Is there something I've missed? Why are they the same?
The user variable is injected by the django.contrib.auth.context_processors.auth context processor.
To solve this issue set the context_object_name to non "user" string:
class ProfileView(DetailView):
model = get_user_model()
context_object_name = 'user_object'
template_name = 'accounts/profile.html'
And then use this name in the template:
{% if user == user_object %}user and object are the same{% endif %}

One blog for each Django user with the "blog role"

What approach is the best way to make content-types restricted to a user in Django?
Let us say I want all users with the user-role "blogger" to have its own blog.
I have created a weblog app. How do I restrict it so that the user logged in can only post in his "own" blog, and how do I make views that shows only a user's blog?
First your blog entries has to be attached to user, so you know on whos blog display, it, right? models.py:
class BlogEntry(models.Model):
user = models.ForeignKey(User, related_name='blog_entries')
other_field_1 = ...
other_field_2 = ...
Next, skip it in ModelForm, forms.py:
class BlogEntryModelForm(forms.ModelForm):
class Meta:
exclude = ('user',)
Then, when user want to post entry you require he's logged, views.py:
#login_required
def post_blog_entry(request):
....
if request.method == 'POST':
form = BlogEntryModelForm(request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.user = request.user
new_entry.save()
When you want display some user blog, views.py:
def view_blog(request, blogger_name):
user = get_object_or_404(User, username=blogger_name)
entries = user.blog_entries.all()
User is django.contrib.auth.models.User
You can add custom role checking to views above to display 404 page or error page if user has no rights to create blog.
Optionally you can replace User from django.contrib.auth with your own User implementation but you'll have to write model, authentication and middleware for it as well...
I didnt try to implement this, but I found another soultion that worked very good. It was easy to implement and did everything i wanted.
Check it out...