From c179bd5cfb1e0d255494e1d2cea970e172b0b729 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 13 May 2010 13:44:32 +0000 Subject: [PATCH] [1.1.X] Fixed #13514 -- Corrected the process of loading multiple javascript translation catalogs. Thanks to jtiai for the report, to Ramiro Morales for working out the test case, and to Ramiro and Jannis for their help on the fix. Backport of r13250 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@13253 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/views/i18n.py | 5 +- tests/regressiontests/admin_views/tests.py | 12 ++- tests/regressiontests/views/app1/__init__.py | 1 + .../app1/locale/fr/LC_MESSAGES/djangojs.mo | Bin 0 -> 482 bytes .../app1/locale/fr/LC_MESSAGES/djangojs.po | 20 +++++ tests/regressiontests/views/app2/__init__.py | 1 + .../app2/locale/fr/LC_MESSAGES/djangojs.mo | Bin 0 -> 482 bytes .../app2/locale/fr/LC_MESSAGES/djangojs.po | 20 +++++ tests/regressiontests/views/app3/__init__.py | 1 + .../app3/locale/es_AR/LC_MESSAGES/djangojs.mo | Bin 0 -> 483 bytes .../app3/locale/es_AR/LC_MESSAGES/djangojs.po | 20 +++++ tests/regressiontests/views/app4/__init__.py | 1 + .../app4/locale/es_AR/LC_MESSAGES/djangojs.mo | Bin 0 -> 483 bytes .../app4/locale/es_AR/LC_MESSAGES/djangojs.po | 20 +++++ .../views/locale/es/LC_MESSAGES/djangojs.mo | Bin 445 -> 490 bytes .../views/locale/es/LC_MESSAGES/djangojs.po | 8 +- .../views/locale/fr/LC_MESSAGES/djangojs.mo | Bin 436 -> 484 bytes .../views/locale/fr/LC_MESSAGES/djangojs.po | 8 +- tests/regressiontests/views/tests/i18n.py | 70 +++++++++++++++++- tests/regressiontests/views/urls.py | 12 +++ 20 files changed, 186 insertions(+), 13 deletions(-) create mode 100644 tests/regressiontests/views/app1/__init__.py create mode 100644 tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.mo create mode 100644 tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.po create mode 100644 tests/regressiontests/views/app2/__init__.py create mode 100644 tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.mo create mode 100644 tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.po create mode 100644 tests/regressiontests/views/app3/__init__.py create mode 100644 tests/regressiontests/views/app3/locale/es_AR/LC_MESSAGES/djangojs.mo create mode 100644 tests/regressiontests/views/app3/locale/es_AR/LC_MESSAGES/djangojs.po create mode 100644 tests/regressiontests/views/app4/__init__.py create mode 100644 tests/regressiontests/views/app4/locale/es_AR/LC_MESSAGES/djangojs.mo create mode 100644 tests/regressiontests/views/app4/locale/es_AR/LC_MESSAGES/djangojs.po diff --git a/django/views/i18n.py b/django/views/i18n.py index e151496bcd..9a12dba49f 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -163,13 +163,16 @@ def javascript_catalog(request, domain='djangojs', packages=None): if en_catalog_missing: t = {} else: + locale_t = {} for path in paths: try: catalog = gettext_module.translation(domain, path, [locale]) except IOError: catalog = None if catalog is not None: - t = catalog._catalog + locale_t.update(catalog._catalog) + if locale_t: + t = locale_t src = [LibHead] plural = None if '' in t: diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 798d3d4e9f..21d4f4ffbb 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -4,7 +4,6 @@ import re import datetime from django.conf import settings from django.core.files import temp as tempfile -from django.test import TestCase from django.contrib.auth.models import User, Permission from django.contrib.contenttypes.models import ContentType from django.contrib.admin.models import LogEntry, DELETION @@ -12,14 +11,15 @@ from django.contrib.admin.sites import LOGIN_FORM_KEY from django.contrib.admin.util import quote from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME from django.forms.util import ErrorList +from django.test import TestCase from django.utils.cache import get_max_age +from django.utils.encoding import iri_to_uri from django.utils.html import escape from django.utils.translation import activate, deactivate -from django.utils.encoding import iri_to_uri # local test models from models import Article, BarAccount, CustomArticle, EmptyModel, \ - ExternalSubscriber, FooAccount, Gallery, ModelWithStringPrimaryKey, \ + FooAccount, Gallery, ModelWithStringPrimaryKey, \ Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, \ Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, \ Category, Plot, FunkyTag @@ -38,9 +38,11 @@ class AdminViewBasicTest(TestCase): urlbit = 'admin' def setUp(self): + self.old_language_code = settings.LANGUAGE_CODE self.client.login(username='super', password='secret') def tearDown(self): + settings.LANGUAGE_CODE = self.old_language_code self.client.logout() def testTrailingSlashRequired(self): @@ -270,26 +272,22 @@ class AdminViewBasicTest(TestCase): if the default language is non-English but the selected language is English. See #13388 and #3594 for more details. """ - old_language_code = settings.LANGUAGE_CODE settings.LANGUAGE_CODE = 'fr' activate('en-us') response = self.client.get('/test_admin/admin/jsi18n/') self.assertNotContains(response, 'Choisir une heure') deactivate() - settings.LANGUAGE_CODE = old_language_code def testI18NLanguageNonEnglishFallback(self): """ Makes sure that the fallback language is still working properly in cases where the selected language cannot be found. """ - old_language_code = settings.LANGUAGE_CODE settings.LANGUAGE_CODE = 'fr' activate('none') response = self.client.get('/test_admin/admin/jsi18n/') self.assertContains(response, 'Choisir une heure') deactivate() - settings.LANGUAGE_CODE = old_language_code class SaveAsTests(TestCase): diff --git a/tests/regressiontests/views/app1/__init__.py b/tests/regressiontests/views/app1/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/regressiontests/views/app1/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..5d6aecb446f3b0b907f540596f8268833603678b GIT binary patch literal 482 zcmYL`!E)0u5QYr{7auuu*aJ7%VufaCP3Y7lZYP7ChQ#SzwYQF#AbF%s2OflX;Lzzy z^gVbMR!pbe(I@R{{#~u4zpq~WPQ;!IuZ4HQOJO2JTMBQ4Z^HOllH9~qxD{Wuui}MmL%hh^*u}D`m zIL}yz-gNk7-v?}54(alu!Ko+Bl7us1S58s&!yvk#)HbYN^AdUHO9vrSdOqNq!llyxz$PK()WRj$`3BDMWq_k<1UA30RT z;(QZZo>bN8&Kx-3pQQD?E}t%?4zhIWER&Tpehtzr(@%as?6k3;pxtU8h(B+dGdz0I z#a^z-V`*F0$rI*qbY(bA%nq*gp5sGyd*caOVwQQU@9!)@C$9Fo<@-OLLJZ?KB>w;k C{e-Fj literal 0 HcmV?d00001 diff --git a/tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.po b/tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..a4627db877 --- /dev/null +++ b/tests/regressiontests/views/app1/locale/fr/LC_MESSAGES/djangojs.po @@ -0,0 +1,20 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 19:15+0200\n" +"PO-Revision-Date: 2010-05-12 12:41-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "this app1 string is to be translated" +msgstr "il faut traduire cette chaîne de caractères de app1" diff --git a/tests/regressiontests/views/app2/__init__.py b/tests/regressiontests/views/app2/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/regressiontests/views/app2/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..17e18636727c1801f37cea95e3fd15d95e2b4234 GIT binary patch literal 482 zcmYL`K~C#15Qf7OY_fc77PDXn<|RQD5DFr%4X7e1rA^tJWJryQ9obU^2jLDZ5SQQ{ zoP{w$F!E>5SpSU2_Q&7#=YZ`Gv&rl*8%&?^Het4yE2g&=1P^{?UfJjIV?O`OXrUa) zu1mm?Rk{TZ$-oT)S*hJp5;noanmepXj2dx`)+wV?m}G;C>^z6-d^#Ilj>9Q-#*!#q zs~Yit)jCm`6vD}6B?cBHagrEvwG@&l+85EGhDLyD){6`l@BI=1a zfh0-UiS}4mNJpaj?#lBqX{*i@zim%gpc&ETS}#mpk7GpkdEionK<~>`Ce|( xid@&G;U`St;6_mxs3qLW75Rs3R>~sONW}9(zQ1XNhFxi8P46!joe%vt1fLCOgslJo literal 0 HcmV?d00001 diff --git a/tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.po b/tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..637b9e6bcd --- /dev/null +++ b/tests/regressiontests/views/app2/locale/fr/LC_MESSAGES/djangojs.po @@ -0,0 +1,20 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 19:15+0200\n" +"PO-Revision-Date: 2010-05-12 22:05-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "this app2 string is to be translated" +msgstr "il faut traduire cette chaîne de caractères de app2" diff --git a/tests/regressiontests/views/app3/__init__.py b/tests/regressiontests/views/app3/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/regressiontests/views/app3/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/regressiontests/views/app3/locale/es_AR/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/app3/locale/es_AR/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c485a9838f77e1ce20134ff06bc1d8ce01c66f8 GIT binary patch literal 483 zcmYL_K~BRk5JdxmO_r=#c*6>&B!vnH1vRuOsz^#n)9&452u8(@YzM&!I01KH#SK_- z56;2_1ReSL+twd@JYQQIuMWjJu}$m|n?#prVnTF?n?~0h=Y@2K_@Fh7pFEOPh$Xw_ zwPjZGq81uij@HtA$3NdCvVxXe^W1*EX*A82SJiRW?T^h(#z}(4o27Qg(QW6Zf#elUv?+CmT@H@;u3H;8kM<-;2 z6dy%%`M=Ni!0UkDW_~+3^uaqIU(Ah#Omk_L+$tTg;Vh2XI7}kejgoK__rk#-ji%Fc zvdXgNB|?V$Az*PhzMM5BcjLIX6fLF8b2k|!(dtuv%X9lmT9ow0b4A5ke6su1k_&m- ybV(buXR~Yw$17h`%Pne%WUdM!%YYp(gmoP>)Y&Fq{WX$wfy|)(?SC!`<$MF1;e`, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 19:15+0200\n" +"PO-Revision-Date: 2010-05-12 12:41-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "il faut traduire cette chaîne de caractères de app3" +msgstr "este texto de app3 debe ser traducido" diff --git a/tests/regressiontests/views/app4/__init__.py b/tests/regressiontests/views/app4/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/regressiontests/views/app4/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/regressiontests/views/app4/locale/es_AR/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/app4/locale/es_AR/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..581fbb03471b1430adf64aa1950766bd14e4c1b1 GIT binary patch literal 483 zcmYL_K~BRk5JdxmO_r=#c*6c*cZ0nCb{$E=guO7uZu}$m|n?##%F(R78jmvAE_dhazb$peu z+hjcH4+s7jYo#q@rV=GwEGq-KikLqd=Frv1EfqnJTZ~vE2#z5*fw0NKlPGNN26RF~ z7~`XGm#=hT06`PN1`8X}Q3$~y=~8Yi3Q7ijg!fw zLsD5Sd4-T8e~4Hb53Z)J<#w8$FT}pmRmaczS@Qp>a6j<7N?Mfk#&b>0T70qx^@0m| y>Ri$W?b$THgx0^#^)g2di7ZqpWEHX2OjzGTL(aN-^=BmI88U, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 19:15+0200\n" +"PO-Revision-Date: 2010-05-12 12:41-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "il faut traduire cette chaîne de caractères de app4" +msgstr "este texto de app4 debe ser traducido" diff --git a/tests/regressiontests/views/locale/es/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/locale/es/LC_MESSAGES/djangojs.mo index 01c002e9e0e3878edd15a03a3d997c0e5124ef33..b6b088752a01696046502cda6205ccd9bccb6487 100644 GIT binary patch delta 162 zcmdnX{E9j6o)F7a1|VPtVi_Pd0b*7l_5orLNC0A9AWj5g2_Vh~VpB#2h7KUj2gLh; zY>>XQKpKd^fC);2%w%xR$j>iMRY+7Q$;?fi7%)N9$iUD**T7WQ&`811$ja1Q*TC4o cVB*)+e6Bf}>8T2(d5H=c`9+D7=QGLy08a`U@&Et; delta 118 zcmaFGyq7s(DvQuP1_)pRQZhiS1H`OAYy-p~5CFsyKpe=xz-S7jvw#?=j&T8yW&~mo q0O\n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,4 +18,8 @@ msgstr "" #: media/js/translate.js:1 msgid "this is to be translated" -msgstr "esto tiene que ser traducido" \ No newline at end of file +msgstr "esto tiene que ser traducido" + + +msgid "Choose a time" +msgstr "Elige una hora" diff --git a/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.mo b/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.mo index 4feca0b44d69463a63957c4869ca210ba7bce725..356147cf11c3f3a9765a75abba326f449f4c5bad 100644 GIT binary patch delta 165 zcmdnO{De90o)F7a1|VPtVi_Pd0b*7l_5orLNC0A9AWj5g2_Vh~VpB#2h7KSt2*mq< zY+)dM0Z0Q87%)L;keLk58Tt9esS1e-C7HRY69XoQ8W|WG=o*;n8X74W8d;eb>KYgu e7)<=SS`er*vpBOzp)@a5AtSZ4D0T9DMo|Eo;T$ml delta 118 zcmaFDyoEVnDvQuP1_)pRQZhiS1H`OAYy-p~5CFsyKpe=xz-S7jvw&C_$X)=X8G#rC qKzhMoV%`MNNLR-oU0;7)7e@sTe=A>4?I?dg*U7?+t0!Mz6afJ3e-Il0 diff --git a/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.po b/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.po index 9cfaa23232..0d03f95845 100644 --- a/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.po +++ b/tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-09-15 19:15+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2010-05-12 12:41-0300\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -17,4 +17,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" msgid "this is to be translated" -msgstr "il faut le traduire" \ No newline at end of file +msgstr "il faut le traduire" + + +msgid "Choose a time" +msgstr "Choisir une heure" diff --git a/tests/regressiontests/views/tests/i18n.py b/tests/regressiontests/views/tests/i18n.py index 5e85688499..91bf291e54 100644 --- a/tests/regressiontests/views/tests/i18n.py +++ b/tests/regressiontests/views/tests/i18n.py @@ -1,8 +1,10 @@ +# -*- coding:utf-8 -*- import gettext from django.conf import settings from django.test import TestCase -from django.utils.translation import activate +from django.utils.translation import activate, deactivate +from django.utils.text import javascript_quote from regressiontests.views.urls import locale_dir @@ -28,6 +30,7 @@ class I18NTests(TestCase): # catalog['this is to be translated'] = 'same_that_trans_txt' self.assertContains(response, trans_txt, 1) + class JsI18NTests(TestCase): """ Tests django views in django/views/i18n.py that need to change @@ -64,3 +67,68 @@ class JsI18NTests(TestCase): activate('fi') response = self.client.get('/views/jsi18n/') self.assertContains(response, 'il faut le traduire') + + def testI18NLanguageNonEnglishDefault(self): + """ + Check if the Javascript i18n view returns an empty language catalog + if the default language is non-English but the selected language + is English. See #13388 and #3594 for more details. + """ + settings.LANGUAGE_CODE = 'fr' + activate('en-us') + response = self.client.get('/views/jsi18n/') + self.assertNotContains(response, 'Choisir une heure') + deactivate() + + def testI18NLanguageNonEnglishFallback(self): + """ + Makes sure that the fallback language is still working properly + in cases where the selected language cannot be found. + """ + settings.LANGUAGE_CODE = 'fr' + activate('none') + response = self.client.get('/views/jsi18n/') + self.assertContains(response, 'Choisir une heure') + deactivate() + + +class JsI18NTestsMultiPackage(TestCase): + """ + Tests for django views in django/views/i18n.py that need to change + settings.LANGUAGE_CODE and merge JS translation from several packages. + """ + + def setUp(self): + self.old_language_code = settings.LANGUAGE_CODE + self.old_installed_apps = settings.INSTALLED_APPS + + def tearDown(self): + settings.LANGUAGE_CODE = self.old_language_code + settings.INSTALLED_APPS = self.old_installed_apps + + def testI18NLanguageEnglishDefault(self): + """ + Check if the JavaScript i18n view returns a complete language catalog + if the default language is en-us, the selected language has a + translation available and a catalog composed by djangojs domain + translations of multiple Python packages is requested. See #13388, + #3594 and #13514 for more details. + """ + settings.LANGUAGE_CODE = 'en-us' + settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) + ['regressiontests.views.app1', 'regressiontests.views.app2'] + activate('fr') + response = self.client.get('/views/jsi18n_multi_packages1/') + self.assertContains(response, javascript_quote('il faut traduire cette chaîne de caractères de app1')) + deactivate() + + def testI18NDifferentNonEnLangs(self): + """ + Similar to above but with neither default or requested language being + English. + """ + settings.LANGUAGE_CODE = 'fr' + settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) + ['regressiontests.views.app3', 'regressiontests.views.app4'] + activate('es-ar') + response = self.client.get('/views/jsi18n_multi_packages2/') + self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido')) + deactivate() diff --git a/tests/regressiontests/views/urls.py b/tests/regressiontests/views/urls.py index a072e77131..f5675d0e28 100644 --- a/tests/regressiontests/views/urls.py +++ b/tests/regressiontests/views/urls.py @@ -16,6 +16,16 @@ js_info_dict = { 'packages': ('regressiontests.views',), } +js_info_dict_multi_packages1 = { + 'domain': 'djangojs', + 'packages': ('regressiontests.views.app1', 'regressiontests.views.app2'), +} + +js_info_dict_multi_packages2 = { + 'domain': 'djangojs', + 'packages': ('regressiontests.views.app3', 'regressiontests.views.app4'), +} + date_based_info_dict = { 'queryset': Article.objects.all(), 'date_field': 'date_created', @@ -36,6 +46,8 @@ urlpatterns = patterns('', # i18n views (r'^i18n/', include('django.conf.urls.i18n')), (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), + (r'^jsi18n_multi_packages1/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages1), + (r'^jsi18n_multi_packages2/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages2), # Static views (r'^site_media/(?P.*)$', 'django.views.static.serve', {'document_root': media_dir}),