Hi so I have an attend session button that when clicked adds the user to the session. I got it working but I want to add a check to see whether the user is already in the ManyToMany field of attendees before I add them. How would I go about doing that?
Here is my view for it
def attend_session(request):
session = Study.objects.get(pk=request.POST['session_id'])
stud = Student.objects.get(student_user=request.user)
if request.method == "POST":
# Add check here to see if student is already attending
session.attendees.add(stud)
session.save()
return HttpResponseRedirect(reverse('study:sessions'))
You can check with:
from django.shortcuts import get_object_or_404, redirect
def attend_session(request):
session = get_object_or_404(Study, pk=request.POST['session_id'])
stud = get_object_or_404(Student, student_user=request.user)
if request.method == 'POST':
if stud not in session.attendees.all():
session.attendees.add(stud)
return redirect('study:sessions')
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: You can make use of redirect(…) [Django-doc] instead
of first calling reverse(…) [Django] and
then wrap it in a HttpResponseRedirect object [Django-doc].
The redirect(…) function does not only offer a more convenient signature to do this, it also for example will use the
.get_absolute_url() method [Django-doc]
if you pass it a model object.
Related
i have a table which include all users and two columns at the end (Edit,Delete) and i just enabled the delete column, the issue is when i click on the delete icon the record will be deleted but the url will stuck on the delete function even if i used return render(request,'getUsersInfo.html') which is get all records function
Model Name: Users
urls:
from django.urls import path
from django.conf.urls import url
from . import views
urlpatterns = [
path('signup.html',views.signup,name=''),
path('getUsersInfo.html',views.getAllUsers,name=''),
url(r'^deleteUser/(?P<fullname>\D+)/$',views.deleteUser, name='deleteUser'),
# this is how to call a function without parameters url(r'^deleteUser/$',views.deleteUser, name='deleteUser'),
in the same view i have 3 functions (singup "add user", getAllUsers "get all the records to the table,deleteUser)
views:
def getAllUsers(request):
print("getAllUsers")
thesearchValue = ''
if 'SearchValue' in request.GET:
thesearchValue = request.GET['SearchValue']
print(request.GET['SearchValue'])
allUsers = User.objects.filter(fullname__icontains=thesearchValue)#all()
# return render(request,'getUsersInfo.html',{'allUsers':allUsers})
return render(request,'getUsersInfo.html',{'allUsers':allUsers})
else:
print("Empty")
allUsers = User.objects.all()
return render(request,'getUsersInfo.html',{'allUsers':allUsers})
def deleteUser(request,fullname):
print('delete the user')
todelete = User.objects.filter(fullname=fullname)
todelete.delete()
return render(request,'getUsersInfo.html')
Notice that i used return render(request,'getUsersInfo.html') which should call getAllUsers(request): but the url stuck on http://127.0.0.1:8000/deleteUser/John/
Rendering the same template as another view does not mean that you will somehow call other views. A template is nothing more than a tool to specify how to convert context data to a string, that is passed as HTTP response. You can use the same template in multiple views, and a view can render multiple templates.
You can make use of redirect(..) [Django-doc] to return a HTTP redirect response (302):
from django.shortcuts import redirect
def deleteUser(request,fullname):
print('delete the user')
todelete = User.objects.filter(fullname=fullname)
todelete.delete()
return redirect(getAllUsers)
Note: A GET request is not supposed to have side-effects, hence removing
objects when a user makes a GET request, is not compliant with the HTTP
standard. Therefore it might be better to remove a User with a POST request.
I'm trying to wrap my head around an issue I'm having.
I want to present the users with a page in which they can look up a user by entering his username.
Yet I can't wrap my head around how to do this. Do I provide a function in my view in which a query is executed that retrieves a user from the database? For example retrieve his username or id and go to his profile page? I can't seem to grasp how to do this, I have been looking for examples on this but I can't find anything so I hope someone here can help me out!
Yes, at the simplest level you would have a view that accepts a form submission which takes the value of the field and does something like User.objects.get(username=my_variable) and returns the results, if any. You should wrap the call in a try/ except block so your view doesn't blow up if no such user exists with that username. Django provides a shortcut function for doing just this, so instead of the line above you could do user = get_object_or_404(User, username=my_variable). Your whole view would look something like
from django.shortcuts import render, get_object_or_404
def username_search(request):
# if there are any form values sent in a GET
if request.GET:
my_variable = request.GET.get('username', '')
user = get_object_or_404(User, username=my_variable)
else:
user = None
return render(request, 'some_template.html', {'user': user}
In reality you might also create a Django form to do some validation on the submissions and make it easier to render your form.
I am writing a web app using Django. I am trying to allow a user to see its profile and only his own.
if(not request.user.id == request.GET.get('user_id', '')):
raise PermissionDenied
My question is: is it safe to check this way or is it possible for a smart kid to somehow alter the value in request.user.id to match the user_id of anyone?
The user must be logged in before accessing this page using this:
user = LDAPBackend().authenticate(username=username, password=password)
if(user is not None):
login(request, user)
Yes it should be safe.
request.user get's only populated when authentication with session cookies. Unless and until someone steals the cookie or token it should be no issue.
One thing i don't understand is why do you need user_id parameter here to be explicitly passed.
if you are putting logged in compulsory to view the page. there are two way i can see this.
/profile
Directly get user profile corresponding to the request.user
/<username>
Query the profile corresponding to the username and compare it with request.user.id
request.user is set using AuthenticationMiddleware for each request:
Adds the user attribute, representing the currently-logged-in user, to every incoming HttpRequest object.
If a user is not logged in then request.user is set to Anonymous User. Have a look at Authentication in Web requests.
So, I am not sure how would a smart kid alter the id of the logged-in user.
Mostly, there is a one-to-one relation between the user and its profile. If that's the case you can modify the queryset to get the profile for request.user directly.
request.user is already an object about the current user who send the request to get the page. You can use login_required or to only allow user login to access (2 solutions : decorator or Mixin).
And then you can use your condition to load the page in the function. Example:
=> url.py:
url(r'^profile/$', login_required(app.views.profile), name='profile'),
=> views.py :
def profile(request):
try:
myProfile = User.objects.get(username=request.user.username)
except ObjectDoesNotExist:
return render(request, "error.html", {'message' : 'No Profile Found'})
return render(request, "app/profile.html",
{'myProfile': myProfile})
Like this you can only display YOUR profile (user who send the request) AND you need to be logged.
EDIT: if you don't want "try and catch" you can use get_object_or_404(User, username=request.user.username)
I want to test some django application urls. However, the associated views are linked to the database. What I'd like to do is mocking these aspects of the view method, but I have no idea how.
Let's suppose I want to try the /signin url, whici is a classical signin form.
The associated view looks like this :
def login(request):
if 'user' in request.session:
return redirect(reverse("home"))
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
return treat_login(request, username, password) # checks if couple
is present in
database, returns
pages accordingly
else:
form = LoginForm()
return render(request, 'login.html', {'form':form, })
In my test, I have no implicit call to the login method, since I only use the url :
class Tests_urls(TestCase):
def test_signin(self):
self.client.post(reverse("login"), {"username":"login", "password":"pwd"})
self.assert_http_status(url, status, "after a standard login")
The problem with that test is that it needs a database to be performed, wich is what I want to avoid (I can't use use the embedded test database).
As a consequence, I would like to know how to mock the treat_login method from the test point of view.
You can use patch from the mock libarary
from mock import patch
class Tests_urls(TestCase):
#patch('my_app.views.treat_login')
def test_signin(self, mock_treat_login):
self.client.post(reverse("login"), {"username":"login", "password":"pwd"})
self.assert_http_status(url, status, "after a standard login")
self.assertTrue(mock_treat_login.called)
You can also inspect the call args. But the way you have written this test makes that a bit hard. If you used the request factory and tested the function by doing something like
request = self.factory.post(
reverse("login"), {"username":"login", "password":"pwd"})
response = login(request
mock_treat_login.assert_called_once_with(request, "login", "pwd)
Then you could actually make sure you were calling it correctly.
I'm nearing what I think is the end of development for a Django application I'm building. The key view in this application is a user dashboard to display metrics of some kind. Basically I don't want users to be able to see the dashboards of other users. Right now my view looks like this:
#login_required
#permission_required('social_followup.add_list')
def user_dashboard(request, list_id):
try:
user_list = models.List.objects.get(pk=list_id)
except models.List.DoesNotExist:
raise Http404
return TemplateResponse(request, 'dashboard/view.html', {'user_list': user_list})
the url for this view is like this:
url(r'u/dashboard/(?P<list_id>\d+)/$', views.user_dashboard, name='user_dashboard'),
Right now any logged in user can just change the list_id in the URL and access a different dashboard. How can I make it so a user can only view the dashboard for their own list_id, without removing the list_id parameter from the URL? I'm pretty new to this part of Django and don't really know which direction to go in.
Just pull request.user and make sure this List is theirs.
You haven't described your model, but it should be straight forward.
Perhaps you have a user ID stored in your List model? In that case,
if not request.user == user_list.user:
response = http.HttpResponse()
response.status_code = 403
return response
I solve similiar situations with a reusable mixin. You can add login_required by means of a method decorator for dispatch method or in urlpatterns for the view.
class OwnershipMixin(object):
"""
Mixin providing a dispatch overload that checks object ownership. is_staff and is_supervisor
are considered object owners as well. This mixin must be loaded before any class based views
are loaded for example class SomeView(OwnershipMixin, ListView)
"""
def dispatch(self, request, *args, **kwargs):
self.request = request
self.args = args
self.kwargs = kwargs
# we need to manually "wake up" self.request.user which is still a SimpleLazyObject at this point
# and manually obtain this object's owner information.
current_user = self.request.user._wrapped if hasattr(self.request.user, '_wrapped') else self.request.user
object_owner = getattr(self.get_object(), 'author')
if current_user != object_owner and not current_user.is_superuser and not current_user.is_staff:
raise PermissionDenied
return super(OwnershipMixin, self).dispatch(request, *args, **kwargs)
You need to have some information stored about what list or lists a user can access, and then include that in the user_list lookup. Let's assume the simple case where List has a single owner, a foreign key to the User model. That's a many-to-one relationship between lists and users; no list is owned by more than one user, but a user can have multiple lists. Then you want something like this:
try:
user_list = models.List.objects.get(pk=list_id, owner=request.user)
except models.List.DoesNotExist:
raise Http404
Whether to return 404 or 403 is to some extent a matter of opinion; the definition for 403 says:
If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4
If you do return a 404, you can use the django shortcut function get_object_or_404 instead of the explicit try/except - there's nothing wrong with doing it explicitly, but the need is common enough that there's a convenience function to do it.