Slide 1

Slide 1 text

Introduction to Django Jacob Kaplan-Moss Strange Loop 2011 http://lanyrd.com/sfypm

Slide 2

Slide 2 text

Django Training Part 1: Introduction to Django.

Slide 3

Slide 3 text

“ ” Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. 2

Slide 4

Slide 4 text

“ ” Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. 3

Slide 5

Slide 5 text

“ ” Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. 4

Slide 6

Slide 6 text

“ ” Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. 5

Slide 7

Slide 7 text

Documentation http://django.me/design http://www.djangobook.com/en/2.0/chapter01/ 6

Slide 8

Slide 8 text

Which Django version should I use? 7

Slide 9

Slide 9 text

Installing Django 8 • Download and run http://bit.ly/dsetup (http://python-­‐distribute.org/distribute_setup.py) •easy_install  Django • Later: learn about pip and virtualenv http://pip.rtfd.org/ http://virtualenv.rtfd.org/

Slide 10

Slide 10 text

“Projects” 9

Slide 11

Slide 11 text

$  django-­‐admin.py  startproject  yabl 10

Slide 12

Slide 12 text

yabl/ __init__.py manage.py settings.py urls.py 11

Slide 13

Slide 13 text

$  python  manage.py  runserver Validating  models... 0  errors  found. Django  version  1.1  beta  1  SVN-­‐10844,  using  settings  'yabl.settings' Development  server  is  running  at  http://127.0.0.1:8000/ Quit  the  server  with  CONTROL-­‐C. 12

Slide 14

Slide 14 text

13

Slide 15

Slide 15 text

•DATABASE_ENGINE •DATABASE_NAME •DATABASE_USER •DATABASE_PASSWORD •DATABASE_HOST Project settings 14

Slide 16

Slide 16 text

$  python  manage.py  syncdb Creating  table  auth_permission Creating  table  auth_group Creating  table  auth_user Creating  table  auth_message Creating  table  django_content_type Creating  table  django_session Creating  table  django_site You  just  installed  Django's  auth  system,   which  means  you  don't  have  any  superusers  defined. Would  you  like  to  create  one  now?  (yes/no):  yes Username  (Leave  blank  to  use  'jacob'):  jacob E-­‐mail  address:  [email protected] Password:   Password  (again):   Superuser  created  successfully. Installing  index  for  auth.Permission  model Installing  index  for  auth.Message  model 15

Slide 17

Slide 17 text

http://django.me/about-settings http://django.me/settings http://django.me/manage.py Documentation 16

Slide 18

Slide 18 text

Exercise: “it worked!” 17

Slide 19

Slide 19 text

Django Training Part 2: Apps, models, and the admin

Slide 20

Slide 20 text

“Apps” 2

Slide 21

Slide 21 text

“Models” 3

Slide 22

Slide 22 text

What’s a model? 4

Slide 23

Slide 23 text

MVC? (Model-View-Controller) 5

Slide 24

Slide 24 text

CREATE  TABLE  "entries_entry"  (        "id"  integer  NOT  NULL  PRIMARY  KEY,        "author_id"  integer  NOT  NULL,        "pub_date"  datetime  NOT  NULL,        "headline"  varchar(200)  NOT  NULL,        "slug"  varchar(50)  NOT  NULL  UNIQUE,        "summary"  text  NOT  NULL,        "body"  text  NOT  NULL ) 6

Slide 25

Slide 25 text

•SQL is tough •SQL knows no version control •DRY •Python is fun! Scary Quirky Language 7

Slide 26

Slide 26 text

import  datetime from  django.db  import  models from  yabl.authors.models  import  Author class  Entry(models.Model):        author              =  models.ForeignKey(Author,  related_name='entries')        pub_date          =  models.DateTimeField(default=datetime.datetime.now)        headline          =  models.CharField(max_length=200)        slug                  =  models.SlugField(unique=True)        summary            =  models.TextField()        body                  =  models.TextField() 8

Slide 27

Slide 27 text

Defining Models 9

Slide 28

Slide 28 text

$  python  manage.py  startapp  authors 10

Slide 29

Slide 29 text

authors/ __init__.py models.py tests.py views.py 11

Slide 30

Slide 30 text

INSTALLED_APPS  =  (        "django.contrib.auth",        "django.contrib.contenttypes",        "django.contrib.sessions",          "django.contrib.sites",        "yabl.authors", ) 12

