Ive got a users profile page and an update_profile page.
My projects urls.py:
re_path(r'^profile/(?P<username>[\w-]+)/$', include('users.urls')),
My users.urls:
path('', views.profile, name='profile'),
path('update_profile', views.update_profile, name='update_profile'),
Prior to adding the username argument to the url both of these links were working. Since adding the username argument, I can access the profile page but the update_profile page throws a 404 error. My understanding is that if the address bar reads www.site/profile/testuser/update_profile the projects urls.py will strip the www.site/profile/testuser/ and pass just update_profile to the profile apps urls.py, which then should match the path ive given.
Why isnt this working?
On my profile page I have a check that ensures the username passed in matches the logged in user (so users can only access their own profiles). I will need a similar check on the update_profile page, but currently arent passing username to the update profile page. How could I perform this check without passing it in a second time like /profile/testuser/update_profile/testuser?
Thank you.
These are the answers to your questions:
1. Your url is not working because of there is a $ at the end of users.urls url. $ is a zero width token which means an end in regex. So remove it.
2. You do not need to add <username> at the profile_update url. If you are using UpdateView, then add slug_url_kwarg attribute to UpdateView, like:
class MyUpdateView(UpdateView):
slug_url_kwarg = "username"
If you are using function based view, then simply use:
def myview(request,username):
....
Related
Django allauth fails when using a custom user model with the email as the primary key, I learnt about this when I tried to test the password change functionality.
Reverse for 'account_reset_password_from_key' with keyword arguments '{'uidb36': 'mgodhrawala402#gmail.com', 'key': 'bbz25w-9c6941d5cb69a49883f15bc8e076f504'}' not found. 1 pattern(s) tried: ['accounts/password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$']
I don't mind going into the code to fix this issue, since my application is still under development, I can still change authentication incase anyone has any suggestions.
The easiest fix for this problem would be adding a sequence integer pk and just updating your email field to index unique because as you see the regex path doesn't accept email format for uidb36, it only accepts 0-9A-Za-z.
If you must use email as pk you can add another path to your urls to accept your email pattern:
from allauth.account import views
path('accounts/', include('allauth.urls')),
re_path(
r"^accounts/password/reset/key/(?P<uidb36>.+)-(?P<key>.+)/$",
views.password_reset_from_key,
name="account_reset_password_from_key_accept_email",
),
I have experienced using reverse within get_absolute_url method in the model, but I wish I have an idea about the difference between reverse and redirect, I have tried to search on google about it but there is almost nothing
I don't know what should I write also to convince stack overflow that I don't have any other description
Reverse and redirect have a different meaning. Here is a simple explanation:
reverse in Django is used to find the URL of a given resource. Let's say that you have a blog website and from the main page, you want to provide links to your blog posts. You can of course just hard-code /posts/123/ and just change the ID of your blog post in URL, but that makes it hard to change your URL for the post in the future. That's why Django comes with reverse function. All you need to do is to pass the name of your URL path (defined in your urlpatterns) and Django will find for you the correct URL. It is called reverse because it is a reverse process of determining which view should be called for a given URL (which process is called resolving).
Redirects are not specific to Django or any other web frameworks. Redirect means that for a given URL (or action), the user should be instructed to visit a specific URL. This can be done by sending a special redirect request and from there the browser will handle it for the user, so no user action is required in that process. You can use reverse in redirect process to determine the URL that the user should be redirected to.
GwynBleidD has given you the answer, but there is a reason why you might be getting confused. The Django redirect shortcut accepts arguments in several different forms. One of them is a URLpattern mane, with arguments, that is then passed to reverse to generate the actual URL to redirect to. But that's just a shortcut, to enable a common pattern.
here's an example
app/views
#imports
def indexView(request):
....
return render(request, 'index.html', context)
def loginView(request):
....
return redirect('index')
def articleDetailView(request, id):
....
return redirect(reverse('article-comments', kwargs={'id':id})
def articleCommentsView(request, id):
....
return render(request, 'comment_list.html', context)
proj/urls
#imports
urlpatterns = [
....,
path('', include(app.urls))
]
app/urls
#imports
urlpatterns = [
....,
path('index/', index, name='index'),
path('login/', loginView, name='login'),
path('article/<int:id>/detail', articleDetailView, name='article-detail'),
path('article/<int:id>/comments/',articleCommentsView, name='article-comments')
....,
]
For loginView redirect will return url as-is i.e. 'index' which will be appended to base(project) urlpatterns. Here redirect(reverse('index')) will also work since kwargs is None by default for reverse function and 'index' view doesn't require any kwarg. It returns '/index/' which is passed to redirect(which again will be appended to base urls).
One thing to note is that reverse is used to make complete url - needed for redirect - that is shown in 'articleDetailview'.
The most basic difference between the two is :
Redirect Method will redirect you to a specific route in General.
Reverse Method will return the complete URL to that route as a String.
I know there are a few questions on the topic already but I have tried to implement those solutions and could not really solve my problem.
I am talking about social signup with allauth here, and facebook in particular.
DESIRED BEHAVIOR: after facebook signup I want user to go to my url "accounts:welcome", but when they simply login I want them to go to my LOGIN_REDIRECT_URL (which is the site's home page).
After looking here and there this is the code I came up with (writing my custom adapter)
settings.py:
LOGIN_REDIRECT_URL = ("gamestream:home")
SOCIALACCOUNT_ADAPTER = "myproject.users.adapter.MySocialAccountAdapter"
adapter.py:
from django.conf import settings
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
print('OK11OK')
super().save_user(request, sociallogin, form=form)
return redirect(reverse('accounts:welcome'))
def get_connect_redirect_url(self, request, socialaccount):
print('OK22OK')
assert is_authenticated(request.user)
url = reverse('accounts:welcome')
return url
Please assume that all links/settings are good as for example the console prints out 'OK11OK' when I create myself as a user via the facebook app. The fact is that the method get_connect_redirect_url never gets triggered as I never read 'OK22OK' on the console.
The user is created and I end up on the home page, which is not what I want.
So I thought that after the save_user method something else gets called as I can tell that I pass through accounts:welcome, but then end up on the home page.
I can tell this because if I return an incorrect url in the save_user method I get an error that is specific to that url on that line.
So, what is wrong here?
I think I might be overriding the wrong method but I have read all the code of the base SocialAccountAdapter and I can't see anything else that would be the right choice.
Just wanted to mention that as I have more control on the normal account signup (not social) I have achieved what I wanted.
Any ideas?
Thanks very much!
I had the same problem too, I found two methods:
METHOD 1
Django doesn't use redirection function of the DefaultSocialAccountAdapter, you'll have to override the get_signup_redirect_url function of DefaultAccountAdapter to achieve the result.
First you need to change the default adapter in settings.py:
ACCOUNT_ADAPTER = 'users.adapter.MyAccountAdapter'
Then, just override the get_signup_redirect_url with your url:
# project/users/adapter.py
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_signup_redirect_url(self, request):
return resolve_url('/your/url/')
METHOD 2
This is the easier one
If you take a look at the source code at DefaultAccountAdapter it says:
Returns the default URL to redirect to after logging in. Note
that URLs passed explicitly (e.g. by passing along a next
GET parameter) take precedence over the value returned here.
So, you can pass along a next parameter in your login template to force the redirection. Here is an example using Google social login:
{% load socialaccount %}
{% providers_media_js %}
{# your html tags #}
<body>
SOCIAL LOGIN
</body>
Of course you can personalize the next url (I'm refering to /success/url/) as you wish. You can pass a context variable with your desired url and put it there instead of that hardcoded url.
I'm trying to use the admin login mechanisms in Django, and redirect to the requested page, and I'm getting a 404 as it's trying to redirect to the url posted, not to the url represented by the next parameter. I'm obviously not understanding something, because when I step through the contrib.auth.login view, it's not parsing the next parameter at all. For example, I have the following view (the main page of the site)
#login_required(login_url='/sdc/admin/login')
def cb_index(request):
#snip
return render_to_response('chargeback_base.html', variables)
So when I enter the url for the cb_index view, /sdc/chargeback/, it properly redirects to the login page, with the next variable set to /sdc/chargeback/, as shown below.
http://localhost:8000/sdc/admin/login/?next=/sdc/chargeback/
The default login view though, from contrib.auth.views, uses that complete url as the redirect_to not the next parameter, so I always get a 404 instead of being redirected to the next url. I can fix it by adding
redirect_to = request.GET.get('next','')
to the POST section of the view, but I thought this was supposed to be built in functionality and it's not working. And more to the point, since this is an edit to the base view, I have to remember to fix this every time I update, which I don't want to do. What am I not understanding?
EDIT:
Login url follows the admin site urls
url(r'^sdc/admin/', include(admin.site.urls)),
The login template is the included login template from the admin site, no changes.
The django auth app has a login view, which you should explicitly include in your url patterns directly.
(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
See the docs on auth views for more information. You don't need to choose /accounts/login/ as your login url. I just want to make it clear that this view is separate from the admin app.
Update LOGIN_URL='/accounts/login/' in your settings, then you don't have to use the login_url parameter when you use the login_required decorator.
Currently, /sdc/admin/login/ is handled by the admin app, but the admin app does provide a login view for this purpose. If you step through the code, you can see that the AdminSite.login method handles the request. This method sets REDIRECT_FIELD_NAME (in your case 'next')to the request path, then calls the auth login view.
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.