What is the third argument for in Django url patterns? - python

I am new to Django and I am trying to understand it. If I write a url pattern like this
url(r'^$', 'newsletter.views.home', name='home'),
it works. and If I write it like this
url(r'^$', 'newsletter.views.home'),
it still works, but I get the following data from the server
RemovedInDjango110Warning: Support for string view arguments to url() is deprecated and will be removed in Django 1.10 (got newsletter.views.contact). Pass the callable instead.
url(r'^contact/$', 'newsletter.views.contact'),
My first question is what does the third argument do. the
name='home' or name='contact'. What is it reffering to.
and my second question is what does
Pass the callable instead.
mean? Again, I have read the docs and came here for a bit more clarity in laymen's terms. All help and advice is welcome

When it says pass the callable, it means you should import the view itself and include that in your url pattern.
from newsletter.views import home
url(r'^$', home, name='home'),
Another option is to import the views module itself
# renaming allows us to import more than one views at once
from newsletter import views as newsletter_views
url(r'^$', newsletter_views.home, name='home'),
Naming url patterns allows you to reverse url patterns (e.g. go from a name to a url). This means you don't have to hardcode urls in your views and templates.
If you have
url(r'^home/$', home, name='home'),
then you can use reverse('home') in your code, and {% url 'home' %} in your templates, instead of writing /home/ repeatedly.

Related

Unable to resolve URL string for path using name with reverse

I have been spending the better part of my week learning Django to build my website and I've stumbled upon an issue I can't seem to get working. I wish to resolve a URL string for a path by including with that path a particular name and then being able to reference that name down the line. This works fine until I change the route in path to use the include method.
First Attempt:
from django.url import include, path
from . import views
urlpatterns = [
path('testapp/', include('testapp.urls'), name='testapp'),
path('about/', views.about, name='about'),
]
Now when I call {% url 'about' %} from my template html file I get back '/about/' as expected but when I try and call {% url 'testapp' %} I get a NoReverseMatch exception instead of getting '/testapp/'. After digging through the documentation I stumbled upon this example that shows path with include using a namespace instead so I adapted the above a bit.
Second Attempt:
# from mysite/urls.py (adapted from before)
from django.url import include, path
from . import views
urlpatterns = [
path('testapp/', include('testapp.urls', namespace='testapp')),
path('about/', views.about, name='about'),
]
#from testapp/urls.py
from django.url import include, path
from . import views
app_name = 'testapp_name'
urlpatterns = [
path('', views.index, name='testapp_index'),
path('directory/', views.directory, name='testapp_directory'),
]
Now from the previous example I try using the namespace in lieu of a name {% url 'testapp' %} and I again get the same NoReverseMatch exception however using the namespace and name from my included url {% url 'testapp:directory' %} does work giving me '/testapp/directory/'.
I know there's some concept I'm not getting or something I'm overlooking but I'm just running around in circles at this point and would really appreciate any help somebody could afford me.
If it helps I'm trying to get the path so that I can use it in a navigation bar to highlight the currently activated tab. I'm also not hardcoding the paths as I'm trying to keep it DRY although at this point if I can't get it done I might have to but I'm hoping someone has a much better idea of what they're doing and could point me in a helpful direction. I appreciate all assistance and thank you!
The problem is that testapp is not a single view: it is an include(..), so it encapsulates a collection of views:
from django.url import include, path
from . import views
urlpatterns = [
path('testapp/', include('testapp.urls'), name='testapp'),
path('about/', views.about, name='about'),
]
It is not said that this collection contains a view at all, or it can contain multiple. Even if it only contains a single view, then it would be unsafe since you can later change your mind, and add an extra view.
If there are two or more views, then how will you decide what view (and therefore URL) to take? If the include(..) has two views: the "homepage" and the profile page, then this makes a significant difference.
You thus should refer to a real name, and whether you give the include(..) a namespace in the include(..) is irrelevant:
{% url 'testapp_name:testapp_index' %} <!-- first attempt -->
{% url 'testapp:testapp_index' %} <!-- second attempt -->
To reference the name of a real view.
{% url 'testapp_name:testapp_index' %}
or
{% url 'testapp_name:testapp_directory' %}
as you are using app_name in the urls file, you need to mention it with the name of the view

Is it better to use path() or url() in urls.py for django 2.0?