Slide 31

Slide 31 text

from  django.db  import  models class  Author(models.Model):        first_name    =  models.CharField(max_length=200)        last_name      =  models.CharField(max_length=200)        bio                  =  models.TextField(blank=True) 13

Slide 32

Slide 32 text

$  python  manage.py  validate 0  errors  found. 14

Slide 33

Slide 33 text

$  python  manage.py  sqlall  authors BEGIN; CREATE  TABLE  "authors_author"  (        "id"  integer  NOT  NULL  PRIMARY  KEY,        "first_name"  varchar(200)  NOT  NULL,        "last_name"  varchar(200)  NOT  NULL,        "bio"  text  NOT  NULL ); COMMIT; 15

Slide 34

Slide 34 text

$  python  manage.py  syncdb Creating  table  authors_author Installing  index  for  authors.Author  model 16

Slide 35

Slide 35 text

$  python  manage.py  shell [1]  >>>  from  yabl.authors.models  import  Author [2]  >>>  a  =  Author(first_name="John",  last_name="Barth") [3]  >>>  a.save() 17

Slide 36

Slide 36 text

[4]  >>>  Author.objects.all() [4]      :  [] [5]  >>>  Author.objects.create(first_name='Miguel',  last_name='de  Cervantes') [5]      :   [6]  >>>  Author.objects.all() [6]      :  [,  ] [7]  >>>  al  =  Author.objects.filter(first_name='John') [8]  >>>  al[0].last_name [8]      :  u'Barth' [9]  >>>  Author.objects.get(last_name__startswith='de').first_name [9]      :  u'Miguel' 18

Slide 37

Slide 37 text

Model metadata 19

Slide 38

Slide 38 text

class  Author(models.Model):        first_name    =  models.CharField(max_length=200)        last_name      =  models.CharField(max_length=200)        bio                  =  models.TextField(blank=True)                def  __unicode__(self):                return  '%s  %s'  %  (self.first_name,  self.last_name) 20

Slide 39

Slide 39 text

class  Author(models.Model):        …        class  Meta:                verbose_name_plural  =  'authors'                ordering  =  ['last_name',  'first_name'] 21

Slide 40

Slide 40 text

[1]  >>>  from  yabl.authors.models  import  Author [2]  >>>  Author.objects.all() [2]      :  [,  ] [3]  >>>  Author.objects.order_by('-­‐first_name') [3]      :  [,  ] 22

Slide 41

Slide 41 text

http://django.me/models http://www.djangobook.com/en/2.0/chapter05/ Documentation 23

Slide 42

Slide 42 text

Exercise: Write some apps and some models: • Author (authors app) • first_name (CharField) • last_name (CharField) • bio (TextField) • Entry (entries app) • author (ForeignKey) • pub_date (DateTimeField) • is_published (BooleanField) • headline (CharField) • slug (SlugField) • summary (TextField) • body (TextField) 24

Slide 43

Slide 43 text

Django’s admin interface 25

Slide 44

Slide 44 text

“ ” A Web-based interface, limited to trusted site administrators, that enables the adding, editing and deletion of site content. — The Django Book http://djangobook.com/en/2.0/chapter06/ 26

Slide 45

Slide 45 text

from  django.contrib  import  admin from  yabl.authors.models  import  Author admin.site.register(Author) 27

Slide 46

Slide 46 text

INSTALLED_APPS  =  (        'django.contrib.auth',        'django.contrib.contenttypes',        'django.contrib.sessions',        'django.contrib.sites',        'django.contrib.admin',        'yabl.authors',        'yabl.entries', ) 28

Slide 47

Slide 47 text

$  python  manage.py  syncdb Creating  table  django_admin_log Installing  index  for  admin.LogEntry  model 29

Slide 48

Slide 48 text

from  django.conf.urls.defaults  import  * #  Uncomment  the  next  two  lines  to  enable  the  admin: from  django.contrib  import  admin admin.autodiscover() urlpatterns  =  patterns('',        #  Example:        #  (r'^yabl/',  include('yabl.foo.urls')),        #  Uncomment  the  admin/doc  line  below  and  add  'django.contrib.admindocs'          #  to  INSTALLED_APPS  to  enable  admin  documentation:        #  (r'^admin/doc/',  include('django.contrib.admindocs.urls')),        #  Uncomment  the  next  line  to  enable  the  admin:        (r'^admin/',  include(admin.site.urls)), ) 30

