Pass logged in user to haystack search - django

I want to show my search results in respect to account type of the current logged in user. Is it possible to pass user from request to object in urls? If not, how else can I pass it?
To be more specific. In haystack urls.py we have
url(r'^$', SearchView(), name='haystack_search'),
Can I somehow to SearchView object pass current logged in user?

I didn`t notice that SearchViews has access to request so it is really easy to get user in this class.

Related

Django user account delete and then return redirect and render

I want to allow a user to delete his account and upon deletion, I want the user to be logged out and see a html page account_deleted.html for confirmation.
students/views.py:
def delete_account(request):
user = User.objects.get(username=request.user)
user.delete()
context = {
"deleted_msg": "Account has been deleted",
}
return render(request, "students/account_deleted.html", context) and redirect("students:logout")
For logout, I'm using the built-in LogoutView function. The logout redirect URL in my settings.py is set to my home page.
students/urls.py:
path('logout/', LogoutView.as_view(), name='logout'),
In case of an account deletion, how can I make the delete_account(request) function return a render and redirect at the same time? Is that even possible?
Thanks!
You can log the user out before deleting the account by placing logout(request) before your user.delete() line. You will need to import it with from django.contrib.auth import logout.
As Bruno said in his answer, using a redirect instead of render is preferable after a POST request, and you should update your view to only respond to POST requests.
If you are having trouble with your website crashing after a user is deleted, make sure you are using the proper access control in all your views, eg by using the #login_required decorator or the equivalent mixin on all views that require a user to be logged in. If you do this the user will just be redirected to the login page if he or she is not logged in instead of crashing your site.
First things firsts: your view should 1/ only accept logged in users and 2/ only accept POST requests (you definitely dont want a GET request to delete anything from your database). Also, this:
User.objects.filter(username=request.user)
is useless - you already have the current user in request.user - and potentially dangerous if your auth backend allows for duplicated usernames.
and this:
return render(request, "students/account_deleted.html", context) and redirect("students:logout")
is of course plain wrong. A view returns one single HTTP response, you can't return two (it wouldn't make any sense), and you can't "and" two responses together (well, you can but the result is certainly not what you expect - read the FineManual about the and operator).
The proper solution is to 1/ manually log out the user (cf voodoo-burger's answer), 2/ use the messages framework to inform the user her accont has been deleted, and 3/ redirect to the home page (you ALWAYS want to redirect after a successful post, cf https://en.wikipedia.org/wiki/Post/Redirect/Get for the why).

How to Redirect to user profile in django? i am using Django registration Redux

I am working on an app where the user will be able to login to his profile. I am using Django-registration-redux. I am using the below code to inculde in my project.
LOGIN_REDIRECT_URL = '/profile/view/(?P<pk>[0-9]+)/'
I want to redirect the user to his profile after logging in. I know that is not the way you can actually call an url in settings file. any solution for the problem?
I believe you can use https://docs.djangoproject.com/en/dev/ref/urlresolvers/#reverse-lazy to add URL resolution to a setting.
You don't need to pass the user pk to the view. You can get this value and every other data field of the user from request.user object.
As stated in Django docs, you could do something like this:
def profile(request):
if request.user.is_authenticated:
# Do something for logged-in users.
request.user.do_something()
[...]
else:
# Do something for anonymous users like redirect to registration
pass

Django redirect shortcut changes request.user

I have an application where we have sub-classed the Django 'User' object into, say, 'AppAccount' object which has additional attributes. Now I have a view where I do the following:
appAccountObject.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, appAccountObject)
redirect(someOtherView)
Now according to pdb, request.user is an instance of AppAccount right after the login() call, but request.user is a Django User instance in the first line of someOtherView.
Why is the redirect call changing the User object back to the normal Django User? How can I avoid this?
Also, is the above code correct? Should adding the backend attribute be okay to bypass a call to authenticate? If not, what should the correct way of doing this be: I want to login a user automatically, without their credentials and then redirect to another view which is wrapped by a #login_required decorator.
Thanks.
A redirect causes a whole new request from the user's browser, hence the user object has to be fetched from the database again based on the session cookie and assigned to request.user. This happens in the authentication middleware. Unless you've written your own version of this, it's always going to use the default user class.
This is just one of the reasons why it's a bad idea to subclass User. Instead, extend it with a UserProfile class with a OneToOne relation to User.

How to pass vulnerable args from templates to views in Django?

I'm creating an app which can create, edit or view a place.
When I edit or view a place, I pass the 'id' field throught the URL, for example:
/places/place/1
/places/place/2
...
When I try to edit a place I do:
place_detail.html
Edit
The 'place' var is a form.
url.py
urlpatterns = patterns('',
url(r'^edit_place/(?P<id_place>\w+)/$',
views.edit_place,
name='places_edit_place'),
)
view.py
def edit_place(request, id_place, template_name='places/edit_place.html'):
I receive the 'id' field of a place object in the 'id_place' arg. But if I change in the url the 'id' arg (/places/edit_place/1 to /places/edit_place/2), the web page go to the second place to be edited and an user could change this arg like he wants.
How I can send this private 'id' arg from a template to a view without the user can't see it.
Don't.
If your app has rules to determine which places a user can edit, you should implement some business logic to ensure that the user can't edit that place, even if they happen to go the URL to do so. You can use Django's authorization decorators to ensure that the user can't access anything they shouldn't.

How to preset the username in Djangos login form?

After being dissatisfied with the existing solutions I wrote an OpenId provider for Django.
If now somebody wants to authenticate himself somewhere as http://tejp.de/users/abc/ and needs to login for that, I want to display the login form with the username preset to "abc". The standard functions like redirect_to_login don't seem to provide any parameters for this and I also don't see how I could preset that value when redirecting to the login view in django.contrib.auth.views.login manually. Also there seems to be no easy way to get an additional parameter value through to the template, so that I could maybe insert the preset value there.
Is there a way to automatically fill in a username in the login form? If possible I'd like to use the normal login view for this, not copy&paste all the login code and edit in the necessary changes.
Remember, django is all python, and the source is your friend.
Here's the original source for redirect_to_login.
def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"Redirects the user to the login page, passing the given 'next' page"
if not login_url:
login_url = settings.LOGIN_URL
return HttpResponseRedirect('%s?%s=%s' % (login_url, urlquote(redirect_field_name), urlquote(next)))
It looks like you could even just override login_url with a link to a URL that takes the appropriate parameters. Something like
return redirect_to_login(login_url=reverse('my_login_view', [], {'username': username}))
You don't need a new form, you just need to prepopulate the existing login form.
Some of ways to solve the above problem are:
Write your own authentication form and prefill the username before displaying.
Use javascript to strip a username from url and put it down in the form.