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