Url
Obsah stránky (hide)
1. URL Dispatcher
Web ovládaný Djangem je propojený odkazy ve formě URL. Každé takové URL ukazuje na konkrétní funkci a pod. ve vrstvě view. Tyto vazby jsou nastaveny v souboru urls.py
, který je v adresáři projektu vedle settings.py
, kde je zase parametr ROOT_URLCONF
, který ve výchozím nastavení ukazuje právě na tento urls.py
(což znamená, že si to můžeme změnit).
1.1 Úvodní příklad
Příklad souboru urls.py
:
from django.conf.urls import patters, url, include urlpatterns = patterns('', url(r'^$', 'myapp.views.index'), url(r'^contacts/$', 'myapp.views.contacts'), url(r'^contacts/(\d)/, 'myapp.views.contacts_show'), ) urlpatterns += patterns('objednavky.views', url(r'^objednavky/$', 'objednavky'), url(r'^objednavky/firma/(\d)/', 'obj_firma'), url(r'^objednavky/fakt/(?P<firma>\d)/(?P<rok>\d{4}), 'obj_firma_prehled'), ) urlpatterns += patterns('', url(r'^sklad/$', include('sklady.urls')), )
Vše potřebné má Django v modulu django.conf.urls
. Vytvoříme proměnnou urlpatterns
pomocí funkce Djanga patterns()
. Ta bere jako argument n-tici. První položka v n-tici je tzv. prefix (viz dále). Následují položky vytvořené funkcí url()
, jejíž prvním argumentem je regulární výraz popisující url adresu. Druhým argumentem je název funkce, která se má spustit.
Django prohledává n-tici postupně. Jakmile narazí na shodu url, zavolá funkci z druhého parametru a předá jí argumenty. Prvním argumentem je vždy request
(slovník obsahující obvyklé http náležitosti jako jsou GET, POST, session,...). Ten je vkládán automaticky Djangem. Další argumenty mohou být přímo v url. Je možné přidat i další paramter slovník s dalšími proměnnými, které budou příslušené view funkci předány.
Pro přehlednost můžeme urlpatterns
plnit postupně a oddělit tak od sebe logické části našeho webu. Jak je to v ukázce výše.
V první části
urlpatterns = patterns('', url(r'^$', 'myapp.views.index'), url(r'^contacts/$', 'myapp.views.contacts'), url(r'^contacts/(\d)/, 'myapp.views.contacts_show'), )
je prefix prázdný. Následuje řádek s prázdným regulárním výrazem - odkazuje na kořenovou adresu webu (http://www.example.com/
) - tedy, kde za lomítkem už nic nenásleduje. V tomto případě se bude volat funkce index(request)
ze souboru views.py
, který je v adresáři aplikace myapp
.
Druhý řádek obsahuje url contacts/
a zavolá se funkce contacts
. Znak $ v regulárním výrazu znamená, že url musí obsahovat právě jen ono contacts/
a už nic za tím.
Třetímu řádku bude odpovídat např http://www.example.com/contacts/249/
. Všimněme si, že znak $ schází, takže tento řádek spolkne i všechno, co by za číslem a lomítkem ještě pokračovalo dále. Tento "ocásek" by byl ale ignorován.
U tohoto řádku bude volána funkce contacts_show
a kromě parametru request
jí bude předán i poziční parametr s číslem (zde 249). Příslušná funkce ve view.py by vypadala takto:
def contacts_show(request, partner_no):
Číslo by bylo předáno do proměnné partner_no
.
- Čísla jsou předávána vždy jako typ string. O konverzi na int, float apod se musíme postarat sami.
- Parametry v url musí být v kulatých závorkách, aby je Django poznalo.
- Úvodní lomítko z URL do vzoru nepíšeme - je automatické, protože je v URL vždy. (r'neco/', nikoliv r'/neco/').
Ve druhé části příkladu
urlpatterns += patterns('objednavky.views', url(r'^objednavky/$', 'objednavky'), url(r'^objednavky/firma/(\d)/', 'obj_firma'), url(r'^objednavky/fakt/(?P<firma>\d)/(?P<rok>\d{4}), 'obj_firma_prehled'), )
Vidíme, že prefix není prázdný, ale obsahuje objednavky.views
. To je vlastně jakési vytknutí před závorku, které jsme mohli využít už v první části příkladu, kdybycho do prefixu dali myapp.views
. Pak bychom odkazy na fuknce mohli zkrátit právě o tento prefix na index
, contacts
a contacts_show
. V druhé části tedy prefix ukazuje na soubor views.py
z aplikace objednavky
). Pokud bychom prefix nevyužili, volali bychom v prvním řádku objednavky.views.objednavky
místo pouhého objednavky
.
Všimněme si, že ve druhém řádku předáváme opět číselný parametr.
Ve třetím řádku rovněž předáváme parametry, tentokrát ale ne pozičním stylem, ale jako klíčové argumenty (pojmenované). U posledního paramteru rok
je ve složených závorkách uvedena požadovaná délka čísla. Příslušná funkce ve views.py
by byla například takováto:
def obj_firma_prehled(request, firma="1", rok="2000"):
Pro jistotu můžeme vkládat defaultní hodnoty.
Třetí část příkladu
urlpatterns += patterns('', url(r'^sklad/', include('sklady.urls')), )
ukazuje možnost, že aplikace sklady
má svůj vlastní soubor urls.py
, který je sem, do hlavního urlpatterns
vložen právě funkcí include()
. Regulární výraz zde nesmí být zakončen znakem $, protože vložený sklady.urls.py
bude dostávat všechna url začínající sklad/
.
Naproti tomu ve vkládaném sklady.urls.py
už jednotlivé regulární výrazy nebudou na začátku obsahovat ono sklady/
. Takže soubor urls.py
v aplikaci sklady
bude obsahovat například
urlpatterns = patterns('', url('^prehled/$), sklady.views.prehled), )
což ve skutečnosti přestavuje URL.
http://www.example.com/sklady/prehled/
Podotkněme, že kdyby "kořenové" url odchytávalo i nějakou proměnnou, byla by předána do vloženého url tak, jak je očekáváno:
# In settings/urls/main.py urlpatterns = patterns('', url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')), ) # In foo/urls/blog.py urlpatterns = patterns('foo.views', url(r'^$', 'blog.index'), url(r'^archive/$', 'blog.archive'), )
Obsah proměnné username
bude předán dál přes include()
.
1.2 Jak Django zpracovává request
Postup:
- Django zjistí, který URLConf modul použít (viz settings.py, parametru ROOT_URLCONF).
- V nalezeném modulu hledá proměnnou
urlpatterns
vytvořenou funkcí Djangapatterns
. - Prohledává postupně vzory regulárních výrazů a zastaví na první shodě.
- Zavolá funkci z druhého parametru (z příslušeného views.py) a předá jí parametr
request
(přesnějiHttpRequest
) a případné další hodnoty jako další poziční či klíčové parametry. - Nenajde-li se žádný odpovídající vzor, nebo nastane výjimka, Django zavolá příslušné view pro obsluhu chyby.
1.3 Další pravidla
Django při zpracování URL ignoruje doménovou část i GET a POST a pod. V URL
http://www.example.com/sklady/
bude hledat sklady/
. V URL
http://www.example.com/sklady/?sklad=6
bude opět hledat jen sklady/
.
1.4 Předání extra parametrů
Funkce url()
má volitelný třetí parametr, který je slovník přes nějž můžeme předat další parametry:
urlpatterns = patterns('blog.views', url(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}), )
Extra parametry lze předat i při použití funkce include()
. Parametry pak budou předány všem řádkům ve volaném url.py
.
1.5 Callable místo řetězce s cestou
Místo dosud používaného stylu
urlpatterns = patterns('', url(r'^archive/$', 'mysite.views.archive'), url(r'^about/$', 'mysite.views.about'), url(r'^contact/$', 'mysite.views.contact'), )
lze postupovat i takto:
from mysite import views urlpatterns = patterns('', url(r'^archive/$', views.archive), url(r'^about/$', views.about), url(r'^contact/$', views.contact), )
1.6 Class based views
Django nabízí generická views, která nejsou funkcí, ale třídou. Pokud taková view používáme, musíme je do url.py
vždy importovat:
from mysite.views import ClassBasedView urlpatterns = patterns('', url(r'^myview/$', ClassBasedView.as_view()), )
1.7 Reverzní vyhodnocování URL
V aplikaci nemusí být pohodlné používat přímo URL. Tak by se aplikace stala natvrdo zadrátovanou a případná změna v url.py
by znamenala hledání odpovídající URL ve všech souborech aplikace a jejich opravování. Místo toho lze použít reverzní vyhodnocení, kdy se uvádí odkaz na příslušnou funkci ve view a Django z tohoto odkazu vygeneruje příslušné URL.
Příklad urls.py:
from django.conf.urls import patterns, url
urlpatterns = patterns('',
#... url(r'^articles/(\d{4})/$', 'news.views.year_archive'), #...
)
V šabloně můžeme potom napsat:
{% load url %} <a href="{% url 'news.views.year_archive' year %}">{{ year }} Archive</a>
year
je normální promměná, kterou dostane šablona z view, které jí volalo. Obsah href="..."
Django převede na normální URL dle vzoru v urls.py
.
V kódu Pythonu (např ve view):
from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse('news.views.year_archive', args=(year,)))
Pojmenování vzorů URL
V některých případech nemusí být dobře použitelné odkazovat se v reverzních voláních na jméno view funkce. Pak můžeme využít možnosti Djanga si takový odkaz pojmenovat:
urlpatterns = patterns('', url(r'^archive/(\d{4})/$', archive, name="full-archive"), url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, name="arch-summary"), )
V šablonách a kódu Pythonu se pak odkazujeme na tato jména daná parametrem name
. Př:
{% url 'arch-summary' 1945 %}
1.8 Jmenné prostory
Slouží k přehlednější identifikaci odkazů v projektech, které jsou modulární a obsahují více aplikací než je malé množství. Pak při vkládání urls aplikace pomocí include
můžeme přiřadit jmenný prostor aplikaci i instanci:
url(r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')),
Někdy je toto řešení nutné, aby se vyřešil problém s konfiltem jmen.
Další příklad z dokumentace se týká embedded dat:
help_patterns = patterns('', url(r'^basic/$', 'apps.help.views.views.basic'), url(r'^advanced/$', 'apps.help.views.views.advanced'), ) url(r'^help/', include(help_patterns, 'bar', 'foo')),
Tady ale praktické využití tak docela nevidím, takže neposloužím.