Overiding URL pattern from a third party app - python

I am using django-registration app and I am implementing the Remember me functionality snippet
Basically, the registration app, needs you to define one URL only,
url(r'^accounts/', include('registration.backends.default.urls')),
under the hood, it defines default urls like /accounts/login, /accounts/logout, each of which points to django.contrib.auth.views functions.
I need to overwrite the login() function, as well as the accompanying URL.
So how do I overwrite URL accounts/login in my urls.py, keeping all the rest urls as default?

Django will use the first URL pattern that matches. So in your urls.py, add a pattern for accounts/login before you include the urls from django-registration. All other URLs will be handled by django-registration.

You could try explicitly catching the accounts/login url request before it hits your more general accounts/* url catcher.
Maybe
# first catch your custom login
url(r'^accounts/login', include('my_custom_login.urls')),
# and everything else beginning with accounts/
url(r'^accounts/', include('registration.backends.default.urls')),

Related

Django URL complicated patterns and paths

I'm trying to generated nested url paths. So far I could only generate 1 level urls. When I try second level urls it doesn't get called anymore, it still only shows the first level url although the address bar on the browser does direct to the second level url. Is this possible or do I need to create a new app?
urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView, TemplateView
from dashboard.models import IPARate,PCPRate
from dashboard import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^medicare/', ListView.as_view(queryset=IPARate.objects.all().order_by("id"), template_name='dashboard/medicare.html')),
url(r'^medicare/medicarepcp/$', ListView.as_view(queryset=PCPRate.objects.all().order_by("id"), template_name='dashboard/medicarepcp.html')),
url(r'^medicare/', views.medicaid, name='medicare'),
url(r'^medicare/medicarepcp/$', views.medicarepcp, name='medicarepcp'),
]
You need to add a dollar (end of line character) to the r'^medicare/ regex, so that it matches /medicare/ but not other URLs like medicare/medicarepcp/.
url(r'^medicare/$', ListView.as_view(queryset=IPARate.objects.all().order_by("id"), template_name='dashboard/medicare.html')),
url(r'^medicare/medicarepcp/$', ListView.as_view(queryset=PCPRate.objects.all().order_by("id"), template_name='dashboard/medicarepcp.html')),
The third and the fourth regexes are the same as the first and the second respectively. Django will always match the first two URL patterns, so you need to change the third and fourth URL patterns to something else.
The order of URLs is important, as Django will react to the first URL pattern that matches the request. A good habit is to put all of your "sub" URLs first, then the top level of that section last, so it works as a fall-back if no others match (i.e. put your '^medicare/$' last).

Django: admin login with parameter

I want to have my custom "/login" page. So in settings.py I did a simple LOGIN_URL = '/login'. But before doing it, I want to develop all other more complex pages. I found a simple but very effective hack like this:
urlpatterns = [
# blabla
url(r'^admin/', include(admin.site.urls)),
url(r'^login/$', RedirectView.as_view(
url=reverse_lazy('admin:login'))),
# blabla
]
This means: when the user is not connected he/she is redirected to /login. In the urls, /login is converted to 'admin:login' which is admin/login. This is a "double" redirect. Everthing works fine except this:
origin URL: "/my_jobs"
redirected to "login?next=/my_jobs"
redirected to "/admin/login"
So my problem is that I want do pass again the "next" parameter in the RedirectView. I found a lot about redirection and custom login, but not something about that on stackoverflow (this is not a duplicate).
You can set query_string to True, so that query strings are appended to the URL.
RedirectView(
url=reverse_lazy('admin:login'),
query_string=True,
# You might want to set permanent=False,
# as it defaults to True for Django < 1.9
permanent=False,
)
Note that Django comes with a built in login view. You can enable it by adding the URL pattern and a simple template, which isn't much more work than your code above.

django-allauth, how can I only allow signup/login through social?

I only want to allow people to sign up or log in with their social account. I have the social sign up and log in working, but I cant figure out how to disable the local sign up.
I've read the docs and this sounds close to what I want
ACCOUNT_FORMS (={})
Used to override forms, for example: {‘login’: ‘myapp.forms.LoginForm’}
It seems like I can make a new sign up form and only include the social log in link, but I was hoping there is any easier way that I'm overlooking. I'm still new to this all so I tend to miss the obvious a lot still.
I also tried changing the code below to False, but that disabled social sign up as well.
allauth.account.adapter.py
def is_open_for_signup(self, request):
"""
Checks whether or not the site is open for signups.
Next to simply returning True/False you can also intervene the
regular flow by raising an ImmediateHttpResponse
"""
return True
Change templates and urlpatterns
You would have to change both the templates (login, signup, etc.) and urlpatterns provided by allauth by default, which relate to the classic signup/login flow using email.
Changing/reducing the available routes via the urlpatterns ensures that only the routes are available that should be there. HTTP error 404 is then shown for any attempt to hack into existing allauth default functionality (related to email) if you do it right.
Changing the templates can ensure that the user interface does not provide what is related to email-based authentication.
No easy option available
Unfortunately, as of today there is no easy switch or setting to simply disable email-based signup and authentication with django-allauth. More details may be on GitHub in future, see:
Issue #1227 ("Social only: disable all local account handling by means of a simple setting")
Issue #345 ("How to disable form login/signup?")
Sample: urls.py
An urls.py like this will work with the current django-allauth (v0.30.0) on Django 1.10:
from django.conf.urls import include, url
from allauth.account.views import confirm_email, login, logout
from allauth.compat import importlib
from allauth.socialaccount import providers
providers_urlpatterns = []
for provider in providers.registry.get_list():
prov_mod = importlib.import_module(provider.get_package() + '.urls')
providers_urlpatterns += getattr(prov_mod, 'urlpatterns', [])
urlpatterns = [
url(r'^auth/', include(providers_urlpatterns)),
url(r'^confirm-email/(?P<key>[-:\w]+)/$', confirm_email, name='account_confirm_email'),
url(r'^login/$', login, name='account_login'),
url(r'^logout/$', logout, name='account_logout'),
url(r'^signup/$', login, name='account_signup'), # disable email signup
]
The solution wasn't what I originally thought. The much easier way to do this, instead of changing the forms, was to change the template and just remove any other options in that template.
My page now correctly only shows social auth and I am happy.
If anyone has a better or more secure answer I'd be open to it. Being new still, I don't know if this is the best solution, but for now it seems great and will mark as answered.
Ok, here is the thing. If you are not using any social account to link to your users, then it's very simple to finish the task you described by simply only include urls you need. However, if you need to use social account to link your users, then you have to include all urls because most third party application will not certify the request from your app. they only accept request from allauth.
from django.urls import path, re_path
from allauth.account import views as accountviews
urlpatterns = [
path('admin/', admin.site.urls),
# remember to comment out the following line since it will
# include all urls from allauth lib
# path('accounts/', include('allauth.urls'))
]
# assume you only want singup page and login page from allauth
urlpatterns += [path("acc/signup/", accountviews.signup, name="account_signup"),
path("acc/login/", accountviews.login, name="account_login")
]

Django Rest Framework Reversing URL

I have two files, one containing the URL like this
url(r'^users/', include('api_manager.users_urls', namespace='user'))
in second URL file i have this:
url(r'^', users_views.UsersList.as_view(), name='index')
When i hit the URL localhost:8000/api/users/ It redirect me to view 'UserList' and here i am using reverse function
reverse("user:index")
it returns me the /apiusers/ instead of /api/users/
Please let me know what is wrong in it.
I have resolved the issue, i find out that i am using api/* in my parent URL file, i just remove the '*' and reverse function returning the /api/users/
:)

Support old and new URI versions both working without breaking the reverse()

How can I support old and new URI versions both working without breaking the reverse()?
For example, I have:
urlpatterns = patterns('',
url(r'^(old_part|new_part)/other/$', 'some_view'),
)
In this case /old_part/other/ and /new_part/other/ point to the same view but reverse() method fails because it doesn't know how to form link properly.
Also, what if we have url(r'^(old_part|new_part)/other/', include(sub_patterns)) how can it be handled?
Do you have any ideas?
Thanks for your help.
I suppose you are migrating. This means you don't want old url work, you want it to redirect to new url. Probably with 301 HTTP code (permanent redirect).
Having several urls for same content makes your site harder to use and hurts your SEO. Permanent redirect will tell Google and any other search engine to reindex page with new address.
You can do it this way in Django:
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^new_part/other/$', 'some_view'),
url(r'^old_part/other/$',
RedirectView.as_view(url='new_part/other/', permanent=True)),
)
If you need to capture everything with a subpath, you can capture url ending and add it to redirect url this way:
urlpatterns = patterns('',
url(r'^new_part/other/$', include(sub_patterns)),
url(r'^old_part/other/(?P<rest>.*)$',
RedirectView.as_view(url='new_part/other/%(rest)s', permanent=True)),
)
You can use redirect_to generic view in Django 1.4 and earlier.
If you want without a redirect, you could try this
url(r'^(?P<url>old_part|new_part)/other/$', 'some_view', name='some_view'),
Then your view will look like this
def some_view(request, url):
...
Then call reverse like this:
# will return /old_part/other/
reverse('some_view', kwargs={'url': 'old_part'})
# will return /new_part/other/
reverse('some_view', kwargs={'url': 'new_part'})
Just redirect the old urls to the new ones (with a 301 Moved Permanently).
NB : if you really insist on supporting both sets of urls (not a good idea IMHO), you'll have to have two distinct url patterns, and choose which one reverse() should resolve to.

Categories