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
urlpatternsvytvoř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.