Advanced Views  and URLconfs

10/08 @ Django Girls meetup

 

Kelly Chang

What we've got now

in Django 1.8

from django.conf.urls import include, url
from django.contrib import admin
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/$', hello),
    url(r'^time/$', current_datetime),
    url(r'^time/plus/(\d{1,2})/$', hours_ahead),
]

Avoiding imports

by importing views module

from django.conf.urls import include, url
from . import views

urlpatterns = [
   url(r'^hello/$', views.hello),
   url(r'^time/$', views.current_datetime),
   url(r'^time/plus/(d{1,2})/$', views.hours_ahead),
]

Avoiding imports

by using strings

from django.conf.urls.defaults import *

urlpatterns = [
    url(r'^hello/$', 'mysite.views.hello'),
    url(r'^time/$', 'mysite.views.current_datetime'),
    url(r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead'),
]

DEBUG only!

from django.conf import settings
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.homepage),
    url(r'^(\d{4})/([a-z]{3})/$', views.archive_month),
]

if settings.DEBUG:
    urlpatterns += [url(r'^debuginfo/$', views.debug),]

Named Groups

capture values from named arguments

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^reviews/2003/$', views.special_case_2003),
    url(r'^reviews/([0-9]{4})/$', views.year_archive),
    url(r'^reviews/([0-9]{4})/([0-9]{2})/$', views.month_archive),
]
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^reviews/2003/$', views.special_case_2003),
    url(r'^reviews/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^reviews/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
]

named

unnamed

Things to keep in mind...

  1. Always strings
  2. named groups first
  3. you can set default values
# URLconf
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^reviews/$', views.page),
    url(r'^reviews/page(?P<num>[0-9]+)/$', views.page),
]

# View (in reviews/views.py)
def page(request, num="1"):
    # Output the appropriate page of review entries, according to num.
    ...

Including other URLconfs

from django.conf.urls import include, url
from .views import *
  
urlpatterns = [
    url(r'', 'schedule.views.dashboard'),  
    url(r'book/', 'shedule.views.booking'),                                                                                                       
]
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^schedule/', include('schedule.urls')),
]

mysite/mysite/urls.py

mysite/schedule/urls.py

File Structure

mysite/

         manage.py

         mysite/

         schedule/

Examples

/schedule/

/schedule/book/

Other includes...

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/history/$', views.history),
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/edit/$', views.edit),
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/discuss/$', views.discuss),
]

Reduce common prefix to...

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/', include([
        url(r'^history/$', views.history),
        url(r'^edit/$', views.edit),
        url(r'^discuss/$', views.discuss),
    ])),
]

Extra options 

passing argument to views

# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^foo/$', views.foo_view),
    (r'^bar/$', views.bar_view),
)

# views.py

from django.shortcuts import render
from mysite.models import MyModel

def foo_view(request):
    m_list = MyModel.objects.filter(is_new=True)
    return render(request, 'template1.html', {'m_list': m_list})

def bar_view(request):
    m_list = MyModel.objects.filter(is_new=True)
    return render(request, 'template2.html', {'m_list': m_list})

example:

# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
    (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
)


# views.py

from django.shortcuts import render
from mysite.models import MyModel

def foobar_view(request, template_name):
    m_list = MyModel.objects.filter(is_new=True)
    return render(request, template_name, {'m_list': m_list})

URL Reversing

Start from the view to obtain certain url.

Avoid hard-coded urls.

Edit just in one place.

case 1, in templates:

Using the url template tag.

# urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    #...
    url(r'^reviews/([0-9]{4})/$', views.year_archive, name='reviews-year-archive'),
    url(r'^index/$', views.index_view, name='indexpage'),
    #...
]
<!--template.html-->

<a href="{% url 'reviews-year-archive' 2012 %}">2012 Archive</a>
<div>{% url 'indexpage' %}</div>

case 2, in python code:

Using django.core.urlresolvers.reverse() function

# urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    #...
    url(r'^reviews/([0-9]{4})/$', views.year_archive, name='reviews-year-archive'),
    #...
]
# views.py

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2012
    # ...
    return HttpResponseRedirect(reverse('reviews-year-archive', args=(year,)))

What if names duplicate?

URL Namespace

Allow you to uniquely reverse named URL patterns even if different applications use the same URL names

Simple example:

# mysite/urls.py

from django.conf.urls import include, url

urlpatterns = [
    url(r'^author-polls/', include('polls.urls', namespace='authors')),
]
# polls/urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]
<!--index.html-->
{% url 'authors:index' %}

Specify namespace in URLConfs

# mysite/urls.py

from django.conf.urls import include, url

urlpatterns = [
    url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
    url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls', app_name='polls')),
]
# polls/urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]
<!--index.html-->
{% url 'polls:index' %}
# views.py
reverse('polls:index', current_app=self.request.resolver_match.namespace)

Thanks for attention!

Django

By Kelly Chang