Failed to to turn django staff flag on programatically - python

I am fetching user from database then is_staff=True then saving it. But yet it fails save.
Why can't I save a user as staff pragmatically using this code?
def approve_staff(self,request,username,):
if request.user.is_superuser:
u=User.objects.filter(username=username)
if u.exists():
u[0].is_staff=True;
u[0].save() #
print u[0],u[0].is_staff
from django.http import HttpResponseRedirect
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

Not that it will necessarily solve your problem, but the Django way to get a single record is Queryset.get
try:
u=User.objects.get(username=username)
except User.DoesNotExist:
raise Http404()
u.is_staff=True;
u.save() #
print u, u.is_staff
Also your view should only accept POST requests.

Can't you just do a
User.objects.filter(username=username).update(is_staff=True)
It will update the data (without having to call save()) for every object the filter finds.

Related

How do I delete sessions when a user logs out Django?

I'm learning Django. I created the Sign out function. But when I loop with for it gives an error.
My Code:
def logout(request):
for key in request.session.keys():
del request.session[key]
return redirect('login')
But get this error ? I am using Python 3. Can you help me ?
RuntimeError at /logout/
dictionary changed size during iteration
Modifying a collection over which you are iterating is tricky, and frequently not allowed. It can easily result in problems, since the iterator is usually implemented under the assumption that the collection will not change.
You however do not need to iterate over the keys here. You can use the clear() method [Django-doc]:
def logout(request):
request.session.clear()
return redirect('login')
This is however not sufficient. Django already made a function to logout a user that will clear the session, delete it, etc. logout(..) [Django-doc]. You thus can implement this as:
from django.contrib.auth import logout as auth_logout
def logout(request):
auth_logout(request)
return redirect('login')

Adding returning form_invalid (or something) with custom form errors in custom signup form with django-allauth

I am trying to prohibit duplicate signups from a single ip. Here is my code.
class SignupForm(forms.Form):
def signup(self, request, user):
ip = get_client_ip(request)
if UserProfile.objects.filter(registration_ip=ip).exists():
self.add_error(
None, "You cannot register more than one account from the same IP")
else:
user.userprofile.registration_ip = ip
user.userprofile.save()
user.save()
Currently, when a user registers having the same ip as another registered user, the form still validates. I need the form to return an error. Can anyone help? Thanks in advance.
(The above code is an override of the SignupForm of the django-allauth package)
The if statement works fine. At first I tried using raise ValidationError and that worked fine, but that is not good for UX. I need the form to invalidate and return my custom error on the form page.
Use the clean function:
def clean_registration_ip(self):
registration_ip = self.cleaned_data.get('registration_ip')
if : # your logic
raise forms.ValidationError("Your msg")
return registration_ip
That filtering, returns an istance and it does not check the IP if they are same or not just checks if exist.
First you need to make uniqe registration_ip via Model.
Then you can use clean method via forms like:
def clean_registration_ip(self,request):
registration_ip = self.cleaned_data['registration_ip']
if UserProfile.objects.filter(registration_ip=registration_ip).exists():
raise forms.ValidationError("This IP exist")
return registration_ip

Am I able to create a form that is able to add a new django.contrib.auth User without logging in to the admin panel?

Have created a form but unsure if is right and also unable to add a user, it will show TypeError/
This is how the form I want it to look like
The following is my coding:
class Form_Add_User(forms.Form):
name=forms.CharField(label="Name", max_length=50)
dateofbirth=forms.DateField(label="Date of Birth", widget=forms.widgets.DateInput(format="%m/%d/%Y"))
contactnum=forms.CharField(label="Contact Number", max_length=9)
def adduser(request):
if len(request.POST)>0:
form=Form_Add_User(request.POST)
if(form.is_valid()):
name=form.cleaned_data['name']
dateofbirth=form.cleaned_data['dateofbirth']
contactnum=form.cleaned_data['contactnum']
new_user=User(name=name,dateofbirth=dateofbirth,contactnum=contactnum)
new_user.save()
return redirect('/adduser')
else:
return render(request,'adduser.html',{'form':form})
else:
form=Form_Add_User
return render(request,'adduser.html',{'form':form})
First off: it's always very useful to also post a full error message if you have one. The more info you give us, the easier (and quicker!) is answering your question.
I assume, your User model is not actually django's auth User model (see, if you had posted the model, I wouldn't have to guess).
The form you pass to your template was not instantiated:
#...
else:
form=Form_Add_User() #!!
return render(request,'adduser.html',{'form':form})

How to enable function to render templates based on try, except blocks from within another view in Django?