Slide 49

Slide 49 text

31

Slide 50

Slide 50 text

32

Slide 51

Slide 51 text

33

Slide 52

Slide 52 text

34

Slide 53

Slide 53 text

from  django.contrib  import  admin from  yabl.authors.models  import  Author class  AuthorAdmin(admin.ModelAdmin):        pass admin.site.register(Author,  AuthorAdmin) 35

Slide 54

Slide 54 text

Documentation http://djangobook.com/en/2.0/chapter06/ http://django.me/admin 36

Slide 55

Slide 55 text

Exercise: 37

Slide 56

Slide 56 text

Django Training Part 3: URLs, views, and templates

Slide 57

Slide 57 text

Views 2

Slide 58

Slide 58 text

What’s a view? 3

Slide 59

Slide 59 text

4

Slide 60

Slide 60 text

URLs 5

Slide 61

Slide 61 text

page.php script.cgi?pageid=144 StoryPage.aspx 6

Slide 62

Slide 62 text

0,2097,1-1-30-72-407-4752,00.html 7

Slide 63

Slide 63 text

/authors/ /authors/jacob/ /authors/adrian/ 8

Slide 64

Slide 64 text

ROOT_URLCONF  =  "yabl.urls" 9

Slide 65

Slide 65 text

from  django.conf.urls.defaults  import  * #  Uncomment  the  next  two  lines  to  enable  the  admin: from  django.contrib  import  admin admin.autodiscover() urlpatterns  =  patterns('',        (r'^authors/$',                  'yabl.authors.views.author_list'),        (r'^authors/(\d+)/$',      'yabl.authors.views.author_detail'),        (r'^admin/',  include(admin.site.urls)), ) 10 yabl/urls.py

Slide 66

Slide 66 text

from  django.conf.urls.defaults  import  * urlpatterns  =  patterns('',        (r'^$',                  'yabl.authors.views.author_list'),        (r'^(\d+)/$',      'yabl.authors.views.author_detail'), ) 11 yabl/authors/urls.py

Slide 67

Slide 67 text

from  django.conf.urls.defaults  import  * #  Uncomment  the  next  two  lines  to  enable  the  admin: from  django.contrib  import  admin admin.autodiscover() urlpatterns  =  patterns('',        (r'^authors/',  include('yabl.authors.urls')),        (r'^admin/',      include(admin.site.urls)), ) 12 yabl/urls.py

Slide 68

Slide 68 text

Regex crash course a The letter “a”. a+ One or more “a”s. b? Zero or one “b”s. c{1,3} One, two, or three “c”s. . Any single character. [abc] Either an “a”, “b”, or “c”. [A-­‐Z] Any character between “A” and “Z”. [A-­‐Za-­‐z0-­‐9]? Zero or one letters “A-Z”, “a-z”, or “0-9”. (\d{3,4}) A group containing three or four digits. (\w*) A group containing zero or more word characters (letters/digits). [^/]+ One or more characters until (and not including) a forward slash. ^(joe|bob) A string starting with “joe” or “bob”. (?P\d+) A group named “id” containing one or more digits. article/$ A string ending with “article/” 13

Slide 69

Slide 69 text

•GET  /authors/1/ •ROOT_URLCONF •yabl.urls •(r'^authors/',  include('yabl.authors.urls')) •yabl.authors.urls •(r'^$',  'author_list')                    (no match) •(r'^(\d+)/',  'author_detail')      (match!) •author_detail(request,  '1') Dissecting a request 14

Slide 70

Slide 70 text

Documentation http://django.me/urls 15

Slide 71

Slide 71 text

A first view 16

Slide 72

Slide 72 text

from  django.http  import  HttpResponse def  author_list(request):        return  HttpResponse("This  is  the  author  list!") 17 yabl/authors/views.py

Slide 73

Slide 73 text

from  django.http  import  HttpResponse from  yabl.authors.models  import  Author def  author_list(request):        r  =  "
    "        for  a  in  Author.objects.all():                r  +=  "
  • %s
  • "  %  a.name        r  +=  "
"        return  HttpResponse(r) 18 yabl/authors/views.py

Slide 74

Slide 74 text

