What's coming in Django 1.2
===========================

Simon Willison - @simonw
DJUGL, 3rd December 2009

------------------------

http://code.djangoproject.com/wiki/Version1.2Roadmap
http://code.djangoproject.com/wiki/Version1.2Features

------------------------

CSRF: Cross site request forgery

Your admin panel:
<a href="/delete.php?id=5">Delete</a>

Evil.com...
<img src="http://admin.yoursite.com/delete.php?id=5" width=1 height=1>

Then social engineers one of your logged-in users to visit that page.

------------------------

Your admin panel, using POST:
<form action="/delete.php" method="post">
	<input type="hidden" name="id" value="4">
	<input type="submit" value="Delete">
</form>

On evil.com...
<form action="http://admin.yoursite.com/delete.php"
	method="post">
	<input type="hidden" name="id" value="4">
	<input type="submit" value="Go">
</form>
<script>document.forms[0].submit()</script>

(Even better, they can hide the above in an invisible iframe)

------------------------

Solution:
<form action="/delete.php" method="post">
	<input type="hidden" name="id" value="4">
	<input type="hidden" name="csrf_token" 
		value="02384029384092">
	<input type="submit" value="Go">
</form>

csrf_token must by unique to the currently logged in user.

------------------------

Improved CSRF protection

http://code.djangoproject.com/wiki/CsrfProtection
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

------------------------

Integrating logging

http://code.djangoproject.com/wiki/LoggingProposal
http://groups.google.com/group/django-developers/msg/7452fac3ae3b8175
http://code.djangoproject.com/ticket/12012

------------------------

Signing and signed cookies

http://code.djangoproject.com/wiki/Signing
http://github.com/simonw/django-signed

------------------------

Smart {% if %} tag

http://www.djangosnippets.org/snippets/1350/
http://groups.google.com/group/django-developers/browse_thread/thread/993d92334c27c717

------------------------

QuerySet.raw()

http://code.djangoproject.com/ticket/11863

>>> Entry.objects.all()
[<Entry: Entry one>,
 <Entry: Entry two>,
 <Entry: Entry three>,
 <Entry: Entry four>]
>>> qs = Entry.objects.raw('select * from blog_entry')
>>> qs
select * from blog_entry
>>> type(qs)
<class 'django.db.models.query.RawQuerySet'>
>>> list(qs)
[<Entry: Entry one>,
 <Entry: Entry two>,
 <Entry: Entry three>,
 <Entry: Entry four>]
>>> list(Entry.objects.raw('select * from blog_entry where id > %s', [2]))
[<Entry: Entry three>, <Entry: Entry four>]

------------------------

Multi-DB

http://code.djangoproject.com/ticket/1142
http://groups.google.com/group/django-developers/browse_thread/thread/7904c7da7cb0085f
http://github.com/alex/django/blob/multiple-db/docs/topics/db/multi-db.txt
http://lazypython.blogspot.com/2009/11/state-of-multidb-in-django.html

------------------------

# In settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'data.db',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    },
    'production': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'multidb_demo_production',
        'USER': 'root',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    }
}

------------------------

>>> from blog.models import Entry
>>> Entry.objects.all()
[<Entry: A blog entry in SQLite>]
>>> Entry.objects.using('default').all()
[<Entry: A blog entry in SQLite>]
>>> Entry.objects.using('production').all()
[<Entry: A blog entry in MySQL>, <Entry: Another blog entry in MySQL>]
>>> e = Entry.objects.using('production')[0]
>>> e._state.__dict__
{'db': 'production'}
>>> e.save(using = 'default') # WARNING: Over-writes SQLite item with same pk
>>> e
<Entry: A blog entry in MySQL>

------------------------

http://www.youtube.com/watch?v=7i5FlC1MpkE