I am creating an application in Django that would allow my users to order items from my site based on information already stored in the database.
Not all my users should be able to order certain items, for this purpose I have written a pipeline with comparison statements and try, except blocks.
A small, reproduce-able piece of code looks like this:
vendor.py
def guest_constraint(request)
# Ensure user in request is a house-guest by checking if it has an active token.
try:
guest = GuestProfile.objects.get(user=request.user.id)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/not_hotel_login.html')
# Check for Hotel Room Information linked to Guest Token
try:
room_information = RoomInformation.objects.get(guest_token=guest.token)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/constraint_error.html')
views.py
from .vendor import guest_constraint
#login_required
def index(request):
guest_contraint(request) # Filter out users with no access to this process.
user = request.user # Grab user defined in request.
name = user.get_short_name() # Grab first name of user.
return render(request, 'extGuest/appGuestFlow/choose_order_type.html')
Challenge: I can successfully import this small script into my view and I can see its content is run except for the return render(request, template) part.
To explain myself better, the try/except block successfully catch the exception, however it does not returns the template specified in the block but instead it goes back to the view and renders the template I have in the view.
What have I tried? If I place the code of guest_constraint (vendor.py) and place it inside index (views.py) I see no problem and works as expected. This however doesn't scale well as I wish to call guest_contraint for many different functions in views.py
I'm fairly new to programming and Django and I still have lots to learn. If you could please give me a hint on what you think I'm doing wrong or what topic on Django (or even basic Python) could help me tackle this issue it would be greatly appreciated. Thanks!
Edit: I forgot to mention, I'm using Django 1.11.6.
Edit 2: Yikes, I forgot to include how I use the function in my index view. My bad, sorry.
Solution:
Thanks to #cwallenpoole and some changes I did on his response I was able to edit my code to do what I wanted to do and it now looks like this:
vendor.py | Updated
def guest_constraint(function):
def _inner_guest_constraint(request)
# This part should be familiar
try:
guest = GuestProfile.objects.get(user=request.user.id)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/not_hotel_login.html')
try:
room_information = RoomInformation.objects.get(guest_token=guest.token)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/constraint_error.html')
# Once all checks are passed return flow back to function.
return function(request)
# return the wrapping
return _inner_guest_constraint
views.py | Updated
from .vendor import guest_constraint
#login_required
#guest_constraint
def index(request):
user = request.user # Grab user defined in request.
name = user.get_short_name() # Grab first name of user.
return render(request, 'extGuest/appGuestFlow/choose_order_type.html')
It seems like you might want to consider using an annotation instead of just as a function:
def guest_constraint(fn):
def _inner_guest_constraint(request)
# This part should be familiar
try:
guest = GuestProfile.objects.get(user=request.user.id)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/not_hotel_login.html')
try:
room_information = RoomInformation.objects.get(guest_token=guest.token)
except ObjectDoesNotExist:
return render(request, 'extGuest/appGuestError/constraint_error.html')
# Call the wrapped function
fn(request)
# return the wrapping
return _inner_guest_constraint
Then you could simply annotate:
#login_required
#guest_constraint
def index(request):
You could also modify it so that your wrapping function adds parameters:
def guest_constraint(fn):
def _inner_guest_constraint(*args,**kwargs):
# stuff
kwargs.update({'guest':guest, 'room_info': room_information})
fn(*args,**kwargs)
return _inner_guest_constraint
That would mean that you'd need to make sure that your annotated views took guest and room_info params, but it would also mean that you're defining variables once.
Your sample views.py doesn't show anything using guest_constraint, just the import. It sounds like you want something in the middle of index (and other views) that will check guest_constraint. One simple way to handle it is to return two values - a result status and the render() results. Add False to each of the existing return render() lines and at the end of the function return True, None. Full function becomes:
def guest_constraint(request)
# Ensure user in request is a house-guest by checking if it has an active token.
try:
guest = GuestProfile.objects.get(user=request.user.id)
except ObjectDoesNotExist:
return False, render(request, 'extGuest/appGuestError/not_hotel_login.html')
# Check for Hotel Room Information linked to Guest Token
try:
room_information = RoomInformation.objects.get(guest_token=guest.token)
except ObjectDoesNotExist:
return False, render(request, 'extGuest/appGuestError/constraint_error.html')
# Everything is good
return True, None
and in views.py you could have:
constraint_ok, constraint_render = guest_constraint(request)
if not constraint_ok:
return constraint_render

How to prevent user changing URL <pk> to see other submission data Django