from  django  import  template from  django.http  import  HttpResponse from  yabl.authors.models  import  Author def  author_list(request):        as  =  Author.objects.all()        tmpl  =  template.loader.get_template("authors/index.html")        context  =  template.Context({"authors":  as})        return  HttpResponse(tmpl.render(context)) 19 yabl/authors/views.py

Slide 75

Slide 75 text

from  django.shortcuts  import  render from  yabl.authors.models  import  Author def  author_list(request):        context  =  {"authors"  :  Author.objects.all()}        return  render(request,  "authors/index.html",  context) 20 yabl/authors/views.py

Slide 76

Slide 76 text

from  django.http  import  Http404 from  django.shortcuts  import  render_to_response from  yabl.authors.models  import  Author def  author_detail(request,  author_id):        try:                author  =  Author.objects.get(id=author_id)        except  Author.DoesNotExist:                raise  Http404()        return  render(request,  "authors/detail.html",  {"author"  :  author}) 21 yabl/authors/views.py

Slide 77

Slide 77 text

from  django.shortcuts  import  render_to_response,  get_object_or_404 from  yabl.authors.models  import  Author def  author_detail(request,  author_id):        author  =  get_object_or_404(Author,  id=author_id)        return  render(request,  "authors/detail.html",  {"author"  :  author}) 22 yabl/authors/views.py

Slide 78

Slide 78 text

Templates 23

Slide 79

Slide 79 text

What’s a template? 24

Slide 80

Slide 80 text

Authors

Authors  ({{  authors|length  }}  total)

25

Slide 81

Slide 81 text

Where to templates go? 26 •In an app’s templates directory. •In directories specified by settings.TEMPLATE_DIRS. •...

Slide 82

Slide 82 text

TEMPLATE_DIRS  =  [        '/path/to/some/templates/',        '/path/to/some/more/other/templates/', ] 27

Slide 83

Slide 83 text

TEMPLATE_DIRS  =  [        '/Users/jacob/Projects/stl-­‐django/yabl/templates/', ] 28

Slide 84

Slide 84 text

Authors

Authors  ({{  authors|length  }}  total)

29

Slide 85

Slide 85 text

•a["name"] •a.name •a.name() The magic dot 30

Slide 86

Slide 86 text

Authors

Authors  ({{  authors|length  }}  total)

31

Slide 87

Slide 87 text

{{  text|escape|linkbreaks  }} 32

Slide 88

Slide 88 text

{{  text|truncatewords:"30"  }} 33

Slide 89

Slide 89 text

Authors

Authors  ({{  authors|length  }}  total)

34

Slide 90

Slide 90 text

Template inheritance 35

Slide 91

Slide 91 text

{%  block  title  %}YABL{%  endblock  %}
{%  block  content  %}{%  endblock  %}
{%  block  footer  %}Copyright  blah..{%  endblock  %}
36

Slide 92

Slide 92 text

{%  block  title  %}YABL{%  endblock  %}
{%  block  content  %}{%  endblock  %}
{%  block  footer  %}Copyright  blah..{%  endblock  %}
37

Slide 93

Slide 93 text

{%  extends  "base.html"  %} {%  block  title  %} Authors  |  {{  block.super  }} {%  endblock  %} {%  block  content  %}

Authors  ({{  authors|length  }}  total)

{%  endblock  %} 38

Slide 94

Slide 94 text

section_index.html !"#$%&$'()#*+,)$-.$'$/0123&45*#"6 !"#+5718#&0&5$#"6 ##!!#)$1&07'2&0&5$#66 !"#$'(+5718#"6 !"#+5718#17'&$'"6 ##93:;!!#)$1&07'2&0&5$#669<3:; ##!"#=7/#)&7/>#0'#)&7/>-50)"6 ####93?;!!#)&7/>23$,(50'$#669<3?; ####9@;!!#)&7/>2&$,)$#66 ##!"#$'(=7/#"6 !"#$'(+5718#"6 base_generic.html !"#$%&$'()#*+,)$23&45*#"6 !"#+5718#&0&5$#"6 ##ABC7/5(2174 !"#$'(+5718#"6 !"#+5718#/,05#"6 ##9D5; ####950;E74$9<50; ####950;A71,5#'$F)9<50; ####222 ##9; ##9(0G#0(H*/,05*; ####!"#+5718#/,05#"6!"#$'(+5718#"6 ##9<(0G; ##9(0G#0(H*17'&$'&*; ####!"#+5718#17'&$'"6!"#$'(+5718#"6 ##9<(0G; 9<+7(>; 9<3&45; ! " # $ 39