In a django online course, the instructor has us use the url() function to call views and utilize regular expressions in the urlpatterns list. I've seen other examples on youtube of this.
e.g.
from django.contrib import admin
from django.urls import include
from django.conf.urls import url
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^polls/', include('polls.urls')),
]
#and in polls/urls.py
urlpatterns = [
url(r'^$', views.index, name="index"),
]
However, in going through the Django tutorial, they use path() instead e.g.:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name="index"),
]
Furthermore regular expressions don't seem to work with the path() function as using a path(r'^$', views.index, name="index") won't find the mysite.com/polls/ view.
Is using path() without regex matching the proper way going forward? Is url() more powerful but more complicated so they're using path() to start us out with? Or is it a case of different tools for different jobs?
From Django documentation for url
url(regex, view, kwargs=None, name=None) This function
is an alias to django.urls.re_path(). It’s likely to be deprecated in
a future release.
Key difference between path and re_path is that path uses route without regex
You can use re_path for complex regex calls and use just path for simpler lookups
The new django.urls.path() function allows a simpler, more readable URL routing syntax. For example, this example from previous Django releases:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive)
could be written as:
path('articles/<int:year>/', views.year_archive)
The django.conf.urls.url() function from previous versions is now available as django.urls.re_path(). The old location remains for backwards compatibility, without an imminent deprecation. The old django.conf.urls.include() function is now importable from django.urls so you can use:
from django.urls import include, path, re_path
in the URLconfs. For further reading django doc
path is simply new in Django 2.0, which was only released a couple of weeks ago. Most tutorials won't have been updated for the new syntax.
It was certainly supposed to be a simpler way of doing things; I wouldn't say that URL is more powerful though, you should be able to express patterns in either format.
Regular expressions don't seem to work with the path() function with the following arguments: path(r'^$', views.index, name="index").
It should be like this: path('', views.index, name="index").
The 1st argument must be blank to enter a regular expression.
Path is a new feature of Django 2.0.
Explained here :
https://docs.djangoproject.com/en/2.0/releases/2.0/#whats-new-2-0
Look like more pythonic way, and enable to not use regular expression in argument you pass to view... you can ue int() function for exemple.
From v2.0 many users are using path, but we can use either path or url.
For example in django 2.1.1
mapping to functions through url can be done as follows
from django.contrib import admin
from django.urls import path
from django.contrib.auth import login
from posts.views import post_home
from django.conf.urls import url
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^posts/$', post_home, name='post_home'),
]
where posts is an application & post_home is a function in views.py

Django: point url behind root of app?

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!

In Django, how can I understand include() function?

I have started learning Django, I'm not sure what the include() function means.
Here is mysite/urls.py. - project
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
Here is polls/urls.py. - app in project
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
From django document, include() function was described as follows.
Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing.
I'm not sure what is that point, what is remaining string.
In case of the example above, what is remining string, what is url strings which was chopped off?
For example, from this URL:
polls/5/results
the URL rule:
url(r'^polls/', include('polls.urls')),
chops off the polls/ part of URL and sends the remaining string after polls/, whatever it might be, for example (see here more):
5/results/
to urls from the poll app's urls.py, where it will then be mapped to a view based on the URL rules defined in this file
Whenever it will encounter any url with /polls then it will include all the urls of polls app.
Example:
If you type /polls/hey
Then as soon as it sees /polls it will go to polls urls file and later it will search for:
hey/ matching over there.
Lets say there is one more entry in your polls/urls.py like
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
here year is the query string parameter. so your url will look like
/polls/articles/2007 so in this case /polls/articles/ will matched up and 2007 will pass to year_archive method
In your example there is no chopped string, the URL comes back as simply polls/, but when you have another url such as '^new$' then that url is being chopped, merged with polls/ and it returns polls/new, hope this makes sense..

string as second argument in url dispatcher for CBV

Before class based views my urls.py looked like that:
urlpatterns= patterns('mypackage.views',
url(r'^$', 'home', name='home'),
url(r'other', name='other'),
)
Now my home view is class based. As i like uniformity, I do not would like to keep the view class as string. I tried:
urlpatterns= patterns('mypackage.views',
url(r'^$', 'Home.as_view', name='home'),
url(r'Other.as_view', name='other'),
)
and I get Parent module mypackage.views.Home does not exist . If I simply give the class name like:
urlpatterns= patterns('mypackage.views',
url(r'^$', 'Home', name='home'),
url(r'Other', name='other'),
)
I get: __init__ takes exactly 1 argument, 2 given
Is there a way to pass a string as second argument to the url function for CBV as for FBV instead of from mypackage.views import * ?
EDIT:
There seems to be no built-in solution for this. In this case: why are strings as second parameter allowed for the url function: Doesn't it violate the zen ("there is only one way to do this)?
You should import the class-based view and specify them that way:
from mypackage.views import *
urlpatterns = patterns('mypackage.views',
url(r'^$', Home.as_view(), name='home'),
url(r'other', Other.as_view() name='other'),
)
Also note that your url() calls should have three parameters: the URL pattern, the view and name (some examples you wrote don't have all of these).
If you want to pass your view as string, then in your views do this:
class Home(View):
pass
home = Home.as_view()
then in your url:
url(r'^$', 'mypackage.views.home', name='home'),
You need to use full path.

Categories

Resources