Django url dispatcher uses strings to specify function, why? - django

The Django documentation shows examples like this:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
]
However, I have seen some code that looks like this:
from django.conf.urls import url
urlpatterns = [
url(r'^articles/2003/$', 'myapp.views.special_case_2003'),
]
Where special_case_2003 is the name of a function in myapp/views.py.
What is the difference between these two approaches?

urlpatterns = [
url(r'^articles/2003/$', 'myapp.views.special_case_2003'),
]
Code like this is out of date. Providing the view as a string like this is deprecated in Django 1.8, and does not work in Django 1.10+. In Django 1.10+, you must use the callable.

Related

Replacing default forms in django-postman via urlpatterns and views

django-postman docs say that you can replace the default forms in views with this:
urlpatterns = patterns('postman.views',
# ...
url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
)
But what is patterns? Where do I import that from, and where would this code go? In the project's urls.py?
My project level urls.py currently includes django-postman, as recommended in the docs, like this:
urlpatterns = [
...
url("r'messages/', include('postman.urls', namespace='postman'),
]
So the custom url pattern should be overwriting the default that will already be included in urls.py.
Yes, this is a code for urls.py. However, it's quite outdated.
The modern version would look like:
from django.urls import re_path
urlpatterns = [
re_path(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
]
Edit
I guess you're including postman urls in your root urls.py, then you can do something like this to overwrite one of them:
urlpatterns = [
...
re_path(r'^messages/write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
path('messages/', include('postman.urls')),
]

Building URL from name

I've got a url of 'accounts:produce_setup' (i.e. namespace/app is 'accounts' and name of url is 'product_setup'). I'd like to build the full url associated with this view and pass it as context into a template.
How would I go about doing this? Would I use build_absolute_uri()?
Thanks!
you should include your app in project_name/urls.py and bind your application to special URL pattern like this:
from account.urls import urlpatterns as account_urlpatterns
urlpatterns = [
url(r'^account/', include(account_urlpatterns, namespace='account')),
url(r'^admin/', admin.site.urls),
]
and after this in your account/urls.py you can implement your urlpatterns and set your special name for each url like this:
from django.conf.urls import url
from .views import produce_setup_view
urlpatterns = [
url(r'^produce_setup/$', produce_setup_view, name='produce_setup')),
]
at the end now you can use them in your template and views or any python file in your django project like this:
.py in django project:
from django.urls import reverse
url_string = reverse('account:produce_setup')
print(url_string)
>>> '/account/produce_setup/'
in template:
Good Luck :)
Actually, you don't need to. You can simply use {% url "accounts:product_setup" %} in template. For more details check here. And if you want to build the url is views(maybe for other reasons) you can use reverse.

adding a static html page to Django project

I'm new to Django and web coding.
I'm following Bucky tuts: Django Tutorial for Beginners - 28 - Creating a Base Template.
I thought of viewing the template page when requested ( PATH/templates/music/base.html ) but I don't know how to do it.
I searched to find that I could put something like this in urls to make it work :
path('base', 'django.views.generic.simple.direct_to_template', {'music/templates/music': 'base.html'}),
but didn't work.
How should I do it?
Did you try this code that is shown in the docs ?
from django.urls import path, url
from django.views.generic import TemplateView
# django 2.0
urlpatterns = [
path('about/', TemplateView.as_view(template_name="about.html")),
]
# django 1.11 and prior
urlpatterns = [
url(r'^about/$', TemplateView.as_view(template_name="about.html")),
]

How to register DRF router url patterns in django 2

My DRF routers specify a namespace so that I can reverse my urls:
urls.py:
router = DefaultRouter()
router.register('widget/', MyWidgetViewSet, base_name='widgets')
urlpatterns =+ [
url(r'/path/to/API/', include(router.urls, namespace='widget-api'),
]
Which, when upgrading to django 2, gives:
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
Django 2 now requires app_name if the namespace kwarg is specified when using include. What's the right way to specify app_name when the url patterns are constructed by a DRF url router? I don't think the documentation is up-to-date for django 2 on this subject.
You need to put app_name = 'x' in your application's url.py file. This is a little buried in the documentation:
https://docs.djangoproject.com/en/2.0/topics/http/urls/#id5
For example, if in /project/project/urls.py you have:
path('', include('app.urls', namespace='app'))
Then in the corresponding url file (in /project/app/urls.py) you need to specify the app_name parameter with:
app_name = 'app' #the weird code
urlpatterns = [
path('', views.index, name = 'index'), #this can be anything
]
It's just necessary to use '{basename}-list' in reverse function.
In your case, it's going to be: reverse('widgets-list')
You need to include the router.urls as a tuple and add the app name to the tuple instead of only include router.urls
According to your example you should try with something like:
router = DefaultRouter()
router.register('widget/', MyWidgetViewSet, base_name='widgets')
urlpatterns =+ [
url(r'/path/to/API/', include((router.urls, 'my_app_name'), namespace='widget-api'),
]
The recommended approach is
from django.conf.urls import url, include
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'widget/', MyWidgetViewSet)
urlpatterns = [
url(r'^path/to/API/', include('rest_framework.urls', namespace='widget-api'))
]
See http://www.tomchristie.com/rest-framework-2-docs/tutorial/quickstart#urls

What's wrong with my urls.py?

I'm trying Django 1.11 and I have an issue :
This my file agora/agora/urls.py :
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^start/', include('start.urls', namespace='start')),
]
And this is my file agora/start/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', view_first, name='view_first'),
url(r'^/inscription', view_second, name='view_second'),
url(r'^/about', view_about, name='view_about'),
]
The Django server return an error :
NameError: name 'view_first' is not defined
Many thanks for your answers !
You should do like this for all functions
views.view_first
views.view_second
....
you have to specify the function name in the import statement
from django.conf.urls import url
from .views import view_first, view_second, view_about
urlpatterns = [
url(r'^$', view_first, name='view_first'),
url(r'^/inscription', view_second, name='view_second'),
url(r'^/about', view_about, name='view_about'),
]
or import the view and assign each function with view.
from django.conf.urls import url
from . import view
urlpatterns = [
url(r'^$', view.view_first, name='view_first'),
url(r'^/inscription', view.view_second, name='view_second'),
url(r'^/about', view.view_about, name='view_about'),
]
Although, the question has already been answered, I did happen to notice a minor but mistake.
When writing urls, adding "$" sign at the end of the endpoint is always recommended. Not adding the same may cause overlapping of similar urls which could confuse the app behaviour and even can cause some serious errors.
The dollar sign marks the end of the url string.
Just a heads up!!