Slide 95

Slide 95 text

Why? 40

Slide 96

Slide 96 text

Inheritance tips •{% extends %} must be the first thing in your template. •More {% block %}s are better. •If you’re duplicating content, you’re missing a block. •{{ block.super }} 41

Slide 97

Slide 97 text

Documentation http://djangobook.com/en/2.0/chapter04/ http://django.me/templates 42

Slide 98

Slide 98 text

Exercise: /authors/ /authors/{id}/ /entries/ /entries/{slug}/ 43

Slide 99

Slide 99 text

Django training BONUS: Models and queries

Slide 100

Slide 100 text

Terminology 2

Slide 101

Slide 101 text

Models a.k.a. “DDL” 3

Slide 102

Slide 102 text

Managers a.k.a. “table” 4

Slide 103

Slide 103 text

QuerySets a.k.a. “selection” 5

Slide 104

Slide 104 text

Model instances a.k.a. “row” 6

Slide 105

Slide 105 text

!!!"!"#$#%&'()*+,-./'"*012'.(31"456,21"7.8$9(6.: !!!"!" #$%&'()*"+,&"-.'/0"123!4"$%&'()*"523"-.'/0"6,&!7 !!!".#$#!";<= !!!". $%&'()*"+,&"-.'/0"123! QuerySet Manager Model Instance 7

Slide 106

Slide 106 text

Models 8

Slide 107

Slide 107 text

Instance methods class  Entry(models.Model):        …        def  is_by_jacob(self):                return  "jacob"  in  self.author.name.lower() … [1]  >>>  e  =  Entry.objects.get(pk=1) [2]  >>>  e.is_by_jacob() [2]      :  False 9

Slide 108

Slide 108 text

“Special” instance methods 10

Slide 109

Slide 109 text

__unicode__ class  Entry(models.Model):        …        def  __unicode__(self):                return  self.headline … [1]  >>>  Entry.objects.all() [1]      :  [,  ] 11

Slide 110

Slide 110 text

save class  Entry(models.Model):        …        def  save(self,  **kwargs):                self.word_count  =  count_words(self.body)                super(Entry,  self).save(**kwargs) 12

Slide 111

Slide 111 text

save class  Entry(models.Model):        …        def  save(self,  **kwargs):                self.word_count  =  count_words(self.body)                super(Entry,  self).save(**kwargs) Don’t forget this part! 13

Slide 112

Slide 112 text

delete class  Author(models.Model):        …        def  delete(self):                nobody  =  Author.objects.get(first_name='')                self.entries.update(author=nobody)                super(Author,  self).delete() 14

Slide 113

Slide 113 text

Managers 15

Slide 114

Slide 114 text

Default manager class  Entry(models.Model):        …        objects  =  models.Manager() … [1]  >>>  from  yabl.entries.models  import  Entry [2]  >>>  Entry.objects [2]      :   16

Slide 115

Slide 115 text

Custom managers class  EntryManager(models.Manager):        def  future(self):                …        def  past(self):                … class  Entry(models.Model):        …        objects  =  EntryManager() 17

Slide 116

Slide 116 text

[1]  >>>  from  yabl.entries.models  import  Entry [2]  >>>  Entry.objects.future() [2]      :  [] [3]  >>>  Entry.objects.past() [3]      :  [,  ] 18

Slide 117

Slide 117 text

Documentation http://django.me/managers 19

Slide 118

Slide 118 text

QuerySets 20

Slide 119

Slide 119 text

[1]  >>>  Author.objects.filter(first_name='Jacob') [1]      :  [] [2]  >>>  Author.objects.filter(last_name__contains='s') [2]      :  [,  ] [3]  >>>  Author.objects.filter(last_name__contains='s',  first_name='Miguel') [3]      :  [] [4]  >>>  Author.objects.filter(last_name__contains='s').filter(first_name='Miguel') [4]      :  [] Filters 21

Slide 120

Slide 120 text

Field lookups exact,  iexact name__exact='Joe' contains,  icontains name__icontains='s' startswith,  endswith,   istartswith,  iendswith name__endswith='nd' in name__in=('Joe',  'Jane') author__in=Author.objects.filter(…) gt,  gte,  lt,  lte cost__gt=100 range cost__range=(100,  500) date__range=(now,  tomrrow) year,  month,  day,  week_day date__year=2009 date__month=7 isnull author__isnull=True regex,  iregex name__regex='^J.*b$' 22