I'm new to the web development world, to Django, and to applications that require securing the URL from users that change the foo/bar/pk to access other user data.
Is there a way to prevent this? Or is there a built-in way to prevent this from happening in Django?
E.g.:
foo/bar/22 can be changed to foo/bar/14 and exposes past users data.
I have read the answers to several questions about this topic and I have had little luck in an answer that can clearly and coherently explain this and the approach to prevent this. I don't know a ton about this so I don't know how to word this question to investigate it properly. Please explain this to me like I'm 5.
There are a few ways you can achieve this:
If you have the concept of login, just restrict the URL to:
/foo/bar/
and in the code, user=request.user and display data only for the logged in user.
Another way would be:
/foo/bar/{{request.user.id}}/
and in the view:
def myview(request, id):
if id != request.user.id:
HttpResponseForbidden('You cannot view what is not yours') #Or however you want to handle this
You could even write a middleware that would redirect the user to their page /foo/bar/userid - or to the login page if not logged in.
I'd recommend using django-guardian if you'd like to control per-object access. Here's how it would look after configuring the settings and installing it (this is from django-guardian's docs):
>>> from django.contrib.auth.models import User
>>> boss = User.objects.create(username='Big Boss')
>>> joe = User.objects.create(username='joe')
>>> task = Task.objects.create(summary='Some job', content='', reported_by=boss)
>>> joe.has_perm('view_task', task)
False
If you'd prefer not to use an external library, there's also ways to do it in Django's views.
Here's how that might look:
from django.http import HttpResponseForbidden
from .models import Bar
def view_bar(request, pk):
bar = Bar.objects.get(pk=pk)
if not bar.user == request.user:
return HttpResponseForbidden("You can't view this Bar.")
# The rest of the view goes here...
Just check that the object retrieved by the primary key belongs to the requesting user. In the view this would be
if some_object.user == request.user:
...
This requires that the model representing the object has a reference to the User model.
In my project, for several models/tables, a user should only be able to see data that he/she entered, and not data that other users entered. For these models/tables, there is a user column.
In the list view, that is easy enough to implement, just filter the query set passed to the list view for model.user = loggged_id.user.
But for the detail/update/delete views, seeing the PK up there in the URL, it is conceivable that user could edit the PK in the URL and access another user's row/data.
I'm using Django's built in class based views.
The views with PK in the URL already have the LoginRequiredMixin, but that does not stop a user from changing the PK in the URL.
My solution: "Does Logged In User Own This Row Mixin"
(DoesLoggedInUserOwnThisRowMixin) -- override the get_object method and test there.
from django.core.exceptions import PermissionDenied
class DoesLoggedInUserOwnThisRowMixin(object):
def get_object(self):
'''only allow owner (or superuser) to access the table row'''
obj = super(DoesLoggedInUserOwnThisRowMixin, self).get_object()
if self.request.user.is_superuser:
pass
elif obj.iUser != self.request.user:
raise PermissionDenied(
"Permission Denied -- that's not your record!")
return obj
Voila!
Just put the mixin on the view class definition line after LoginRequiredMixin, and with a 403.html template that outputs the message, you are good to go.
In django, the currently logged in user is available in your views as the property user of the request object.
The idea is to filter your models by the logged in user first, and then if there are any results only show those results.
If the user is trying to access an object that doesn't belong to them, don't show the object.
One way to take care of all of that is to use the get_object_or_404 shortcut function, which will raise a 404 error if an object that matches the given parameters is not found.
Using this, we can just pass the primary key and the current logged in user to this method, if it returns an object, that means the primary key belongs to this user, otherwise it will return a 404 as if the page doesn't exist.
Its quite simple to plug it into your view:
from django.shortcuts import get_object_or_404, render
from .models import YourModel
def some_view(request, pk=None):
obj = get_object_or_404(YourModel, pk=pk, user=request.user)
return render(request, 'details.html', {'object': obj})
Now, if the user tries to access a link with a pk that doesn't belong to them, a 404 is raised.
You're going to want to look into user authentication and authorization, which are both supplied by [Django's Auth package] (https://docs.djangoproject.com/en/4.0/topics/auth/) . There's a big difference between the two things, as well.
Authentication is making sure someone is who they say they are. Think, logging in. You get someone to entire their user name and password to prove they are the owner of the account.
Authorization is making sure that someone is able to access what they are trying to access. So, a normal user for instance, won't be able to just switch PK's.
Authorization is well documented in the link I provided above. I'd start there and run through some of the sample code. Hopefully that answers your question. If not, hopefully it provides you with enough information to come back and ask a more specific question.
This is a recurring question and also implies a serious security flaw. My contribution is this:
There are 2 basic aspects to take care of.
The first is the view:
a) Take care to add a decorator to the function-based view (such as #login_required) or a mixin to the class-based function (such as LoginRequiredMixin). I find the official Django documentation quite helpful on this (https://docs.djangoproject.com/en/4.0/topics/auth/default/).
b) When, in your view, you define the data to be retrieved or inserted (GET or POST methods), the data of the user must be filtered by the ID of that user. Something like this:
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=User.objects.filter(pk=self.request.user.id))
return super().get(request, *args, **kwargs)
The second aspect is the URL:
In the URL you should also limit the URL to the pk that was defined in the view. Something like this:
path('int:pk/blog-add/', AddBlogView.as_view(), name='blog-add'),
In my experience, this prevents that an user sees the data of another user, simply by changing a number in the URL.
Hope it helps.
In django CBV (class based views) you can prevent this by comparing the
user entered pk and the current logged in user:
Note: I tested it in django 4 and python 3.9.
from django.http import HttpResponseForbidden
class UserDetailView(LoginRequiredMixin, DetailView):
model = your_model
def dispatch(self, request, *args, **kwargs):
if kwargs.get('pk') != self.request.user.pk:
return HttpResponseForbidden(_('You do not have permission to view this page'))
return super().dispatch(request, *args, **kwargs)

Categories

Resources