Till now i have been using userid's (pk) as an argument in the profile urls for my application. Recently i decided to use the username instead of the user id's So i changed the following :
Urls.py
# This was what i was using previously
url(r'^profile/(?P<uid>\d+)/$', 'app.views.user_profile', name="profile"),
# Changed the above to this.
url(r'^profile/(?P<username>[-\w\d]+)/$', 'app.views.user_profile', name="profile"),
Views.py
# Previous view
#login_required
def user_profile(request, uid):
user = get_object_or_404(models.User, pk=uid)
profile = helpers.get_profile(user)
render_to_response('profile.html', {'profile' : profile})
# Changed the above to
#login_required
def user_profile(request, username):
user = get_object_or_404(models.User, username=username)
profile = helpers.get_profile(user)
render_to_response('profile.html', {'profile' : profile})
Until Now it's all good. When i try to visit 127.0.0.1:8000/profile/some_username/ instead of the previous 127.0.0.1:8000/profile/some_number/ it works fine.
I have a toolbar in the profile.html, which contains links such as:
/profile/edit/
/profile/settings/
in the urls.py these urls map to very simple views. Such as the following.
#login_required
def profile_settings(request):
"""
This view helpers.renders the profile's settings panel
"""
print 'hello'
rec, can = helpers.get_user_or_noprofile(request.user)
if not can is None:
gform = forms.CandidateGeneralSettingsForm(instance=can)
jsform = forms.CandidateJobSearchSettingsForm(instance=can)
data = {'candidate' : can, 'gform' : gform, 'jsform' : jsform }
else:
form = forms.RecruiterSettingsForm(instance=rec)
data = { 'recruiter' : rec, 'form' : form }
return helpers.render(request, 'profile_settings.html', data)
The weird part is after i changed to use username in the profile url. As soon as i click on any of the links in the toolbar, i see the 404 : Error : No User matches the given query. page.
To debug i tried printing a few debug statements within these views and found out something more weird. Nothing gets printed even if i Comment the whole code inside the view and just write a print statement.
This makes me doubt that the problem might be with the login_required decorator. but if that's the case howcome it is working while visitng 127.0.0.1:8000/profile/some_username/.
I really can't think of anything that might be causing this. Any help will be greatly appreciated. Thanks.
PS: Also, JFYI, i am using a custom Email Authentication backend that lets user login through their email address instead of the username.
It doesn't work because edit is not a valid username.
This url /profile/edit/ matches ^profile/(?P<username>[-\w\d]+)/$, and username becomes edit.
Since you don't have a user called "edit", this user = get_object_or_404(models.User, username=username) fails, and raises a 404.
The same for /profile/settings/.
Related
I can't get my redirect to work correctly after updating a bicycle in my Django app.
When I use my bikes_update() method and update the bicycle profile, if my redirect is just to '/bikes', I'm taken back to the bicycle collection/bicycles owned with no issue. But when I try and redirect back to the profile of the bike I just editted, I get the error that my return pathway doesn't match any of the url patterns. Even though that's the same pathway that initially takes me to the bicycle profile view (not the same one where I edit the bicycle, that is a different view).
I've pasted the bikes_update() method here:
def bikes_update(request, bike_id):
if request.method != 'POST' or 'user_id' not in request.session:
return redirect("/")
this_bike = Bike.objects.filter(id=bike_id).update(
name = request.POST['bike_name'],
model = request.POST['model_id'],
)
return redirect('/bikes')
return redirect('/bikes/<int:bike_id>')
return redirect('/bikes/<int:bike_id>/')
I obviously only use one of the redirects, not all the three in the final block. But I can't figure out why at least one of the final two do not work. When I have the bottom two redirects commented out, the 'return redirect('/bikes')' line works fine, but it takes me to the page listing all of my bikes when I want to go back the profile of the bike I just editted so I don't have to navigate back to it from the bicycle collection.
Navigating to /bikes/int:bike_id/ works fine when going to the profile initially from the list of bikes, but after I finishing editing I run into this error even though it's the same line as what got me to the profile in the first place. As soon as I click the submit button and try to redirect back to /bikes/int:bike_id/ I get my error.
I'm able to update the bicycle profile correctly, so it's something to do with this redirect, but I don't get it.
I don't understand how line 12 in my screen snippet and the current path (both highlighted in the image), aren't the same/don't match.
If you want to redirect on /bikes/<int:bike_id>/ then you can use a format string like this...
def bikes_update(request, bike_id):
if request.method != 'POST' or 'user_id' not in request.session:
return redirect("/")
this_bike = Bike.objects.filter(id=bike_id).update(
name = request.POST['bike_name'],
model = request.POST['model_id'],
)
return redirect(f'/bikes/{bike_id}/')
You have to add the id here not this "int:bike_id". put your id variable here like this redirect(f'/bikes/{Id}').
redirect can take a model as an argument, so you could do something like:
def bikes_update(request, bike_id):
if request.method != 'POST' or 'user_id' not in request.session:
return redirect("/")
this_bike = Bike.objects.filter(id=bike_id).update(
name = request.POST['bike_name'],
model = request.POST['model_id'],
)
this_bike = get_object_or_404(Bike, pk=bike_id)
return redirect(this_bike)
You will need a get_absolute_url method in your models.py though. For example:
def get_absolute_url(self):
return reverse("bikes", kwargs={"pk": self.pk})
This can be used for other things in Django as well (including usage in templates).
More info here: Django Docs
Of course, as you're obtaining the object now for this purpose, you may want to consider refactoring (not using a queryset update and perhaps changing the this_bike attributes instead) how you update it in the first place, as you're only dealing with a single object here.
I am little bit new to django and was working on my first instagram clone project all by myself. I got confused in a place where I needed to fetch user data based on 127.0.0.1:8000/username and I found a useful but useless answer(for me) from medium(.com) .The author was using class based view. In class based view, I didnot get any documentation to use multiple models as much as I searched so i had to do it with function based view as I have not learned class based view yet.I had to use post model, profile model and User model to get data for profile page.
This is the code that somehow worked but should I use this view?
from django.contrib.auth.models import User
from .models import Profile
#profile view
def profile_data(request, username):
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
mycontext ={'profile': myprofile}
return render(request,'firstapp/profile.html', context=mycontext)
#in urls.py,
from firstapp import views
path('<str:username>/', views.profile_data , name='profile'),
#in models.py,
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
fullname = models.CharField(max_length=100)
def __str__(self):
return self.fullname
In firstapp/profile.html,
<a href="#" class="text-3xl mt-5 text-center">{{user.profile.fullname}}
But I got confused on how to attatch my Profile model in it. So I created this, my own function-based view for it after few hours of researching . Is this ok to use or will give any error in my back? Thank you
I am expecting to get new ways or the correction or additon in my code if possible.
It seems ok, but be careful about the url part, because you will have problems when adding new urls (eg: /login) because it might be treated as a username.
You could get away by editing the order in your urlpatterns so the profile page is the last but now you have an issue if a user has the same username as a url in your page.
For example if a user has "login" as username, you won't be able to go to their profile page.
A solution is to use a prefix for the profile pages (eg: /u/<username> or /#<username>).
Some other improvements:
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
Can be rewriten with only one request:
user = User.objects.get(username=username).select_related("profile")
myprofile = user.profile
See the documentation for select_related: https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-related
You should also handle the case where the user is not found:
try:
user = User.objects.select_related("profile").get(username=username)
except User.DoesNotExist:
raise Http404("No User matches the given query.")
myprofile = user.profile
So let me start with the registration process in my web page. The user would register first, and then right after registration, he/she is redirected to a page where the user has to input his/her personal info, such as self-introduction, full name, etc. When the user completes filling his/her personal info in, then the user will be redirected to home page.
So what I wanted to do is this: When the user tries to access home page, check if he/she is logged in. If yes, check if he/she has filled in the personal info. If no, redirect the user to register page. If the user has filled in (=matching query exists), redirect him/her to the home page. If not, redirect him/her to the personal info page, to fill the fields in. And here's my code in views.py
def userHome(request):
if request.user.is_authenticated:
current_user = request.user
if PersonalInfo.objects.get(authuser_id=current_user.id).exists():
context = {
'thisUser' : thisUser,
'newSeed' : newSeed
}
return render(request, '/userhome.html', context)
else:
return redirect('/inputpersonalinfo')
else:
return redirect('/register')
models.py
from django.db import models
from django.contrib.auth.models import User
class PersonalInfo(models.Model):
objects = models.Manager()
authuser = models.OneToOneField(User, on_delete=models.CASCADE, related_name = 'personalinfo', null=True, default=None)
name = models.CharField(max_length=50)
...
I keep getting an error saying PersonalInfo matching query deos not exist. I do understand why this occurs, but can't think of the solution. Please help.
You have to use filter instead of get when you check if PersonalInfo exists:
PersonalInfo.objects.filter(authuser_id=current_user.id).exists()
get throws an error if there's no object matching the query. filter will return an empty queryset.
See the example in the documentation, and a question about get vs. filter
Even if the answer already provided works, I would avoid simply using exists() simply because I'm often likely to use the result of the query and exists() doesn't return the object. In your case I would rather do something like that:
try:
info = PersonalInfo.objects.get(authuser_id=current_user.id)
context = {
'thisUser' : thisUser,
'newSeed' : newSeed,
'someinfo' : info.whatever
}
return render(request, '/userhome.html', context)
except PersonalInfo.DoesNotExist:
return redirect('/inputpersonalinfo')
I am having a problem with HttpResponseRedirect in Django. It seems that, whatever parameters I try, it either throws an error, or it redirects without changing the URL. I am using it on a custom login_user view, and I want the URL in the address bar to change after they are redirected. If I use redirect instead of HttpResponseRedirect, it does not change. Either way, I can get it to serve the correct template, but the URL stays the same. Being new to Django, it would be helpful if someone could explain to me how to do this and why my current code is not working.
I have seen a couple of similar questions to mine on Stack Exchange, but the answers have not helped.
Here are the relevant parts of my views.py (please note the indenting has gone weird due to copying and pasting in here, and is not the cause of the error).
from django.http import *
from django.contrib.auth import authenticate, login, logout
def login_user(request):
logout(request)
username = password = ''
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('dashboard')
else:
state = "Your account is not active, please contact the app administrator."
else:
state = "Your username and/or password were incorrect."
state = "Please log in below..."
context = RequestContext(request, {
'state': state,
'username': username,
})
return render_to_response('bank/auth.html', {}, context)
dashboard is the name of another view, and it works fine in a redirect from my index view. I've also tried hard-coding the url in, but that doesn't work either. Any suggestions?? Thanks.
If you use HttpResponseRedirect, you must provide the url, not the name of the url.
You can either get the url by using reverse:
from django.core.urlresolvers import reverse
def my_view(request):
...
return HttpResponseRedirect(reverse('dashboard'))
or by using the redirect shortcut.
from django.shortcuts import redirect
def my_view(request):
...
return redirect('dashboard')
If using the either of the above approaches does not work, then there's probably a mistake somewhere else in the view. It's difficult to tell where, since the indentation is incorrect. Try adding some logging or print statements to see if you are really returning the redirect where you think you are.
In this particular case, the problem wasn't anything to do with my view code, it was actually a problem caused through using JQuery mobile. I found the answer here: Error with Redirects in JQuery Mobile which was to set the data-url attribute on the page div.
However, I have up-voted Alasdair's answer, as his way is the correct one of the ways I had tried.
I personally prefer the simple way as follows:
In urls.py:
url(r'^dashboard/$', 'appname.views.dashboard_view', name='dashboard_view'),
In views.py:
from django.http import HttpResponseRedirect
def dashboard_view(request):
...
return HttpResponseRedirect('/dashboard/')
How to validate the url if some change the name in url and update the form,
Suppose :
If i want to update a profile ,after click on the update button.ulr link will be like below
url : http://localhost:8000/profile_edit/sushanth/
i found there is an security loop here,a person can change the name on the url and he can edit other person profile,how to close this loop hole while updating the form in django.
Thanks in advance...:)
You just need to check in your view that the user is the correct one.
#login_required
def profile_edit(request, username):
if username != request.user.username:
return HttpResponseNotAllowed()