Slide 121

Slide 121 text

Following relationships [1]  >>>  Entry.objects.filter(author__first_name__startswith='J') [1]      :  [] [2]  >>>  Author.objects.filter(entries__headline='Hi') [2]      :  [] Where’d that come from? 23

Slide 122

Slide 122 text

related_name class  Entry(models.Model):        author  =  models.ForeignKey(Author,  related_name='entries') 24

Slide 123

Slide 123 text

select_related() [1]  >>>  e  =  Entry.objects.get(pk=1) [2]  >>>  e.author [2]      :   Oops,  that  did  a  second,  needless  query. [3]  >>>  e  =  Entry.objects.select_related().get(pk=1) [4]  >>>  e.author [5]      :   No  second  query  needed  for  e.author 25

Slide 124

Slide 124 text

Limiting select_related() [1]  >>>  Entry.objects.select_related('author',  'category') [2]  >>>  Entry.objects.select_related(depth=2) 26

Slide 125

Slide 125 text

QuerySet details 27

Slide 126

Slide 126 text

QuerySets are chainable [1]  >>>  Entry.objects.filter(    ....:          headline__contains='bites',    ....:  ).exclude(    ....:          pub_date__year=2008    ....:  ).filter(    ....:          pub_date__month=9    ....:  ) 28

Slide 127

Slide 127 text

QuerySets are unique [1]  >>>  qs1  =  Entry.objects.filter(headline__icontains='dog') [2]  >>>  qs2  =  qs1.exclude(pub_date__year=2008) [3]  >>>  qs3  =  qs1.filter(pub_date__year=2008) 29

Slide 128

Slide 128 text

QuerySets are lazy [1]  >>>  qs  =  Entry.objects.filter(headline__icontains='dog') [2]  >>>  qs  =  qs.exclude(pub_date__year=2008) [3]  >>>  qs  =  qs.filter(author__first_name='Jacob') [4]  >>>  qs [4]      :  [,  ] 30

Slide 129

Slide 129 text

When QuerySets are evaluated •Iteration •Slicing •Printing •len() •list() for  i  in  qs qs[0:5] print  qs,  str(qs) len(qs) list(qs) 31

Slide 130

Slide 130 text

Chainable methods filter(),  exclude() qs.filter(name='Joe') order_by() qs.order_by('-­‐first_name') reverse() qs.reverse() distinct() qs.distinct() values(),  values_list() qs.values('first_name',  'last_name') dates() qs.dates('pub_date',  'year') qs.dates('pub_date',  'month') select_related() qs.select_related() defer(),  only() qs.defer('body') qs.only('body',  'headline') none(),  all() qs.all() qs.none() 32

Slide 131

Slide 131 text

Other QuerySet methods get() e  =  Entry.objects.get(…) create() e  =  Entry.objects.create(…) get_or_create() e,  created  =  Entry.objects.get_or_create(…) count() Entry.objects.count() in_bulk() Entry.objects.in_bulk([1,  2,  3]) latest() Entry.objects.latest('pub_date') 33

Slide 132

Slide 132 text

Raw SQL [1]  >>>  query  =  "SELECT  *  FROM  authors_author  WHERE  first_name  =  %s" [2]  >>>  params  =  ["Jacob"] [3]  >>>  Entry.objects.raw(query,  params) [3]          [] 34

Slide 133

Slide 133 text

Entry.objects.raw(query  %  params) No! 35

Slide 134

Slide 134 text

Other topics 36

Slide 135

Slide 135 text

Aggregation http://jacobian.org/r/django-aggregation 37

Slide 136

Slide 136 text

Transaction control http://jacobian.org/r/django-transactions 38

Slide 137

Slide 137 text

Exercise: /entries/future/ /entries/past/ 39

Slide 138

Slide 138 text

• Forms, model forms, form sets, ... • File storage - local and remote. • Cookies, sessions, authn/authz. • GeoDjango • Built-in SQLi, XSS and CSRF protection. • i18n and l10n support. • Generic views, • &c! 1 What else?

Slide 139

Slide 139 text

Thank you! [email protected] http://lanyrd.com/sfypm 2