I am having trouble understanding the following warning. I have a namespace called "v1" and I am using these namespaces to determine versioning in my API (using django rest framework). So, I have paths like these:
/v1/accounts/me
/v1/listings
Here is the URLs configuration (project/urls.py):
urlpatterns = [
path('admin/', admin.site.urls),
path('v1/accounts/', include('accounts.urls', namespace='v1')),
path('v1/listings/', include('listings.urls', namespace='v1'))
]
accounts/urls.py
app_name = 'accounts'
urlpatterns = [
url(r'^token/$', views.obtain_auth_token, name='obtain_token'),
url(r'^me/$', my_account, name='my_account'),
]
listings/urls.py
app_name = 'listings'
urlpatterns = [
path('', recent_listings, name='recent_listings')
]
Everything works as expected. All urls are dispatched. Versioning works. However, I keep getting the following error:
?: (urls.W005) URL namespace 'v1' isn't unique. You may not be able to reverse all URLs in this namespace
I know it is a warning and I might be able to suppress it; however, I want to understand why this is happening. Based on my URLconf and this warning, it seems like there cannot be multiple namespaced paths as "siblings." They need to be children of one namespaced path (e.g "v1"). If my understanding is correct, how am I supposed to create this URL configuration.
Basically what happens is that, namespace plays a significant role on reverse finding the url. For example:
In your example reverse('v1:obtain_token') will return /v1/accounts/token/. Lets say you have two urls with same name in accounts and listings, then you might not be able to find accounts url in reverse query. That is why the warning is for. Better if you use different namespaces for each include. In you case, it should be:
path('v1/accounts/', include('accounts.urls', namespace='accounts')),
path('v1/listings/', include('listings.urls', namespace='listings'))
Please read the documentations for more details.
Update
you can do the versioning like this:
path('accounts/', include('accounts.urls', namespace='accounts')), # accounts url
inside accounts app:
path('v1/token/', views.obtain_auth_token, name='obtain_token_v1'),
path('v2/token/', views.obtain_auth_token2, name='obtain_token_v2'),
...
Related
My code is not working, and I am not sure why.
I have the problem with hours_ahead function.
Here is urlpatterns path('time/plus/(\d{1,2})/', hours_ahead),
And I imported hours_ahead too
One of these may work
In your urls.py add something like:
urlpatterns = [
path('admin/', admin.site.urls),
path('hours/<int:offset>/', hours_ahead)
]
the "int:offset" is a way of saying what is the parameter you are going to receive and the type.
in settings.py add:
INSTALLED_APPS = [ # careful to not create another INSTALLED_APPS,add the app to the list!
# ...
'playground'
]
Also, I got this error on my terminal:
CommandError: 'playgrounds' conflicts with the name of an existing Python module and cannot be used as an app name. Please try another name.
I could not run the code until I created and app with another name.
I have a url path in urls.py:
urlpatterns = [
...
url(r'^accounts/', include('allauth.urls')),
...
]
but the url will show: unresolved reference 'url'. Did I miss something to import?
As of Django 2 url() was replaced with path() and re_path(). If you are not using Django 1, you can update your code to use path().
from django.urls import path, include
urlpatterns = [
path('accounts/', include('allauth.urls')),
]
For matching a path with RegEx like the Django 1 url() function you can use re_path() like this...
from django.urls import path, include
urlpatterns = [
re_path(r'^accounts/', include('allauth.urls')),
]
However, because of how simple the path you are trying to match is, I would recommend using path(). It saves to overhead of performing a regular expression match. Use path() over re_path() as much as possible.
You can read more on the official Django documentation. See links below.
Django 3 Documentation
Old Django 1 Documentation
You may be using Django 2.x
For django-1.x, you can not use such path(..)s, and in that case you need to write a regular expression, like:
url(r'^complete/(?P<todo_id>[0-9]+)$', views.completeTodo, name='complete'),
If you are using django-2.x, you probably want to use path(..), like you have.
I believe it may be to do with how you've set up your regex.
For urls, instead of this:
url('complete/<todo_id>', views.completeTodo, name='complete'),
try this:
url(r'^complete/(?P<todo_id>\d+)$', views.completeTodo, name='complete'),
Or incase you want to use [path]
path('complete/<int:todo_id>', views.completeTodo, name='complete'),
I am going through Django's tutorials (Django tutorial part 3) and I am at the part where we are adding views and urls.
In this demo app they add subviews for polls, e.g. /polls/34/ to get to the 34th poll. Quoting from the tutorial:
When somebody requests a page from your website – say, “/polls/34/”, Django will load the mysite.urls Python module because it’s pointed to by the ROOT_URLCONF setting. It finds the variable named urlpatterns and traverses the regular expressions in order. After finding the match at '^polls/', it strips off the matching text ("polls/") and sends the remaining text – "34/" – to the ‘polls.urls’ URLconf for further processing. There it matches r'^(?P<question_id>[0-9]+)/$', resulting in a call to the detail() view like so:
My question is as follows:
suppose you have a view that is related to your app, but where the url - prepended by the app name - makes less sense than just the new view by itself. How could you make a view (which is part of the app) start at a new path name.
This might be confusing so here is an example.
Suppose you have an app (decks) for decks users make out of a set of cards. Then /deck/regex would take you to a given deck. If someone wanted to see more information about a card in the deck then /decks/cards/regex makes less sense then /cards/regex as a card can be in multiple decks.
It isn't a perfect example, but I think it highlights what I am trying to do.
I had some type of URL for you:
1st:
# The url in Projects, which you have to include to link your app.
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^table/', include('table.urls')),
]
This upper case is your code now:
# So you can change is to:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('table.urls',namespace="table")),
]
And then: in tables.urls.py you can do what ever you want:
urlpatterns = [ url(r'^$', views.index, name='index'),
url(r'^decks/(?P<pk>.*)$', views.decksView, name='decksView'),
url(r'^card/(?P<pk>.*)$', views.cardView, name='cardView'),
]
What you are saying can easily be done but it is not done so because it causes a lot of confusion with regards to routing.
Talking about your decks example. Lets say you are in an app called decks, where root urls.py file is this :
from django.conf.urls import url,include
from django.contrib import admin
from Decks import views as deckviews
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'/cards/regex^$',deckviews.get_card_information),
url(r'^decks/',include('deckviews.urls')),
]
and the urls.py in Decks app can be:
from django.conf.urls import url,include
import views
urlpatterns = [
url(r'^regex/',views.generate_decks)
]
Here is an example where to generate decks, the decks/regex calls the generate random decks from within the urls.py of the decks app meanwhile you get your desired cards/regex which points to the views inside the decks app but still has the url that you wish for.
This ways you can route any url to any function and thats the beauty of django. This is rarely used though as it creates a lot of confusion when the apps get bigger and more complex.
Hope this helps. Cheers!
I am trying to learn Django and I am currently stuck in an issue.
I created an app Contact and run the server, I get the error.
The error page displayed by server:
The urls.py file in the app Contact
urls.py in conatct
When the pattern in urls.py is
urlpatterns =[url(r'^$', views.form, name ='form')]
it works properly, but not with other pattern shown in the picture
Your help would be greatly appreciated.
The Page not found error message tells you what went wrong: For the URL (/contact) you requested, Django was unable to find a suitable view. Because you have debugging enabled, you get some information, including a list of registered views.
First things first: You probably have url(r'^contact/', include('contact.urls')) somewhere in your top level urls.py. This makes the URLs defined in the contact/urls.py available under the prefix /contact.
With
urlpatterns = [
url(r'^form/', views.form, name='form'),
]
in contact/urls.py you are telling Django that you want urls starting with contact/form/ to be handled by views.form.
Consequently, when you access http://localhost:8000/contact/ in your browser, there is no view associated with that URL, hence the 404. Your view is reacting to to http://localhost:8000/contact/form, not http://localhost:8000/contact.
When you change the URL pattern to
urlpatterns = [
url(r'^$', views.form, name='form'),
]
you modify the URL views.form reacts to.
I'm currently using the following urls.py:
api_patterns = [
url(r'^users/', include('users.urls', namespace='user')),
]
internal_patterns = [
# ...
]
urlpatterns = [
url(r'^api/', include(api_patterns)),
url(r'^internal/', include(internal_patterns)),
url(r'^admin/', include(admin.site.urls)),
url(r'^(?!(?:api|internal|admin)/)', MainView.as_view()),
]
The point of this config is to render MainView if url doesn't have the api, internal or admin prefix:
/api/users/... — found
/api/foo/ — not found
/foo/ — found
How can I make it simplier and more intent revealing?
I think your intent will be more clear if you do this in two urls:
url(r'^(api|internal|admin)/', SomeView.as_view()),
url(r'^.*', MainView.as_view())
MainView will be executed only if a url does not begin with api, internal or admin.
SomeView will be executed if a url begins with api/internal/admin but doesn't match the patterns above it. You can customize this view to either return a default 404 page, or perform other functions as you need.
Using your examples:
/api/users will execute include(api_patterns)
/api/foo will execute SomeView
/foo will execute MainView
Edit
To address the first point in your comment: url patterns are regexes, while you can extract these into variables to remove duplication, it can make code hard to read. Here's one example for removing duplication (I'm sure you can come up with others):
d = OrderedDict([
(r'api', api_patterns),
(r'internal', internal_patterns),
(r'admin', admin.site.urls),
])
main_view_re = r'^!({})/'.format('|'.join(d.keys()))
urlpatterns = [url(r'^{}/'.format(k), include(v)) for k, v in d]
urlpatterns.append(url(main_view_re, MainView.as_view()))
For django >= 3 rather use re_path:
from django.urls import re_path
urlpatterns = [
re_path(r'^.*',MainView.as_view())
]
urlpatterns = [
url(r'^api/', include(api_patterns)),
url(r'^internal/', include(internal_patterns)),
url(r'^admin/', include(admin.site.urls)),
url(r'', MainView.as_view()),
]
Leaving no prefix would allow you to catch any URL that a user might try after the URL conf matches the api, internal and admin url's.