summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS46
-rw-r--r--django/__init__.py3
-rwxr-xr-xdjango/bin/make-messages.py21
-rw-r--r--django/conf/__init__.py2
-rw-r--r--django/conf/global_settings.py11
-rw-r--r--django/conf/locale/ca/LC_MESSAGES/django.mobin49503 -> 49588 bytes
-rw-r--r--django/conf/locale/ca/LC_MESSAGES/django.po8
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.mobin44039 -> 44119 bytes
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.po453
-rw-r--r--django/conf/locale/de/LC_MESSAGES/djangojs.mobin1569 -> 1571 bytes
-rw-r--r--django/conf/locale/de/LC_MESSAGES/djangojs.po16
-rw-r--r--django/conf/locale/es/LC_MESSAGES/django.mobin40333 -> 53873 bytes
-rw-r--r--django/conf/locale/es/LC_MESSAGES/django.po3845
-rw-r--r--django/conf/locale/es/LC_MESSAGES/djangojs.mobin1427 -> 1561 bytes
-rw-r--r--django/conf/locale/es/LC_MESSAGES/djangojs.po83
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/django.mobin44251 -> 49719 bytes
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/django.po3607
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/djangojs.mobin1576 -> 1633 bytes
-rw-r--r--django/conf/locale/es_AR/LC_MESSAGES/djangojs.po22
-rw-r--r--django/conf/locale/fr/LC_MESSAGES/django.mobin46214 -> 49592 bytes
-rw-r--r--django/conf/locale/fr/LC_MESSAGES/django.po1081
-rw-r--r--django/conf/locale/fr/LC_MESSAGES/djangojs.mobin1533 -> 1540 bytes
-rw-r--r--django/conf/locale/fr/LC_MESSAGES/djangojs.po18
-rw-r--r--django/conf/locale/hr/LC_MESSAGES/django.mobin0 -> 5413 bytes
-rw-r--r--django/conf/locale/hr/LC_MESSAGES/django.po3282
-rw-r--r--django/conf/locale/hr/LC_MESSAGES/djangojs.mobin0 -> 367 bytes
-rw-r--r--django/conf/locale/hr/LC_MESSAGES/djangojs.po118
-rw-r--r--django/conf/locale/it/LC_MESSAGES/django.mobin40774 -> 45114 bytes
-rw-r--r--django/conf/locale/it/LC_MESSAGES/django.po3460
-rw-r--r--django/conf/locale/it/LC_MESSAGES/djangojs.mobin1643 -> 1637 bytes
-rw-r--r--django/conf/locale/it/LC_MESSAGES/djangojs.po6
-rw-r--r--django/conf/locale/sk/LC_MESSAGES/django.mobin44089 -> 44426 bytes
-rw-r--r--django/conf/locale/sk/LC_MESSAGES/django.po1022
-rw-r--r--django/conf/locale/sl/LC_MESSAGES/django.mobin32469 -> 49385 bytes
-rw-r--r--django/conf/locale/sl/LC_MESSAGES/django.po3304
-rw-r--r--django/conf/locale/sl/LC_MESSAGES/djangojs.mobin1523 -> 1612 bytes
-rw-r--r--django/conf/locale/sl/LC_MESSAGES/djangojs.po67
-rw-r--r--django/conf/locale/sv/LC_MESSAGES/django.mobin45632 -> 47968 bytes
-rw-r--r--django/conf/locale/sv/LC_MESSAGES/django.po1383
-rw-r--r--django/conf/locale/zh_CN/LC_MESSAGES/django.mobin30798 -> 41991 bytes
-rw-r--r--django/conf/locale/zh_CN/LC_MESSAGES/django.po3042
-rw-r--r--django/conf/project_template/settings.py5
-rw-r--r--django/contrib/admin/filterspecs.py14
-rw-r--r--django/contrib/admin/media/js/admin/RelatedObjectLookups.js9
-rw-r--r--django/contrib/admin/media/js/urlify.js106
-rw-r--r--django/contrib/admin/models.py11
-rw-r--r--django/contrib/admin/templates/admin/auth/user/change_password.html2
-rw-r--r--django/contrib/admin/templates/admin/filter.html2
-rw-r--r--django/contrib/admin/templates/admin/index.html2
-rw-r--r--django/contrib/admin/templatetags/admin_list.py39
-rw-r--r--django/contrib/admin/templatetags/admin_modify.py29
-rw-r--r--django/contrib/admin/templatetags/adminapplist.py5
-rw-r--r--django/contrib/admin/views/auth.py1
-rw-r--r--django/contrib/admin/views/decorators.py4
-rw-r--r--django/contrib/admin/views/doc.py5
-rw-r--r--django/contrib/admin/views/main.py76
-rw-r--r--django/contrib/auth/__init__.py2
-rw-r--r--django/contrib/auth/forms.py22
-rw-r--r--django/contrib/auth/management.py4
-rw-r--r--django/contrib/auth/models.py85
-rw-r--r--django/contrib/auth/tests.py19
-rw-r--r--django/contrib/auth/views.py11
-rw-r--r--django/contrib/comments/feeds.py4
-rw-r--r--django/contrib/comments/models.py20
-rw-r--r--django/contrib/comments/templatetags/comments.py6
-rw-r--r--django/contrib/comments/views/comments.py17
-rw-r--r--django/contrib/comments/views/karma.py1
-rw-r--r--django/contrib/contenttypes/generic.py14
-rw-r--r--django/contrib/contenttypes/management.py3
-rw-r--r--django/contrib/contenttypes/models.py19
-rw-r--r--django/contrib/databrowse/datastructures.py55
-rw-r--r--django/contrib/databrowse/plugins/calendars.py19
-rw-r--r--django/contrib/databrowse/plugins/fieldchoices.py13
-rw-r--r--django/contrib/databrowse/sites.py2
-rw-r--r--django/contrib/databrowse/templates/databrowse/base.html5
-rw-r--r--django/contrib/databrowse/templates/databrowse/base_site.html1
-rw-r--r--django/contrib/databrowse/templates/databrowse/calendar_day.html6
-rw-r--r--django/contrib/databrowse/templates/databrowse/calendar_homepage.html2
-rw-r--r--django/contrib/databrowse/templates/databrowse/calendar_main.html2
-rw-r--r--django/contrib/databrowse/templates/databrowse/calendar_month.html6
-rw-r--r--django/contrib/databrowse/templates/databrowse/calendar_year.html2
-rw-r--r--django/contrib/databrowse/templates/databrowse/choice_detail.html4
-rw-r--r--django/contrib/databrowse/templates/databrowse/choice_list.html4
-rw-r--r--django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html4
-rw-r--r--django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html2
-rw-r--r--django/contrib/databrowse/templates/databrowse/fieldchoice_list.html4
-rw-r--r--django/contrib/databrowse/templates/databrowse/homepage.html4
-rw-r--r--django/contrib/databrowse/templates/databrowse/model_detail.html6
-rw-r--r--django/contrib/databrowse/templates/databrowse/object_detail.html12
-rw-r--r--django/contrib/flatpages/models.py12
-rw-r--r--django/contrib/gis/db/backend/__init__.py7
-rw-r--r--django/contrib/gis/db/backend/postgis/creation.py11
-rw-r--r--django/contrib/gis/db/backend/postgis/query.py7
-rw-r--r--django/contrib/gis/db/models/fields/__init__.py5
-rw-r--r--django/contrib/gis/db/models/query.py20
-rw-r--r--django/contrib/gis/gdal/srs.py8
-rw-r--r--django/contrib/gis/models.py10
-rw-r--r--django/contrib/gis/tests/__init__.py2
-rw-r--r--django/contrib/gis/tests/test_spatialrefsys.py13
-rw-r--r--django/contrib/humanize/templatetags/humanize.py45
-rw-r--r--django/contrib/localflavor/au/forms.py12
-rw-r--r--django/contrib/localflavor/br/forms.py20
-rw-r--r--django/contrib/localflavor/ch/ch_states.py2
-rw-r--r--django/contrib/localflavor/ch/forms.py6
-rw-r--r--django/contrib/localflavor/cl/cl_regions.py25
-rw-r--r--django/contrib/localflavor/cl/forms.py27
-rw-r--r--django/contrib/localflavor/de/de_states.py2
-rw-r--r--django/contrib/localflavor/de/forms.py12
-rw-r--r--django/contrib/localflavor/fi/forms.py12
-rw-r--r--django/contrib/localflavor/fr/forms.py8
-rw-r--r--django/contrib/localflavor/in_/__init__.py0
-rw-r--r--django/contrib/localflavor/in_/forms.py49
-rw-r--r--django/contrib/localflavor/in_/in_states.py84
-rw-r--r--django/contrib/localflavor/is_/forms.py9
-rw-r--r--django/contrib/localflavor/it/forms.py14
-rw-r--r--django/contrib/localflavor/it/it_province.py2
-rw-r--r--django/contrib/localflavor/it/util.py26
-rw-r--r--django/contrib/localflavor/jp/forms.py6
-rw-r--r--django/contrib/localflavor/jp/jp_prefectures.py96
-rw-r--r--django/contrib/localflavor/no/forms.py15
-rw-r--r--django/contrib/localflavor/no/no_municipalities.py10
-rw-r--r--django/contrib/localflavor/pl/__init__.py0
-rw-r--r--django/contrib/localflavor/pl/forms.py84
-rw-r--r--django/contrib/localflavor/pl/pl_administrativeunits.py385
-rw-r--r--django/contrib/localflavor/pl/pl_voivodeships.py24
-rw-r--r--django/contrib/localflavor/sk/__init__.py0
-rw-r--r--django/contrib/localflavor/sk/forms.py41
-rw-r--r--django/contrib/localflavor/sk/sk_districts.py87
-rw-r--r--django/contrib/localflavor/sk/sk_regions.py16
-rw-r--r--django/contrib/localflavor/uk/forms.py4
-rw-r--r--django/contrib/localflavor/us/forms.py20
-rw-r--r--django/contrib/markup/templatetags/markup.py15
-rw-r--r--django/contrib/redirects/models.py10
-rw-r--r--django/contrib/sessions/middleware.py9
-rw-r--r--django/contrib/sessions/models.py4
-rw-r--r--django/contrib/sessions/tests.py16
-rw-r--r--django/contrib/sitemaps/views.py3
-rw-r--r--django/contrib/sites/models.py32
-rw-r--r--django/contrib/syndication/feeds.py31
-rw-r--r--django/contrib/syndication/views.py2
-rw-r--r--django/contrib/webdesign/lorem_ipsum.py46
-rw-r--r--django/contrib/webdesign/templatetags/webdesign.py2
-rw-r--r--django/contrib/webdesign/tests.py4
-rw-r--r--django/core/cache/backends/filebased.py5
-rw-r--r--django/core/cache/backends/locmem.py17
-rw-r--r--django/core/cache/backends/memcached.py16
-rw-r--r--django/core/handlers/modpython.py9
-rw-r--r--django/core/handlers/wsgi.py22
-rw-r--r--django/core/mail.py46
-rw-r--r--django/core/management.py1747
-rw-r--r--django/core/management/__init__.py180
-rw-r--r--django/core/management/base.py159
-rw-r--r--django/core/management/color.py28
-rw-r--r--django/core/management/commands/__init__.py0
-rw-r--r--django/core/management/commands/adminindex.py33
-rw-r--r--django/core/management/commands/createcachetable.py42
-rw-r--r--django/core/management/commands/dbshell.py10
-rw-r--r--django/core/management/commands/diffsettings.py32
-rw-r--r--django/core/management/commands/dumpdata.py33
-rw-r--r--django/core/management/commands/flush.py64
-rw-r--r--django/core/management/commands/inspectdb.py120
-rw-r--r--django/core/management/commands/loaddata.py123
-rw-r--r--django/core/management/commands/reset.py47
-rw-r--r--django/core/management/commands/runfcgi.py16
-rw-r--r--django/core/management/commands/runserver.py70
-rw-r--r--django/core/management/commands/shell.py42
-rw-r--r--django/core/management/commands/sql.py10
-rw-r--r--django/core/management/commands/sqlall.py10
-rw-r--r--django/core/management/commands/sqlclear.py10
-rw-r--r--django/core/management/commands/sqlcustom.py10
-rw-r--r--django/core/management/commands/sqlflush.py10
-rw-r--r--django/core/management/commands/sqlindexes.py10
-rw-r--r--django/core/management/commands/sqlinitialdata.py7
-rw-r--r--django/core/management/commands/sqlreset.py10
-rw-r--r--django/core/management/commands/sqlsequencereset.py9
-rw-r--r--django/core/management/commands/startapp.py34
-rw-r--r--django/core/management/commands/startproject.py40
-rw-r--r--django/core/management/commands/syncdb.py130
-rw-r--r--django/core/management/commands/test.py28
-rw-r--r--django/core/management/commands/testserver.py26
-rw-r--r--django/core/management/commands/validate.py9
-rw-r--r--django/core/management/sql.py433
-rw-r--r--django/core/management/validation.py221
-rw-r--r--django/core/serializers/__init__.py16
-rw-r--r--django/core/serializers/base.py12
-rw-r--r--django/core/serializers/python.py49
-rw-r--r--django/core/serializers/pyyaml.py4
-rw-r--r--django/core/serializers/xml_serializer.py86
-rw-r--r--django/core/servers/basehttp.py10
-rw-r--r--django/core/urlresolvers.py38
-rw-r--r--django/core/validators.py144
-rw-r--r--django/core/xheaders.py6
-rw-r--r--django/db/backends/__init__.py218
-rw-r--r--django/db/backends/ado_mssql/base.py191
-rw-r--r--django/db/backends/ado_mssql/creation.py6
-rw-r--r--django/db/backends/dummy/base.py35
-rw-r--r--django/db/backends/mysql/base.py254
-rw-r--r--django/db/backends/mysql/creation.py6
-rw-r--r--django/db/backends/mysql/introspection.py3
-rw-r--r--django/db/backends/mysql_old/base.py270
-rw-r--r--django/db/backends/mysql_old/creation.py7
-rw-r--r--django/db/backends/mysql_old/introspection.py3
-rw-r--r--django/db/backends/oracle/base.py862
-rw-r--r--django/db/backends/oracle/creation.py33
-rw-r--r--django/db/backends/oracle/introspection.py4
-rw-r--r--django/db/backends/postgresql/base.py276
-rw-r--r--django/db/backends/postgresql/creation.py8
-rw-r--r--django/db/backends/postgresql/introspection.py4
-rw-r--r--django/db/backends/postgresql/operations.py109
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py230
-rw-r--r--django/db/backends/postgresql_psycopg2/introspection.py11
-rw-r--r--django/db/backends/sqlite3/base.py215
-rw-r--r--django/db/backends/sqlite3/creation.py6
-rw-r--r--django/db/backends/sqlite3/introspection.py6
-rw-r--r--django/db/backends/util.py46
-rw-r--r--django/db/models/__init__.py16
-rw-r--r--django/db/models/base.py80
-rw-r--r--django/db/models/fields/__init__.py130
-rw-r--r--django/db/models/fields/related.py50
-rw-r--r--django/db/models/loading.py273
-rw-r--r--django/db/models/manager.py6
-rw-r--r--django/db/models/manipulators.py6
-rw-r--r--django/db/models/options.py32
-rw-r--r--django/db/models/query.py139
-rw-r--r--django/http/__init__.py119
-rw-r--r--django/middleware/common.py4
-rw-r--r--django/middleware/gzip.py5
-rw-r--r--django/middleware/http.py5
-rw-r--r--django/newforms/extras/widgets.py4
-rw-r--r--django/newforms/fields.py167
-rw-r--r--django/newforms/forms.py50
-rw-r--r--django/newforms/models.py36
-rw-r--r--django/newforms/util.py18
-rw-r--r--django/newforms/widgets.py92
-rw-r--r--django/oldforms/__init__.py282
-rw-r--r--django/shortcuts/__init__.py60
-rw-r--r--django/template/__init__.py45
-rw-r--r--django/template/defaultfilters.py139
-rw-r--r--django/template/defaulttags.py34
-rw-r--r--django/template/loader_tags.py2
-rw-r--r--django/template/loaders/app_directories.py21
-rw-r--r--django/template/loaders/eggs.py2
-rw-r--r--django/template/loaders/filesystem.py14
-rw-r--r--django/templatetags/i18n.py8
-rw-r--r--django/test/client.py51
-rw-r--r--django/test/simple.py129
-rw-r--r--django/test/testcases.py37
-rw-r--r--django/test/utils.py73
-rw-r--r--django/utils/_os.py23
-rw-r--r--django/utils/cache.py20
-rw-r--r--django/utils/datastructures.py13
-rw-r--r--django/utils/dateformat.py56
-rw-r--r--django/utils/dates.py6
-rw-r--r--django/utils/decorators.py26
-rw-r--r--django/utils/encoding.py85
-rw-r--r--django/utils/feedgenerator.py55
-rw-r--r--django/utils/functional.py67
-rw-r--r--django/utils/html.py80
-rw-r--r--django/utils/http.py38
-rw-r--r--django/utils/maxlength.py67
-rw-r--r--django/utils/stopwords.py2
-rw-r--r--django/utils/text.py55
-rw-r--r--django/utils/timesince.py24
-rw-r--r--django/utils/translation/__init__.py23
-rw-r--r--django/utils/translation/trans_null.py11
-rw-r--r--django/utils/translation/trans_real.py95
-rw-r--r--django/utils/tzinfo.py13
-rw-r--r--django/utils/version.py39
-rw-r--r--django/views/debug.py31
-rw-r--r--django/views/defaults.py5
-rw-r--r--django/views/generic/create_update.py12
-rw-r--r--django/views/generic/date_based.py2
-rw-r--r--django/views/generic/list_detail.py2
-rw-r--r--django/views/i18n.py4
-rw-r--r--docs/add_ons.txt25
-rw-r--r--docs/api_stability.txt5
-rw-r--r--docs/authentication.txt33
-rw-r--r--docs/cache.txt2
-rw-r--r--docs/contributing.txt96
-rw-r--r--docs/csrf.txt10
-rw-r--r--docs/databases.txt2
-rw-r--r--docs/databrowse.txt1
-rw-r--r--docs/db-api.txt113
-rw-r--r--docs/distributions.txt24
-rw-r--r--docs/django-admin.txt55
-rw-r--r--docs/email.txt2
-rw-r--r--docs/faq.txt3
-rw-r--r--docs/fastcgi.txt2
-rw-r--r--docs/forms.txt12
-rw-r--r--docs/generic_views.txt10
-rw-r--r--docs/i18n.txt178
-rw-r--r--docs/install.txt32
-rw-r--r--docs/man/compile-messages.140
-rw-r--r--docs/man/daily_cleanup.134
-rw-r--r--docs/man/gather_profile_stats.126
-rw-r--r--docs/man/make-messages.162
-rw-r--r--docs/middleware.txt14
-rw-r--r--docs/model-api.txt294
-rw-r--r--docs/modpython.txt28
-rw-r--r--docs/newforms.txt379
-rw-r--r--docs/overview.txt28
-rw-r--r--docs/release_notes_0.95.txt2
-rw-r--r--docs/request_response.txt26
-rw-r--r--docs/sessions.txt6
-rw-r--r--docs/settings.txt19
-rw-r--r--docs/sitemaps.txt2
-rw-r--r--docs/sites.txt28
-rw-r--r--docs/static_files.txt8
-rw-r--r--docs/syndication_feeds.txt50
-rw-r--r--docs/templates.txt122
-rw-r--r--docs/templates_python.txt11
-rw-r--r--docs/testing.txt1038
-rw-r--r--docs/tutorial01.txt69
-rw-r--r--docs/tutorial02.txt8
-rw-r--r--docs/tutorial03.txt5
-rw-r--r--docs/tutorial04.txt24
-rw-r--r--docs/unicode.txt364
-rw-r--r--docs/url_dispatch.txt24
-rw-r--r--tests/modeltests/basic/models.py26
-rw-r--r--tests/modeltests/choices/models.py10
-rw-r--r--tests/modeltests/custom_columns/models.py24
-rw-r--r--tests/modeltests/custom_managers/models.py18
-rw-r--r--tests/modeltests/custom_methods/models.py4
-rw-r--r--tests/modeltests/custom_pk/models.py18
-rw-r--r--tests/modeltests/field_defaults/models.py4
-rw-r--r--tests/modeltests/fixtures/models.py40
-rw-r--r--tests/modeltests/generic_relations/models.py24
-rw-r--r--tests/modeltests/get_latest/models.py8
-rw-r--r--tests/modeltests/get_object_or_404/models.py35
-rw-r--r--tests/modeltests/get_or_create/models.py8
-rw-r--r--tests/modeltests/invalid_models/models.py44
-rw-r--r--tests/modeltests/lookup/models.py56
-rw-r--r--tests/modeltests/m2m_and_m2o/models.py6
-rw-r--r--tests/modeltests/m2m_intermediary/models.py18
-rw-r--r--tests/modeltests/m2m_multiple/models.py8
-rw-r--r--tests/modeltests/m2m_recursive/models.py4
-rw-r--r--tests/modeltests/m2o_recursive/models.py4
-rw-r--r--tests/modeltests/m2o_recursive2/models.py4
-rw-r--r--tests/modeltests/manipulators/models.py22
-rw-r--r--tests/modeltests/many_to_many/models.py8
-rw-r--r--tests/modeltests/many_to_one/models.py21
-rw-r--r--tests/modeltests/many_to_one_null/models.py8
-rw-r--r--tests/modeltests/model_forms/models.py48
-rw-r--r--tests/modeltests/model_inheritance/models.py16
-rw-r--r--tests/modeltests/mutually_referential/models.py4
-rw-r--r--tests/modeltests/one_to_one/models.py24
-rw-r--r--tests/modeltests/or_lookups/models.py6
-rw-r--r--tests/modeltests/ordering/models.py4
-rw-r--r--tests/modeltests/pagination/models.py4
-rw-r--r--tests/modeltests/properties/models.py4
-rw-r--r--tests/modeltests/reserved_names/models.py18
-rw-r--r--tests/modeltests/reverse_lookup/models.py12
-rw-r--r--tests/modeltests/save_delete_hooks/models.py8
-rw-r--r--tests/modeltests/select_related/models.py32
-rw-r--r--tests/modeltests/serializers/models.py16
-rw-r--r--tests/modeltests/str/models.py37
-rw-r--r--tests/modeltests/test_client/fixtures/testdata.json18
-rw-r--r--tests/modeltests/test_client/models.py45
-rw-r--r--tests/modeltests/test_client/tests.py20
-rw-r--r--tests/modeltests/test_client/views.py5
-rw-r--r--tests/modeltests/transactions/models.py10
-rw-r--r--tests/modeltests/validation/models.py16
-rw-r--r--tests/regressiontests/bug639/models.py2
-rw-r--r--tests/regressiontests/cache/tests.py41
-rw-r--r--tests/regressiontests/datastructures/tests.py9
-rw-r--r--tests/regressiontests/datatypes/models.py2
-rw-r--r--tests/regressiontests/dateformat/tests.py46
-rw-r--r--tests/regressiontests/defaultfilters/tests.py446
-rw-r--r--tests/regressiontests/fixtures_regress/fixtures/pretty.xml11
-rw-r--r--tests/regressiontests/fixtures_regress/models.py31
-rw-r--r--tests/regressiontests/forms/localflavor.py118
-rw-r--r--tests/regressiontests/forms/regressions.py49
-rw-r--r--tests/regressiontests/forms/tests.py154
-rw-r--r--tests/regressiontests/httpwrappers/tests.py76
-rw-r--r--tests/regressiontests/humanize/tests.py32
-rw-r--r--tests/regressiontests/i18n/__init__.py0
-rw-r--r--tests/regressiontests/i18n/models.py0
-rw-r--r--tests/regressiontests/i18n/tests.py33
-rw-r--r--tests/regressiontests/initial_sql_regress/models.py2
-rw-r--r--tests/regressiontests/invalid_admin_options/models.py74
-rw-r--r--tests/regressiontests/many_to_one_regress/models.py6
-rw-r--r--tests/regressiontests/maxlength/__init__.py0
-rw-r--r--tests/regressiontests/maxlength/models.py0
-rw-r--r--tests/regressiontests/maxlength/tests.py160
-rw-r--r--tests/regressiontests/model_fields/__init__.py0
-rw-r--r--tests/regressiontests/model_fields/models.py0
-rw-r--r--tests/regressiontests/model_fields/tests.py18
-rw-r--r--tests/regressiontests/model_regress/__init__.py0
-rw-r--r--tests/regressiontests/model_regress/models.py40
-rw-r--r--tests/regressiontests/null_queries/models.py12
-rw-r--r--tests/regressiontests/one_to_one_regress/models.py18
-rw-r--r--tests/regressiontests/serializers_regress/models.py37
-rw-r--r--tests/regressiontests/serializers_regress/tests.py39
-rw-r--r--tests/regressiontests/string_lookup/models.py62
-rw-r--r--tests/regressiontests/templates/tests.py72
-rw-r--r--tests/regressiontests/templates/unicode.py33
-rw-r--r--tests/regressiontests/templates/urls.py4
-rw-r--r--tests/regressiontests/test_client_regress/models.py59
-rw-r--r--tests/regressiontests/test_client_regress/urls.py2
-rw-r--r--tests/regressiontests/test_client_regress/views.py16
-rw-r--r--tests/regressiontests/text/tests.py31
-rw-r--r--tests/regressiontests/utils/__init__.py0
-rw-r--r--tests/regressiontests/utils/models.py1
-rw-r--r--tests/regressiontests/utils/tests.py115
-rwxr-xr-xtests/runtests.py25
405 files changed, 27865 insertions, 15117 deletions
diff --git a/AUTHORS b/AUTHORS
index 35ad3b7ef3..bc5c44b335 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -44,6 +44,7 @@ answer newbie questions, and generally made Django that much better:
alang@bright-green.com
Marty Alchin <gulopine@gamemusic.org>
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
+ AgarFu <heaven@croasanaso.sytes.net>
Andreas
andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com>
@@ -56,15 +57,21 @@ answer newbie questions, and generally made Django that much better:
Ned Batchelder <http://www.nedbatchelder.com/>
Shannon -jj Behrens <http://jjinux.blogspot.com/>
Esdras Beleza <linux@esdrasbeleza.com>
+ Chris Bennett <chrisrbennett@yahoo.com>
James Bennett
Ben <afternoon@uk2.net>
Paul Bissex <http://e-scribe.com/>
Simon Blanchard
+ Matt Boersma <ogghead@gmail.com>
+ boobsd@gmail.com
Andrew Brehaut <http://brehaut.net/blog>
brut.alll@gmail.com
Jonathan Buchanan <jonathan.buchanan@gmail.com>
+ Trevor Caira <trevor@caira.com>
+ Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
Antonio Cavedoni <http://cavedoni.com/>
C8E
+ cedric@terramater.net
Chris Chamberlin <dja@cdc.msbx.net>
Amit Chakradeo <http://amit.chakradeo.net/>
ChaosKCW
@@ -72,6 +79,7 @@ answer newbie questions, and generally made Django that much better:
Bryan Chow <bryan at verdjn dot com>
Michal Chruszcz <troll@pld-linux.org>
Ian Clelland <clelland@gmail.com>
+ colin@owlfish.com
crankycoder@gmail.com
Pete Crosier <pete.crosier@gmail.com>
Matt Croydon <http://www.postneo.com/>
@@ -91,10 +99,14 @@ answer newbie questions, and generally made Django that much better:
Maximillian Dornseif <md@hudora.de>
Jeremy Dunck <http://dunck.us/>
Andrew Durdin <adurdin@gmail.com>
+ dusk@woofle.net
Andy Dustman <farcepest@gmail.com>
Clint Ecker
+ Nick Efford <nick@efford.org>
+ eibaan@gmail.com
enlight
Enrico <rico.bl@gmail.com>
+ A. Murat Eren <meren@pardus.org.tr>
Ludvig Ericson <ludvig.ericson@gmail.com>
Dirk Eschler <dirk.eschler@gmx.net>
Marc Fargas <telenieko@telenieko.com>
@@ -106,19 +118,26 @@ answer newbie questions, and generally made Django that much better:
Eric Floehr <eric@intellovations.com>
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info
+ Marc Garcia <marc.garcia@accopensys.com>
Baishampayan Ghose
glin@seznam.cz
martin.glueck@gmail.com
GomoX <gomo@datafull.com>
+ Mario Gonzalez <gonzalemario@gmail.com>
+ pradeep.gowda@gmail.com
Simon Greenhill <dev@simon.net.nz>
Owen Griffiths
Espen Grindhaug <http://grindhaug.org/>
+ Thomas Güttler <hv@tbz-pariv.de>
+ dAniel hAhler
Brian Harring <ferringb@gmail.com>
Brant Harris
Hawkeye
Joe Heck <http://www.rhonabwy.com/wp/>
Joel Heenan <joelh-django@planetjoel.com>
hipertracker@gmail.com
+ Deryck Hodge <http://www.devurandom.org/>
+ Brett Hoerner <bretthoerner@bretthoerner.com>
Ian Holsman <http://feh.holsman.net/>
Kieran Holland <http://www.kieranholland.com>
Sung-Jin Hong <serialx.net@gmail.com>
@@ -128,6 +147,7 @@ answer newbie questions, and generally made Django that much better:
Hyun Mi Ae
Tom Insam
Baurzhan Ismagulov <ibr@radix50.net>
+ james_027@yahoo.com
jcrasta@gmail.com
Zak Johnson <zakj@nox.cx>
Michael Josephson <http://www.sdjournal.com/>
@@ -135,18 +155,23 @@ answer newbie questions, and generally made Django that much better:
junzhang.jn@gmail.com
Antti Kaihola <http://akaihola.blogspot.com/>
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
- ian.g.kelly@gmail.com
+ Ian G. Kelly <ian.g.kelly@gmail.com>
+ Ben Khoo <khoobks@westnet.com.au>
Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/>
Bastian Kleineidam <calvin@debian.org>
Cameron Knight (ckknight)
+ Nena Kojadin <nena@kiberpipa.org>
+ Igor Kolar <ike@email.si>
Gasper Koren
Martin Kosír <martin@martinkosir.net>
Meir Kriheli <http://mksoft.co.il/>
Bruce Kroeze <http://coderseye.com/>
+ krzysiek.pawlik@silvermedia.pl
Joseph Kocherhans
konrad@gwu.edu
+ kurtiss@meetro.com
lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
Stuart Langridge <http://www.kryogenix.org/>
@@ -158,13 +183,14 @@ answer newbie questions, and generally made Django that much better:
lerouxb@gmail.com
Waylan Limberg <waylan@gmail.com>
limodou
+ Philip Lindborg <philip.lindborg@gmail.com>
Matt McClanahan <http://mmcc.cx/>
Martin Maney <http://www.chipy.org/Martin_Maney>
masonsimon+django@gmail.com
Manuzhai
Petar Marić <http://www.petarmaric.com/>
Nuno Mariz <nmariz@gmail.com>
- marijn@metronomo.cl
+ Marijn Vriens <marijn@metronomo.cl>
mark@junklight.com
Yasushi Masuda <whosaysni@gmail.com>
mattycakes@gmail.com
@@ -172,9 +198,13 @@ answer newbie questions, and generally made Django that much better:
mccutchen@gmail.com
michael.mcewan@gmail.com
mikko@sorl.net
+ Slawek Mikula <slawek dot mikula at gmail dot com>
mitakummaa@gmail.com
mmarshall
+ Andreas Mock <andreas.mock@web.de>
Reza Mohammadi <reza@zeerak.ir>
+ Aljosa Mohorovic <aljosa.mohorovic@gmail.com>
+ Ramiro Morales <rm0@gmx.net>
Eric Moritz <http://eric.themoritzfamily.com/>
mrmachine <real.human@mrmachine.net>
Robin Munn <http://www.geekforgod.com/>
@@ -184,6 +214,7 @@ answer newbie questions, and generally made Django that much better:
Fraser Nevett <mail@nevett.org>
Sam Newman <http://www.magpiebrain.com/>
Neal Norwitz <nnorwitz@google.com>
+ Todd O'Bryan <toddobryan@mac.com>
oggie rob <oz.robharvey@gmail.com>
Jay Parlar <parlar@gmail.com>
pavithran s <pavithran.s@gmail.com>
@@ -198,22 +229,26 @@ answer newbie questions, and generally made Django that much better:
plisk
Daniel Poelzleithner <http://poelzi.org/>
polpak@yahoo.com
+ Jyrki Pulliainen <jyrki.pulliainen@gmail.com>
+ Johann Queuniet <johann.queuniet@adh.naellia.eu>
J. Rademaker
Michael Radziej <mir@noris.de>
- Ramiro Morales <rm0@gmx.net>
Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
Brian Ray <http://brianray.chipy.org/>
remco@diji.biz
rhettg@gmail.com
Henrique Romano <onaiort@gmail.com>
Armin Ronacher
+ Brian Rosner <brosner@gmail.com>
Oliver Rutherfurd <http://rutherfurd.net/>
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
Vinay Sajip <vinay_sajip@yahoo.co.uk>
David Schein
scott@staplefish.com
serbaut@gmail.com
+ John Shaffer <jshaffer2112@gmail.com>
Pete Shinners <pete@shinners.org>
+ Jozko Skrablin <jozko.skrablin@gmail.com>
SmileyChris <smileychris@gmail.com>
smurf@smurf.noris.de
sopel
@@ -222,6 +257,8 @@ answer newbie questions, and generally made Django that much better:
Vasiliy Stavenko <stavenko@gmail.com>
Thomas Steinacher <http://www.eggdrop.ch/>
nowell strite
+ Sundance
+ SuperJared
Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/>
@@ -231,10 +268,12 @@ answer newbie questions, and generally made Django that much better:
thebjorn <bp@datakortet.no>
Zach Thompson <zthompson47@gmail.com>
tibimicu@gmax.net
+ tobias@neuyork.de
Tom Tobin
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
torne-django@wolfpuppy.org.uk
Karen Tracey <graybark@bellsouth.net>
+ tstromberg@google.com
Makoto Tsuyuki <mtsuyuki@gmail.com>
tt@gurgle.no
Amit Upadhyay
@@ -250,6 +289,7 @@ answer newbie questions, and generally made Django that much better:
charly.wilhelm@gmail.com
Rachel Willmer <http://www.willmer.com/kb/>
Gary Wilson <gary.wilson@gmail.com>
+ Jakub Wiśniowski <restless.being@gmail.com>
wojtek
ye7cakf02@sneakemail.com
ymasuda@ethercube.com
diff --git a/django/__init__.py b/django/__init__.py
index 17d8c519cc..de473fa4e9 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -4,5 +4,6 @@ def get_version():
"Returns the version as a human-format string."
v = '.'.join([str(i) for i in VERSION[:-1]])
if VERSION[-1]:
- v += '-' + VERSION[-1]
+ from django.utils.version import get_svn_revision
+ v = '%s-%s-%s' % (v, VERSION[-1], get_svn_revision())
return v
diff --git a/django/bin/make-messages.py b/django/bin/make-messages.py
index bf9e7a1962..11616c9ca5 100755
--- a/django/bin/make-messages.py
+++ b/django/bin/make-messages.py
@@ -9,6 +9,7 @@ import re
import os
import sys
import getopt
+from itertools import dropwhile
pythonize_re = re.compile(r'\n\s*//')
@@ -83,7 +84,7 @@ def make_messages():
thefile = '%s.py' % file
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
- (stdin, stdout, stderr) = os.popen3(cmd, 'b')
+ (stdin, stdout, stderr) = os.popen3(cmd, 't')
msgs = stdout.read()
errors = stderr.read()
if errors:
@@ -100,12 +101,13 @@ def make_messages():
thefile = file
if file.endswith('.html'):
src = open(os.path.join(dirpath, file), "rb").read()
- open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file
- if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
- cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
- os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
- (stdin, stdout, stderr) = os.popen3(cmd, 'b')
+ open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
+ if verbose:
+ sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
+ cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
+ domain, os.path.join(dirpath, thefile))
+ (stdin, stdout, stderr) = os.popen3(cmd, 't')
msgs = stdout.read()
errors = stderr.read()
if errors:
@@ -116,13 +118,18 @@ def make_messages():
old = '#: '+os.path.join(dirpath, thefile)[2:]
new = '#: '+os.path.join(dirpath, file)[2:]
msgs = msgs.replace(old, new)
+ if os.path.exists(potfile):
+ # Strip the header
+ msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
+ else:
+ msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
if msgs:
open(potfile, 'ab').write(msgs)
if thefile != file:
os.unlink(os.path.join(dirpath, thefile))
if os.path.exists(potfile):
- (stdin, stdout, stderr) = os.popen3('msguniq "%s"' % potfile, 'b')
+ (stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
msgs = stdout.read()
errors = stderr.read()
if errors:
diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index 021ecc8131..f28da2d764 100644
--- a/django/conf/__init__.py
+++ b/django/conf/__init__.py
@@ -37,6 +37,8 @@ class LazySettings(object):
# __setattr__(), which would be an infinite loop.
self.__dict__['_target'] = value
else:
+ if self._target is None:
+ self._import_settings()
setattr(self._target, name, value)
def _import_settings(self):
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index ea92d13eb3..e11ea7531b 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -25,12 +25,12 @@ ADMINS = ()
INTERNAL_IPS = ()
# Local time zone for this installation. All choices can be found here:
-# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name (although not all
+# systems may support all possibilities).
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
-# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE = 'en-us'
# Languages we provide translations for, out of the box. The language name
@@ -54,6 +54,7 @@ LANGUAGES = (
('gl', gettext_noop('Galician')),
('hu', gettext_noop('Hungarian')),
('he', gettext_noop('Hebrew')),
+ ('hr', gettext_noop('Croatian')),
('is', gettext_noop('Icelandic')),
('it', gettext_noop('Italian')),
('ja', gettext_noop('Japanese')),
@@ -81,7 +82,7 @@ LANGUAGES = (
)
# Languages using BiDi (right-to-left) layout
-LANGUAGES_BIDI = ("he", "ar")
+LANGUAGES_BIDI = ("he", "ar", "fa")
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
@@ -97,6 +98,9 @@ MANAGERS = ADMINS
DEFAULT_CONTENT_TYPE = 'text/html'
DEFAULT_CHARSET = 'utf-8'
+# Encoding of files read from disk (template and initial SQL files).
+FILE_CHARSET = 'utf-8'
+
# E-mail address that error messages come from.
SERVER_EMAIL = 'root@localhost'
@@ -280,6 +284,7 @@ SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user
# possible values.
CACHE_BACKEND = 'simple://'
CACHE_MIDDLEWARE_KEY_PREFIX = ''
+CACHE_MIDDLEWARE_SECONDS = 600
####################
# COMMENTS #
diff --git a/django/conf/locale/ca/LC_MESSAGES/django.mo b/django/conf/locale/ca/LC_MESSAGES/django.mo
index f308c7589a..82cd1bee4b 100644
--- a/django/conf/locale/ca/LC_MESSAGES/django.mo
+++ b/django/conf/locale/ca/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/ca/LC_MESSAGES/django.po b/django/conf/locale/ca/LC_MESSAGES/django.po
index b8450ad1b9..451c60e2db 100644
--- a/django/conf/locale/ca/LC_MESSAGES/django.po
+++ b/django/conf/locale/ca/LC_MESSAGES/django.po
@@ -237,7 +237,7 @@ msgstr "Coreà"
#: conf/global_settings.py:61
msgid "Kannada"
-msgstr ""
+msgstr "Canès"
#: conf/global_settings.py:62
msgid "Latvian"
@@ -1230,7 +1230,7 @@ msgstr "Pot editar-lo de nou abaix."
#: contrib/admin/views/auth.py:30
msgid "Add user"
-msgstr "Agregar usuari"
+msgstr "Afegir usuari"
#: contrib/admin/views/auth.py:57
msgid "Password changed successfully."
@@ -1248,12 +1248,12 @@ msgstr "Lloc administratiu"
#: contrib/admin/views/main.py:276 contrib/admin/views/main.py:361
#, python-format
msgid "You may add another %s below."
-msgstr "Pot agregar un altre %s abaix."
+msgstr "Pot afegir un altre %s a baix."
#: contrib/admin/views/main.py:294
#, python-format
msgid "Add %s"
-msgstr "Agregar %s"
+msgstr "Afegir %s"
#: contrib/admin/views/main.py:340
#, python-format
diff --git a/django/conf/locale/de/LC_MESSAGES/django.mo b/django/conf/locale/de/LC_MESSAGES/django.mo
index d1981a679d..307976e4d5 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.mo
+++ b/django/conf/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/de/LC_MESSAGES/django.po b/django/conf/locale/de/LC_MESSAGES/django.po
index 3ccbefe249..6978cf2d44 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.po
+++ b/django/conf/locale/de/LC_MESSAGES/django.po
@@ -3,10 +3,10 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
-msgstr ""
-"Project-Id-Version: Django 1.0\n"
+""
+msgstr "Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-04-09 22:42+0200\n"
+"POT-Creation-Date: 2007-07-28 12:33+0200\n"
"PO-Revision-Date: 2007-02-05 03:19+0100\n"
"Last-Translator: Jannis Leidel <jl@websushi.org>\n"
"Language-Team: \n"
@@ -19,591 +19,590 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Generator: KBabel 1.11.4\n"
-#: conf/global_settings.py:39
+#:conf/global_settings.py:38
msgid "Arabic"
msgstr "Arabisch"
-#: conf/global_settings.py:40
+#:conf/global_settings.py:39
msgid "Bengali"
msgstr "Bengali"
-#: conf/global_settings.py:41
+#:conf/global_settings.py:40
+msgid "Bulgarian"
+msgstr "Bulgarisch"
+
+#:conf/global_settings.py:41
msgid "Catalan"
msgstr "Katalanisch"
-#: conf/global_settings.py:42
+#:conf/global_settings.py:42
msgid "Czech"
msgstr "Tschechisch"
-#: conf/global_settings.py:43
+#:conf/global_settings.py:43
msgid "Welsh"
msgstr "Walisisch"
-#: conf/global_settings.py:44
+#:conf/global_settings.py:44
msgid "Danish"
msgstr "Dänisch"
-#: conf/global_settings.py:45
+#:conf/global_settings.py:45
msgid "German"
msgstr "Deutsch"
-#: conf/global_settings.py:46
+#:conf/global_settings.py:46
msgid "Greek"
msgstr "Griechisch"
-#: conf/global_settings.py:47
+#:conf/global_settings.py:47
msgid "English"
msgstr "Englisch"
-#: conf/global_settings.py:48
+#:conf/global_settings.py:48
msgid "Spanish"
msgstr "Spanisch"
-#: conf/global_settings.py:49
+#:conf/global_settings.py:49
msgid "Argentinean Spanish"
msgstr "Argentinisches Spanisch"
-#: conf/global_settings.py:50
+#:conf/global_settings.py:50
+msgid "Persian"
+msgstr "Persisch"
+
+#:conf/global_settings.py:51
msgid "Finnish"
msgstr "Finnisch"
-#: conf/global_settings.py:51
+#:conf/global_settings.py:52
msgid "French"
msgstr "Französisch"
-#: conf/global_settings.py:52
+#:conf/global_settings.py:53
msgid "Galician"
msgstr "Galicisch"
-#: conf/global_settings.py:53
+#:conf/global_settings.py:54
msgid "Hungarian"
msgstr "Ungarisch"
-#: conf/global_settings.py:54
+#:conf/global_settings.py:55
msgid "Hebrew"
msgstr "Hebräisch"
-#: conf/global_settings.py:55
+#:conf/global_settings.py:56
msgid "Icelandic"
msgstr "Isländisch"
-#: conf/global_settings.py:56
+#:conf/global_settings.py:57
msgid "Italian"
msgstr "Italienisch"
-#: conf/global_settings.py:57
+#:conf/global_settings.py:58
msgid "Japanese"
msgstr "Japanisch"
-#: conf/global_settings.py:58
+#:conf/global_settings.py:59
msgid "Korean"
msgstr "Koreanisch"
-#: conf/global_settings.py:59
+#:conf/global_settings.py:60
msgid "Kannada"
msgstr "Kannada"
-#: conf/global_settings.py:60
+#:conf/global_settings.py:61
msgid "Latvian"
msgstr "Lettisch"
-#: conf/global_settings.py:61
+#:conf/global_settings.py:62
msgid "Macedonian"
msgstr "Mazedonisch"
-#: conf/global_settings.py:62
+#:conf/global_settings.py:63
msgid "Dutch"
msgstr "Holländisch"
-#: conf/global_settings.py:63
+#:conf/global_settings.py:64
msgid "Norwegian"
msgstr "Norwegisch"
-#: conf/global_settings.py:64
+#:conf/global_settings.py:65
msgid "Polish"
msgstr "Polnisch"
-#: conf/global_settings.py:65
+#:conf/global_settings.py:66
msgid "Portugese"
msgstr "Portugiesisch"
-#: conf/global_settings.py:66
+#:conf/global_settings.py:67
msgid "Brazilian"
msgstr "Brasilianisches Portugiesisch"
-#: conf/global_settings.py:67
+#:conf/global_settings.py:68
msgid "Romanian"
msgstr "Rumänisch"
-#: conf/global_settings.py:68
+#:conf/global_settings.py:69
msgid "Russian"
msgstr "Russisch"
-#: conf/global_settings.py:69
+#:conf/global_settings.py:70
msgid "Slovak"
msgstr "Slowakisch"
-#: conf/global_settings.py:70
+#:conf/global_settings.py:71
msgid "Slovenian"
msgstr "Slowenisch"
-#: conf/global_settings.py:71
+#:conf/global_settings.py:72
msgid "Serbian"
msgstr "Serbisch"
-#: conf/global_settings.py:72
+#:conf/global_settings.py:73
msgid "Swedish"
msgstr "Schwedisch"
-#: conf/global_settings.py:73
+#:conf/global_settings.py:74
msgid "Tamil"
msgstr "Tamilisch"
-#: conf/global_settings.py:74
+#:conf/global_settings.py:75
msgid "Telugu"
msgstr "Telugisch"
-#: conf/global_settings.py:75
+#:conf/global_settings.py:76
msgid "Turkish"
msgstr "Türkisch"
-#: conf/global_settings.py:76
+#:conf/global_settings.py:77
msgid "Ukrainian"
msgstr "Ukrainisch"
-#: conf/global_settings.py:77
+#:conf/global_settings.py:78
msgid "Simplified Chinese"
msgstr "Vereinfachtes Chinesisch"
-#: conf/global_settings.py:78
+#:conf/global_settings.py:79
msgid "Traditional Chinese"
msgstr "Traditionelles Chinesisch"
-#: contrib/admin/filterspecs.py:40
-#, python-format
+#:contrib/admin/filterspecs.py:42
+#,python-format
msgid ""
"<h3>By %s:</h3>\n"
"<ul>\n"
-msgstr ""
-"<h3>Nach %s:</h3>\n"
+msgstr "<h3>Nach %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#:contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#:contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Alle"
-#: contrib/admin/filterspecs.py:109
+#:contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Alle Daten"
-#: contrib/admin/filterspecs.py:110
+#:contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Heute"
-#: contrib/admin/filterspecs.py:113
+#:contrib/admin/filterspecs.py:115
msgid "Past 7 days"
msgstr "Letzte 7 Tage"
-#: contrib/admin/filterspecs.py:115
+#:contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Diesen Monat"
-#: contrib/admin/filterspecs.py:117
+#:contrib/admin/filterspecs.py:119
msgid "This year"
msgstr "Dieses Jahr"
-#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#:contrib/admin/filterspecs.py:145 newforms/widgets.py:181
+#:oldforms/__init__.py:587
msgid "Yes"
msgstr "Ja"
-#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#:contrib/admin/filterspecs.py:145 newforms/widgets.py:181
+#:oldforms/__init__.py:587
msgid "No"
msgstr "Nein"
-#: contrib/admin/filterspecs.py:150 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#:contrib/admin/filterspecs.py:152 newforms/widgets.py:181
+#:oldforms/__init__.py:587
msgid "Unknown"
msgstr "Unbekannt"
-#: contrib/admin/models.py:16
+#:contrib/admin/models.py:17
msgid "action time"
msgstr "Zeitpunkt der Aktion"
-#: contrib/admin/models.py:19
+#:contrib/admin/models.py:20
msgid "object id"
msgstr "Objekt-ID"
-#: contrib/admin/models.py:20
+#:contrib/admin/models.py:21
msgid "object repr"
msgstr "Objekt Darst."
-#: contrib/admin/models.py:21
+#:contrib/admin/models.py:22
msgid "action flag"
msgstr "Aktionskennzeichen"
-#: contrib/admin/models.py:22
+#:contrib/admin/models.py:23
msgid "change message"
msgstr "Änderungsmeldung"
-#: contrib/admin/models.py:25
+#:contrib/admin/models.py:26
msgid "log entry"
msgstr "Logeintrag"
-#: contrib/admin/models.py:26
+#:contrib/admin/models.py:27
msgid "log entries"
msgstr "Logeinträge"
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
+#:contrib/admin/templates/admin/404.html:4
+#:contrib/admin/templates/admin/404.html:8
msgid "Page not found"
msgstr "Seite nicht gefunden"
-#: contrib/admin/templates/admin/404.html:10
+#:contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found."
-msgstr ""
-"Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
+msgstr "Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
-#: contrib/admin/templates/admin/500.html:4
-#: contrib/admin/templates/admin/base.html:30
-#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/delete_confirmation.html:6
-#: contrib/admin/templates/admin/invalid_setup.html:4
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/auth/user/change_password.html:12
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/registration/logged_out.html:4
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_reset_done.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:4
+#:contrib/admin/templates/admin/500.html:4
+#:contrib/admin/templates/admin/base.html:30
+#:contrib/admin/templates/admin/change_form.html:13
+#:contrib/admin/templates/admin/change_list.html:6
+#:contrib/admin/templates/admin/delete_confirmation.html:6
+#:contrib/admin/templates/admin/invalid_setup.html:4
+#:contrib/admin/templates/admin/object_history.html:5
+#:contrib/admin/templates/admin/auth/user/change_password.html:12
+#:contrib/admin/templates/admin_doc/bookmarklets.html:3
+#:contrib/admin/templates/registration/logged_out.html:4
+#:contrib/admin/templates/registration/password_change_done.html:4
+#:contrib/admin/templates/registration/password_change_form.html:4
+#:contrib/admin/templates/registration/password_reset_done.html:4
+#:contrib/admin/templates/registration/password_reset_form.html:4
msgid "Home"
msgstr "Start"
-#: contrib/admin/templates/admin/500.html:4
+#:contrib/admin/templates/admin/500.html:4
msgid "Server error"
msgstr "Serverfehler"
-#: contrib/admin/templates/admin/500.html:6
+#:contrib/admin/templates/admin/500.html:6
msgid "Server error (500)"
msgstr "Serverfehler (500)"
-#: contrib/admin/templates/admin/500.html:9
+#:contrib/admin/templates/admin/500.html:9
msgid "Server Error <em>(500)</em>"
msgstr "Serverfehler <em>(500)</em>"
-#: contrib/admin/templates/admin/500.html:10
+#:contrib/admin/templates/admin/500.html:10
msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
-msgstr ""
-"Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-"
+msgstr "Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-"
"Mail weitergegeben und sollte bald behoben sein. Vielen Dank für Ihr "
"Verständnis."
-#: contrib/admin/templates/admin/base.html:25
+#:contrib/admin/templates/admin/base.html:25
msgid "Welcome,"
msgstr "Willkommen,"
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
+#:contrib/admin/templates/admin/base.html:25
+#:contrib/admin/templates/admin/change_form.html:10
+#:contrib/admin/templates/admin/change_list.html:5
+#:contrib/admin/templates/admin/delete_confirmation.html:3
+#:contrib/admin/templates/admin/object_history.html:3
+#:contrib/admin/templates/admin/auth/user/change_password.html:9
+#:contrib/admin/templates/admin_doc/bookmarklets.html:3
+#:contrib/admin/templates/registration/password_change_done.html:3
+#:contrib/admin/templates/registration/password_change_form.html:3
msgid "Documentation"
msgstr "Dokumentation"
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/admin/auth/user/change_password.html:15
-#: contrib/admin/templates/admin/auth/user/change_password.html:46
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
+#:contrib/admin/templates/admin/base.html:25
+#:contrib/admin/templates/admin/change_form.html:10
+#:contrib/admin/templates/admin/change_list.html:5
+#:contrib/admin/templates/admin/delete_confirmation.html:3
+#:contrib/admin/templates/admin/object_history.html:3
+#:contrib/admin/templates/admin/auth/user/change_password.html:9
+#:contrib/admin/templates/admin/auth/user/change_password.html:15
+#:contrib/admin/templates/admin/auth/user/change_password.html:46
+#:contrib/admin/templates/admin_doc/bookmarklets.html:4
+#:contrib/admin/templates/admin_doc/index.html:4
+#:contrib/admin/templates/admin_doc/missing_docutils.html:4
+#:contrib/admin/templates/admin_doc/model_detail.html:3
+#:contrib/admin/templates/admin_doc/model_index.html:5
+#:contrib/admin/templates/admin_doc/template_detail.html:4
+#:contrib/admin/templates/admin_doc/template_filter_index.html:5
+#:contrib/admin/templates/admin_doc/template_tag_index.html:5
+#:contrib/admin/templates/admin_doc/view_detail.html:4
+#:contrib/admin/templates/admin_doc/view_index.html:5
+#:contrib/admin/templates/registration/password_change_done.html:3
+#:contrib/admin/templates/registration/password_change_form.html:3
msgid "Change password"
msgstr "Passwort ändern"
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/comments/templates/comments/form.html:6
+#:contrib/admin/templates/admin/base.html:25
+#:contrib/admin/templates/admin/change_form.html:10
+#:contrib/admin/templates/admin/change_list.html:5
+#:contrib/admin/templates/admin/delete_confirmation.html:3
+#:contrib/admin/templates/admin/object_history.html:3
+#:contrib/admin/templates/admin/auth/user/change_password.html:9
+#:contrib/admin/templates/admin_doc/bookmarklets.html:4
+#:contrib/admin/templates/admin_doc/index.html:4
+#:contrib/admin/templates/admin_doc/missing_docutils.html:4
+#:contrib/admin/templates/admin_doc/model_detail.html:3
+#:contrib/admin/templates/admin_doc/model_index.html:5
+#:contrib/admin/templates/admin_doc/template_detail.html:4
+#:contrib/admin/templates/admin_doc/template_filter_index.html:5
+#:contrib/admin/templates/admin_doc/template_tag_index.html:5
+#:contrib/admin/templates/admin_doc/view_detail.html:4
+#:contrib/admin/templates/admin_doc/view_index.html:5
+#:contrib/admin/templates/registration/password_change_done.html:3
+#:contrib/admin/templates/registration/password_change_form.html:3
+#:contrib/comments/templates/comments/form.html:6
msgid "Log out"
msgstr "Abmelden"
-#: contrib/admin/templates/admin/base_site.html:4
+#:contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin"
msgstr "Django-Systemverwaltung"
-#: contrib/admin/templates/admin/base_site.html:7
+#:contrib/admin/templates/admin/base_site.html:7
msgid "Django administration"
msgstr "Django-Verwaltung"
-#: contrib/admin/templates/admin/change_form.html:15
-#: contrib/admin/templates/admin/index.html:28
+#:contrib/admin/templates/admin/change_form.html:15
+#:contrib/admin/templates/admin/index.html:28
msgid "Add"
msgstr "Hinzufügen"
-#: contrib/admin/templates/admin/change_form.html:21
-#: contrib/admin/templates/admin/object_history.html:5
+#:contrib/admin/templates/admin/change_form.html:21
+#:contrib/admin/templates/admin/object_history.html:5
msgid "History"
msgstr "Geschichte"
-#: contrib/admin/templates/admin/change_form.html:22
+#:contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
msgstr "Im Web anzeigen"
-#: contrib/admin/templates/admin/change_form.html:32
-#: contrib/admin/templates/admin/auth/user/change_password.html:24
+#:contrib/admin/templates/admin/change_form.html:32
+#:contrib/admin/templates/admin/auth/user/change_password.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] "Bitte den aufgeführten Fehler korrigieren."
msgstr[1] "Bitte die aufgeführten Fehler korrigieren."
-#: contrib/admin/templates/admin/change_form.html:50
+#:contrib/admin/templates/admin/change_form.html:50
msgid "Ordering"
msgstr "Sortierung"
-#: contrib/admin/templates/admin/change_form.html:53
+#:contrib/admin/templates/admin/change_form.html:53
msgid "Order:"
msgstr "Reihenfolge:"
-#: contrib/admin/templates/admin/change_list.html:12
-#, python-format
+#:contrib/admin/templates/admin/change_list.html:12
+#,python-format
msgid "Add %(name)s"
msgstr "%(name)s hinzufügen"
-#: contrib/admin/templates/admin/delete_confirmation.html:9
-#: contrib/admin/templates/admin/submit_line.html:3
+#:contrib/admin/templates/admin/delete_confirmation.html:9
+#:contrib/admin/templates/admin/submit_line.html:3
msgid "Delete"
msgstr "Löschen"
-#: contrib/admin/templates/admin/delete_confirmation.html:14
-#, python-format
+#:contrib/admin/templates/admin/delete_confirmation.html:14
+#,python-format
msgid ""
"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
"related objects, but your account doesn't have permission to delete the "
"following types of objects:"
-msgstr ""
-"Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von "
+msgstr "Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von "
"abhängigen Daten zur Folge, aber Sie haben nicht die nötigen Rechte um die "
"folgenden abhängigen Daten zu löschen:"
-#: contrib/admin/templates/admin/delete_confirmation.html:21
-#, python-format
+#:contrib/admin/templates/admin/delete_confirmation.html:21
+#,python-format
msgid ""
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
"All of the following related items will be deleted:"
-msgstr ""
-"Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen "
+msgstr "Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen "
"wollen? Es werden zusätzlich die folgenden abhängigen Daten mit gelöscht:"
-#: contrib/admin/templates/admin/delete_confirmation.html:26
+#:contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
msgstr "Ja, ich bin sicher"
-#: contrib/admin/templates/admin/filter.html:2
-#, python-format
+#:contrib/admin/templates/admin/filter.html:2
+#,python-format
msgid " By %(filter_title)s "
msgstr " Nach %(filter_title)s "
-#: contrib/admin/templates/admin/filters.html:4
+#:contrib/admin/templates/admin/filters.html:4
msgid "Filter"
msgstr "Filter"
-#: contrib/admin/templates/admin/index.html:17
-#, python-format
+#:contrib/admin/templates/admin/index.html:17
+#,python-format
msgid "Models available in the %(name)s application."
msgstr "Modelle, die in der Anwendung %(name)s vorhanden sind."
-#: contrib/admin/templates/admin/index.html:18
-#, python-format
+#:contrib/admin/templates/admin/index.html:18
+#,python-format
msgid "%(name)s"
msgstr "%(name)s"
-#: contrib/admin/templates/admin/index.html:34
+#:contrib/admin/templates/admin/index.html:34
msgid "Change"
msgstr "Ändern"
-#: contrib/admin/templates/admin/index.html:44
+#:contrib/admin/templates/admin/index.html:44
msgid "You don't have permission to edit anything."
msgstr "Sie haben keine Berechtigung irgendwas zu ändern."
-#: contrib/admin/templates/admin/index.html:52
+#:contrib/admin/templates/admin/index.html:52
msgid "Recent Actions"
msgstr "Kürzliche Aktionen"
-#: contrib/admin/templates/admin/index.html:53
+#:contrib/admin/templates/admin/index.html:53
msgid "My Actions"
msgstr "Meine Aktionen"
-#: contrib/admin/templates/admin/index.html:57
+#:contrib/admin/templates/admin/index.html:57
msgid "None available"
msgstr "Keine vorhanden"
-#: contrib/admin/templates/admin/invalid_setup.html:8
+#:contrib/admin/templates/admin/invalid_setup.html:8
msgid ""
"Something's wrong with your database installation. Make sure the appropriate "
"database tables have been created, and make sure the database is readable by "
"the appropriate user."
-msgstr ""
-"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
-"die richtigen Datenbanktabellen angelegt wurden und "
-"die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist."
+msgstr "Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
+"die richtigen Datenbanktabellen angelegt wurden und die Datenbank vom "
+"verwendeten Datenbankbenutzer auch lesbar ist."
-#: contrib/admin/templates/admin/login.html:17
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
+#:contrib/admin/templates/admin/login.html:17
+#:contrib/comments/templates/comments/form.html:6
+#:contrib/comments/templates/comments/form.html:8
msgid "Username:"
msgstr "Benutzername:"
-#: contrib/admin/templates/admin/login.html:20
-#: contrib/comments/templates/comments/form.html:8
+#:contrib/admin/templates/admin/login.html:20
+#:contrib/comments/templates/comments/form.html:8
msgid "Password:"
msgstr "Passwort:"
-#: contrib/admin/templates/admin/login.html:25
-#: contrib/admin/views/decorators.py:24
+#:contrib/admin/templates/admin/login.html:25
+#:contrib/admin/views/decorators.py:24
msgid "Log in"
msgstr "Anmelden"
-#: contrib/admin/templates/admin/object_history.html:18
+#:contrib/admin/templates/admin/object_history.html:18
msgid "Date/time"
msgstr "Datum/Zeit"
-#: contrib/admin/templates/admin/object_history.html:19
+#:contrib/admin/templates/admin/object_history.html:19
msgid "User"
msgstr "Benutzer"
-#: contrib/admin/templates/admin/object_history.html:20
+#:contrib/admin/templates/admin/object_history.html:20
msgid "Action"
msgstr "Aktion"
-#: contrib/admin/templates/admin/object_history.html:26
+#:contrib/admin/templates/admin/object_history.html:26
msgid "DATE_WITH_TIME_FULL"
msgstr "j. N Y, H:i"
-#: contrib/admin/templates/admin/object_history.html:36
+#:contrib/admin/templates/admin/object_history.html:36
msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
-msgstr ""
-"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
+msgstr "Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
"über diese Verwaltungsseiten angelegt."
-#: contrib/admin/templates/admin/pagination.html:10
+#:contrib/admin/templates/admin/pagination.html:10
msgid "Show all"
msgstr "Zeige alle"
-#: contrib/admin/templates/admin/search_form.html:8
+#:contrib/admin/templates/admin/search_form.html:8
msgid "Go"
msgstr "Los"
-#: contrib/admin/templates/admin/search_form.html:10
-#, python-format
+#:contrib/admin/templates/admin/search_form.html:10
+#,python-format
msgid "1 result"
msgid_plural "%(counter)s results"
msgstr[0] "Ein Ergebnis"
msgstr[1] "%(counter)s Ergebnisse"
-#: contrib/admin/templates/admin/search_form.html:10
-#, python-format
+#:contrib/admin/templates/admin/search_form.html:10
+#,python-format
msgid "%(full_result_count)s total"
msgstr "%(full_result_count)s gesamt"
-#: contrib/admin/templates/admin/submit_line.html:4
+#:contrib/admin/templates/admin/submit_line.html:4
msgid "Save as new"
msgstr "Als neu sichern"
-#: contrib/admin/templates/admin/submit_line.html:5
+#:contrib/admin/templates/admin/submit_line.html:5
msgid "Save and add another"
msgstr "Sichern und neu hinzufügen"
-#: contrib/admin/templates/admin/submit_line.html:6
+#:contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing"
msgstr "Sichern und weiter bearbeiten"
-#: contrib/admin/templates/admin/submit_line.html:7
+#:contrib/admin/templates/admin/submit_line.html:7
msgid "Save"
msgstr "Sichern"
-#: contrib/admin/templates/admin/auth/user/add_form.html:6
+#:contrib/admin/templates/admin/auth/user/add_form.html:6
msgid ""
"First, enter a username and password. Then, you'll be able to edit more user "
"options."
-msgstr ""
-"Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere "
+msgstr "Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere "
"Optionen für den Benutzer geändert werden."
-#: contrib/admin/templates/admin/auth/user/add_form.html:12
+#:contrib/admin/templates/admin/auth/user/add_form.html:12
msgid "Username"
msgstr "Benutzername"
-#: contrib/admin/templates/admin/auth/user/add_form.html:18
-#: contrib/admin/templates/admin/auth/user/change_password.html:34
+#:contrib/admin/templates/admin/auth/user/add_form.html:18
+#:contrib/admin/templates/admin/auth/user/change_password.html:34
msgid "Password"
msgstr "Passwort"
-#: contrib/admin/templates/admin/auth/user/add_form.html:23
-#: contrib/admin/templates/admin/auth/user/change_password.html:39
+#:contrib/admin/templates/admin/auth/user/add_form.html:23
+#:contrib/admin/templates/admin/auth/user/change_password.html:39
msgid "Password (again)"
msgstr "Passwort (wiederholen)"
-#: contrib/admin/templates/admin/auth/user/add_form.html:24
-#: contrib/admin/templates/admin/auth/user/change_password.html:40
+#:contrib/admin/templates/admin/auth/user/add_form.html:24
+#:contrib/admin/templates/admin/auth/user/change_password.html:40
msgid "Enter the same password as above, for verification."
msgstr "Bitte das gleiche Passwort zur Überprüfung nochmal eingeben."
-#: contrib/admin/templates/admin/auth/user/change_password.html:28
-#, python-format
+#:contrib/admin/templates/admin/auth/user/change_password.html:28
+#,python-format
msgid "Enter a new password for the user <strong>%(username)s</strong>."
-msgstr ""
-"Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</"
+msgstr "Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</"
"strong> ein."
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#:contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets"
msgstr "Bookmarklets"
-#: contrib/admin/templates/admin_doc/bookmarklets.html:5
+#:contrib/admin/templates/admin_doc/bookmarklets.html:5
msgid "Documentation bookmarklets"
msgstr "Dokumentations-Bookmarklets"
-#: contrib/admin/templates/admin_doc/bookmarklets.html:9
+#:contrib/admin/templates/admin_doc/bookmarklets.html:9
msgid ""
"\n"
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
@@ -612,9 +611,9 @@ msgid ""
"bookmarklets require you to be viewing the site from a computer designated\n"
"as \"internal\" (talk to your system administrator if you aren't sure if\n"
"your computer is \"internal\").</p>\n"
-msgstr ""
-"\n"
-"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in die\n"
+msgstr "\n"
+"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in "
+"die\n"
"Browser-Werkzeugleiste gezogen werden, oder mittels rechter Maustaste in "
"die\n"
"Bookmarks gespeichert werden. Danach können die Bookmarklets von jeder "
@@ -830,7 +829,7 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgstr ""
-"Bitte einen Benutzernamen und ein Passwort eingeben. Beide Felder "
+"Bitte einen gültigen Benutzernamen und ein Passwort eingeben. Beide Felder "
"berücksichtigen die Groß-/Kleinschreibung."
#: contrib/admin/views/decorators.py:62
diff --git a/django/conf/locale/de/LC_MESSAGES/djangojs.mo b/django/conf/locale/de/LC_MESSAGES/djangojs.mo
index 9f39c16444..896847bb99 100644
--- a/django/conf/locale/de/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/de/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/de/LC_MESSAGES/djangojs.po b/django/conf/locale/de/LC_MESSAGES/djangojs.po
index 3c0852ebac..936dcb454f 100644
--- a/django/conf/locale/de/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/de/LC_MESSAGES/djangojs.po
@@ -11,21 +11,21 @@ msgstr ""
"PO-Revision-Date: 2005-12-04 13:21+0100\n"
"Last-Translator: Dirk Eschler <dirk.eschler@gmx.net>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
-msgstr "Verfgbare %s"
+msgstr "Verfügbare %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
-msgstr "Alles auswhlen"
+msgstr "Alles auswählen"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
-msgstr "Hinzufgen"
+msgstr "Hinzufügen"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
@@ -34,15 +34,15 @@ msgstr "Entfernen"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
-msgstr "Ausgewhlte %s"
+msgstr "Ausgewählte %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
-msgstr "Gewnschte Auswahl treffen und "
+msgstr "Gewünschte Auswahl treffen und "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
-msgstr "Alles abwhlen"
+msgstr "Alles abwählen"
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
@@ -50,7 +50,7 @@ msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
-"Januar Februar Mrz April Mai Juni Juli August September Oktober November "
+"Januar Februar März April Mai Juni Juli August September Oktober November "
"Dezember"
#: contrib/admin/media/js/dateparse.js:27
diff --git a/django/conf/locale/es/LC_MESSAGES/django.mo b/django/conf/locale/es/LC_MESSAGES/django.mo
index b8b9185b6d..be8be19162 100644
--- a/django/conf/locale/es/LC_MESSAGES/django.mo
+++ b/django/conf/locale/es/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/es/LC_MESSAGES/django.po b/django/conf/locale/es/LC_MESSAGES/django.po
index 6b55435a12..5f11644cfa 100644
--- a/django/conf/locale/es/LC_MESSAGES/django.po
+++ b/django/conf/locale/es/LC_MESSAGES/django.po
@@ -2,242 +2,117 @@
# This file is distributed under the same license as the PACKAGE package.
# Copyright (C) 2007 THE PACKAGE'S COPYRIGHT HOLDER.
#
-# Ricardo Javier Crdenes Medina <ricardo.cardenes@gmail.com>, 2005.
-# Ricardo Javier Cardenes Medina <ricardo.cardenes@gmail.com>, 2005.
-# AgarFu <heaven@croasanaso.sytes.net>, 2007.
-# Mario Gonzalez <gonzalemario @t gmail.com>, 2007
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-02-24 17:08+0000\n"
-"PO-Revision-Date: 2007-02-24 18:02-0600\n"
+"POT-Creation-Date: 2007-08-17 15:35-0400\n"
+"PO-Revision-Date: 2007-07-14 13:00-0500\n"
"Last-Translator: Mario Gonzalez <gonzalemario @t gmail.com>\n"
"Language-Team: Castellano <Django-I18N@googlegroups.com>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: utils/dates.py:6
-msgid "Monday"
-msgstr "Lunes"
-
-#: utils/dates.py:6
-msgid "Tuesday"
-msgstr "Martes"
-
-#: utils/dates.py:6
-msgid "Wednesday"
-msgstr "Mircoles"
-
-#: utils/dates.py:6
-msgid "Thursday"
-msgstr "Jueves"
-
-#: utils/dates.py:6
-msgid "Friday"
-msgstr "Viernes"
-
-#: utils/dates.py:7
-msgid "Saturday"
-msgstr "Sbado"
-
-#: utils/dates.py:7
-msgid "Sunday"
-msgstr "Domingo"
-
-#: utils/dates.py:14
-msgid "January"
-msgstr "Enero"
-
-#: utils/dates.py:14
-msgid "February"
-msgstr "Febrero"
-
-#: utils/dates.py:14 utils/dates.py:27
-msgid "March"
-msgstr "Marzo"
-
-#: utils/dates.py:14 utils/dates.py:27
-msgid "April"
-msgstr "Abril"
-
-#: utils/dates.py:14 utils/dates.py:27
-msgid "May"
-msgstr "Mayo"
-
-#: utils/dates.py:14 utils/dates.py:27
-msgid "June"
-msgstr "Junio"
-
-#: utils/dates.py:15 utils/dates.py:27
-msgid "July"
-msgstr "Julio"
-
-#: utils/dates.py:15
-msgid "August"
-msgstr "Agosto"
-
-#: utils/dates.py:15
-msgid "September"
-msgstr "Septiembre"
-
-#: utils/dates.py:15
-msgid "October"
-msgstr "Octubre"
-
-#: utils/dates.py:15
-msgid "November"
-msgstr "Noviembre"
-
-#: utils/dates.py:16
-msgid "December"
-msgstr "Diciembre"
-
-#: utils/dates.py:19
-msgid "jan"
-msgstr "ene"
-
-#: utils/dates.py:19
-msgid "feb"
-msgstr "feb"
-
-#: utils/dates.py:19
-msgid "mar"
-msgstr "mar"
-
-#: utils/dates.py:19
-msgid "apr"
-msgstr "abr"
-
-#: utils/dates.py:19
-msgid "may"
-msgstr "may"
-
-#: utils/dates.py:19
-msgid "jun"
-msgstr "jun"
-
-#: utils/dates.py:20
-msgid "jul"
-msgstr "jul"
-
-#: utils/dates.py:20
-msgid "aug"
-msgstr "ago"
-
-#: utils/dates.py:20
-msgid "sep"
-msgstr "sep"
-
-#: utils/dates.py:20
-msgid "oct"
-msgstr "oct"
-
-#: utils/dates.py:20
-msgid "nov"
-msgstr "nov"
-
-#: utils/dates.py:20
-msgid "dec"
-msgstr "dic"
-
-#: utils/dates.py:27
-msgid "Jan."
-msgstr "Ene."
-
-#: utils/dates.py:27
-msgid "Feb."
-msgstr "Feb."
+#: db/models/manipulators.py:309
+#, python-format
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "%(object)s de este %(type)s ya existen en este %(field)s."
-#: utils/dates.py:28
-msgid "Aug."
-msgstr "Ago."
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+#: core/validators.py:275
+msgid "and"
+msgstr "y"
-#: utils/dates.py:28
-msgid "Sept."
-msgstr "Sept."
+#: db/models/fields/__init__.py:49
+#, python-format
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "Ya existe %(optname)s con este %(fieldname)s."
-#: utils/dates.py:28
-msgid "Oct."
-msgstr "Oct."
+#: db/models/fields/__init__.py:156 db/models/fields/__init__.py:313
+#: db/models/fields/__init__.py:721 db/models/fields/__init__.py:732
+#: newforms/fields.py:92 newforms/fields.py:490 newforms/fields.py:566
+#: newforms/fields.py:577 newforms/models.py:193 oldforms/__init__.py:373
+msgid "This field is required."
+msgstr "Este campo es obligatorio."
-#: utils/dates.py:28
-msgid "Nov."
-msgstr "Nov."
+#: db/models/fields/__init__.py:411
+msgid "This value must be an integer."
+msgstr "Este valor debe ser un entero."
-#: utils/dates.py:28
-msgid "Dec."
-msgstr "Dic."
+#: db/models/fields/__init__.py:446
+msgid "This value must be either True or False."
+msgstr "Este valor debe ser Verdadero o Falso."
-#: utils/timesince.py:12
-msgid "year"
-msgid_plural "years"
-msgstr[0] "ao"
-msgstr[1] "aos"
+#: db/models/fields/__init__.py:467
+msgid "This field cannot be null."
+msgstr "Este campo no puede estar vacío."
-#: utils/timesince.py:13
-msgid "month"
-msgid_plural "months"
-msgstr[0] "mes"
-msgstr[1] "meses"
+#: db/models/fields/__init__.py:501 core/validators.py:155
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "Introduzca una fecha válida en formato AAAA-MM-DD."
-#: utils/timesince.py:14
-msgid "week"
-msgid_plural "weeks"
-msgstr[0] "semana"
-msgstr[1] "semanas"
+#: db/models/fields/__init__.py:570 core/validators.py:164
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "Introduzca una fecha/hora válida en formato AAAA-MM-DD HH:MM."
-#: utils/timesince.py:15
-msgid "day"
-msgid_plural "days"
-msgstr[0] "da"
-msgstr[1] "das"
+#: db/models/fields/__init__.py:631
+msgid "This value must be a decimal number."
+msgstr "Este valor debe ser un entero."
-#: utils/timesince.py:16
-msgid "hour"
-msgid_plural "hours"
-msgstr[0] "hora"
-msgstr[1] "horas"
+#: db/models/fields/__init__.py:741
+msgid "Enter a valid filename."
+msgstr "Introduzca un nombre de fichero válido"
-#: utils/timesince.py:17
-msgid "minute"
-msgid_plural "minutes"
-msgstr[0] "minuto"
-msgstr[1] "minutos"
+#: db/models/fields/__init__.py:883
+msgid "This value must be either None, True or False."
+msgstr "Este valor debe ser Verdadero o Falso."
-#: utils/translation/trans_real.py:362
-msgid "DATE_FORMAT"
-msgstr "j N Y"
+#: db/models/fields/related.py:55
+#, python-format
+msgid "Please enter a valid %s."
+msgstr "Por favor, introduzca un %s válido."
-#: utils/translation/trans_real.py:363
-msgid "DATETIME_FORMAT"
-msgstr "j N Y P"
+#: db/models/fields/related.py:661
+msgid "Separate multiple IDs with commas."
+msgstr "Separe múltiples IDs con comas."
-#: utils/translation/trans_real.py:364
-msgid "TIME_FORMAT"
-msgstr "P"
+#: db/models/fields/related.py:663
+msgid ""
+"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr ""
+"Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar "
+"más de uno."
-#: utils/translation/trans_real.py:380
-msgid "YEAR_MONTH_FORMAT"
-msgstr "F Y"
+#: db/models/fields/related.py:710
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural ""
+"Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] ""
+"Por favor, introduzca IDs de %(self)s válidos. El valor %(value)r no es "
+"válido."
+msgstr[1] ""
+"Por favor, introduzca IDs de %(self)s válidos. Los valores %(value)r no son "
+"válidos."
-#: utils/translation/trans_real.py:381
-msgid "MONTH_DAY_FORMAT"
-msgstr "j \\de F"
+#: conf/global_settings.py:38
+msgid "Arabic"
+msgstr "Árabe"
#: conf/global_settings.py:39
-msgid "Arabic"
-msgstr "rabe"
+msgid "Bengali"
+msgstr "Bengalí"
#: conf/global_settings.py:40
-msgid "Bengali"
-msgstr "Bengal"
+msgid "Bulgarian"
+msgstr "Búlgaro"
#: conf/global_settings.py:41
msgid "Catalan"
-msgstr "Cataln"
+msgstr "Catalán"
#: conf/global_settings.py:42
msgid "Czech"
@@ -245,15 +120,15 @@ msgstr "Checo"
#: conf/global_settings.py:43
msgid "Welsh"
-msgstr "Gals"
+msgstr "Galés"
#: conf/global_settings.py:44
msgid "Danish"
-msgstr "Dans"
+msgstr "Danés"
#: conf/global_settings.py:45
msgid "German"
-msgstr "Alemn"
+msgstr "Alemán"
#: conf/global_settings.py:46
msgid "Greek"
@@ -261,812 +136,787 @@ msgstr "Griego"
#: conf/global_settings.py:47
msgid "English"
-msgstr "Ingls"
+msgstr "Inglés"
#: conf/global_settings.py:48
msgid "Spanish"
-msgstr "Espaol"
+msgstr "Español"
#: conf/global_settings.py:49
msgid "Argentinean Spanish"
-msgstr "Espaol Argentino"
+msgstr "Español Argentino"
#: conf/global_settings.py:50
-msgid "Finnish"
-msgstr "Fins"
+msgid "Persian"
+msgstr "Persa"
#: conf/global_settings.py:51
-msgid "French"
-msgstr "Francs"
+msgid "Finnish"
+msgstr "Finés"
#: conf/global_settings.py:52
+msgid "French"
+msgstr "Francés"
+
+#: conf/global_settings.py:53
msgid "Galician"
msgstr "Gallego"
-#: conf/global_settings.py:53
+#: conf/global_settings.py:54
msgid "Hungarian"
-msgstr "Hngaro"
+msgstr "Húngaro"
-#: conf/global_settings.py:54
+#: conf/global_settings.py:55
msgid "Hebrew"
msgstr "Hebreo"
-#: conf/global_settings.py:55
+#: conf/global_settings.py:56
+msgid "Croatian"
+msgstr "Croata"
+
+#: conf/global_settings.py:57
msgid "Icelandic"
-msgstr "Islands"
+msgstr "Islandés"
-#: conf/global_settings.py:56
+#: conf/global_settings.py:58
msgid "Italian"
msgstr "Italiano"
-#: conf/global_settings.py:57
+#: conf/global_settings.py:59
msgid "Japanese"
-msgstr "Japons"
+msgstr "Japonés"
-#: conf/global_settings.py:58
+#: conf/global_settings.py:60
+msgid "Korean"
+msgstr "Koreano"
+
+#: conf/global_settings.py:61
+msgid "Kannada"
+msgstr "Kannada"
+
+#: conf/global_settings.py:62
msgid "Latvian"
msgstr "Latvio"
-#: conf/global_settings.py:59
+#: conf/global_settings.py:63
msgid "Macedonian"
msgstr "Macedonio"
-#: conf/global_settings.py:60
+#: conf/global_settings.py:64
msgid "Dutch"
-msgstr "Alemn"
+msgstr "Alemán"
-#: conf/global_settings.py:61
+#: conf/global_settings.py:65
msgid "Norwegian"
msgstr "Noruego"
-#: conf/global_settings.py:62
+#: conf/global_settings.py:66
msgid "Polish"
msgstr "Polaco"
-#: conf/global_settings.py:63
+#: conf/global_settings.py:67
+msgid "Portugese"
+msgstr "Portugés"
+
+#: conf/global_settings.py:68
msgid "Brazilian"
-msgstr "Brasileo"
+msgstr "Brasileño"
-#: conf/global_settings.py:64
+#: conf/global_settings.py:69
msgid "Romanian"
msgstr "Rumano"
-#: conf/global_settings.py:65
+#: conf/global_settings.py:70
msgid "Russian"
msgstr "Ruso"
-#: conf/global_settings.py:66
+#: conf/global_settings.py:71
msgid "Slovak"
msgstr "Eslovaco"
-#: conf/global_settings.py:67
+#: conf/global_settings.py:72
msgid "Slovenian"
msgstr "Esloveno"
-#: conf/global_settings.py:68
+#: conf/global_settings.py:73
msgid "Serbian"
msgstr "Serbio"
-#: conf/global_settings.py:69
+#: conf/global_settings.py:74
msgid "Swedish"
msgstr "Sueco"
-#: conf/global_settings.py:70
+#: conf/global_settings.py:75
msgid "Tamil"
msgstr "Tamil"
-#: conf/global_settings.py:71
+#: conf/global_settings.py:76
+msgid "Telugu"
+msgstr "Telugu"
+
+#: conf/global_settings.py:77
msgid "Turkish"
msgstr "Turco"
-#: conf/global_settings.py:72
+#: conf/global_settings.py:78
msgid "Ukrainian"
msgstr "Ucraniano"
-#: conf/global_settings.py:73
+#: conf/global_settings.py:79
msgid "Simplified Chinese"
msgstr "Chino simplificado"
-#: conf/global_settings.py:74
+#: conf/global_settings.py:80
msgid "Traditional Chinese"
msgstr "Chino tradicional"
-#: db/models/manipulators.py:305
+#: views/generic/create_update.py:43
#, python-format
-msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "%(object)s de este %(type)s ya existen en este %(field)s."
+msgid "The %(verbose_name)s was created successfully."
+msgstr "El %(verbose_name)s se ha creado correctamente."
-#: db/models/manipulators.py:306 contrib/admin/views/main.py:335
-#: contrib/admin/views/main.py:337 contrib/admin/views/main.py:339
-msgid "and"
-msgstr "y"
+#: views/generic/create_update.py:117
+#, python-format
+msgid "The %(verbose_name)s was updated successfully."
+msgstr "Se actualizó con éxito el %(verbose_name)s."
-#: db/models/fields/related.py:53
+#: views/generic/create_update.py:184
#, python-format
-msgid "Please enter a valid %s."
-msgstr "Por favor, introduzca un %s vlido."
+msgid "The %(verbose_name)s was deleted."
+msgstr "El %(verbose_name)s ha sido eliminado."
-#: db/models/fields/related.py:642
-msgid "Separate multiple IDs with commas."
-msgstr "Separe mltiples IDs con comas."
+#: utils/dates.py:6
+msgid "Monday"
+msgstr "Lunes"
-#: db/models/fields/related.py:644
-msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
-msgstr "Mantenga presionado \"Control\", o \"Command\" en un Mac, para seleccionar ms de uno."
+#: utils/dates.py:6
+msgid "Tuesday"
+msgstr "Martes"
-#: db/models/fields/related.py:691
-#, python-format
-msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] ""
-"Por favor, introduzca IDs de %(self)s vlidos. El valor %(value)r no es "
-"vlido."
-msgstr[1] ""
-"Por favor, introduzca IDs de %(self)s vlidos. Los valores %(value)r no son "
-"vlidos."
+#: utils/dates.py:6
+msgid "Wednesday"
+msgstr "Miércoles"
-#: db/models/fields/__init__.py:42
-#, python-format
-msgid "%(optname)s with this %(fieldname)s already exists."
-msgstr "Ya existe %(optname)s con este %(fieldname)s."
+#: utils/dates.py:6
+msgid "Thursday"
+msgstr "Jueves"
-#: db/models/fields/__init__.py:116 db/models/fields/__init__.py:273
-#: db/models/fields/__init__.py:605 db/models/fields/__init__.py:616
-#: newforms/models.py:177 newforms/fields.py:78 newforms/fields.py:374
-#: newforms/fields.py:450 newforms/fields.py:461 oldforms/__init__.py:352
-msgid "This field is required."
-msgstr "Este campo es obligatorio."
+#: utils/dates.py:6
+msgid "Friday"
+msgstr "Viernes"
-#: db/models/fields/__init__.py:366
-msgid "This value must be an integer."
-msgstr "Este valor debe ser un entero."
+#: utils/dates.py:7
+msgid "Saturday"
+msgstr "Sábado"
-#: db/models/fields/__init__.py:401
-msgid "This value must be either True or False."
-msgstr "Este valor debe ser Verdadero o Falso."
+#: utils/dates.py:7
+msgid "Sunday"
+msgstr "Domingo"
-#: db/models/fields/__init__.py:422
-msgid "This field cannot be null."
-msgstr "Este campo no puede estar vaco."
+#: utils/dates.py:10
+msgid "Mon"
+msgstr "Lun"
-#: db/models/fields/__init__.py:454 core/validators.py:147
-msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "Introduzca una fecha vlida en formato AAAA-MM-DD."
+#: utils/dates.py:10
+msgid "Tue"
+msgstr "Mar"
-#: db/models/fields/__init__.py:521 core/validators.py:156
-msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Introduzca una fecha/hora vlida en formato AAAA-MM-DD HH:MM."
+#: utils/dates.py:10
+msgid "Wed"
+msgstr "Mie"
-#: db/models/fields/__init__.py:625
-msgid "Enter a valid filename."
-msgstr "Introduzca un nombre de fichero vlido"
+#: utils/dates.py:10
+msgid "Thu"
+msgstr "Jue"
-#: template/defaultfilters.py:436
-msgid "yes,no,maybe"
-msgstr "si,no,tal vez"
+#: utils/dates.py:10
+msgid "Fri"
+msgstr "Vie"
-#: newforms/models.py:164 newforms/fields.py:360
-msgid "Select a valid choice. That choice is not one of the available choices."
-msgstr "Escoja una opcin vlida. Esa opcin no est entre las aceptadas."
+#: utils/dates.py:11
+msgid "Sat"
+msgstr "Sab"
-#: newforms/models.py:181 newforms/fields.py:378 newforms/fields.py:454
-msgid "Enter a list of values."
-msgstr "Introduzca una lista de valores."
+#: utils/dates.py:11
+msgid "Sun"
+msgstr "Dom"
-#: newforms/models.py:187 newforms/fields.py:387
-#, python-format
-msgid "Select a valid choice. %s is not one of the available choices."
-msgstr "Escoja una opcin vlida; '%s' no es una de las opciones disponibles."
+#: utils/dates.py:18
+msgid "January"
+msgstr "Enero"
-#: newforms/fields.py:101 newforms/fields.py:254
-#, python-format
-msgid "Ensure this value has at most %d characters."
-msgstr "Asegrese de que su texto tiene a lo ms %d caracteres."
+#: utils/dates.py:18
+msgid "February"
+msgstr "Febrero"
-#: newforms/fields.py:103 newforms/fields.py:256
-#, python-format
-msgid "Ensure this value has at least %d characters."
-msgstr "Asegrese de que su texto tiene al menos %d caracteres."
+#: utils/dates.py:18 utils/dates.py:31
+msgid "March"
+msgstr "Marzo"
-#: newforms/fields.py:126 core/validators.py:120
-msgid "Enter a whole number."
-msgstr "Introduzca un nmero entero."
+#: utils/dates.py:18 utils/dates.py:31
+msgid "April"
+msgstr "Abril"
-#: newforms/fields.py:128
-#, python-format
-msgid "Ensure this value is less than or equal to %s."
-msgstr "Asegrese de que este valor es menor o igual a %s."
+#: utils/dates.py:18 utils/dates.py:31
+msgid "May"
+msgstr "Mayo"
-#: newforms/fields.py:130
-#, python-format
-msgid "Ensure this value is greater than or equal to %s."
-msgstr "Asegrese de que este valor es mayor o igual a %s."
+#: utils/dates.py:18 utils/dates.py:31
+msgid "June"
+msgstr "Junio"
-#: newforms/fields.py:163
-msgid "Enter a valid date."
-msgstr "Introduzca una fecha vlida."
+#: utils/dates.py:19 utils/dates.py:31
+msgid "July"
+msgstr "Julio"
-#: newforms/fields.py:190
-msgid "Enter a valid time."
-msgstr "Introduzca una hora vlida."
+#: utils/dates.py:19
+msgid "August"
+msgstr "Agosto"
-#: newforms/fields.py:226
-msgid "Enter a valid date/time."
-msgstr "Introduzca una fecha/hora vlida."
+#: utils/dates.py:19
+msgid "September"
+msgstr "Septiembre"
-#: newforms/fields.py:240
-msgid "Enter a valid value."
-msgstr "Introduzca un valor correcto."
+#: utils/dates.py:19
+msgid "October"
+msgstr "Octubre"
-#: newforms/fields.py:269 core/validators.py:161
-msgid "Enter a valid e-mail address."
-msgstr "Introduzca una direccin de correo electrnico vlida"
+#: utils/dates.py:19
+msgid "November"
+msgstr "Noviembre"
-#: newforms/fields.py:287 newforms/fields.py:309
-msgid "Enter a valid URL."
-msgstr "Introduzca una URL vlida."
+#: utils/dates.py:20
+msgid "December"
+msgstr "Diciembre"
-#: newforms/fields.py:311
-msgid "This URL appears to be a broken link."
-msgstr "La URL parece ser un enlace roto."
+#: utils/dates.py:23
+msgid "jan"
+msgstr "ene"
-#: newforms/widgets.py:170 oldforms/__init__.py:572
-#: contrib/admin/filterspecs.py:150
-msgid "Unknown"
-msgstr "Desconocido"
+#: utils/dates.py:23
+msgid "feb"
+msgstr "feb"
-#: newforms/widgets.py:170 oldforms/__init__.py:572
-#: contrib/admin/filterspecs.py:143
-msgid "Yes"
-msgstr "S"
+#: utils/dates.py:23
+msgid "mar"
+msgstr "mar"
-#: newforms/widgets.py:170 oldforms/__init__.py:572
-#: contrib/admin/filterspecs.py:143
-msgid "No"
-msgstr "No"
+#: utils/dates.py:23
+msgid "apr"
+msgstr "abr"
-#: core/validators.py:64
-msgid "This value must contain only letters, numbers and underscores."
-msgstr "Este valor debe contener slo letras, nmeros y guiones bajos."
+#: utils/dates.py:23
+msgid "may"
+msgstr "may"
-#: core/validators.py:68
-msgid ""
-"This value must contain only letters, numbers, underscores, dashes or "
-"slashes."
-msgstr "Este valor debe contener letras, nmeros, guiones bajos o barras solamente."
+#: utils/dates.py:23
+msgid "jun"
+msgstr "jun"
-#: core/validators.py:72
-msgid "This value must contain only letters, numbers, underscores or hyphens."
-msgstr "Este valor debe contener slo letras, nmeros, guiones bajos o medios."
+#: utils/dates.py:24
+msgid "jul"
+msgstr "jul"
-#: core/validators.py:76
-msgid "Uppercase letters are not allowed here."
-msgstr "No se admiten letras maysculas."
+#: utils/dates.py:24
+msgid "aug"
+msgstr "ago"
-#: core/validators.py:80
-msgid "Lowercase letters are not allowed here."
-msgstr "No se admiten letras minsculas."
+#: utils/dates.py:24
+msgid "sep"
+msgstr "sep"
-#: core/validators.py:87
-msgid "Enter only digits separated by commas."
-msgstr "Introduzca slo dgitos separados por comas."
+#: utils/dates.py:24
+msgid "oct"
+msgstr "oct"
-#: core/validators.py:99
-msgid "Enter valid e-mail addresses separated by commas."
-msgstr "Introduzca direcciones de correo vlidas separadas por comas."
+#: utils/dates.py:24
+msgid "nov"
+msgstr "nov"
-#: core/validators.py:103
-msgid "Please enter a valid IP address."
-msgstr "Por favor introduzca una direccin IP vlida."
+#: utils/dates.py:24
+msgid "dec"
+msgstr "dic"
-#: core/validators.py:107
-msgid "Empty values are not allowed here."
-msgstr "No se admiten valores vacos."
+#: utils/dates.py:31
+msgid "Jan."
+msgstr "Ene."
-#: core/validators.py:111
-msgid "Non-numeric characters aren't allowed here."
-msgstr "No se admiten caracteres no numricos."
+#: utils/dates.py:31
+msgid "Feb."
+msgstr "Feb."
-#: core/validators.py:115
-msgid "This value can't be comprised solely of digits."
-msgstr "Este valor no puede comprender slo dgitos."
+#: utils/dates.py:32
+msgid "Aug."
+msgstr "Ago."
-#: core/validators.py:124
-msgid "Only alphabetical characters are allowed here."
-msgstr "Slo se admiten caracteres alfabticos."
+#: utils/dates.py:32
+msgid "Sept."
+msgstr "Sept."
-#: core/validators.py:139
-msgid "Year must be 1900 or later."
-msgstr "El ao debe ser 1900 o posterior."
+#: utils/dates.py:32
+msgid "Oct."
+msgstr "Oct."
-#: core/validators.py:143
-#, python-format
-msgid "Invalid date: %s."
-msgstr "Fecha no vlida: %s"
+#: utils/dates.py:32
+msgid "Nov."
+msgstr "Nov."
-#: core/validators.py:152
-msgid "Enter a valid time in HH:MM format."
-msgstr "Introduzca una hora vlida en formato HH:MM."
+#: utils/dates.py:32
+msgid "Dec."
+msgstr "Dic."
-#: core/validators.py:173 core/validators.py:443 oldforms/__init__.py:667
-msgid "No file was submitted. Check the encoding type on the form."
-msgstr ""
-"No se ha enviado ningn fichero. Compruebe el tipo de codificacin en el "
-"formulario."
+#: utils/timesince.py:12
+msgid "year"
+msgid_plural "years"
+msgstr[0] "año"
+msgstr[1] "años"
-#: core/validators.py:177
-msgid ""
-"Upload a valid image. The file you uploaded was either not an image or a "
-"corrupted image."
-msgstr ""
-"Enve una imagen vlida. El fichero que ha enviado no era una imagen o se "
-"trataba de una imagen corrupta."
+#: utils/timesince.py:13
+msgid "month"
+msgid_plural "months"
+msgstr[0] "mes"
+msgstr[1] "meses"
-#: core/validators.py:184
-#, python-format
-msgid "The URL %s does not point to a valid image."
-msgstr "La URL %s no apunta a una imagen vlida."
+#: utils/timesince.py:14
+msgid "week"
+msgid_plural "weeks"
+msgstr[0] "semana"
+msgstr[1] "semanas"
-#: core/validators.py:188
-#, python-format
-msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
-msgstr ""
-"Los nmeros de telfono deben guardar el formato XXX-XXX-XXXX. \"%s\" "
-"no es vlido."
+#: utils/timesince.py:15
+msgid "day"
+msgid_plural "days"
+msgstr[0] "día"
+msgstr[1] "días"
-#: core/validators.py:196
-#, python-format
-msgid "The URL %s does not point to a valid QuickTime video."
-msgstr "La URL %s no apunta a un vdeo QuickTime vlido."
+#: utils/timesince.py:16
+msgid "hour"
+msgid_plural "hours"
+msgstr[0] "hora"
+msgstr[1] "horas"
-#: core/validators.py:200
-msgid "A valid URL is required."
-msgstr "Se precisa una URL vlida."
+#: utils/timesince.py:17
+msgid "minute"
+msgid_plural "minutes"
+msgstr[0] "minuto"
+msgstr[1] "minutos"
-#: core/validators.py:214
+#: utils/timesince.py:39
#, python-format
-msgid ""
-"Valid HTML is required. Specific errors are:\n"
-"%s"
-msgstr ""
-"Se precisa HTML vlido. Los errores especficos son:\n"
-"%s"
+msgid "%(number)d %(type)s"
+msgstr "%(number)d %(type)s"
-#: core/validators.py:221
+#: utils/timesince.py:45
#, python-format
-msgid "Badly formed XML: %s"
-msgstr "XML mal formado: %s"
+msgid ", %(number)d %(type)s"
+msgstr ", %(number)d %(type)s"
-#: core/validators.py:238
-#, python-format
-msgid "Invalid URL: %s"
-msgstr "URL no vlida: %s"
+#: utils/text.py:127
+msgid "or"
+msgstr "o"
-#: core/validators.py:243 core/validators.py:245
-#, python-format
-msgid "The URL %s is a broken link."
-msgstr "La URL %s es un enlace roto."
+#: utils/dateformat.py:41
+msgid "p.m."
+msgstr "p.m"
-#: core/validators.py:251
-msgid "Enter a valid U.S. state abbreviation."
-msgstr "Introduzca una abreviatura vlida de estado de los EEUU."
+#: utils/dateformat.py:42
+msgid "a.m."
+msgstr "a.m"
-#: core/validators.py:265
-#, python-format
-msgid "Watch your mouth! The word %s is not allowed here."
-msgid_plural "Watch your mouth! The words %s are not allowed here."
-msgstr[0] "Cuida tu vocabulario! Aqu no admitimos la palabra %s."
-msgstr[1] "Cuida tu vocabulario! Aqu no admitimos las palabras %s."
+#: utils/dateformat.py:47
+msgid "PM"
+msgstr "PM"
-#: core/validators.py:272
-#, python-format
-msgid "This field must match the '%s' field."
-msgstr "Este campo debe concordar con el campo '%s'."
+#: utils/dateformat.py:48
+msgid "AM"
+msgstr "AM"
-#: core/validators.py:291
-msgid "Please enter something for at least one field."
-msgstr "Por favor, introduzca algo en al menos un campo."
+#: utils/dateformat.py:97
+msgid "midnight"
+msgstr "media noche"
-#: core/validators.py:300 core/validators.py:311
-msgid "Please enter both fields or leave them both empty."
-msgstr "Por favor, rellene ambos campos o deje ambos vacos."
+#: utils/dateformat.py:99
+msgid "noon"
+msgstr "medio día"
-#: core/validators.py:318
-#, python-format
-msgid "This field must be given if %(field)s is %(value)s"
-msgstr "Se debe proporcionar este campo si %(field)s es %(value)s"
+#: utils/translation/trans_real.py:391
+msgid "DATE_FORMAT"
+msgstr "j N Y"
-#: core/validators.py:330
-#, python-format
-msgid "This field must be given if %(field)s is not %(value)s"
-msgstr "Se debe proporcionar este campo si %(field)s no es %(value)s"
+#: utils/translation/trans_real.py:392
+msgid "DATETIME_FORMAT"
+msgstr "j N Y P"
-#: core/validators.py:349
-msgid "Duplicate values are not allowed."
-msgstr "No se admiten valores duplicados."
+#: utils/translation/trans_real.py:393
+msgid "TIME_FORMAT"
+msgstr "P"
-#: core/validators.py:364
-#, python-format
-msgid "This value must be between %(lower)s and %(upper)s."
-msgstr "Este valor debe estar entre %(lower)s y %(upper)s."
+#: utils/translation/trans_real.py:409
+msgid "YEAR_MONTH_FORMAT"
+msgstr "F Y"
-#: core/validators.py:367
-#, python-format
-msgid "This value must be at least %s."
-msgstr "Este valor debe ser como mnimo %s."
+#: utils/translation/trans_real.py:410
+msgid "MONTH_DAY_FORMAT"
+msgstr "j \\de F"
-#: core/validators.py:369
+#: newforms/fields.py:116
#, python-format
-msgid "This value must be no more than %s."
-msgstr "Este valor no debe ser mayor que %s."
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr ""
+"Asegúrese de que su texto tiene a lo más %(max)d caracteres (actualmente "
+"tiene %(length)d)."
-#: core/validators.py:405
+#: newforms/fields.py:118
#, python-format
-msgid "This value must be a power of %s."
-msgstr "Este valor debe ser una potencia de %s."
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr ""
+"Asegúrese de que su texto tiene al menos %(min)d caracteres (actualmente "
+"tiene %(length)d)."
-#: core/validators.py:416
-msgid "Please enter a valid decimal number."
-msgstr "Por favor, introduzca un nmero decimal vlido."
+#: newforms/fields.py:142 core/validators.py:127
+msgid "Enter a whole number."
+msgstr "Introduzca un número entero."
-#: core/validators.py:420
+#: newforms/fields.py:144 newforms/fields.py:167 newforms/fields.py:197
#, python-format
-msgid "Please enter a valid decimal number with at most %s total digit."
-msgid_plural "Please enter a valid decimal number with at most %s total digits."
-msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgito en "
-"total."
-msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgitos en "
-"total."
+msgid "Ensure this value is less than or equal to %s."
+msgstr "Asegúrese de que este valor es menor o igual a %s."
-#: core/validators.py:423
+#: newforms/fields.py:146 newforms/fields.py:169 newforms/fields.py:199
#, python-format
-msgid "Please enter a valid decimal number with a whole part of at most %s digit."
-msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits."
-msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgito en "
-"su parte entera."
-msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgitos en "
-"su parte entera."
+msgid "Ensure this value is greater than or equal to %s."
+msgstr "Asegúrese de que este valor es mayor o igual a %s."
-#: core/validators.py:426
+#: newforms/fields.py:165 newforms/fields.py:192
+msgid "Enter a number."
+msgstr "Introduzca un número."
+
+#: newforms/fields.py:201
#, python-format
-msgid "Please enter a valid decimal number with at most %s decimal place."
-msgid_plural "Please enter a valid decimal number with at most %s decimal places."
-msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgito "
-"decimal."
-msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con a lo ms %s dgitos "
-"decimales."
+msgid "Ensure that there are no more than %s digits in total."
+msgstr "Asegúrese de que no hay más de %s dígitos en total."
-#: core/validators.py:436
+#: newforms/fields.py:203
#, python-format
-msgid "Make sure your uploaded file is at least %s bytes big."
-msgstr "Asegrese de que el fichero que enva tiene al menos %s bytes."
+msgid "Ensure that there are no more than %s decimal places."
+msgstr "Asegúrese de que no hay más de %s decimales."
-#: core/validators.py:437
+#: newforms/fields.py:205
#, python-format
-msgid "Make sure your uploaded file is at most %s bytes big."
-msgstr "Asegrese de que el fichero que enva tiene como mximo %s bytes."
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr "Asegúrese de que no hay más de %s dígitos antes del punto decimal."
-#: core/validators.py:454
-msgid "The format for this field is wrong."
-msgstr "El formato de este campo es incorrecto."
+#: newforms/fields.py:238 newforms/fields.py:610
+msgid "Enter a valid date."
+msgstr "Introduzca una fecha válida."
-#: core/validators.py:469
-msgid "This field is invalid."
-msgstr "Este campo no es vlido."
+#: newforms/fields.py:265 newforms/fields.py:612
+msgid "Enter a valid time."
+msgstr "Introduzca una hora válida."
-#: core/validators.py:505
-#, python-format
-msgid "Could not retrieve anything from %s."
-msgstr "No pude obtener nada de %s."
+#: newforms/fields.py:301
+msgid "Enter a valid date/time."
+msgstr "Introduzca una fecha/hora válida."
-#: core/validators.py:508
-#, python-format
-msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
-msgstr ""
-"La URL %(url)s devolvi la cabecera Content-Type '%(contenttype)s', que no "
-"es vlida."
+#: newforms/fields.py:314
+msgid "Enter a valid value."
+msgstr "Introduzca un valor correcto."
-#: core/validators.py:541
-#, python-format
-msgid ""
-"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
-"\"%(start)s\".)"
-msgstr ""
-"Por favor, cierre la etiqueta %(tag)s de la lnea %(line)s. (La lnea "
-"empieza por \"%(start)s\".)"
+#: newforms/fields.py:336 core/validators.py:169
+msgid "Enter a valid e-mail address."
+msgstr "Introduzca una dirección de correo electrónico válida"
-#: core/validators.py:545
-#, python-format
-msgid ""
-"Some text starting on line %(line)s is not allowed in that context. (Line "
-"starts with \"%(start)s\".)"
+#: newforms/fields.py:376 oldforms/__init__.py:686 core/validators.py:181
+#: core/validators.py:461
+msgid "No file was submitted. Check the encoding type on the form."
msgstr ""
-"Parte del texto que comienza en la lnea %(line)s no est permitido en ese "
-"contexto. (La lnea empieza por \"%(start)s\".)"
+"No se ha enviado ningún fichero. Compruebe el tipo de codificación en el "
+"formulario."
-#: core/validators.py:550
-#, python-format
-msgid ""
-"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
-"(start)s\".)"
-msgstr ""
-"El \"%(attr)s\" de la lnea %(line)s no es un atributo vlido. (La lnea "
-"empieza por \"%(start)s\".)"
+#: newforms/fields.py:378
+msgid "No file was submitted."
+msgstr "No se ha enviado ningún fichero"
-#: core/validators.py:555
-#, python-format
-msgid ""
-"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
-"(start)s\".)"
-msgstr ""
-"La \"<%(tag)s>\" de la lnea %(line)s no es una etiqueta vlida. (La lnea "
-"empieza por \"%(start)s\".)"
+#: newforms/fields.py:380 oldforms/__init__.py:688
+msgid "The submitted file is empty."
+msgstr "El fichero enviado está vacío."
-#: core/validators.py:559
-#, python-format
+#: newforms/fields.py:397 core/validators.py:185
msgid ""
-"A tag on line %(line)s is missing one or more required attributes. (Line "
-"starts with \"%(start)s\".)"
+"Upload a valid image. The file you uploaded was either not an image or a "
+"corrupted image."
msgstr ""
-"A una etiqueta de la lnea %(line)s le faltan uno o ms atributos "
-"requeridos. (La lnea empieza por \"%(start)s\".)"
+"Envíe una imagen válida. El fichero que ha enviado no era una imagen o se "
+"trataba de una imagen corrupta."
-#: core/validators.py:564
-#, python-format
-msgid ""
-"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
-"starts with \"%(start)s\".)"
-msgstr ""
-"El atributo \"%(attr)s\" de la lnea %(line)s tiene un valor que no es "
-"vlido. (La lnea empieza por \"%(start)s\".)"
+#: newforms/fields.py:403 newforms/fields.py:425
+msgid "Enter a valid URL."
+msgstr "Introduzca una URL válida."
-#: oldforms/__init__.py:387
-#, python-format
-msgid "Ensure your text is less than %s character."
-msgid_plural "Ensure your text is less than %s characters."
-msgstr[0] "Asegrese de que su texto tiene menos de %s carcter."
-msgstr[1] "Asegrese de que su texto tiene menos de %s caracteres."
+#: newforms/fields.py:427
+msgid "This URL appears to be a broken link."
+msgstr "La URL parece ser un enlace roto."
-#: oldforms/__init__.py:392
-msgid "Line breaks are not allowed here."
-msgstr "No se permiten saltos de lnea."
+#: newforms/fields.py:478 newforms/models.py:180
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr "Escoja una opción válida. Esa opción no está entre las aceptadas."
-#: oldforms/__init__.py:493 oldforms/__init__.py:566 oldforms/__init__.py:605
-#, python-format
-msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "Escoja una opcin vlida; '%(data)s' no est en %(choices)s."
+#: newforms/fields.py:494 newforms/fields.py:570 newforms/models.py:197
+msgid "Enter a list of values."
+msgstr "Introduzca una lista de valores."
-#: oldforms/__init__.py:669
-msgid "The submitted file is empty."
-msgstr "El fichero enviado est vaco."
+#: newforms/fields.py:500 newforms/models.py:203
+#, python-format
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr "Escoja una opción válida; '%s' no es una de las opciones disponibles."
-#: oldforms/__init__.py:725
-msgid "Enter a whole number between -32,768 and 32,767."
-msgstr "Introduzca un nmero entero entre -32,768 y 32,767."
+#: newforms/widgets.py:188 contrib/admin/filterspecs.py:152
+#: oldforms/__init__.py:591
+msgid "Unknown"
+msgstr "Desconocido"
-#: oldforms/__init__.py:735
-msgid "Enter a positive number."
-msgstr "Introduzca un nmero positivo."
+#: newforms/widgets.py:188 contrib/admin/filterspecs.py:145
+#: oldforms/__init__.py:591
+msgid "Yes"
+msgstr "Sí"
-#: oldforms/__init__.py:745
-msgid "Enter a whole number between 0 and 32,767."
-msgstr "Introduzca un nmero entero entre 0 y 32,767."
+#: newforms/widgets.py:188 contrib/admin/filterspecs.py:145
+#: oldforms/__init__.py:591
+msgid "No"
+msgstr "No"
-#: contrib/contenttypes/models.py:26
+#: contrib/contenttypes/models.py:37
msgid "python model class name"
-msgstr "nombre de mdulo python"
+msgstr "nombre de módulo python"
-#: contrib/contenttypes/models.py:29
+#: contrib/contenttypes/models.py:40
msgid "content type"
msgstr "tipo de contenido"
-#: contrib/contenttypes/models.py:30
+#: contrib/contenttypes/models.py:41
msgid "content types"
msgstr "tipos de contenido"
-#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:318
-msgid "URL"
-msgstr "URL"
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "th"
+msgstr "th"
-#: contrib/flatpages/models.py:8
-msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
-msgstr ""
-"Ejemplo: '/about/contact/'. Asegrese de que pone barras al principio y al "
-"final."
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "st"
+msgstr "st"
-#: contrib/flatpages/models.py:9
-msgid "title"
-msgstr "ttulo"
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "nd"
+msgstr "nd"
-#: contrib/flatpages/models.py:10
-msgid "content"
-msgstr "contenido"
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "rd"
+msgstr "rd"
-#: contrib/flatpages/models.py:11
-msgid "enable comments"
-msgstr "admitir comentarios"
+#: contrib/humanize/templatetags/humanize.py:47
+#, python-format
+msgid "%(value).1f million"
+msgid_plural "%(value).1f million"
+msgstr[0] "%(value).1f millón"
+msgstr[1] "%(value).1f millión"
-#: contrib/flatpages/models.py:12
-msgid "template name"
-msgstr "nombre de plantilla"
+#: contrib/humanize/templatetags/humanize.py:50
+#, python-format
+msgid "%(value).1f billion"
+msgid_plural "%(value).1f billion"
+msgstr[0] "%(value).1f billión"
+msgstr[1] "%(value).1f billión"
-#: contrib/flatpages/models.py:13
-msgid ""
-"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
-"will use 'flatpages/default.html'."
-msgstr ""
-"Ejemplo: 'flatpages/contact_page.html'. Si no es proporcionado, el sistema usar "
-"'flatpages/default.html'."
+#: contrib/humanize/templatetags/humanize.py:53
+#, python-format
+msgid "%(value).1f trillion"
+msgid_plural "%(value).1f trillion"
+msgstr[0] "%(value).1f trillión"
+msgstr[1] "%(value).1f trillión"
-#: contrib/flatpages/models.py:14
-msgid "registration required"
-msgstr "debe estar registrado"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "one"
+msgstr "uno"
-#: contrib/flatpages/models.py:14
-msgid "If this is checked, only logged-in users will be able to view the page."
-msgstr "Si est marcado, slo los usuarios registrados podrn ver la pgina."
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "two"
+msgstr "dos"
-#: contrib/flatpages/models.py:18
-msgid "flat page"
-msgstr "pgina esttica"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "three"
+msgstr "tres"
-#: contrib/flatpages/models.py:19
-msgid "flat pages"
-msgstr "pginas estticas"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "four"
+msgstr "cuatro"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "five"
+msgstr "cinco"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "six"
+msgstr "seis"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "seven"
+msgstr "siete"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "eight"
+msgstr "ocho"
-#: contrib/auth/views.py:39
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "nine"
+msgstr "nueve"
+
+#: contrib/auth/views.py:47
msgid "Logged out"
-msgstr "Sesin terminada"
+msgstr "Sesión terminada"
-#: contrib/auth/models.py:38 contrib/auth/models.py:57
+#: contrib/auth/models.py:53 contrib/auth/models.py:73
msgid "name"
msgstr "nombre"
-#: contrib/auth/models.py:40
+#: contrib/auth/models.py:55
msgid "codename"
-msgstr "nombre en cdigo"
+msgstr "nombre en código"
-#: contrib/auth/models.py:42
+#: contrib/auth/models.py:58
msgid "permission"
msgstr "permiso"
-#: contrib/auth/models.py:43 contrib/auth/models.py:58
+#: contrib/auth/models.py:59 contrib/auth/models.py:74
msgid "permissions"
msgstr "permisos"
-#: contrib/auth/models.py:60
+#: contrib/auth/models.py:77
msgid "group"
msgstr "grupo"
-#: contrib/auth/models.py:61 contrib/auth/models.py:100
+#: contrib/auth/models.py:78 contrib/auth/models.py:121
msgid "groups"
msgstr "grupos"
-#: contrib/auth/models.py:90
+#: contrib/auth/models.py:111
msgid "username"
msgstr "nombre de usuario"
-#: contrib/auth/models.py:90
+#: contrib/auth/models.py:111
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
msgstr ""
-"Requerido. 30 caracteres o menos. Slo caracteres alfanumricos (letras, "
-"dgitos y guiones bajos)."
+"Requerido. 30 caracteres o menos. Sólo caracteres alfanuméricos (letras, "
+"dígitos y guiones bajos)."
-#: contrib/auth/models.py:91
+#: contrib/auth/models.py:112
msgid "first name"
msgstr "nombre"
-#: contrib/auth/models.py:92
+#: contrib/auth/models.py:113
msgid "last name"
msgstr "apellidos"
-#: contrib/auth/models.py:93
+#: contrib/auth/models.py:114
msgid "e-mail address"
-msgstr "direccin de correo"
+msgstr "dirección de correo"
-#: contrib/auth/models.py:94
+#: contrib/auth/models.py:115
msgid "password"
msgstr "clave"
-#: contrib/auth/models.py:94
+#: contrib/auth/models.py:115
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
msgstr ""
"Use'[algo]$[sal]$[hash hexadecimal]' o use <a href=\"password/\">el "
-"formulario para cambiar la contrasea</a>."
+"formulario para cambiar la contraseña</a>."
-#: contrib/auth/models.py:95
+#: contrib/auth/models.py:116
msgid "staff status"
msgstr "es staff"
-#: contrib/auth/models.py:95
+#: contrib/auth/models.py:116
msgid "Designates whether the user can log into this admin site."
-msgstr "Indica si el usuario puede entrar en este sitio de administracin."
+msgstr "Indica si el usuario puede entrar en este sitio de administración."
-#: contrib/auth/models.py:96
+#: contrib/auth/models.py:117
msgid "active"
msgstr "activo"
-#: contrib/auth/models.py:96
+#: contrib/auth/models.py:117
msgid ""
"Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts."
msgstr ""
-"Indica si el usuario puede entrar en este sitio de administracin. Desmarque "
+"Indica si el usuario puede entrar en este sitio de administración. Desmarque "
"esto en lugar de borrar la cuenta."
-#: contrib/auth/models.py:97
+#: contrib/auth/models.py:118
msgid "superuser status"
msgstr "es superusuario"
-#: contrib/auth/models.py:97
+#: contrib/auth/models.py:118
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
msgstr ""
-"Indica que este usuario tiene todos los permisos sin asignrselos "
-"explcitamente."
+"Indica que este usuario tiene todos los permisos sin asignárselos "
+"explícitamente."
-#: contrib/auth/models.py:98
+#: contrib/auth/models.py:119
msgid "last login"
-msgstr "ltimo registro"
+msgstr "Último registro"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:120
msgid "date joined"
-msgstr "fecha de creacin"
+msgstr "fecha de creación"
-#: contrib/auth/models.py:101
+#: contrib/auth/models.py:122
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
msgstr ""
-"Adems de los permisos asignados manualmente, este usuario tambin tendr "
-"todos los permisos de los grupos en los que est."
+"Además de los permisos asignados manualmente, este usuario también tendrá "
+"todos los permisos de los grupos en los que esté."
-#: contrib/auth/models.py:102
+#: contrib/auth/models.py:123
msgid "user permissions"
msgstr "permisos"
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:127
msgid "user"
msgstr "usuario"
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:128
msgid "users"
msgstr "usuarios"
-#: contrib/auth/models.py:111
+#: contrib/auth/models.py:134
msgid "Personal info"
-msgstr "Informacin personal"
+msgstr "Información personal"
-#: contrib/auth/models.py:112
+#: contrib/auth/models.py:135
msgid "Permissions"
msgstr "Permisos"
-#: contrib/auth/models.py:113
+#: contrib/auth/models.py:136
msgid "Important dates"
msgstr "Fechas importantes"
-#: contrib/auth/models.py:114
+#: contrib/auth/models.py:137
msgid "Groups"
msgstr "Grupos"
-#: contrib/auth/models.py:258
+#: contrib/auth/models.py:287
msgid "message"
msgstr "mensaje"
#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match."
-msgstr "Las dos contraseas no coinciden."
+msgstr "Las dos contraseñas no coinciden."
#: contrib/auth/forms.py:25
msgid "A user with that username already exists."
@@ -1085,32 +935,65 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgstr ""
-"Por favor, introduzca un correcto nombre de usuario y contrasea. Note que "
-"ambos campos son sensibles a maysculas/minsculas."
+"Por favor, introduzca un correcto nombre de usuario y contraseña. Note que "
+"ambos campos son sensibles a mayúsculas/minúsculas."
#: contrib/auth/forms.py:62
msgid "This account is inactive."
-msgstr "Esta cuenta est inactiva."
+msgstr "Esta cuenta está inactiva."
-#: contrib/auth/forms.py:85
+#: contrib/auth/forms.py:84
msgid ""
"That e-mail address doesn't have an associated user account. Are you sure "
"you've registered?"
msgstr ""
-"Esta direccin de correo electrnico no tiene una cuenta de usuario "
-"asociada. Est seguro de que se ha registrado?"
+"Esta dirección de correo electrónico no tiene una cuenta de usuario "
+"asociada. ¿Está seguro de que se ha registrado?"
#: contrib/auth/forms.py:117
msgid "The two 'new password' fields didn't match."
-msgstr "Las contraseas introducidas en los campos 'nueva contrasea' no coinciden."
+msgstr ""
+"Las contraseñas introducidas en los campos 'nueva contraseña' no coinciden."
#: contrib/auth/forms.py:124
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr ""
-"Tu contrasea antigua es incorrecta. Por favor, vuelve a introducirla "
+"Tu contraseña antigua es incorrecta. Por favor, vuelve a introducirla "
"correctamente."
-#: contrib/comments/models.py:67 contrib/comments/models.py:166
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr "redirigir desde"
+
+#: contrib/redirects/models.py:8
+msgid ""
+"This should be an absolute path, excluding the domain name. Example: '/"
+"events/search/'."
+msgstr ""
+"Esta ruta debería ser absoluta, excluyendo el nombre de dominio. Ejeplo: '/"
+"events/search/'."
+
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr "redirigir a"
+
+#: contrib/redirects/models.py:10
+msgid ""
+"This can be either an absolute path (as above) or a full URL starting with "
+"'http://'."
+msgstr ""
+"Esto puede ser bien una ruta absoluta (como antes) o una URL completa que "
+"empiece con 'http://'."
+
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr "redirección"
+
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr "redirecciones"
+
+#: contrib/comments/models.py:67 contrib/comments/models.py:169
msgid "object ID"
msgstr "ID de objeto"
@@ -1119,79 +1002,79 @@ msgid "headline"
msgstr "encabezado"
#: contrib/comments/models.py:69 contrib/comments/models.py:90
-#: contrib/comments/models.py:167
+#: contrib/comments/models.py:170
msgid "comment"
msgstr "comentario"
#: contrib/comments/models.py:70
msgid "rating #1"
-msgstr "calificacin 1"
+msgstr "calificación 1"
#: contrib/comments/models.py:71
msgid "rating #2"
-msgstr "calificacin 2"
+msgstr "calificación 2"
#: contrib/comments/models.py:72
msgid "rating #3"
-msgstr "calificacin 3"
+msgstr "calificación 3"
#: contrib/comments/models.py:73
msgid "rating #4"
-msgstr "calificacin 4"
+msgstr "calificación 4"
#: contrib/comments/models.py:74
msgid "rating #5"
-msgstr "calificacin 5"
+msgstr "calificación 5"
#: contrib/comments/models.py:75
msgid "rating #6"
-msgstr "calificacin 6"
+msgstr "calificación 6"
#: contrib/comments/models.py:76
msgid "rating #7"
-msgstr "calificacin 7"
+msgstr "calificación 7"
#: contrib/comments/models.py:77
msgid "rating #8"
-msgstr "calificacin 8"
+msgstr "calificación 8"
#: contrib/comments/models.py:82
msgid "is valid rating"
-msgstr "es calificacin vlida"
+msgstr "es calificación válida"
-#: contrib/comments/models.py:83 contrib/comments/models.py:169
+#: contrib/comments/models.py:83 contrib/comments/models.py:172
msgid "date/time submitted"
-msgstr "fecha/hora de envo"
+msgstr "fecha/hora de envío"
-#: contrib/comments/models.py:84 contrib/comments/models.py:170
+#: contrib/comments/models.py:84 contrib/comments/models.py:173
msgid "is public"
-msgstr "es pblico"
+msgstr "es público"
-#: contrib/comments/models.py:85 contrib/admin/views/doc.py:307
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:306
msgid "IP address"
-msgstr "Direccin IP"
+msgstr "Dirección IP"
#: contrib/comments/models.py:86
msgid "is removed"
-msgstr "est eliminado"
+msgstr "está eliminado"
#: contrib/comments/models.py:86
msgid ""
"Check this box if the comment is inappropriate. A \"This comment has been "
"removed\" message will be displayed instead."
msgstr ""
-"Marque esta caja si el comentario es inapropiado. En su lugar se mostrar "
+"Marque esta caja si el comentario es inapropiado. En su lugar se mostrará "
"\"Este comentario ha sido eliminado\"."
#: contrib/comments/models.py:91
msgid "comments"
msgstr "comentarios"
-#: contrib/comments/models.py:131 contrib/comments/models.py:207
+#: contrib/comments/models.py:134 contrib/comments/models.py:213
msgid "Content object"
msgstr "Objeto contenido"
-#: contrib/comments/models.py:159
+#: contrib/comments/models.py:162
#, python-format
msgid ""
"Posted by %(user)s at %(date)s\n"
@@ -1206,48 +1089,48 @@ msgstr ""
"\n"
"http://%(domain)s%(url)s"
-#: contrib/comments/models.py:168
+#: contrib/comments/models.py:171
msgid "person's name"
msgstr "nombre de la persona"
-#: contrib/comments/models.py:171
+#: contrib/comments/models.py:174
msgid "ip address"
-msgstr "direccin ip"
+msgstr "dirección ip"
-#: contrib/comments/models.py:173
+#: contrib/comments/models.py:176
msgid "approved by staff"
msgstr "aprobado por el staff"
-#: contrib/comments/models.py:176
+#: contrib/comments/models.py:179
msgid "free comment"
msgstr "comentario libre"
-#: contrib/comments/models.py:177
+#: contrib/comments/models.py:180
msgid "free comments"
msgstr "comentarios libres"
-#: contrib/comments/models.py:233
+#: contrib/comments/models.py:239
msgid "score"
-msgstr "puntuacin"
+msgstr "puntuación"
-#: contrib/comments/models.py:234
+#: contrib/comments/models.py:240
msgid "score date"
-msgstr "fecha de la puntuacin"
+msgstr "fecha de la puntuación"
-#: contrib/comments/models.py:237
+#: contrib/comments/models.py:243
msgid "karma score"
msgstr "punto karma"
-#: contrib/comments/models.py:238
+#: contrib/comments/models.py:244
msgid "karma scores"
msgstr "puntos karma"
-#: contrib/comments/models.py:242
+#: contrib/comments/models.py:248
#, python-format
msgid "%(score)d rating by %(user)s"
msgstr "puntuado %(score)d por %(user)s"
-#: contrib/comments/models.py:258
+#: contrib/comments/models.py:264
#, python-format
msgid ""
"This comment was flagged by %(user)s:\n"
@@ -1258,114 +1141,58 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/models.py:265
+#: contrib/comments/models.py:271
msgid "flag date"
msgstr "fecha de la marca"
-#: contrib/comments/models.py:268
+#: contrib/comments/models.py:274
msgid "user flag"
msgstr "marca de usuario"
-#: contrib/comments/models.py:269
+#: contrib/comments/models.py:275
msgid "user flags"
msgstr "marcas de usuario"
-#: contrib/comments/models.py:273
+#: contrib/comments/models.py:279
#, python-format
msgid "Flag by %r"
msgstr "Marca de %r"
-#: contrib/comments/models.py:278
+#: contrib/comments/models.py:284
msgid "deletion date"
-msgstr "fecha de eliminacin"
+msgstr "fecha de eliminación"
-#: contrib/comments/models.py:280
+#: contrib/comments/models.py:286
msgid "moderator deletion"
-msgstr "eliminacin de moderador"
+msgstr "eliminación de moderador"
-#: contrib/comments/models.py:281
+#: contrib/comments/models.py:287
msgid "moderator deletions"
msgstr "eliminaciones de moderador"
-#: contrib/comments/models.py:285
+#: contrib/comments/models.py:291
#, python-format
msgid "Moderator deletion by %r"
-msgstr "Eliminacin del moderador %r"
-
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "Tu nombre:"
-
-#: contrib/comments/templates/comments/freeform.html:5
-#: contrib/comments/templates/comments/form.html:28
-msgid "Comment:"
-msgstr "Comentario:"
-
-#: contrib/comments/templates/comments/freeform.html:10
-#: contrib/comments/templates/comments/form.html:35
-msgid "Preview comment"
-msgstr "Previsualizar comentario"
-
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/login.html:17
-msgid "Username:"
-msgstr "Usuario:"
-
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/registration/password_change_done.html:3
-msgid "Log out"
-msgstr "Terminar sesin"
-
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/login.html:20
-msgid "Password:"
-msgstr "Clave:"
+msgstr "Eliminación del moderador %r"
-#: contrib/comments/templates/comments/form.html:8
-msgid "Forgotten your password?"
-msgstr "Has olvidado tu contrasea?"
-
-#: contrib/comments/templates/comments/form.html:12
-msgid "Ratings"
-msgstr "Calificaciones"
-
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Required"
-msgstr "Requerido"
+#: contrib/comments/views/karma.py:20
+msgid "Anonymous users cannot vote"
+msgstr "Los usuarios anónimos no pueden votar"
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Optional"
-msgstr "Opcional"
+#: contrib/comments/views/karma.py:24
+msgid "Invalid comment ID"
+msgstr "ID de comentario no válido"
-#: contrib/comments/templates/comments/form.html:23
-msgid "Post a photo"
-msgstr "Postea una fotografa"
+#: contrib/comments/views/karma.py:26
+msgid "No voting for yourself"
+msgstr "No puedes votarte tú mismo"
-#: contrib/comments/views/comments.py:27
-msgid "This rating is required because you've entered at least one other rating."
-msgstr "Se precisa esta puntuacin porque ha introducido al menos otra ms."
+#: contrib/comments/views/comments.py:28
+msgid ""
+"This rating is required because you've entered at least one other rating."
+msgstr "Se precisa esta puntuación porque ha introducido al menos otra más."
-#: contrib/comments/views/comments.py:111
+#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
@@ -1378,17 +1205,17 @@ msgid_plural ""
"\n"
"%(text)s"
msgstr[0] ""
-"Este comentario lo envi un usuario que ha enviado menos de %(count)s "
+"Este comentario lo envió un usuario que ha enviado menos de %(count)s "
"comentario:\n"
"\n"
"%(text)s"
msgstr[1] ""
-"Este comentario lo envi un usuario que ha enviado menos de %(count)s "
+"Este comentario lo envió un usuario que ha enviado menos de %(count)s "
"comentarios:\n"
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:116
+#: contrib/comments/views/comments.py:117
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
@@ -1399,98 +1226,194 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
msgid "Only POSTs are allowed"
-msgstr "Slo se admite POST"
+msgstr "Sólo se admite POST"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
msgid "One or more of the required fields wasn't submitted"
-msgstr "No se proporcion uno o ms de los siguientes campos requeridos"
+msgstr "No se proporcionó uno o más de los siguientes campos requeridos"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
msgid "Somebody tampered with the comment form (security violation)"
msgstr ""
-"Alguien est jugando con el formulario de comentarios (violacin de "
+"Alguien está jugando con el formulario de comentarios (violación de "
"seguridad)"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
msgstr ""
-"El formulario de comentarios tiene un parmetro 'target' no vlido (el ID de "
-"objeto era invlido)"
+"El formulario de comentarios tiene un parámetro 'target' no válido (el ID de "
+"objeto era inválido)"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
msgid "The comment form didn't provide either 'preview' or 'post'"
-msgstr "El formulario de comentario no proporcion 'previsualizar' ni 'enviar'"
+msgstr "El formulario de comentario no proporcionó 'previsualizar' ni 'enviar'"
-#: contrib/comments/views/karma.py:19
-msgid "Anonymous users cannot vote"
-msgstr "Los usuarios annimos no pueden votar"
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:17
+msgid "Username:"
+msgstr "Usuario:"
-#: contrib/comments/views/karma.py:23
-msgid "Invalid comment ID"
-msgstr "ID de comentario no vlido"
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+msgid "Log out"
+msgstr "Terminar sesión"
-#: contrib/comments/views/karma.py:25
-msgid "No voting for yourself"
-msgstr "No puedes votarte t mismo"
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:20
+msgid "Password:"
+msgstr "Clave:"
-#: contrib/redirects/models.py:7
-msgid "redirect from"
-msgstr "redirigir desde"
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr "¿Has olvidado tu contraseña?"
-#: contrib/redirects/models.py:8
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr "Calificaciones"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr "Requerido"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr "Opcional"
+
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr "Postea una fotografía"
+
+#: contrib/comments/templates/comments/form.html:28
+#: contrib/comments/templates/comments/freeform.html:5
+msgid "Comment:"
+msgstr "Comentario:"
+
+#: contrib/comments/templates/comments/form.html:35
+#: contrib/comments/templates/comments/freeform.html:10
+msgid "Preview comment"
+msgstr "Previsualizar comentario"
+
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "Tu nombre:"
+
+#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:317
+msgid "URL"
+msgstr "URL"
+
+#: contrib/flatpages/models.py:8
msgid ""
-"This should be an absolute path, excluding the domain name. Example: '/"
-"events/search/'."
+"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr ""
-"Esta ruta debera ser absoluta, excluyendo el nombre de dominio. Ejeplo: '/"
-"events/search/'."
+"Ejemplo: '/about/contact/'. Asegúrese de que pone barras al principio y al "
+"final."
-#: contrib/redirects/models.py:9
-msgid "redirect to"
-msgstr "redirigir a"
+#: contrib/flatpages/models.py:9
+msgid "title"
+msgstr "título"
-#: contrib/redirects/models.py:10
+#: contrib/flatpages/models.py:10
+msgid "content"
+msgstr "contenido"
+
+#: contrib/flatpages/models.py:11
+msgid "enable comments"
+msgstr "admitir comentarios"
+
+#: contrib/flatpages/models.py:12
+msgid "template name"
+msgstr "nombre de plantilla"
+
+#: contrib/flatpages/models.py:13
msgid ""
-"This can be either an absolute path (as above) or a full URL starting with "
-"'http://'."
+"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
+"will use 'flatpages/default.html'."
msgstr ""
-"Esto puede ser bien una ruta absoluta (como antes) o una URL completa que "
-"empiece con 'http://'."
+"Ejemplo: 'flatpages/contact_page.html'. Si no es proporcionado, el sistema "
+"usará 'flatpages/default.html'."
-#: contrib/redirects/models.py:13
-msgid "redirect"
-msgstr "redireccin"
+#: contrib/flatpages/models.py:14
+msgid "registration required"
+msgstr "debe estar registrado"
-#: contrib/redirects/models.py:14
-msgid "redirects"
-msgstr "redirecciones"
+#: contrib/flatpages/models.py:14
+msgid "If this is checked, only logged-in users will be able to view the page."
+msgstr "Si está marcado, sólo los usuarios registrados podrán ver la página."
+
+#: contrib/flatpages/models.py:18
+msgid "flat page"
+msgstr "página estática"
+
+#: contrib/flatpages/models.py:19
+msgid "flat pages"
+msgstr "páginas estáticas"
+
+#: contrib/sessions/models.py:68
+msgid "session key"
+msgstr "clave de sesión"
-#: contrib/sites/models.py:10
+#: contrib/sessions/models.py:69
+msgid "session data"
+msgstr "datos de sesión"
+
+#: contrib/sessions/models.py:70
+msgid "expire date"
+msgstr "fecha de caducidad"
+
+#: contrib/sessions/models.py:74
+msgid "session"
+msgstr "sesión"
+
+#: contrib/sessions/models.py:75
+msgid "sessions"
+msgstr "sesiones"
+
+#: contrib/sites/models.py:15
msgid "domain name"
msgstr "nombre de dominio"
-#: contrib/sites/models.py:11
+#: contrib/sites/models.py:16
msgid "display name"
msgstr "nombre para mostrar"
-#: contrib/sites/models.py:15
+#: contrib/sites/models.py:20
msgid "site"
msgstr "sitio"
-#: contrib/sites/models.py:16
+#: contrib/sites/models.py:21
msgid "sites"
msgstr "sitios"
-#: contrib/admin/filterspecs.py:40
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
@@ -1499,59 +1422,338 @@ msgstr ""
"<h3>Por %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Todo"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Cualquier fecha"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Hoy"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
-msgstr "ltimos 7 das"
+msgstr "Últimos 7 días"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Este mes"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
-msgstr "Este ao"
+msgstr "Este año"
-#: contrib/admin/models.py:16
+#: contrib/admin/models.py:17
msgid "action time"
-msgstr "hora de accin"
+msgstr "hora de acción"
-#: contrib/admin/models.py:19
+#: contrib/admin/models.py:20
msgid "object id"
msgstr "id de objeto"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object repr"
msgstr "repr de objeto"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "action flag"
-msgstr "marca de accin"
+msgstr "marca de acción"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "change message"
msgstr "mensaje de cambio"
-#: contrib/admin/models.py:25
+#: contrib/admin/models.py:26
msgid "log entry"
msgstr "entrada de registro"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entries"
msgstr "entradas de registro"
+#: contrib/admin/templatetags/admin_list.py:254
+msgid "All dates"
+msgstr "Todas las fechas"
+
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully."
+msgstr "Se añadió con éxito el %(name)s \"%(obj)s\"."
+
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
+#: contrib/admin/views/main.py:354
+msgid "You may edit it again below."
+msgstr "Puede editarlo de nuevo abajo."
+
+#: contrib/admin/views/auth.py:31
+msgid "Add user"
+msgstr "Añadir usuario"
+
+#: contrib/admin/views/auth.py:58
+msgid "Password changed successfully."
+msgstr "La clave se ha cambiado exitosamente."
+
+#: contrib/admin/views/auth.py:65
+#, python-format
+msgid "Change password: %s"
+msgstr "Cambiar clave: %s"
+
+#: contrib/admin/views/main.py:230
+msgid "Site administration"
+msgstr "Sitio administrativo"
+
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
+#, python-format
+msgid "You may add another %s below."
+msgstr "Puede agregar otro %s abajo."
+
+#: contrib/admin/views/main.py:296
+#, python-format
+msgid "Add %s"
+msgstr "Agregar %s"
+
+#: contrib/admin/views/main.py:342
+#, python-format
+msgid "Added %s."
+msgstr "Agregado %s."
+
+#: contrib/admin/views/main.py:344
+#, python-format
+msgid "Changed %s."
+msgstr "Modificado %s."
+
+#: contrib/admin/views/main.py:346
+#, python-format
+msgid "Deleted %s."
+msgstr "Borrado %s."
+
+#: contrib/admin/views/main.py:349
+msgid "No fields changed."
+msgstr "No ha cambiado ningún campo."
+
+#: contrib/admin/views/main.py:352
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was changed successfully."
+msgstr "Se modificó con éxito el %(name)s \"%(obj)s."
+
+#: contrib/admin/views/main.py:360
+#, python-format
+msgid ""
+"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
+msgstr ""
+"Se agregó con éxito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo."
+
+#: contrib/admin/views/main.py:398
+#, python-format
+msgid "Change %s"
+msgstr "Modificar %s"
+
+#: contrib/admin/views/main.py:483
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
+msgstr "Uno o más %(fieldname)s en %(name)s: %(obj)s"
+
+#: contrib/admin/views/main.py:488
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s:"
+msgstr "Uno o más %(fieldname)s en %(name)s:"
+
+#: contrib/admin/views/main.py:520
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was deleted successfully."
+msgstr "Se eliminó con éxito el %(name)s \"%(obj)s\"."
+
+#: contrib/admin/views/main.py:523
+msgid "Are you sure?"
+msgstr "¿Está seguro?"
+
+#: contrib/admin/views/main.py:545
+#, python-format
+msgid "Change history: %s"
+msgstr "Modificar histórico: %s"
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s"
+msgstr "Escoja %s"
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s to change"
+msgstr "Escoja %s para modificar"
+
+#: contrib/admin/views/main.py:780
+msgid "Database error"
+msgstr "Erorr en la base de datos"
+
+#: contrib/admin/views/decorators.py:24
+#: contrib/admin/templates/admin/login.html:25
+msgid "Log in"
+msgstr "Identificarse"
+
+#: contrib/admin/views/decorators.py:62
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+"Por favor, identifíquese de nuevo, porque su sesión ha caducado. No se "
+"preocupe: se ha guardado su envío."
+
+#: contrib/admin/views/decorators.py:69
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr ""
+"Parece que su navegador no está configurado para aceptar cookies. Actívelas "
+"por favor, recargue esta página, e inténtelo de nuevo."
+
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr "Los nombres de usuario no pueden contener el carácter '@'."
+
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr ""
+"Su dirección de correo no es su nombre de usuario. Pruebe con '%s' en su "
+"lugar."
+
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
+msgid "tag:"
+msgstr "etiqueta:"
+
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
+msgid "filter:"
+msgstr "filtro:"
+
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
+msgid "view:"
+msgstr "vista:"
+
+#: contrib/admin/views/doc.py:165
+#, python-format
+msgid "App %r not found"
+msgstr "Aplicación %r no encontrada"
+
+#: contrib/admin/views/doc.py:172
+#, python-format
+msgid "Model %(name)r not found in app %(label)r"
+msgstr "El modelo %(name)s no se ha encontrado en la aplicación %(label)r"
+
+#: contrib/admin/views/doc.py:184
+#, python-format
+msgid "the related `%(label)s.%(type)s` object"
+msgstr "el objeto relacionado`%(label)s.%(type)s` "
+
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
+msgid "model:"
+msgstr "modelo:"
+
+#: contrib/admin/views/doc.py:215
+#, python-format
+msgid "related `%(label)s.%(name)s` objects"
+msgstr "los objetos relacionados `%(label)s.%(name)s`"
+
+#: contrib/admin/views/doc.py:220
+#, python-format
+msgid "all %s"
+msgstr "todo %s"
+
+#: contrib/admin/views/doc.py:225
+#, python-format
+msgid "number of %s"
+msgstr "número de %s"
+
+#: contrib/admin/views/doc.py:230
+#, python-format
+msgid "Fields on %s objects"
+msgstr "Campos en %s objetos"
+
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
+msgid "Integer"
+msgstr "Entero"
+
+#: contrib/admin/views/doc.py:293
+msgid "Boolean (Either True or False)"
+msgstr "Booleano (Verdadero o Falso)"
+
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
+#, python-format
+msgid "String (up to %(max_length)s)"
+msgstr "Cadena (máximo %(max_length)s)"
+
+#: contrib/admin/views/doc.py:295
+msgid "Comma-separated integers"
+msgstr "Enteros separados por comas"
+
+#: contrib/admin/views/doc.py:296
+msgid "Date (without time)"
+msgstr "Fecha (sin hora)"
+
+#: contrib/admin/views/doc.py:297
+msgid "Date (with time)"
+msgstr "Fecha (con hora)"
+
+#: contrib/admin/views/doc.py:298
+msgid "Decimal number"
+msgstr "Número decimal"
+
+#: contrib/admin/views/doc.py:299
+msgid "E-mail address"
+msgstr "Dirección de correo electrónico"
+
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
+msgid "File path"
+msgstr "Ruta de fichero"
+
+#: contrib/admin/views/doc.py:302
+msgid "Floating point number"
+msgstr "Número decimal"
+
+#: contrib/admin/views/doc.py:308
+msgid "Boolean (Either True, False or None)"
+msgstr "Booleano (Verdadero, Falso o Nulo)"
+
+#: contrib/admin/views/doc.py:309
+msgid "Relation to parent model"
+msgstr "Relación con el modelo padre"
+
+#: contrib/admin/views/doc.py:310
+msgid "Phone number"
+msgstr "Número de teléfono"
+
+#: contrib/admin/views/doc.py:315
+msgid "Text"
+msgstr "Texto"
+
+#: contrib/admin/views/doc.py:316
+msgid "Time"
+msgstr "Hora"
+
+#: contrib/admin/views/doc.py:318
+msgid "U.S. state (two uppercase letters)"
+msgstr "Estado de los EEUU (dos letras mayúsculas)"
+
+#: contrib/admin/views/doc.py:319
+msgid "XML text"
+msgstr "Texto XML"
+
+#: contrib/admin/views/doc.py:345
+#, python-format
+msgid "%s does not appear to be a urlpattern object"
+msgstr "%s no parece ser un objeto urlpattern"
+
#: contrib/admin/templates/widget/file.html:2
msgid "Currently:"
msgstr "Actualmente:"
@@ -1568,167 +1770,72 @@ msgstr "Fecha:"
msgid "Time:"
msgstr "Hora:"
-#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Documentation"
+msgstr "Documentación"
+
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin/auth/user/change_password.html:15
#: contrib/admin/templates/admin/auth/user/change_password.html:46
-#: contrib/admin/templates/registration/password_change_form.html:3
#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
msgid "Change password"
msgstr "Cambiar clave"
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/admin/500.html:4
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/base.html:30
#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/delete_confirmation.html:6
-#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/500.html:4
#: contrib/admin/templates/admin/invalid_setup.html:4
+#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/base.html:30
#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/registration/password_change_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/logged_out.html:4
#: contrib/admin/templates/registration/password_reset_done.html:4
#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Home"
msgstr "Inicio"
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/registration/password_change_done.html:3
-msgid "Documentation"
-msgstr "Documentacin"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-msgid "Bookmarklets"
-msgstr "Bookmarklets"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:5
-msgid "Documentation bookmarklets"
-msgstr "Bookmarklets de documentacin"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:9
-msgid ""
-"\n"
-"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
-"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
-"select the bookmarklet from any page in the site. Note that some of these\n"
-"bookmarklets require you to be viewing the site from a computer designated\n"
-"as \"internal\" (talk to your system administrator if you aren't sure if\n"
-"your computer is \"internal\").</p>\n"
-msgstr ""
-"\n"
-"<p class=\"help\">Para instalar bookmarklets, arrastre el enlace a su barra\n"
-"de favoritos, o pulse con el botn derecho el enlace y adalo a sus "
-"favoritos.\n"
-"Ahora puede escoger el bookmarklet desde cualquier pgina en el sitio.\n"
-"Observer que algunos de estos bookmarklets precisan que est viendo\n"
-"el sitio desde un computador sealado como \"interno\" (hable\n"
-"con su administrador de sistemas si no est seguro de si el suyo lo es).</"
-"p>\n"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:19
-msgid "Documentation for this page"
-msgstr "Documentacin de esta pgina"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:20
-msgid ""
-"Jumps you from any page to the documentation for the view that generates "
-"that page."
-msgstr "Le lleva desde cualquier pgina a la documentacin de la vista que la genera."
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:22
-msgid "Show object ID"
-msgstr "Mostrar ID de objeto"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:23
-msgid ""
-"Shows the content-type and unique ID for pages that represent a single "
-"object."
-msgstr ""
-"Muestra el tipo de contenido e ID unvoco de las pginas que representan un "
-"nico objeto."
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:25
-msgid "Edit this object (current window)"
-msgstr "Editar este objeto (ventana actual)"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:26
-msgid "Jumps to the admin page for pages that represent a single object."
-msgstr ""
-"Le lleva a la pgina de administracin de pginas que representan un nico "
-"objeto."
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:28
-msgid "Edit this object (new window)"
-msgstr "Editar este objeto (nueva ventana)"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:29
-msgid "As above, but opens the admin page in a new window."
-msgstr "Como antes, pero abre la pgina de administracin en una nueva ventana."
-
-#: contrib/admin/templates/admin/500.html:4
-msgid "Server error"
-msgstr "Error del servidor"
-
-#: contrib/admin/templates/admin/500.html:6
-msgid "Server error (500)"
-msgstr "Error del servidor (500)"
-
-#: contrib/admin/templates/admin/500.html:9
-msgid "Server Error <em>(500)</em>"
-msgstr "Error de servidor <em>(500)</em>"
-
-#: contrib/admin/templates/admin/500.html:10
-msgid ""
-"There's been an error. It's been reported to the site administrators via e-"
-"mail and should be fixed shortly. Thanks for your patience."
-msgstr ""
-"Ha ocurrido un error. Se ha informado a los administradores del sitio "
-"mediante correo electrnico y debera arreglarse en breve. Gracias por su "
-"paciencia."
-
-#: contrib/admin/templates/admin/search_form.html:8
-msgid "Go"
-msgstr "Buscar"
-
-#: contrib/admin/templates/admin/search_form.html:10
+#: contrib/admin/templates/admin/change_list.html:12
#, python-format
-msgid "1 result"
-msgid_plural "%(counter)s results"
-msgstr[0] "1 resultado"
-msgstr[1] "%(counter)s resultados"
+msgid "Add %(name)s"
+msgstr "Agregar %(name)s"
-#: contrib/admin/templates/admin/search_form.html:10
+#: contrib/admin/templates/admin/filter.html:2
#, python-format
-msgid "%(full_result_count)s total"
-msgstr "%(full_result_count)s total"
+msgid " By %(filter_title)s "
+msgstr " Por %(filter_title)s "
#: contrib/admin/templates/admin/object_history.html:5
#: contrib/admin/templates/admin/change_form.html:21
msgid "History"
-msgstr "Histrico"
+msgstr "Histórico"
#: contrib/admin/templates/admin/object_history.html:18
msgid "Date/time"
@@ -1740,7 +1847,7 @@ msgstr "Usuario"
#: contrib/admin/templates/admin/object_history.html:20
msgid "Action"
-msgstr "Accin"
+msgstr "Acción"
#: contrib/admin/templates/admin/object_history.html:26
msgid "DATE_WITH_TIME_FULL"
@@ -1751,93 +1858,72 @@ msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgstr ""
-"Este objeto no tiene histrico de cambios. Probablemente no fue aadido "
-"usando este sitio de administracin."
+"Este objeto no tiene histórico de cambios. Probablemente no fue añadido "
+"usando este sitio de administración."
+
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr "Buscar"
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "1 resultado"
+msgstr[1] "%(counter)s resultados"
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr "%(full_result_count)s total"
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Mostrarlo todo"
#: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin"
-msgstr "Sitio de administracin de Django"
+msgstr "Sitio de administración de Django"
#: contrib/admin/templates/admin/base_site.html:7
msgid "Django administration"
-msgstr "Administracin de Django"
+msgstr "Administración de Django"
-#: contrib/admin/templates/admin/base.html:25
-msgid "Welcome,"
-msgstr "Bienvenido,"
-
-#: contrib/admin/templates/admin/login.html:25
-#: contrib/admin/views/decorators.py:24
-msgid "Log in"
-msgstr "Identificarse"
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "Error del servidor"
-#: contrib/admin/templates/admin/change_list.html:12
-#, python-format
-msgid "Add %(name)s"
-msgstr "Agregar %(name)s"
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr "Error del servidor (500)"
-#: contrib/admin/templates/admin/delete_confirmation.html:9
-#: contrib/admin/templates/admin/submit_line.html:3
-msgid "Delete"
-msgstr "Eliminar"
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr "Error de servidor <em>(500)</em>"
-#: contrib/admin/templates/admin/delete_confirmation.html:14
-#, python-format
+#: contrib/admin/templates/admin/500.html:10
msgid ""
-"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
-"related objects, but your account doesn't have permission to delete the "
-"following types of objects:"
+"There's been an error. It's been reported to the site administrators via e-"
+"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
-"Eliminar el %(object_name)s '%(escaped_object)s' provocara la eliminacin "
-"de objetos relacionados, pero su cuenta no tiene permiso para borrar los "
-"siguientes tipos de objetos:"
+"Ha ocurrido un error. Se ha informado a los administradores del sitio "
+"mediante correo electrónico y debería arreglarse en breve. Gracias por su "
+"paciencia."
-#: contrib/admin/templates/admin/delete_confirmation.html:21
-#, python-format
+#: contrib/admin/templates/admin/invalid_setup.html:8
msgid ""
-"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
-"All of the following related items will be deleted:"
+"Something's wrong with your database installation. Make sure the appropriate "
+"database tables have been created, and make sure the database is readable by "
+"the appropriate user."
msgstr ""
-"Est seguro de que quiere borrar los %(object_name)s \"%(escaped_object)s"
-"\"? Se borrarn los siguientes objetos relacionados:"
-
-#: contrib/admin/templates/admin/delete_confirmation.html:26
-msgid "Yes, I'm sure"
-msgstr "S, estoy seguro"
-
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
-msgid "Page not found"
-msgstr "Pgina no encontrada"
-
-#: contrib/admin/templates/admin/404.html:10
-msgid "We're sorry, but the requested page could not be found."
-msgstr "Lo sentimos, pero no se encuentra la pgina solicitada."
-
-#: contrib/admin/templates/admin/filters.html:4
-msgid "Filter"
-msgstr "Filtro"
-
-#: contrib/admin/templates/admin/submit_line.html:4
-msgid "Save as new"
-msgstr "Grabar como nuevo"
-
-#: contrib/admin/templates/admin/submit_line.html:5
-msgid "Save and add another"
-msgstr "Grabar y aadir otro"
-
-#: contrib/admin/templates/admin/submit_line.html:6
-msgid "Save and continue editing"
-msgstr "Grabar y continuar editando"
-
-#: contrib/admin/templates/admin/submit_line.html:7
-msgid "Save"
-msgstr "Grabar"
+"Algo va mal con la instalación de la base de datos. Asegúrate que las tablas "
+"necesarias han sido creadas, y que la base de datos puede ser leída por el "
+"usuario apropiado."
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
-msgstr "Modelos disponibles en la aplicacin %(name)s."
+msgstr "Modelos disponibles en la aplicación %(name)s."
#: contrib/admin/templates/admin/index.html:18
#, python-format
@@ -1869,9 +1955,18 @@ msgstr "Mis acciones"
msgid "None available"
msgstr "Ninguno disponible"
-#: contrib/admin/templates/admin/pagination.html:10
-msgid "Show all"
-msgstr "Mostrarlo todo"
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr "Página no encontrada"
+
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr "Lo sentimos, pero no se encuentra la página solicitada."
+
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filtro"
#: contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
@@ -1886,34 +1981,68 @@ msgstr[1] "Por favor, corrija los siguientes errores."
#: contrib/admin/templates/admin/change_form.html:50
msgid "Ordering"
-msgstr "Ordenacin"
+msgstr "Ordenación"
#: contrib/admin/templates/admin/change_form.html:53
msgid "Order:"
msgstr "Orden:"
-#: contrib/admin/templates/admin/invalid_setup.html:8
+#: contrib/admin/templates/admin/delete_confirmation.html:9
+#: contrib/admin/templates/admin/submit_line.html:3
+msgid "Delete"
+msgstr "Eliminar"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:14
+#, python-format
msgid ""
-"Something's wrong with your database installation. Make sure the appropriate "
-"database tables have been created, and make sure the database is readable by "
-"the appropriate user."
+"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
+"related objects, but your account doesn't have permission to delete the "
+"following types of objects:"
msgstr ""
-"Algo va mal con la instalacin de la base de datos. Asegrate que las tablas "
-"necesarias han sido creadas, y que la base de datos puede ser leda por el "
-"usuario apropiado."
+"Eliminar el %(object_name)s '%(escaped_object)s' provocaría la eliminación "
+"de objetos relacionados, pero su cuenta no tiene permiso para borrar los "
+"siguientes tipos de objetos:"
-#: contrib/admin/templates/admin/filter.html:2
+#: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format
-msgid " By %(filter_title)s "
-msgstr " Por %(filter_title)s "
+msgid ""
+"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
+"All of the following related items will be deleted:"
+msgstr ""
+"¿Está seguro de que quiere borrar los %(object_name)s \"%(escaped_object)s"
+"\"? Se borrarán los siguientes objetos relacionados:"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:26
+msgid "Yes, I'm sure"
+msgstr "Sí, estoy seguro"
+
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr "Bienvenido,"
+
+#: contrib/admin/templates/admin/submit_line.html:4
+msgid "Save as new"
+msgstr "Grabar como nuevo"
+
+#: contrib/admin/templates/admin/submit_line.html:5
+msgid "Save and add another"
+msgstr "Grabar y añadir otro"
+
+#: contrib/admin/templates/admin/submit_line.html:6
+msgid "Save and continue editing"
+msgstr "Grabar y continuar editando"
+
+#: contrib/admin/templates/admin/submit_line.html:7
+msgid "Save"
+msgstr "Grabar"
#: contrib/admin/templates/admin/auth/user/add_form.html:6
msgid ""
"First, enter a username and password. Then, you'll be able to edit more user "
"options."
msgstr ""
-"Primero introduzca un nombre de usuario y una contrasea. Luego podr "
-"editar el resto de opciones del usuario."
+"Primero introduzca un nombre de usuario y una contraseña. Luego podrá editar "
+"el resto de opciones del usuario."
#: contrib/admin/templates/admin/auth/user/add_form.html:12
msgid "Username"
@@ -1922,25 +2051,41 @@ msgstr "Nombre de usuario"
#: contrib/admin/templates/admin/auth/user/add_form.html:18
#: contrib/admin/templates/admin/auth/user/change_password.html:34
msgid "Password"
-msgstr "Contrasea"
+msgstr "Contraseña"
#: contrib/admin/templates/admin/auth/user/add_form.html:23
#: contrib/admin/templates/admin/auth/user/change_password.html:39
msgid "Password (again)"
-msgstr "Contrasea (de nuevo)"
+msgstr "Contraseña (de nuevo)"
#: contrib/admin/templates/admin/auth/user/add_form.html:24
#: contrib/admin/templates/admin/auth/user/change_password.html:40
msgid "Enter the same password as above, for verification."
-msgstr "Introduzca la misma contrasea que arriba, para verificacin"
+msgstr "Introduzca la misma contraseña que arriba, para verificación"
#: contrib/admin/templates/admin/auth/user/change_password.html:28
#, python-format
msgid "Enter a new password for the user <strong>%(username)s</strong>."
msgstr ""
-"Introduzca una nueva contrasea para el usuario <strong>%(username)s</"
+"Introduzca una nueva contraseña para el usuario <strong>%(username)s</"
"strong>."
+#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+msgid "Password change"
+msgstr "Cambio de clave"
+
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr "Cambio de clave exitoso"
+
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr "Su clave ha sido cambiada."
+
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/password_reset_form.html:6
#: contrib/admin/templates/registration/password_reset_form.html:10
@@ -1953,12 +2098,12 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you."
msgstr ""
-"Ha olvidado su clave? Introduzca su direccin de correo electrnico, y "
+"¿Ha olvidado su clave? Introduzca su dirección de correo electrónico, y "
"crearemos una nueva que le enviaremos por correo."
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
-msgstr "Direccin de correo electrnico:"
+msgstr "Dirección de correo electrónico:"
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "Reset my password"
@@ -1972,9 +2117,46 @@ msgstr "Gracias por el tiempo que ha dedicado al sitio web hoy."
msgid "Log in again"
msgstr "Identificarse de nuevo"
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr "Recuperación de clave exitosa"
+
+#: contrib/admin/templates/registration/password_reset_done.html:12
+msgid ""
+"We've e-mailed a new password to the e-mail address you submitted. You "
+"should be receiving it shortly."
+msgstr ""
+"Le hemos enviado una clave nueva a la dirección que ha suministrado. Debería "
+"recibirla en breve."
+
+#: contrib/admin/templates/registration/password_change_form.html:12
+msgid ""
+"Please enter your old password, for security's sake, and then enter your new "
+"password twice so we can verify you typed it in correctly."
+msgstr ""
+"Por favor, introduzca su clave antigua, por seguridad, y después introduzca "
+"la nueva clave dos veces para verificar que la ha escrito correctamente."
+
+#: contrib/admin/templates/registration/password_change_form.html:17
+msgid "Old password:"
+msgstr "Clave antigua:"
+
+#: contrib/admin/templates/registration/password_change_form.html:19
+msgid "New password:"
+msgstr "Clave nueva:"
+
+#: contrib/admin/templates/registration/password_change_form.html:21
+msgid "Confirm password:"
+msgstr "Confirme clave:"
+
+#: contrib/admin/templates/registration/password_change_form.html:23
+msgid "Change my password"
+msgstr "Cambiar mi clave"
+
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
-msgstr "Est recibiendo este mensaje debido a que solicit recuperar la clave"
+msgstr "Está recibiendo este mensaje debido a que solicitó recuperar la clave"
#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
@@ -1988,7 +2170,7 @@ msgstr "Su nueva clave es: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
-msgstr "Puede cambiarla accediendo a esta pgina:"
+msgstr "Puede cambiarla accediendo a esta página:"
#: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:"
@@ -1996,376 +2178,1257 @@ msgstr "Su nombre de usuario, en caso de haberlo olvidado:"
#: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!"
-msgstr "Gracias por usar nuestro sitio!"
+msgstr "¡Gracias por usar nuestro sitio!"
#: contrib/admin/templates/registration/password_reset_email.html:15
#, python-format
msgid "The %(site_name)s team"
msgstr "El equipo de %(site_name)s"
-#: contrib/admin/templates/registration/password_reset_done.html:6
-#: contrib/admin/templates/registration/password_reset_done.html:10
-msgid "Password reset successful"
-msgstr "Recuperacin de clave exitosa"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Bookmarklets"
+msgstr "Bookmarklets"
-#: contrib/admin/templates/registration/password_reset_done.html:12
+#: contrib/admin/templates/admin_doc/bookmarklets.html:5
+msgid "Documentation bookmarklets"
+msgstr "Bookmarklets de documentación"
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:9
msgid ""
-"We've e-mailed a new password to the e-mail address you submitted. You "
-"should be receiving it shortly."
+"\n"
+"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
+"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
+"select the bookmarklet from any page in the site. Note that some of these\n"
+"bookmarklets require you to be viewing the site from a computer designated\n"
+"as \"internal\" (talk to your system administrator if you aren't sure if\n"
+"your computer is \"internal\").</p>\n"
msgstr ""
-"Le hemos enviado una clave nueva a la direccin que ha suministrado. Debera "
-"recibirla en breve."
+"\n"
+"<p class=\"help\">Para instalar bookmarklets, arrastre el enlace a su barra\n"
+"de favoritos, o pulse con el botón derecho el enlace y añádalo a sus "
+"favoritos.\n"
+"Ahora puede escoger el bookmarklet desde cualquier página en el sitio.\n"
+"Observer que algunos de estos bookmarklets precisan que esté viendo\n"
+"el sitio desde un computador señalado como \"interno\" (hable\n"
+"con su administrador de sistemas si no está seguro de si el suyo lo es).</"
+"p>\n"
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_form.html:6
-#: contrib/admin/templates/registration/password_change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:4
-msgid "Password change"
-msgstr "Cambio de clave"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:19
+msgid "Documentation for this page"
+msgstr "Documentación de esta página"
-#: contrib/admin/templates/registration/password_change_form.html:12
+#: contrib/admin/templates/admin_doc/bookmarklets.html:20
msgid ""
-"Please enter your old password, for security's sake, and then enter your new "
-"password twice so we can verify you typed it in correctly."
+"Jumps you from any page to the documentation for the view that generates "
+"that page."
msgstr ""
-"Por favor, introduzca su clave antigua, por seguridad, y despus introduzca "
-"la nueva clave dos veces para verificar que la ha escrito correctamente."
+"Le lleva desde cualquier página a la documentación de la vista que la genera."
-#: contrib/admin/templates/registration/password_change_form.html:17
-msgid "Old password:"
-msgstr "Clave antigua:"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:22
+msgid "Show object ID"
+msgstr "Mostrar ID de objeto"
-#: contrib/admin/templates/registration/password_change_form.html:19
-msgid "New password:"
-msgstr "Clave nueva:"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:23
+msgid ""
+"Shows the content-type and unique ID for pages that represent a single "
+"object."
+msgstr ""
+"Muestra el tipo de contenido e ID unívoco de las páginas que representan un "
+"único objeto."
-#: contrib/admin/templates/registration/password_change_form.html:21
-msgid "Confirm password:"
-msgstr "Confirme clave:"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:25
+msgid "Edit this object (current window)"
+msgstr "Editar este objeto (ventana actual)"
-#: contrib/admin/templates/registration/password_change_form.html:23
-msgid "Change my password"
-msgstr "Cambiar mi clave"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:26
+msgid "Jumps to the admin page for pages that represent a single object."
+msgstr ""
+"Le lleva a la página de administración de páginas que representan un único "
+"objeto."
-#: contrib/admin/templates/registration/password_change_done.html:6
-#: contrib/admin/templates/registration/password_change_done.html:10
-msgid "Password change successful"
-msgstr "Cambio de clave exitoso"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:28
+msgid "Edit this object (new window)"
+msgstr "Editar este objeto (nueva ventana)"
-#: contrib/admin/templates/registration/password_change_done.html:12
-msgid "Your password was changed."
-msgstr "Su clave ha sido cambiada."
+#: contrib/admin/templates/admin_doc/bookmarklets.html:29
+msgid "As above, but opens the admin page in a new window."
+msgstr ""
+"Como antes, pero abre la página de administración en una nueva ventana."
-#: contrib/admin/templatetags/admin_list.py:238
-msgid "All dates"
-msgstr "Todas las fechas"
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr ""
+"Introduzca un código postal. Se necesita un espacio entre las dos partes del "
+"código."
-#: contrib/admin/views/decorators.py:62
+#: contrib/localflavor/fr/forms.py:17 contrib/localflavor/fi/forms.py:14
+#: contrib/localflavor/de/forms.py:16
+msgid "Enter a zip code in the format XXXXX."
+msgstr "Introduzca un código postal en el formato XXXXX."
+
+#: contrib/localflavor/jp/jp_prefectures.py:4
+msgid "Hokkaido"
+msgstr "Hokkaido"
+
+#: contrib/localflavor/jp/jp_prefectures.py:5
+msgid "Aomori"
+msgstr "Aomori"
+
+#: contrib/localflavor/jp/jp_prefectures.py:6
+msgid "Iwate"
+msgstr "Iwate"
+
+#: contrib/localflavor/jp/jp_prefectures.py:7
+msgid "Miyagi"
+msgstr "Miyagi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:8
+msgid "Akita"
+msgstr "Akita"
+
+#: contrib/localflavor/jp/jp_prefectures.py:9
+msgid "Yamagata"
+msgstr "Yamagata"
+
+#: contrib/localflavor/jp/jp_prefectures.py:10
+msgid "Fukushima"
+msgstr "Fukushima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:11
+msgid "Ibaraki"
+msgstr "Ibaraki"
+
+#: contrib/localflavor/jp/jp_prefectures.py:12
+msgid "Tochigi"
+msgstr "Tochigi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:13
+msgid "Gunma"
+msgstr "Gunma"
+
+#: contrib/localflavor/jp/jp_prefectures.py:14
+msgid "Saitama"
+msgstr "Saitama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:15
+msgid "Chiba"
+msgstr "Chiba"
+
+#: contrib/localflavor/jp/jp_prefectures.py:16
+msgid "Tokyo"
+msgstr "Tokyo"
+
+#: contrib/localflavor/jp/jp_prefectures.py:17
+msgid "Kanagawa"
+msgstr "Kanagawa"
+
+#: contrib/localflavor/jp/jp_prefectures.py:18
+msgid "Yamanashi"
+msgstr "Yamanashi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:19
+msgid "Nagano"
+msgstr "Nagano"
+
+#: contrib/localflavor/jp/jp_prefectures.py:20
+msgid "Niigata"
+msgstr "Niigata"
+
+#: contrib/localflavor/jp/jp_prefectures.py:21
+msgid "Toyama"
+msgstr "Toyama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:22
+msgid "Ishikawa"
+msgstr "Ishikawa"
+
+#: contrib/localflavor/jp/jp_prefectures.py:23
+msgid "Fukui"
+msgstr "Fukui"
+
+#: contrib/localflavor/jp/jp_prefectures.py:24
+msgid "Gifu"
+msgstr "Gifu"
+
+#: contrib/localflavor/jp/jp_prefectures.py:25
+msgid "Shizuoka"
+msgstr "Shizuoka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:26
+msgid "Aichi"
+msgstr "Aichi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:27
+msgid "Mie"
+msgstr "Mie"
+
+#: contrib/localflavor/jp/jp_prefectures.py:28
+msgid "Shiga"
+msgstr "Shiga"
+
+#: contrib/localflavor/jp/jp_prefectures.py:29
+msgid "Kyoto"
+msgstr "Kyoto"
+
+#: contrib/localflavor/jp/jp_prefectures.py:30
+msgid "Osaka"
+msgstr "Osaka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:31
+msgid "Hyogo"
+msgstr "Hyogo"
+
+#: contrib/localflavor/jp/jp_prefectures.py:32
+msgid "Nara"
+msgstr "Nara"
+
+#: contrib/localflavor/jp/jp_prefectures.py:33
+msgid "Wakayama"
+msgstr "Wakayama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:34
+msgid "Tottori"
+msgstr "Tottori"
+
+#: contrib/localflavor/jp/jp_prefectures.py:35
+msgid "Shimane"
+msgstr "Shimane"
+
+#: contrib/localflavor/jp/jp_prefectures.py:36
+msgid "Okayama"
+msgstr "Okayama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:37
+msgid "Hiroshima"
+msgstr "Hiroshima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:38
+msgid "Yamaguchi"
+msgstr "Yamaguchi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:39
+msgid "Tokushima"
+msgstr "Tokushima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:40
+msgid "Kagawa"
+msgstr "Kagawa"
+
+#: contrib/localflavor/jp/jp_prefectures.py:41
+msgid "Ehime"
+msgstr "Ehime"
+
+#: contrib/localflavor/jp/jp_prefectures.py:42
+msgid "Kochi"
+msgstr "Kochi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:43
+msgid "Fukuoka"
+msgstr "Fukuoka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:44
+msgid "Saga"
+msgstr "Saga"
+
+#: contrib/localflavor/jp/jp_prefectures.py:45
+msgid "Nagasaki"
+msgstr "Nagasaki"
+
+#: contrib/localflavor/jp/jp_prefectures.py:46
+msgid "Kumamoto"
+msgstr "Kumamoto"
+
+#: contrib/localflavor/jp/jp_prefectures.py:47
+msgid "Oita"
+msgstr "Oita"
+
+#: contrib/localflavor/jp/jp_prefectures.py:48
+msgid "Miyazaki"
+msgstr "Miyazaki"
+
+#: contrib/localflavor/jp/jp_prefectures.py:49
+msgid "Kagoshima"
+msgstr "Kagoshima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:50
+msgid "Okinawa"
+msgstr "Okinawa"
+
+#: contrib/localflavor/jp/forms.py:21
+msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
+msgstr "Introduzca un código postal en el formato XXXXX o XXXX-XXXX."
+
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr "Introduzca un código postal en el formato XXXX-XXXX."
+
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr "Los números de teléfono deben tener el formato XXX-XXX-XXXX."
+
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr "Este campo sólo acepta números."
+
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr "Este campo necesita al menos 11 o 14 caracteres"
+
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr "Número CPF inválido."
+
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr "Este campo necesita 14 dígitos como máximo"
+
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr "Número CNPJ inválido"
+
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Introduzca un código postal válido."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Introduzca un número de Seguro Social válido."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Introduzca un número VAT válido."
+
+#: contrib/localflavor/no/forms.py:14 contrib/localflavor/ch/forms.py:18
+msgid "Enter a zip code in the format XXXX."
+msgstr "Introduzca un código postal en el formato XXXX."
+
+#: contrib/localflavor/no/forms.py:35
+msgid "Enter a valid Norwegian social security number."
+msgstr "Introduzca un número de seguro social de Noruega válido."
+
+#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
+msgid "Enter a valid Finnish social security number."
+msgstr "Introduzca un número de seguro social finlandés válido."
+
+#: contrib/localflavor/de/de_states.py:5
+msgid "Baden-Wuerttemberg"
+msgstr "Baden-Wuerttemberg"
+
+#: contrib/localflavor/de/de_states.py:6
+msgid "Bavaria"
+msgstr "Bavaria"
+
+#: contrib/localflavor/de/de_states.py:7
+msgid "Berlin"
+msgstr "Berlín"
+
+#: contrib/localflavor/de/de_states.py:8
+msgid "Brandenburg"
+msgstr "Brandenburg"
+
+#: contrib/localflavor/de/de_states.py:9
+msgid "Bremen"
+msgstr "Bremen"
+
+#: contrib/localflavor/de/de_states.py:10
+msgid "Hamburg"
+msgstr "Hamburg"
+
+#: contrib/localflavor/de/de_states.py:11
+msgid "Hessen"
+msgstr "Hessen"
+
+#: contrib/localflavor/de/de_states.py:12
+msgid "Mecklenburg-Western Pomerania"
+msgstr "Mecklenburg-Western Pomerania"
+
+#: contrib/localflavor/de/de_states.py:13
+msgid "Lower Saxony"
+msgstr "Lower Saxony"
+
+#: contrib/localflavor/de/de_states.py:14
+msgid "North Rhine-Westphalia"
+msgstr "North Rhine-Westphalia"
+
+#: contrib/localflavor/de/de_states.py:15
+msgid "Rhineland-Palatinate"
+msgstr "Rhineland-Palatinate"
+
+#: contrib/localflavor/de/de_states.py:16
+msgid "Saarland"
+msgstr "Saarland"
+
+#: contrib/localflavor/de/de_states.py:17
+msgid "Saxony"
+msgstr "Saxony"
+
+#: contrib/localflavor/de/de_states.py:18
+msgid "Saxony-Anhalt"
+msgstr "Saxony-Anhalt"
+
+#: contrib/localflavor/de/de_states.py:19
+msgid "Schleswig-Holstein"
+msgstr "Schleswig-Holstein"
+
+#: contrib/localflavor/de/de_states.py:20
+msgid "Thuringia"
+msgstr "Thuringia"
+
+#: contrib/localflavor/de/forms.py:60
msgid ""
-"Please log in again, because your session has expired. Don't worry: Your "
-"submission has been saved."
+"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
+"format."
msgstr ""
-"Por favor, identifquese de nuevo, porque su sesin ha caducado. No se "
-"preocupe: se ha guardado su envo."
+"Introduzca un número de tarjeta de identidad de Alemania válida en el "
+"formato XXXXXXXXXXX-XXXXXXX-XXXXXXX-X."
-#: contrib/admin/views/decorators.py:69
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr "Introduzca un código postal de 4 dígitos."
+
+#: contrib/localflavor/us/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr "Introduzca un código postal en el formato XXXXX o XXXX-XXXX."
+
+#: contrib/localflavor/us/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr ""
+"Introduzca un Número Seguro Social de EEUU válido en el formato XXX-XX-XXXX"
+
+#: contrib/localflavor/is_/forms.py:17
msgid ""
-"Looks like your browser isn't configured to accept cookies. Please enable "
-"cookies, reload this page, and try again."
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
msgstr ""
-"Parece que su navegador no est configurado para aceptar cookies. Actvelas "
-"por favor, recargue esta pgina, e intntelo de nuevo."
+"Introduzca un número de identificación de Islandia válido. El formato es "
+"XXXXXX-XXXX."
-#: contrib/admin/views/decorators.py:83
-msgid "Usernames cannot contain the '@' character."
-msgstr "Los nombres de usuario no pueden contener el carcter '@'."
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr "El número de identificación de Islandia no es válido."
-#: contrib/admin/views/decorators.py:85
-#, python-format
-msgid "Your e-mail address is not your username. Try '%s' instead."
+#: contrib/localflavor/cl/forms.py:32
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Introduzca un RUT chileno válido. El formato es XX.XXX.XXX-X."
+
+#: contrib/localflavor/cl/forms.py:37
+msgid "Enter valid a Chilean RUT"
+msgstr "Introduzca un RUT chileno válido"
+
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr "Aargau"
+
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
+msgstr "Appenzell Innerrhoden"
+
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr "Appenzell Ausserrhoden"
+
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr "Basel-Stadt"
+
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
+msgstr "Basel-Land"
+
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr "Berne"
+
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr "Fribourg"
+
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr "Geneva"
+
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr "Glarus"
+
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr "Graubuenden"
+
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr "Jura"
+
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr "Lucerne"
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
+msgstr "Neuchatel"
+
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr "Nidwalden"
+
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr "Obwalden"
+
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr "Schaffhausen"
+
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr "Schwyz"
+
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr "Solothurn"
+
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr "St. Gallen"
+
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr "Thurgau"
+
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr "Ticino"
+
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr "Uri"
+
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr "Valais"
+
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
+msgstr "Vaud"
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr "Zug"
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr "Zurich"
+
+#: contrib/localflavor/ch/forms.py:90
+msgid ""
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
msgstr ""
-"Su direccin de correo no es su nombre de usuario. Pruebe con '%s' en su "
-"lugar."
+"Introduzca una identificación suiza válida o un número de pasaporte en el "
+"formato X1234567<0 or 1234567890."
-#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
-msgid "tag:"
-msgstr "etiqueta:"
+#: contrib/localflavor/sk/sk_regions.py:8
+msgid "Banska Bystrica region"
+msgstr "Región de Banska Bystrica"
-#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
-msgid "filter:"
-msgstr "filtro:"
+#: contrib/localflavor/sk/sk_regions.py:9
+msgid "Bratislava region"
+msgstr "Región de Bratislava"
-#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
-msgid "view:"
-msgstr "vista:"
+#: contrib/localflavor/sk/sk_regions.py:10
+msgid "Kosice region"
+msgstr "Región de Kosice"
-#: contrib/admin/views/doc.py:164
-#, python-format
-msgid "App %r not found"
-msgstr "Aplicacin %r no encontrada"
+#: contrib/localflavor/sk/sk_regions.py:11
+msgid "Nitra region"
+msgstr "Región de Nitra"
-#: contrib/admin/views/doc.py:171
-#, python-format
-msgid "Model %(model_name)r not found in app %(app_label)r"
-msgstr "El modelo %(model_name)s no se ha encontrado en la aplicacin %(app_label)r"
+#: contrib/localflavor/sk/sk_regions.py:12
+msgid "Presov region"
+msgstr "Región de Presov"
-#: contrib/admin/views/doc.py:184
-#, python-format
-msgid "the related `%(app_label)s.%(data_type)s` object"
-msgstr "el objeto relacionado`%(app_label)s.%(data_type)s` "
+#: contrib/localflavor/sk/sk_regions.py:13
+msgid "Trencin region"
+msgstr "Región de Trencin"
-#: contrib/admin/views/doc.py:185 contrib/admin/views/doc.py:207
-#: contrib/admin/views/doc.py:222 contrib/admin/views/doc.py:227
-msgid "model:"
-msgstr "modelo:"
+#: contrib/localflavor/sk/sk_regions.py:14
+msgid "Trnava region"
+msgstr "Región de Trnava"
+
+#: contrib/localflavor/sk/sk_regions.py:15
+msgid "Zilina region"
+msgstr "Región de Zilina"
+
+#: contrib/localflavor/sk/sk_districts.py:8
+msgid "Banska Bystrica"
+msgstr "Región de Bystrica"
+
+#: contrib/localflavor/sk/sk_districts.py:9
+msgid "Banska Stiavnica"
+msgstr "Región de Banska Stiavnica"
+
+#: contrib/localflavor/sk/sk_districts.py:10
+msgid "Bardejov"
+msgstr "Región de Bardejov"
+
+#: contrib/localflavor/sk/sk_districts.py:11
+msgid "Banovce nad Bebravou"
+msgstr "Región de Banovce nad Bebravou"
+
+#: contrib/localflavor/sk/sk_districts.py:12
+msgid "Brezno"
+msgstr "Región de Brezno"
+
+#: contrib/localflavor/sk/sk_districts.py:13
+msgid "Bratislava I"
+msgstr "Región de Bratislava I"
+
+#: contrib/localflavor/sk/sk_districts.py:14
+msgid "Bratislava II"
+msgstr "Región de Bratislava II"
+
+#: contrib/localflavor/sk/sk_districts.py:15
+msgid "Bratislava III"
+msgstr "Región de Bratislava III"
+
+#: contrib/localflavor/sk/sk_districts.py:16
+msgid "Bratislava IV"
+msgstr "Región de Bratislava IV"
+
+#: contrib/localflavor/sk/sk_districts.py:17
+msgid "Bratislava V"
+msgstr "Región de Bratislava V"
+
+#: contrib/localflavor/sk/sk_districts.py:18
+msgid "Bytca"
+msgstr "Región de Bytca"
+
+#: contrib/localflavor/sk/sk_districts.py:19
+msgid "Cadca"
+msgstr "Región de Cadca"
+
+#: contrib/localflavor/sk/sk_districts.py:20
+msgid "Detva"
+msgstr "Región de Detva"
+
+#: contrib/localflavor/sk/sk_districts.py:21
+msgid "Dolny Kubin"
+msgstr "Región de Dolny Kubin"
+
+#: contrib/localflavor/sk/sk_districts.py:22
+msgid "Dunajska Streda"
+msgstr "Región de Dunajska Streda"
+
+#: contrib/localflavor/sk/sk_districts.py:23
+msgid "Galanta"
+msgstr "Galanta"
+
+#: contrib/localflavor/sk/sk_districts.py:24
+msgid "Gelnica"
+msgstr "Gelnica"
+
+#: contrib/localflavor/sk/sk_districts.py:25
+msgid "Hlohovec"
+msgstr "Hlohovec"
+
+#: contrib/localflavor/sk/sk_districts.py:26
+msgid "Humenne"
+msgstr "Humenne"
+
+#: contrib/localflavor/sk/sk_districts.py:27
+msgid "Ilava"
+msgstr "Ilava"
+
+#: contrib/localflavor/sk/sk_districts.py:28
+msgid "Kezmarok"
+msgstr "Kezmarok"
+
+#: contrib/localflavor/sk/sk_districts.py:29
+msgid "Komarno"
+msgstr "Komarno"
+
+#: contrib/localflavor/sk/sk_districts.py:30
+msgid "Kosice I"
+msgstr "Kosice I"
+
+#: contrib/localflavor/sk/sk_districts.py:31
+msgid "Kosice II"
+msgstr "Kosice II"
+
+#: contrib/localflavor/sk/sk_districts.py:32
+msgid "Kosice III"
+msgstr "Kosice III"
+
+#: contrib/localflavor/sk/sk_districts.py:33
+msgid "Kosice IV"
+msgstr "Kosice IV"
+
+#: contrib/localflavor/sk/sk_districts.py:34
+msgid "Kosice - okolie"
+msgstr "Kosice - okolie"
+
+#: contrib/localflavor/sk/sk_districts.py:35
+msgid "Krupina"
+msgstr "Krupina"
+
+#: contrib/localflavor/sk/sk_districts.py:36
+msgid "Kysucke Nove Mesto"
+msgstr "Kysucke Nove Mesto"
+
+#: contrib/localflavor/sk/sk_districts.py:37
+msgid "Levice"
+msgstr "Levice"
+
+#: contrib/localflavor/sk/sk_districts.py:38
+msgid "Levoca"
+msgstr "Levoca"
+
+#: contrib/localflavor/sk/sk_districts.py:39
+msgid "Liptovsky Mikulas"
+msgstr "Liptovsky Mikulas"
+
+#: contrib/localflavor/sk/sk_districts.py:40
+msgid "Lucenec"
+msgstr "Lucenec"
+
+#: contrib/localflavor/sk/sk_districts.py:41
+msgid "Malacky"
+msgstr "Malacky"
+
+#: contrib/localflavor/sk/sk_districts.py:42
+msgid "Martin"
+msgstr "Martin"
+
+#: contrib/localflavor/sk/sk_districts.py:43
+msgid "Medzilaborce"
+msgstr "Medzilaborce"
+
+#: contrib/localflavor/sk/sk_districts.py:44
+msgid "Michalovce"
+msgstr "Michalovce"
+
+#: contrib/localflavor/sk/sk_districts.py:45
+msgid "Myjava"
+msgstr "Myjava"
+
+#: contrib/localflavor/sk/sk_districts.py:46
+msgid "Namestovo"
+msgstr "Namestovo"
+
+#: contrib/localflavor/sk/sk_districts.py:47
+msgid "Nitra"
+msgstr "Nitra"
+
+#: contrib/localflavor/sk/sk_districts.py:48
+msgid "Nove Mesto nad Vahom"
+msgstr "Nove Mesto nad Vahom"
+
+#: contrib/localflavor/sk/sk_districts.py:49
+msgid "Nove Zamky"
+msgstr "Nove Zamky"
+
+#: contrib/localflavor/sk/sk_districts.py:50
+msgid "Partizanske"
+msgstr "Partizanske"
+
+#: contrib/localflavor/sk/sk_districts.py:51
+msgid "Pezinok"
+msgstr "Pezinok"
+
+#: contrib/localflavor/sk/sk_districts.py:52
+msgid "Piestany"
+msgstr "Piestany"
+
+#: contrib/localflavor/sk/sk_districts.py:53
+msgid "Poltar"
+msgstr "Poltar"
+
+#: contrib/localflavor/sk/sk_districts.py:54
+msgid "Poprad"
+msgstr "Poprad"
+
+#: contrib/localflavor/sk/sk_districts.py:55
+msgid "Povazska Bystrica"
+msgstr "Povazska Bystrica"
+
+#: contrib/localflavor/sk/sk_districts.py:56
+msgid "Presov"
+msgstr "Presov"
+
+#: contrib/localflavor/sk/sk_districts.py:57
+msgid "Prievidza"
+msgstr "Prievidza"
+
+#: contrib/localflavor/sk/sk_districts.py:58
+msgid "Puchov"
+msgstr "Puchov"
+
+#: contrib/localflavor/sk/sk_districts.py:59
+msgid "Revuca"
+msgstr "Revuca"
+
+#: contrib/localflavor/sk/sk_districts.py:60
+msgid "Rimavska Sobota"
+msgstr "Rimavska Sobota"
+
+#: contrib/localflavor/sk/sk_districts.py:61
+msgid "Roznava"
+msgstr "Roznava"
+
+#: contrib/localflavor/sk/sk_districts.py:62
+msgid "Ruzomberok"
+msgstr "Ruzomberok"
+
+#: contrib/localflavor/sk/sk_districts.py:63
+msgid "Sabinov"
+msgstr "Sabinov"
+
+#: contrib/localflavor/sk/sk_districts.py:64
+msgid "Senec"
+msgstr "Senec"
+
+#: contrib/localflavor/sk/sk_districts.py:65
+msgid "Senica"
+msgstr "Senica"
+
+#: contrib/localflavor/sk/sk_districts.py:66
+msgid "Skalica"
+msgstr "Skalica"
+
+#: contrib/localflavor/sk/sk_districts.py:67
+msgid "Snina"
+msgstr "Snina"
+
+#: contrib/localflavor/sk/sk_districts.py:68
+msgid "Sobrance"
+msgstr "Sobrance"
+
+#: contrib/localflavor/sk/sk_districts.py:69
+msgid "Spisska Nova Ves"
+msgstr "Spisska Nova Ves"
+
+#: contrib/localflavor/sk/sk_districts.py:70
+msgid "Stara Lubovna"
+msgstr "Stara Lubovna"
+
+#: contrib/localflavor/sk/sk_districts.py:71
+msgid "Stropkov"
+msgstr "Stropkov"
+
+#: contrib/localflavor/sk/sk_districts.py:72
+msgid "Svidnik"
+msgstr "Svidnik"
+
+#: contrib/localflavor/sk/sk_districts.py:73
+msgid "Sala"
+msgstr "Sala"
+
+#: contrib/localflavor/sk/sk_districts.py:74
+msgid "Topolcany"
+msgstr "Topolcany"
-#: contrib/admin/views/doc.py:216
+#: contrib/localflavor/sk/sk_districts.py:75
+msgid "Trebisov"
+msgstr "Trebisov"
+
+#: contrib/localflavor/sk/sk_districts.py:76
+msgid "Trencin"
+msgstr "Trencin"
+
+#: contrib/localflavor/sk/sk_districts.py:77
+msgid "Trnava"
+msgstr "Trnava"
+
+#: contrib/localflavor/sk/sk_districts.py:78
+msgid "Turcianske Teplice"
+msgstr "Turcianske Teplice"
+
+#: contrib/localflavor/sk/sk_districts.py:79
+msgid "Tvrdosin"
+msgstr "Tvrdosin"
+
+#: contrib/localflavor/sk/sk_districts.py:80
+msgid "Velky Krtis"
+msgstr "Velky Krtis"
+
+#: contrib/localflavor/sk/sk_districts.py:81
+msgid "Vranov nad Toplou"
+msgstr "Vranov nad Toplou"
+
+#: contrib/localflavor/sk/sk_districts.py:82
+msgid "Zlate Moravce"
+msgstr "Zlate Moravce"
+
+#: contrib/localflavor/sk/sk_districts.py:83
+msgid "Zvolen"
+msgstr "Zvolen"
+
+#: contrib/localflavor/sk/sk_districts.py:84
+msgid "Zarnovica"
+msgstr "Zarnovica"
+
+#: contrib/localflavor/sk/sk_districts.py:85
+msgid "Ziar nad Hronom"
+msgstr "Ziar nad Hronom"
+
+#: contrib/localflavor/sk/sk_districts.py:86
+msgid "Zilina"
+msgstr "Zilina"
+
+#: contrib/localflavor/sk/forms.py:32
+msgid "Enter a postal code in the format XXXXX or XXX XX."
+msgstr "Introduzca un código postal en el formato XXXXX o XXX XX."
+
+#: contrib/localflavor/in_/forms.py:16
+msgid "Enter a zip code in the format XXXXXXX."
+msgstr "Introduzca un código postal en el formato XXXXXXX."
+
+#: template/defaultfilters.py:485
+msgid "yes,no,maybe"
+msgstr "sí,no,tal vez"
+
+#: template/defaultfilters.py:514
#, python-format
-msgid "related `%(app_label)s.%(object_name)s` objects"
-msgstr "los objetos relacionados `%(app_label)s.%(object_name)s`"
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] "%(size)d byte"
+msgstr[1] "%(size)d bytes"
-#: contrib/admin/views/doc.py:222
+#: template/defaultfilters.py:516
#, python-format
-msgid "all %s"
-msgstr "todo %s"
+msgid "%.1f KB"
+msgstr "%.1f KB"
-#: contrib/admin/views/doc.py:227
+#: template/defaultfilters.py:518
#, python-format
-msgid "number of %s"
-msgstr "nmero de %s"
+msgid "%.1f MB"
+msgstr "%.1f MB"
-#: contrib/admin/views/doc.py:232
+#: template/defaultfilters.py:519
#, python-format
-msgid "Fields on %s objects"
-msgstr "Campos en %s objetos"
+msgid "%.1f GB"
+msgstr "%.1f GB"
-#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:304
-#: contrib/admin/views/doc.py:306 contrib/admin/views/doc.py:312
-#: contrib/admin/views/doc.py:313 contrib/admin/views/doc.py:315
-msgid "Integer"
-msgstr "Entero"
+#: oldforms/__init__.py:408
+#, python-format
+msgid "Ensure your text is less than %s character."
+msgid_plural "Ensure your text is less than %s characters."
+msgstr[0] "Asegúrese de que su texto tiene menos de %s carácter."
+msgstr[1] "Asegúrese de que su texto tiene menos de %s caracteres."
-#: contrib/admin/views/doc.py:295
-msgid "Boolean (Either True or False)"
-msgstr "Booleano (Verdadero o Falso)"
+#: oldforms/__init__.py:413
+msgid "Line breaks are not allowed here."
+msgstr "No se permiten saltos de línea."
-#: contrib/admin/views/doc.py:296 contrib/admin/views/doc.py:314
+#: oldforms/__init__.py:511 oldforms/__init__.py:585 oldforms/__init__.py:624
#, python-format
-msgid "String (up to %(maxlength)s)"
-msgstr "Cadena (mximo %(maxlength)s)"
+msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
+msgstr "Escoja una opción válida; '%(data)s' no está en %(choices)s."
-#: contrib/admin/views/doc.py:297
-msgid "Comma-separated integers"
-msgstr "Enteros separados por comas"
+#: oldforms/__init__.py:744
+msgid "Enter a whole number between -32,768 and 32,767."
+msgstr "Introduzca un número entero entre -32,768 y 32,767."
-#: contrib/admin/views/doc.py:298
-msgid "Date (without time)"
-msgstr "Fecha (sin hora)"
+#: oldforms/__init__.py:754
+msgid "Enter a positive number."
+msgstr "Introduzca un número positivo."
-#: contrib/admin/views/doc.py:299
-msgid "Date (with time)"
-msgstr "Fecha (con hora)"
+#: oldforms/__init__.py:764
+msgid "Enter a whole number between 0 and 32,767."
+msgstr "Introduzca un número entero entre 0 y 32,767."
-#: contrib/admin/views/doc.py:300
-msgid "E-mail address"
-msgstr "Direccin de correo electrnico"
+#: core/validators.py:71
+msgid "This value must contain only letters, numbers and underscores."
+msgstr "Este valor debe contener sólo letras, números y guiones bajos."
-#: contrib/admin/views/doc.py:301 contrib/admin/views/doc.py:302
-#: contrib/admin/views/doc.py:305
-msgid "File path"
-msgstr "Ruta de fichero"
+#: core/validators.py:75
+msgid ""
+"This value must contain only letters, numbers, underscores, dashes or "
+"slashes."
+msgstr ""
+"Este valor debe contener letras, números, guiones bajos o barras solamente."
-#: contrib/admin/views/doc.py:303
-msgid "Decimal number"
-msgstr "Nmero decimal"
+#: core/validators.py:79
+msgid "This value must contain only letters, numbers, underscores or hyphens."
+msgstr "Este valor debe contener sólo letras, números, guiones bajos o medios."
-#: contrib/admin/views/doc.py:309
-msgid "Boolean (Either True, False or None)"
-msgstr "Booleano (Verdadero, Falso o Nulo)"
+#: core/validators.py:83
+msgid "Uppercase letters are not allowed here."
+msgstr "No se admiten letras mayúsculas."
-#: contrib/admin/views/doc.py:310
-msgid "Relation to parent model"
-msgstr "Relacin con el modelo padre"
+#: core/validators.py:87
+msgid "Lowercase letters are not allowed here."
+msgstr "No se admiten letras minúsculas."
-#: contrib/admin/views/doc.py:311
-msgid "Phone number"
-msgstr "Nmero de telfono"
+#: core/validators.py:94
+msgid "Enter only digits separated by commas."
+msgstr "Introduzca sólo dígitos separados por comas."
-#: contrib/admin/views/doc.py:316
-msgid "Text"
-msgstr "Texto"
+#: core/validators.py:106
+msgid "Enter valid e-mail addresses separated by commas."
+msgstr "Introduzca direcciones de correo válidas separadas por comas."
-#: contrib/admin/views/doc.py:317
-msgid "Time"
-msgstr "Hora"
+#: core/validators.py:110
+msgid "Please enter a valid IP address."
+msgstr "Por favor introduzca una dirección IP válida."
-#: contrib/admin/views/doc.py:319
-msgid "U.S. state (two uppercase letters)"
-msgstr "Estado de los EEUU (dos letras maysculas)"
+#: core/validators.py:114
+msgid "Empty values are not allowed here."
+msgstr "No se admiten valores vacíos."
-#: contrib/admin/views/doc.py:320
-msgid "XML text"
-msgstr "Texto XML"
+#: core/validators.py:118
+msgid "Non-numeric characters aren't allowed here."
+msgstr "No se admiten caracteres no numéricos."
-#: contrib/admin/views/doc.py:346
-#, python-format
-msgid "%s does not appear to be a urlpattern object"
-msgstr "%s no parece ser un objeto urlpattern"
+#: core/validators.py:122
+msgid "This value can't be comprised solely of digits."
+msgstr "Este valor no puede comprender sólo dígitos."
-#: contrib/admin/views/main.py:223
-msgid "Site administration"
-msgstr "Sitio administrativo"
+#: core/validators.py:131
+msgid "Only alphabetical characters are allowed here."
+msgstr "Sólo se admiten caracteres alfabéticos."
+
+#: core/validators.py:146
+msgid "Year must be 1900 or later."
+msgstr "El año debe ser 1900 o posterior."
-#: contrib/admin/views/main.py:257 contrib/admin/views/auth.py:19
+#: core/validators.py:150
#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully."
-msgstr "Se aadi con xito el %(name)s \"%(obj)s\"."
+msgid "Invalid date: %s"
+msgstr "Fecha no válida: %s"
-#: contrib/admin/views/main.py:261 contrib/admin/views/main.py:347
-#: contrib/admin/views/auth.py:24
-msgid "You may edit it again below."
-msgstr "Puede editarlo de nuevo abajo."
+#: core/validators.py:160
+msgid "Enter a valid time in HH:MM format."
+msgstr "Introduzca una hora válida en formato HH:MM."
-#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
+#: core/validators.py:192
#, python-format
-msgid "You may add another %s below."
-msgstr "Puede agregar otro %s abajo."
+msgid "The URL %s does not point to a valid image."
+msgstr "La URL %s no apunta a una imagen válida."
-#: contrib/admin/views/main.py:289
+#: core/validators.py:196
#, python-format
-msgid "Add %s"
-msgstr "Agregar %s"
+msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
+msgstr ""
+"Los números de teléfono deben guardar el formato XXX-XXX-XXXX. \"%s\" no es "
+"válido."
-#: contrib/admin/views/main.py:335
+#: core/validators.py:204
#, python-format
-msgid "Added %s."
-msgstr "Agregado %s."
+msgid "The URL %s does not point to a valid QuickTime video."
+msgstr "La URL %s no apunta a un vídeo QuickTime válido."
+
+#: core/validators.py:208
+msgid "A valid URL is required."
+msgstr "Se precisa una URL válida."
-#: contrib/admin/views/main.py:337
+#: core/validators.py:222
#, python-format
-msgid "Changed %s."
-msgstr "Modificado %s."
+msgid ""
+"Valid HTML is required. Specific errors are:\n"
+"%s"
+msgstr ""
+"Se precisa HTML válido. Los errores específicos son:\n"
+"%s"
-#: contrib/admin/views/main.py:339
+#: core/validators.py:229
#, python-format
-msgid "Deleted %s."
-msgstr "Borrado %s."
+msgid "Badly formed XML: %s"
+msgstr "XML mal formado: %s"
-#: contrib/admin/views/main.py:342
-msgid "No fields changed."
-msgstr "No ha cambiado ningn campo."
+#: core/validators.py:246
+#, python-format
+msgid "Invalid URL: %s"
+msgstr "URL no válida: %s"
-#: contrib/admin/views/main.py:345
+#: core/validators.py:251 core/validators.py:253
#, python-format
-msgid "The %(name)s \"%(obj)s\" was changed successfully."
-msgstr "Se modific con xito el %(name)s \"%(obj)s."
+msgid "The URL %s is a broken link."
+msgstr "La URL %s es un enlace roto."
-#: contrib/admin/views/main.py:353
+#: core/validators.py:259
+msgid "Enter a valid U.S. state abbreviation."
+msgstr "Introduzca una abreviatura válida de estado de los EEUU."
+
+#: core/validators.py:273
#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
-msgstr "Se agreg con xito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo."
+msgid "Watch your mouth! The word %s is not allowed here."
+msgid_plural "Watch your mouth! The words %s are not allowed here."
+msgstr[0] "¡Cuida tu vocabulario! Aquí no admitimos la palabra %s."
+msgstr[1] "¡Cuida tu vocabulario! Aquí no admitimos las palabras %s."
-#: contrib/admin/views/main.py:391
+#: core/validators.py:280
#, python-format
-msgid "Change %s"
-msgstr "Modificar %s"
+msgid "This field must match the '%s' field."
+msgstr "Este campo debe concordar con el campo '%s'."
+
+#: core/validators.py:299
+msgid "Please enter something for at least one field."
+msgstr "Por favor, introduzca algo en al menos un campo."
+
+#: core/validators.py:308 core/validators.py:319
+msgid "Please enter both fields or leave them both empty."
+msgstr "Por favor, rellene ambos campos o deje ambos vacíos."
-#: contrib/admin/views/main.py:473
+#: core/validators.py:327
#, python-format
-msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
-msgstr "Uno o ms %(fieldname)s en %(name)s: %(obj)s"
+msgid "This field must be given if %(field)s is %(value)s"
+msgstr "Se debe proporcionar este campo si %(field)s es %(value)s"
-#: contrib/admin/views/main.py:478
+#: core/validators.py:340
#, python-format
-msgid "One or more %(fieldname)s in %(name)s:"
-msgstr "Uno o ms %(fieldname)s en %(name)s:"
+msgid "This field must be given if %(field)s is not %(value)s"
+msgstr "Se debe proporcionar este campo si %(field)s no es %(value)s"
-#: contrib/admin/views/main.py:511
+#: core/validators.py:359
+msgid "Duplicate values are not allowed."
+msgstr "No se admiten valores duplicados."
+
+#: core/validators.py:374
#, python-format
-msgid "The %(name)s \"%(obj)s\" was deleted successfully."
-msgstr "Se elimin con xito el %(name)s \"%(obj)s\"."
+msgid "This value must be between %(lower)s and %(upper)s."
+msgstr "Este valor debe estar entre %(lower)s y %(upper)s."
-#: contrib/admin/views/main.py:514
-msgid "Are you sure?"
-msgstr "Est seguro?"
+#: core/validators.py:376
+#, python-format
+msgid "This value must be at least %s."
+msgstr "Este valor debe ser como mínimo %s."
-#: contrib/admin/views/main.py:536
+#: core/validators.py:378
#, python-format
-msgid "Change history: %s"
-msgstr "Modificar histrico: %s"
+msgid "This value must be no more than %s."
+msgstr "Este valor no debe ser mayor que %s."
-#: contrib/admin/views/main.py:570
+#: core/validators.py:414
#, python-format
-msgid "Select %s"
-msgstr "Escoja %s"
+msgid "This value must be a power of %s."
+msgstr "Este valor debe ser una potencia de %s."
-#: contrib/admin/views/main.py:570
+#: core/validators.py:424
+msgid "Please enter a valid decimal number."
+msgstr "Por favor, introduzca un número decimal válido."
+
+#: core/validators.py:431
#, python-format
-msgid "Select %s to change"
-msgstr "Escoja %s para modificar"
+msgid "Please enter a valid decimal number with at most %s total digit."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s total digits."
+msgstr[0] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígito en "
+"total."
+msgstr[1] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígitos en "
+"total."
-#: contrib/admin/views/main.py:758
-msgid "Database error"
-msgstr "Erorr en la base de datos"
+#: core/validators.py:434
+#, python-format
+msgid ""
+"Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural ""
+"Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígito en su "
+"parte entera."
+msgstr[1] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígitos en su "
+"parte entera."
-#: contrib/admin/views/auth.py:30
-msgid "Add user"
-msgstr "Aadir usuario"
+#: core/validators.py:437
+#, python-format
+msgid "Please enter a valid decimal number with at most %s decimal place."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s decimal places."
+msgstr[0] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígito "
+"decimal."
+msgstr[1] ""
+"Por favor, introduzca un número decimal válido con a lo más %s dígitos "
+"decimales."
-#: contrib/admin/views/auth.py:57
-msgid "Password changed successfully."
-msgstr "La clave se ha cambiado exitosamente."
+#: core/validators.py:445
+msgid "Please enter a valid floating point number."
+msgstr "Por favor, introduzca un número decimal válido."
-#: contrib/admin/views/auth.py:64
+#: core/validators.py:454
#, python-format
-msgid "Change password: %s"
-msgstr "Cambiar clave: %s"
+msgid "Make sure your uploaded file is at least %s bytes big."
+msgstr "Asegúrese de que el fichero que envía tiene al menos %s bytes."
-#: contrib/localflavor/usa/forms.py:17
-msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
-msgstr "Introduzca un cdigo postal en el formato XXXXX o XXXX-XXXX."
+#: core/validators.py:455
+#, python-format
+msgid "Make sure your uploaded file is at most %s bytes big."
+msgstr "Asegúrese de que el fichero que envía tiene como máximo %s bytes."
-#: contrib/localflavor/uk/forms.py:18
-msgid "Enter a postcode. A space is required between the two postcode parts."
-msgstr ""
-"Introduzca un cdigo postal. Se necesita un espacio entre las dos partes del "
-"cdigo."
+#: core/validators.py:472
+msgid "The format for this field is wrong."
+msgstr "El formato de este campo es incorrecto."
-#: contrib/sessions/models.py:51
-msgid "session key"
-msgstr "clave de sesin"
+#: core/validators.py:487
+msgid "This field is invalid."
+msgstr "Este campo no es válido."
-#: contrib/sessions/models.py:52
-msgid "session data"
-msgstr "datos de sesin"
+#: core/validators.py:523
+#, python-format
+msgid "Could not retrieve anything from %s."
+msgstr "No pude obtener nada de %s."
-#: contrib/sessions/models.py:53
-msgid "expire date"
-msgstr "fecha de caducidad"
+#: core/validators.py:526
+#, python-format
+msgid ""
+"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+msgstr ""
+"La URL %(url)s devolvió la cabecera Content-Type '%(contenttype)s', que no "
+"es válida."
-#: contrib/sessions/models.py:57
-msgid "session"
-msgstr "sesin"
+#: core/validators.py:559
+#, python-format
+msgid ""
+"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
+"\"%(start)s\".)"
+msgstr ""
+"Por favor, cierre la etiqueta %(tag)s de la línea %(line)s. (La línea "
+"empieza por \"%(start)s\".)"
-#: contrib/sessions/models.py:58
-msgid "sessions"
-msgstr "sesiones"
+#: core/validators.py:563
+#, python-format
+msgid ""
+"Some text starting on line %(line)s is not allowed in that context. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"Parte del texto que comienza en la línea %(line)s no está permitido en ese "
+"contexto. (La línea empieza por \"%(start)s\".)"
-#: views/generic/create_update.py:43
+#: core/validators.py:568
#, python-format
-msgid "The %(verbose_name)s was created successfully."
-msgstr "El %(verbose_name)s se ha creado correctamente."
+msgid ""
+"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"El \"%(attr)s\" de la línea %(line)s no es un atributo válido. (La línea "
+"empieza por \"%(start)s\".)"
-#: views/generic/create_update.py:117
+#: core/validators.py:573
#, python-format
-msgid "The %(verbose_name)s was updated successfully."
-msgstr "Se actualiz con xito el %(verbose_name)s."
+msgid ""
+"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"La \"<%(tag)s>\" de la línea %(line)s no es una etiqueta válida. (La línea "
+"empieza por \"%(start)s\".)"
-#: views/generic/create_update.py:184
+#: core/validators.py:577
#, python-format
-msgid "The %(verbose_name)s was deleted."
-msgstr "El %(verbose_name)s ha sido eliminado."
+msgid ""
+"A tag on line %(line)s is missing one or more required attributes. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"A una etiqueta de la línea %(line)s le faltan uno o más atributos "
+"requeridos. (La línea empieza por \"%(start)s\".)"
+#: core/validators.py:582
+#, python-format
+msgid ""
+"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"El atributo \"%(attr)s\" de la línea %(line)s tiene un valor que no es "
+"válido. (La línea empieza por \"%(start)s\".)"
diff --git a/django/conf/locale/es/LC_MESSAGES/djangojs.mo b/django/conf/locale/es/LC_MESSAGES/djangojs.mo
index 701443cace..6d098c5041 100644
--- a/django/conf/locale/es/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/es/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/es/LC_MESSAGES/djangojs.po b/django/conf/locale/es/LC_MESSAGES/djangojs.po
index 99856cec36..d193cf660e 100644
--- a/django/conf/locale/es/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/es/LC_MESSAGES/djangojs.po
@@ -1,26 +1,41 @@
# Spanish translation for the django-admin JS files.
# Copyright (C)
# This file is distributed under the same license as the PACKAGE package.
-# Jorge Gajon <gajon@gajon.org>, 2005.
#
msgid ""
msgstr ""
"Project-Id-Version: Django JavaScript 1.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2005-12-09 11:51+0100\n"
-"PO-Revision-Date: 2005-12-06 21:32+0100\n"
+"POT-Creation-Date: 2007-07-14 13:47-0500\n"
+"PO-Revision-Date: 2007-07-14 13:41-0500\n"
"Last-Translator: Jorge Gajon <gajon@gajon.org>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+#: contrib/admin/media/js/calendar.js:24
+#: contrib/admin/media/js/dateparse.js:32
+msgid ""
+"January February March April May June July August September October November "
+"December"
+msgstr ""
+"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre "
+"Noviembre Diciembre"
+
+#: contrib/admin/media/js/calendar.js:25
+msgid "S M T W T F S"
+msgstr "D L M M J V S"
+
+#: contrib/admin/media/js/dateparse.js:33
+msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
+
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "%s Disponibles"
#: contrib/admin/media/js/SelectFilter2.js:41
-#, fuzzy
msgid "Choose all"
msgstr "Selecciona todos"
@@ -45,66 +60,58 @@ msgstr "Haz tus elecciones y da click en "
msgid "Clear all"
msgstr "Elimina todos"
-#: contrib/admin/media/js/dateparse.js:26
-#: contrib/admin/media/js/calendar.js:24
-msgid ""
-"January February March April May June July August September October November "
-"December"
-msgstr ""
-"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre "
-"Noviembre Diciembre"
-
-#: contrib/admin/media/js/dateparse.js:27
-msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
-msgstr "Domingo Lunes Martes Mircoles Jueves Viernes Sbado"
-
-#: contrib/admin/media/js/calendar.js:25
-msgid "S M T W T F S"
-msgstr "D L M M J V S"
-
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Ahora"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "Reloj"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Elige una hora"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Medianoche"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "6 a.m."
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
-msgstr "Medioda"
+msgstr "Mediodía"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Cancelar"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Hoy"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Calendario"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Ayer"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
-msgstr "Maana"
+msgstr "Mañana"
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
+msgid "Show"
+msgstr "Mostrar"
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
+msgid "Hide"
+msgstr "Esconder"
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.mo b/django/conf/locale/es_AR/LC_MESSAGES/django.mo
index 717bbcbd05..5c12160a7c 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/django.mo
+++ b/django/conf/locale/es_AR/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.po b/django/conf/locale/es_AR/LC_MESSAGES/django.po
index 02f80682e7..93beac1e1b 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/django.po
+++ b/django/conf/locale/es_AR/LC_MESSAGES/django.po
@@ -4,182 +4,333 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: django\n"
+"Project-Id-Version: Django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-05-19 13:22-0300\n"
-"PO-Revision-Date: 2007-05-19 13:33-0300\n"
+"POT-Creation-Date: 2007-07-14 12:13-0300\n"
+"PO-Revision-Date: 2007-07-14 14:37-0300\n"
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
-"Language-Team: Spanish <es@li.org>\n"
+"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: newforms/fields.py:82 newforms/fields.py:378 newforms/fields.py:454
-#: newforms/fields.py:465 newforms/models.py:186
-#: db/models/fields/__init__.py:117 db/models/fields/__init__.py:274
-#: db/models/fields/__init__.py:612 db/models/fields/__init__.py:623
-#: oldforms/__init__.py:357
-msgid "This field is required."
-msgstr "Este campo es obligatorio."
-
-#: newforms/fields.py:105 newforms/fields.py:258
+#: views/generic/create_update.py:43
#, python-format
-msgid "Ensure this value has at most %d characters."
-msgstr "Asegrese de que este valor tenga como mximo %d caracteres."
+msgid "The %(verbose_name)s was created successfully."
+msgstr "Se creó con éxito %(verbose_name)s."
-#: newforms/fields.py:107 newforms/fields.py:260
+#: views/generic/create_update.py:117
#, python-format
-msgid "Ensure this value has at least %d characters."
-msgstr "Asegrese de que este valor tenga al menos %d caracteres."
+msgid "The %(verbose_name)s was updated successfully."
+msgstr "Se actualizó con éxito %(verbose_name)s."
-#: newforms/fields.py:130 core/validators.py:120
-msgid "Enter a whole number."
-msgstr "Introduzca un nmero entero."
+#: views/generic/create_update.py:184
+#, python-format
+msgid "The %(verbose_name)s was deleted."
+msgstr "Se eliminó %(verbose_name)s."
-#: newforms/fields.py:132
+#: db/models/manipulators.py:309
#, python-format
-msgid "Ensure this value is less than or equal to %s."
-msgstr "Asegrese de que este valor sea menor o igual a %s."
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "Ya existe un(a) %(object)s con este/a %(type)s para %(field)s."
-#: newforms/fields.py:134
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+msgid "and"
+msgstr "y"
+
+#: db/models/fields/__init__.py:47
#, python-format
-msgid "Ensure this value is greater than or equal to %s."
-msgstr "Asegrese de que este valor sea mayor o igual a %s."
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "Ya existe %(optname)s con este %(fieldname)s."
-#: newforms/fields.py:167
-msgid "Enter a valid date."
-msgstr "Introduzca una fecha vlida."
+#: db/models/fields/__init__.py:127 db/models/fields/__init__.py:284
+#: db/models/fields/__init__.py:681 db/models/fields/__init__.py:692
+#: oldforms/__init__.py:369 newforms/fields.py:92 newforms/fields.py:440
+#: newforms/fields.py:516 newforms/fields.py:527 newforms/models.py:187
+msgid "This field is required."
+msgstr "Este campo es obligatorio."
-#: newforms/fields.py:194
-msgid "Enter a valid time."
-msgstr "Introduzca una hora vlida."
+#: db/models/fields/__init__.py:379
+msgid "This value must be an integer."
+msgstr "Este valor debe ser un número entero."
-#: newforms/fields.py:230
-msgid "Enter a valid date/time."
-msgstr "Introduzca una fecha/hora vlida."
+#: db/models/fields/__init__.py:414
+msgid "This value must be either True or False."
+msgstr "Este valor debe ser True o False."
-#: newforms/fields.py:244
-msgid "Enter a valid value."
-msgstr "Introduzca un valor vlido."
+#: db/models/fields/__init__.py:435
+msgid "This field cannot be null."
+msgstr "Este campo no puede ser nulo."
-#: newforms/fields.py:273 core/validators.py:162
-msgid "Enter a valid e-mail address."
-msgstr "Introduzca una direccin de correo electrnico vlida"
+#: db/models/fields/__init__.py:469 core/validators.py:155
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "Introduzca una fecha válida en formato AAAA-MM-DD."
-#: newforms/fields.py:291 newforms/fields.py:313
-msgid "Enter a valid URL."
-msgstr "Introduzca una URL vlida."
+#: db/models/fields/__init__.py:538 core/validators.py:164
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "Introduzca una fecha/hora válida en formato AAAA-MM-DD HH:MM."
-#: newforms/fields.py:315
-msgid "This URL appears to be a broken link."
-msgstr "La URL parece ser un enlace roto."
+#: db/models/fields/__init__.py:598
+msgid "This value must be a decimal number."
+msgstr "Este valor debe ser un número decimal."
-#: newforms/fields.py:366 newforms/models.py:173
-msgid "Select a valid choice. That choice is not one of the available choices."
-msgstr ""
-"Seleccione una opcin vlida. Esa opcin no es una de las opciones "
-"disponibles."
+#: db/models/fields/__init__.py:701
+msgid "Enter a valid filename."
+msgstr "Introduzca un nombre de archivo válido."
-#: newforms/fields.py:382 newforms/fields.py:458 newforms/models.py:190
-msgid "Enter a list of values."
-msgstr "Introduzca una lista de valores."
+#: db/models/fields/__init__.py:826
+msgid "This value must be either None, True or False."
+msgstr "Este valor debe ser None, True o False."
-#: newforms/fields.py:391 newforms/models.py:196
+#: db/models/fields/related.py:55
#, python-format
-msgid "Select a valid choice. %s is not one of the available choices."
+msgid "Please enter a valid %s."
+msgstr "Por favor, introduzca un %s válido."
+
+#: db/models/fields/related.py:641
+msgid "Separate multiple IDs with commas."
+msgstr " Separe múltiples identificadores con comas."
+
+#: db/models/fields/related.py:643
+msgid ""
+"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
-"Seleccione una opcin vlida. %s no es una de las opciones disponibles."
+"Mantenga presionada \"Control\" (\"Command\" en una Mac) para seleccionar "
+"más de uno."
-#: newforms/widgets.py:182 contrib/admin/filterspecs.py:150
-#: oldforms/__init__.py:577
+#: db/models/fields/related.py:690
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural ""
+"Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] ""
+"Por favor, introduzca IDs de %(self)s válidos. El valor %(value)r no es "
+"válido."
+msgstr[1] ""
+"Por favor, introduzca IDs de %(self)s válidos. Los valores %(value)r no son "
+"válidos."
+
+#: oldforms/__init__.py:404
+#, python-format
+msgid "Ensure your text is less than %s character."
+msgid_plural "Ensure your text is less than %s characters."
+msgstr[0] "Asegúrese de que su texto tiene menos de %s caracter."
+msgstr[1] "Asegúrese de que su texto tiene menos de %s caracteres."
+
+#: oldforms/__init__.py:409
+msgid "Line breaks are not allowed here."
+msgstr "No se permiten saltos de línea."
+
+#: oldforms/__init__.py:507 oldforms/__init__.py:581 oldforms/__init__.py:620
+#, python-format
+msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
+msgstr "Seleccione una opción válida; '%(data)s' no está en %(choices)s."
+
+#: oldforms/__init__.py:587 contrib/admin/filterspecs.py:152
+#: newforms/widgets.py:181
msgid "Unknown"
msgstr "Desconocido"
-#: newforms/widgets.py:182 contrib/admin/filterspecs.py:143
-#: oldforms/__init__.py:577
+#: oldforms/__init__.py:587 contrib/admin/filterspecs.py:145
+#: newforms/widgets.py:181
msgid "Yes"
-msgstr "S"
+msgstr "Sí"
-#: newforms/widgets.py:182 contrib/admin/filterspecs.py:143
-#: oldforms/__init__.py:577
+#: oldforms/__init__.py:587 contrib/admin/filterspecs.py:145
+#: newforms/widgets.py:181
msgid "No"
msgstr "No"
-#: utils/dateformat.py:40
-msgid "p.m."
+#: oldforms/__init__.py:682 core/validators.py:181 core/validators.py:461
+msgid "No file was submitted. Check the encoding type on the form."
msgstr ""
+"No se envió un archivo. Verifique el tipo de codificación en el formulario."
-#: utils/dateformat.py:41
-msgid "a.m."
-msgstr ""
+#: oldforms/__init__.py:684
+msgid "The submitted file is empty."
+msgstr "El archivo enviado está vacío."
-#: utils/dateformat.py:46
-msgid "PM"
-msgstr ""
+#: oldforms/__init__.py:740
+msgid "Enter a whole number between -32,768 and 32,767."
+msgstr "Introduzca un número entero entre -32.768 y 32.767."
-#: utils/dateformat.py:47
-msgid "AM"
-msgstr ""
+#: oldforms/__init__.py:750
+msgid "Enter a positive number."
+msgstr "Introduzca un número positivo."
-#: utils/dateformat.py:95
-msgid "midnight"
-msgstr "medianoche"
+#: oldforms/__init__.py:760
+msgid "Enter a whole number between 0 and 32,767."
+msgstr "Introduzca un número entero entre 0 y 32.767."
-#: utils/dateformat.py:97
-msgid "noon"
-msgstr "medioda"
+#: conf/global_settings.py:38
+msgid "Arabic"
+msgstr "Árabe"
-#: utils/timesince.py:12
-msgid "year"
-msgid_plural "years"
-msgstr[0] "ao"
-msgstr[1] "aos"
+#: conf/global_settings.py:39
+msgid "Bengali"
+msgstr "Bengalí"
-#: utils/timesince.py:13
-msgid "month"
-msgid_plural "months"
-msgstr[0] "mes"
-msgstr[1] "meses"
+#: conf/global_settings.py:40
+msgid "Bulgarian"
+msgstr "Búlgaro"
-#: utils/timesince.py:14
-msgid "week"
-msgid_plural "weeks"
-msgstr[0] "semana"
-msgstr[1] "semanas"
+#: conf/global_settings.py:41
+msgid "Catalan"
+msgstr "Catalán"
-#: utils/timesince.py:15
-msgid "day"
-msgid_plural "days"
-msgstr[0] "da"
-msgstr[1] "das"
+#: conf/global_settings.py:42
+msgid "Czech"
+msgstr "Checo"
-#: utils/timesince.py:16
-msgid "hour"
-msgid_plural "hours"
-msgstr[0] "hora"
-msgstr[1] "horas"
+#: conf/global_settings.py:43
+msgid "Welsh"
+msgstr "Galés"
-#: utils/timesince.py:17
-msgid "minute"
-msgid_plural "minutes"
-msgstr[0] "minuto"
-msgstr[1] "minutos"
+#: conf/global_settings.py:44
+msgid "Danish"
+msgstr "Danés"
-#: utils/timesince.py:40
-#, python-format
-msgid "%d milliseconds"
-msgstr "%d milisegundos"
+#: conf/global_settings.py:45
+msgid "German"
+msgstr "Alemán"
-#: utils/timesince.py:41
-#, python-format
-msgid "%(number)d %(type)s"
-msgstr ""
+#: conf/global_settings.py:46
+msgid "Greek"
+msgstr "Griego"
-#: utils/timesince.py:47
-#, python-format
-msgid ", %(number)d %(type)s"
-msgstr ""
+#: conf/global_settings.py:47
+msgid "English"
+msgstr "Inglés"
+
+#: conf/global_settings.py:48
+msgid "Spanish"
+msgstr "Español"
+
+#: conf/global_settings.py:49
+msgid "Argentinean Spanish"
+msgstr "Español Argentino"
+
+#: conf/global_settings.py:50
+msgid "Persian"
+msgstr "Persa"
+
+#: conf/global_settings.py:51
+msgid "Finnish"
+msgstr "Finlandés"
+
+#: conf/global_settings.py:52
+msgid "French"
+msgstr "Francés"
+
+#: conf/global_settings.py:53
+msgid "Galician"
+msgstr "Gallego"
+
+#: conf/global_settings.py:54
+msgid "Hungarian"
+msgstr "Húngaro"
+
+#: conf/global_settings.py:55
+msgid "Hebrew"
+msgstr "Hebreo"
+
+#: conf/global_settings.py:56
+msgid "Icelandic"
+msgstr "Islandés"
+
+#: conf/global_settings.py:57
+msgid "Italian"
+msgstr "Italiano"
+
+#: conf/global_settings.py:58
+msgid "Japanese"
+msgstr "Japonés"
+
+#: conf/global_settings.py:59
+msgid "Korean"
+msgstr "Koreano"
+
+#: conf/global_settings.py:60
+msgid "Kannada"
+msgstr "Canarés"
+
+#: conf/global_settings.py:61
+msgid "Latvian"
+msgstr "Letón"
+
+#: conf/global_settings.py:62
+msgid "Macedonian"
+msgstr "Macedonio"
+
+#: conf/global_settings.py:63
+msgid "Dutch"
+msgstr "Holandés"
+
+#: conf/global_settings.py:64
+msgid "Norwegian"
+msgstr "Noruego"
+
+#: conf/global_settings.py:65
+msgid "Polish"
+msgstr "Polaco"
+
+#: conf/global_settings.py:66
+msgid "Portugese"
+msgstr "Portugués"
+
+#: conf/global_settings.py:67
+msgid "Brazilian"
+msgstr "Brasileño"
+
+#: conf/global_settings.py:68
+msgid "Romanian"
+msgstr "Rumano"
+
+#: conf/global_settings.py:69
+msgid "Russian"
+msgstr "Ruso"
+
+#: conf/global_settings.py:70
+msgid "Slovak"
+msgstr "Eslovaco"
+
+#: conf/global_settings.py:71
+msgid "Slovenian"
+msgstr "Esloveno"
+
+#: conf/global_settings.py:72
+msgid "Serbian"
+msgstr "Serbio"
+
+#: conf/global_settings.py:73
+msgid "Swedish"
+msgstr "Sueco"
+
+#: conf/global_settings.py:74
+msgid "Tamil"
+msgstr "Tamil"
+
+#: conf/global_settings.py:75
+msgid "Telugu"
+msgstr "Telugu"
+
+#: conf/global_settings.py:76
+msgid "Turkish"
+msgstr "Turco"
+
+#: conf/global_settings.py:77
+msgid "Ukrainian"
+msgstr "Ucraniano"
+
+#: conf/global_settings.py:78
+msgid "Simplified Chinese"
+msgstr "Chino simplificado"
+
+#: conf/global_settings.py:79
+msgid "Traditional Chinese"
+msgstr "Chino tradicional"
#: utils/dates.py:6
msgid "Monday"
@@ -191,7 +342,7 @@ msgstr "Martes"
#: utils/dates.py:6
msgid "Wednesday"
-msgstr "Mircoles"
+msgstr "Miércoles"
#: utils/dates.py:6
msgid "Thursday"
@@ -203,383 +354,794 @@ msgstr "Viernes"
#: utils/dates.py:7
msgid "Saturday"
-msgstr "Sbado"
+msgstr "Sábado"
#: utils/dates.py:7
msgid "Sunday"
msgstr "Domingo"
-#: utils/dates.py:14
+#: utils/dates.py:10
+msgid "Mon"
+msgstr "Lun"
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr "Mar"
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr "Mie"
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr "Jue"
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr "Vie"
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr "Sab"
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr "Dom"
+
+#: utils/dates.py:18
msgid "January"
msgstr "Enero"
-#: utils/dates.py:14
+#: utils/dates.py:18
msgid "February"
msgstr "Febrero"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "Marzo"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "Abril"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Mayo"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Junio"
-#: utils/dates.py:15 utils/dates.py:27
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Julio"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "August"
msgstr "Agosto"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "September"
msgstr "Setiembre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "October"
msgstr "Octubre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "November"
msgstr "Noviembre"
-#: utils/dates.py:16
+#: utils/dates.py:20
msgid "December"
msgstr "Diciembre"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jan"
msgstr "ene"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "feb"
msgstr "feb"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "mar"
msgstr "mar"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "apr"
msgstr "abr"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "may"
msgstr "may"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jun"
msgstr "jun"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "jul"
msgstr "jul"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "aug"
msgstr "ago"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "sep"
msgstr "set"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "oct"
msgstr "oct"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "nov"
msgstr "nov"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "dec"
msgstr "dic"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Jan."
msgstr "Enero"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Feb."
msgstr "Feb."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Aug."
msgstr "Ago."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Sept."
msgstr "Set."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Oct."
msgstr "Oct."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Nov."
msgstr "Nov."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Dec."
msgstr "Dic."
-#: utils/translation/trans_real.py:358
+#: utils/timesince.py:12
+msgid "year"
+msgid_plural "years"
+msgstr[0] "año"
+msgstr[1] "años"
+
+#: utils/timesince.py:13
+msgid "month"
+msgid_plural "months"
+msgstr[0] "mes"
+msgstr[1] "meses"
+
+#: utils/timesince.py:14
+msgid "week"
+msgid_plural "weeks"
+msgstr[0] "semana"
+msgstr[1] "semanas"
+
+#: utils/timesince.py:15
+msgid "day"
+msgid_plural "days"
+msgstr[0] "día"
+msgstr[1] "días"
+
+#: utils/timesince.py:16
+msgid "hour"
+msgid_plural "hours"
+msgstr[0] "hora"
+msgstr[1] "horas"
+
+#: utils/timesince.py:17
+msgid "minute"
+msgid_plural "minutes"
+msgstr[0] "minuto"
+msgstr[1] "minutos"
+
+#: utils/timesince.py:39
+#, python-format
+msgid "%(number)d %(type)s"
+msgstr "%(number)d %(type)s"
+
+#: utils/timesince.py:45
+#, python-format
+msgid ", %(number)d %(type)s"
+msgstr ", %(number)d %(type)s"
+
+#: utils/dateformat.py:41
+msgid "p.m."
+msgstr "p.m."
+
+#: utils/dateformat.py:42
+msgid "a.m."
+msgstr "a.m."
+
+#: utils/dateformat.py:47
+msgid "PM"
+msgstr "PM"
+
+#: utils/dateformat.py:48
+msgid "AM"
+msgstr "AM"
+
+#: utils/dateformat.py:97
+msgid "midnight"
+msgstr "medianoche"
+
+#: utils/dateformat.py:99
+msgid "noon"
+msgstr "mediodía"
+
+#: utils/translation/trans_real.py:391
msgid "DATE_FORMAT"
msgstr "j N Y"
-#: utils/translation/trans_real.py:359
+#: utils/translation/trans_real.py:392
msgid "DATETIME_FORMAT"
msgstr "j N Y P"
-#: utils/translation/trans_real.py:360
+#: utils/translation/trans_real.py:393
msgid "TIME_FORMAT"
msgstr "P"
-#: utils/translation/trans_real.py:376
+#: utils/translation/trans_real.py:409
msgid "YEAR_MONTH_FORMAT"
msgstr "F Y"
-#: utils/translation/trans_real.py:377
+#: utils/translation/trans_real.py:410
msgid "MONTH_DAY_FORMAT"
msgstr "j \\de F"
-#: contrib/redirects/models.py:7
-msgid "redirect from"
-msgstr "redirigir desde"
+#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
+msgid "The two password fields didn't match."
+msgstr "Los dos campos de contraseñas no coinciden entre si."
-#: contrib/redirects/models.py:8
+#: contrib/auth/forms.py:25
+msgid "A user with that username already exists."
+msgstr "Ya existe un usuario con ese nombre."
+
+#: contrib/auth/forms.py:53
msgid ""
-"This should be an absolute path, excluding the domain name. Example: '/"
-"events/search/'."
+"Your Web browser doesn't appear to have cookies enabled. Cookies are "
+"required for logging in."
msgstr ""
-"Esta ruta debera ser absoluta, excluyendo el nombre de dominio. Ejemplo: '/"
-"events/search/'."
+"Su navegador Web aparenta no tener cookies activas. Las cookies son un "
+"requerimiento para poder ingresar."
-#: contrib/redirects/models.py:9
-msgid "redirect to"
-msgstr "redirigir a"
+#: contrib/auth/forms.py:60 contrib/admin/views/decorators.py:10
+msgid ""
+"Please enter a correct username and password. Note that both fields are case-"
+"sensitive."
+msgstr ""
+"Por favor introduzca un nombre de usuario y una contraseña correctos. Note "
+"que ambos campos son sensibles a mayúsculas/minúsculas."
-#: contrib/redirects/models.py:10
+#: contrib/auth/forms.py:62
+msgid "This account is inactive."
+msgstr "Esta cuenta está inactiva"
+
+#: contrib/auth/forms.py:84
msgid ""
-"This can be either an absolute path (as above) or a full URL starting with "
-"'http://'."
+"That e-mail address doesn't have an associated user account. Are you sure "
+"you've registered?"
msgstr ""
-"Esto puede ser bien una ruta absoluta (como antes) o una URL completa que "
-"empiece con 'http://'."
+"Esa dirección de e-mail no está asociada a ninguna cuenta de usuario. ¿Está "
+"seguro de que ya se ha registrado?"
-#: contrib/redirects/models.py:13
-msgid "redirect"
-msgstr "redireccin"
+#: contrib/auth/forms.py:117
+msgid "The two 'new password' fields didn't match."
+msgstr "Los dos campos 'nueva contraseña' no coinciden entre si."
-#: contrib/redirects/models.py:14
-msgid "redirects"
-msgstr "redirecciones"
+#: contrib/auth/forms.py:124
+msgid "Your old password was entered incorrectly. Please enter it again."
+msgstr ""
+"La antigua contraseña ingresada es incorrecta. Por favor ingrésela "
+"nuevamente."
-#: contrib/auth/models.py:44 contrib/auth/models.py:64
+#: contrib/auth/models.py:51 contrib/auth/models.py:71
msgid "name"
msgstr "nombre"
-#: contrib/auth/models.py:46
+#: contrib/auth/models.py:53
msgid "codename"
-msgstr "nombre en cdigo"
+msgstr "nombre en código"
-#: contrib/auth/models.py:49
+#: contrib/auth/models.py:56
msgid "permission"
msgstr "permiso"
-#: contrib/auth/models.py:50 contrib/auth/models.py:65
+#: contrib/auth/models.py:57 contrib/auth/models.py:72
msgid "permissions"
msgstr "permisos"
-#: contrib/auth/models.py:68
+#: contrib/auth/models.py:75
msgid "group"
msgstr "grupo"
-#: contrib/auth/models.py:69 contrib/auth/models.py:109
+#: contrib/auth/models.py:76 contrib/auth/models.py:116
msgid "groups"
msgstr "grupos"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid "username"
msgstr "nombre de usuario"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
msgstr ""
-"Requerido. Longitud mxima 30 caracteres alfanumricos (letras, dgitos y "
+"Requerido. Longitud máxima 30 caracteres alfanuméricos (letras, dígitos y "
"guiones bajos)."
-#: contrib/auth/models.py:100
+#: contrib/auth/models.py:107
msgid "first name"
msgstr "nombre"
-#: contrib/auth/models.py:101
+#: contrib/auth/models.py:108
msgid "last name"
msgstr "apellido"
-#: contrib/auth/models.py:102
+#: contrib/auth/models.py:109
msgid "e-mail address"
-msgstr "direccin de correo"
+msgstr "dirección de correo"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid "password"
-msgstr "contrasea"
+msgstr "contraseña"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
msgstr ""
"Use '[algo]$[salt]$[hexdigest]' o use el <a href=\"password/\">formulario de "
-"cambio de contrasea</a>."
+"cambio de contraseña</a>."
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "staff status"
msgstr "es staff"
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "Designates whether the user can log into this admin site."
-msgstr "Indica si el usuario puede ingresar a este sitio de administracin."
+msgstr "Indica si el usuario puede ingresar a este sitio de administración."
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid "active"
msgstr "activo"
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid ""
"Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts."
msgstr ""
-"Indica si el usuario puede ingresar al sitio de administracin Django."
+"Indica si el usuario puede ingresar al sitio de administración Django. "
"Desactive este campo en lugar de eliminar usuarios."
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid "superuser status"
msgstr "es superusuario"
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
msgstr ""
-"Indica que este usuario posee todos los permisos, sin asignarle los mismos "
-"explcitamente."
+"Indica que este usuario posee todos los permisos, sin que sea neceario "
+"asignarle los mismos en forma explícita."
-#: contrib/auth/models.py:107
+#: contrib/auth/models.py:114
msgid "last login"
-msgstr "ltimo ingreso"
+msgstr "último ingreso"
-#: contrib/auth/models.py:108
+#: contrib/auth/models.py:115
msgid "date joined"
-msgstr "fecha de creacin"
+msgstr "fecha de creación"
-#: contrib/auth/models.py:110
+#: contrib/auth/models.py:117
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
msgstr ""
-"Adems de los permisos asignados manualmente, este usuario tambin poseer "
+"Además de los permisos asignados manualmente, este usuario también poseerá "
"todos los permisos de los grupos a los que pertenezca."
-#: contrib/auth/models.py:111
+#: contrib/auth/models.py:118
msgid "user permissions"
msgstr "permisos de usuario"
-#: contrib/auth/models.py:115
+#: contrib/auth/models.py:122
msgid "user"
msgstr "usuario"
-#: contrib/auth/models.py:116
+#: contrib/auth/models.py:123
msgid "users"
msgstr "usuarios"
-#: contrib/auth/models.py:122
+#: contrib/auth/models.py:129
msgid "Personal info"
-msgstr "Informacin personal"
+msgstr "Información personal"
-#: contrib/auth/models.py:123
+#: contrib/auth/models.py:130
msgid "Permissions"
msgstr "Permisos"
-#: contrib/auth/models.py:124
+#: contrib/auth/models.py:131
msgid "Important dates"
msgstr "Fechas importantes"
-#: contrib/auth/models.py:125
+#: contrib/auth/models.py:132
msgid "Groups"
msgstr "Grupos"
-#: contrib/auth/models.py:269
+#: contrib/auth/models.py:274
msgid "message"
msgstr "mensaje"
-#: contrib/auth/models.py:282
-msgid "AnonymousUser"
-msgstr "UsuarioAnonimo"
+#: contrib/auth/views.py:41
+msgid "Logged out"
+msgstr "Sesión cerrada"
-#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
-msgid "The two password fields didn't match."
-msgstr "Los dos campos de contraseas no coinciden entre si."
+#: contrib/comments/models.py:67 contrib/comments/models.py:166
+msgid "object ID"
+msgstr "ID de objeto"
-#: contrib/auth/forms.py:25
-msgid "A user with that username already exists."
-msgstr "Ya existe un usuario con ese nombre."
+#: contrib/comments/models.py:68
+msgid "headline"
+msgstr "encabezado"
-#: contrib/auth/forms.py:53
+#: contrib/comments/models.py:69 contrib/comments/models.py:90
+#: contrib/comments/models.py:167
+msgid "comment"
+msgstr "comentario"
+
+#: contrib/comments/models.py:70
+msgid "rating #1"
+msgstr "calificación 1"
+
+#: contrib/comments/models.py:71
+msgid "rating #2"
+msgstr "calificación 2"
+
+#: contrib/comments/models.py:72
+msgid "rating #3"
+msgstr "calificación 3"
+
+#: contrib/comments/models.py:73
+msgid "rating #4"
+msgstr "calificación 4"
+
+#: contrib/comments/models.py:74
+msgid "rating #5"
+msgstr "calificación 5"
+
+#: contrib/comments/models.py:75
+msgid "rating #6"
+msgstr "calificación 6"
+
+#: contrib/comments/models.py:76
+msgid "rating #7"
+msgstr "calificación 7"
+
+#: contrib/comments/models.py:77
+msgid "rating #8"
+msgstr "calificación 8"
+
+#: contrib/comments/models.py:82
+msgid "is valid rating"
+msgstr "es calificación válida"
+
+#: contrib/comments/models.py:83 contrib/comments/models.py:169
+msgid "date/time submitted"
+msgstr "fecha/hora de envío"
+
+#: contrib/comments/models.py:84 contrib/comments/models.py:170
+msgid "is public"
+msgstr "es público"
+
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:306
+msgid "IP address"
+msgstr "Dirección IP"
+
+#: contrib/comments/models.py:86
+msgid "is removed"
+msgstr "se ha eliminado"
+
+#: contrib/comments/models.py:86
msgid ""
-"Your Web browser doesn't appear to have cookies enabled. Cookies are "
-"required for logging in."
+"Check this box if the comment is inappropriate. A \"This comment has been "
+"removed\" message will be displayed instead."
msgstr ""
-"Su navegador Web aparenta no tener cookies activas. Las cookies son un "
-"requerimiento para poder ingresar."
+"Marque esta caja si el comentario es inapropiado. En su lugar se mostrará un "
+"mensaje \"Este comentario ha sido eliminado\"."
-#: contrib/auth/forms.py:60 contrib/admin/views/decorators.py:10
+#: contrib/comments/models.py:91
+msgid "comments"
+msgstr "comentarios"
+
+#: contrib/comments/models.py:131 contrib/comments/models.py:207
+msgid "Content object"
+msgstr "Objeto contenido"
+
+#: contrib/comments/models.py:159
+#, python-format
msgid ""
-"Please enter a correct username and password. Note that both fields are case-"
-"sensitive."
+"Posted by %(user)s at %(date)s\n"
+"\n"
+"%(comment)s\n"
+"\n"
+"http://%(domain)s%(url)s"
msgstr ""
-"Por favor introduzca un nombre de usuario y una contrasea correctos. Note "
-"que ambos campos son sensibles a maysculas/minsculas."
+"Enviado por %(user)s el %(date)s\n"
+"\n"
+"%(comment)s\n"
+"\n"
+"http://%(domain)s%(url)s"
-#: contrib/auth/forms.py:62
-msgid "This account is inactive."
-msgstr "Esta cuenta est inactiva"
+#: contrib/comments/models.py:168
+msgid "person's name"
+msgstr "nombre de la persona"
-#: contrib/auth/forms.py:85
+#: contrib/comments/models.py:171
+msgid "ip address"
+msgstr "dirección ip"
+
+#: contrib/comments/models.py:173
+msgid "approved by staff"
+msgstr "aprobado por el staff"
+
+#: contrib/comments/models.py:176
+msgid "free comment"
+msgstr "comentario libre"
+
+#: contrib/comments/models.py:177
+msgid "free comments"
+msgstr "comentarios libres"
+
+#: contrib/comments/models.py:233
+msgid "score"
+msgstr "puntuación"
+
+#: contrib/comments/models.py:234
+msgid "score date"
+msgstr "fecha de la puntuación"
+
+#: contrib/comments/models.py:237
+msgid "karma score"
+msgstr "punto karma"
+
+#: contrib/comments/models.py:238
+msgid "karma scores"
+msgstr "puntos karma"
+
+#: contrib/comments/models.py:242
+#, python-format
+msgid "%(score)d rating by %(user)s"
+msgstr "puntuado %(score)d por %(user)s"
+
+#: contrib/comments/models.py:258
+#, python-format
msgid ""
-"That e-mail address doesn't have an associated user account. Are you sure "
-"you've registered?"
+"This comment was flagged by %(user)s:\n"
+"\n"
+"%(text)s"
msgstr ""
-"Esa direccin de e-mail no est asociada a ninguna cuenta de usuario. Est "
-"seguro de que ya se ha registrado?"
+"Este comentario fue marcado por %(user)s:\n"
+"\n"
+"%(text)s"
-#: contrib/auth/forms.py:117
-msgid "The two 'new password' fields didn't match."
-msgstr "Los dos campos 'nueva contrasea' no coinciden entre si."
+#: contrib/comments/models.py:265
+msgid "flag date"
+msgstr "fecha de la marca"
-#: contrib/auth/forms.py:124
-msgid "Your old password was entered incorrectly. Please enter it again."
+#: contrib/comments/models.py:268
+msgid "user flag"
+msgstr "marca de usuario"
+
+#: contrib/comments/models.py:269
+msgid "user flags"
+msgstr "marcas de usuario"
+
+#: contrib/comments/models.py:273
+#, python-format
+msgid "Flag by %r"
+msgstr "Marca de %r"
+
+#: contrib/comments/models.py:278
+msgid "deletion date"
+msgstr "fecha de eliminación"
+
+#: contrib/comments/models.py:280
+msgid "moderator deletion"
+msgstr "Eliminación por moderador"
+
+#: contrib/comments/models.py:281
+msgid "moderator deletions"
+msgstr "eliminaciones por moderador"
+
+#: contrib/comments/models.py:285
+#, python-format
+msgid "Moderator deletion by %r"
+msgstr "Eliminación del moderador %r"
+
+#: contrib/comments/views/karma.py:20
+msgid "Anonymous users cannot vote"
+msgstr "Los usuarios anónimos no pueden votar"
+
+#: contrib/comments/views/karma.py:24
+msgid "Invalid comment ID"
+msgstr "ID de comentario no válido"
+
+#: contrib/comments/views/karma.py:26
+msgid "No voting for yourself"
+msgstr "Ud. no puede votarse a sí mismo"
+
+#: contrib/comments/views/comments.py:28
+msgid ""
+"This rating is required because you've entered at least one other rating."
+msgstr "Se precisa esta puntuación porque ha introducido al menos otra más."
+
+#: contrib/comments/views/comments.py:112
+#, python-format
+msgid ""
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comment:\n"
+"\n"
+"%(text)s"
+msgid_plural ""
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comments:\n"
+"\n"
+"%(text)s"
+msgstr[0] ""
+"Este comentario lo envió un usuario que ha enviado menos de %(count)s "
+"comentario:\n"
+"\n"
+"%(text)s"
+msgstr[1] ""
+"Este comentario lo envió un usuario que ha enviado menos de %(count)s "
+"comentarios:\n"
+"\n"
+"%(text)s"
+
+#: contrib/comments/views/comments.py:117
+#, python-format
+msgid ""
+"This comment was posted by a sketchy user:\n"
+"\n"
+"%(text)s"
msgstr ""
-"La antigua contrasea ingresada es incorrecta. Por favor ingrsela "
-"nuevamente."
+"Este comentario ha sido enviado por un usuario 'semi-anónimo':\n"
+"\n"
+"%(text)s"
-#: contrib/auth/views.py:40
-msgid "Logged out"
-msgstr "Sesin cerrada"
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
+msgid "Only POSTs are allowed"
+msgstr "Sólo se admiten POSTs"
+
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
+msgid "One or more of the required fields wasn't submitted"
+msgstr "No se proporcionó uno o más de los siguientes campos requeridos"
+
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
+msgid "Somebody tampered with the comment form (security violation)"
+msgstr ""
+"Alguien está jugando con el formulario de comentarios (violación de "
+"seguridad)"
+
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
+msgid ""
+"The comment form had an invalid 'target' parameter -- the object ID was "
+"invalid"
+msgstr ""
+"El formulario de comentarios tiene un parámetro 'target' no válido (el ID de "
+"objeto era inválido)"
+
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
+msgid "The comment form didn't provide either 'preview' or 'post'"
+msgstr "El formulario de comentario no proporcionó 'previsualizar' ni 'enviar'"
+
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "Su nombre:"
+
+#: contrib/comments/templates/comments/freeform.html:5
+#: contrib/comments/templates/comments/form.html:28
+msgid "Comment:"
+msgstr "Comentario:"
-#: contrib/admin/filterspecs.py:40
+#: contrib/comments/templates/comments/freeform.html:10
+#: contrib/comments/templates/comments/form.html:35
+msgid "Preview comment"
+msgstr "Previsualizar comentario"
+
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:17
+msgid "Username:"
+msgstr "Usuario:"
+
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+msgid "Log out"
+msgstr "Cerrar sesión"
+
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:20
+msgid "Password:"
+msgstr "Contraseña:"
+
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr "Olvidó su contraseña?"
+
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr "Calificaciones"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr "Requerido"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr "Opcional"
+
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr "Enviar una foto"
+
+#: contrib/sites/models.py:15
+msgid "domain name"
+msgstr "nombre de dominio"
+
+#: contrib/sites/models.py:16
+msgid "display name"
+msgstr "nombre para visualizar"
+
+#: contrib/sites/models.py:20
+msgid "site"
+msgstr "sitio"
+
+#: contrib/sites/models.py:21
+msgid "sites"
+msgstr "sitios"
+
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
@@ -588,506 +1150,502 @@ msgstr ""
"<h3>Por %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Todos/as"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Cualquier fecha"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Hoy"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
-msgstr "ltimos 7 das"
+msgstr "Últimos 7 días"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Este mes"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
-msgstr "Este ao"
+msgstr "Este año"
-#: contrib/admin/models.py:16
+#: contrib/admin/models.py:17
msgid "action time"
-msgstr "hora de accin"
+msgstr "hora de acción"
-#: contrib/admin/models.py:19
+#: contrib/admin/models.py:20
msgid "object id"
msgstr "id de objeto"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object repr"
msgstr "repr de objeto"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "action flag"
-msgstr "marca de accin"
+msgstr "marca de acción"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "change message"
msgstr "mensaje de cambio"
-#: contrib/admin/models.py:25
+#: contrib/admin/models.py:26
msgid "log entry"
msgstr "entrada de registro"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entries"
msgstr "entradas de registro"
-#: contrib/admin/views/decorators.py:24
-#: contrib/admin/templates/admin/login.html:25
-msgid "Log in"
-msgstr "Identificarse"
-
-#: contrib/admin/views/decorators.py:62
-msgid ""
-"Please log in again, because your session has expired. Don't worry: Your "
-"submission has been saved."
-msgstr ""
-"Por favor, identifquese de nuevo porque su sesin ha caducado. No se "
-"preocupe: se ha guardado su envo."
-
-#: contrib/admin/views/decorators.py:69
-msgid ""
-"Looks like your browser isn't configured to accept cookies. Please enable "
-"cookies, reload this page, and try again."
-msgstr ""
-"Parece que su navegador no est configurado para aceptar cookies. Actvelas "
-"por favor, recargue esta pgina, e intntelo de nuevo."
-
-#: contrib/admin/views/decorators.py:83
-msgid "Usernames cannot contain the '@' character."
-msgstr "Los nombres de usuario no pueden contener el carcter '@'."
-
-#: contrib/admin/views/decorators.py:85
-#, python-format
-msgid "Your e-mail address is not your username. Try '%s' instead."
-msgstr ""
-"Su direccin de correo no es su nombre de usuario. Intente nuevamente usando "
-"'%s'."
-
-#: contrib/admin/views/auth.py:19 contrib/admin/views/main.py:257
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully."
-msgstr "Se agreg con xito %(name)s \"%(obj)s\"."
-
-#: contrib/admin/views/auth.py:24 contrib/admin/views/main.py:261
-#: contrib/admin/views/main.py:347
-msgid "You may edit it again below."
-msgstr "Puede modificarlo nuevamente abajo."
-
-#: contrib/admin/views/auth.py:30
-msgid "Add user"
-msgstr "Agregar usuario"
-
-#: contrib/admin/views/auth.py:57
-msgid "Password changed successfully."
-msgstr "Cambio de contrasea exitoso"
-
-#: contrib/admin/views/auth.py:64
-#, python-format
-msgid "Change password: %s"
-msgstr "Cambiar contrasea: %s"
-
-#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
msgid "tag:"
msgstr "etiqueta:"
-#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
msgid "filter:"
msgstr "filtrar:"
-#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
msgid "view:"
msgstr "ver:"
-#: contrib/admin/views/doc.py:164
+#: contrib/admin/views/doc.py:165
#, python-format
msgid "App %r not found"
-msgstr "Aplicacin %r no encontrada"
+msgstr "Aplicación %r no encontrada"
-#: contrib/admin/views/doc.py:171
+#: contrib/admin/views/doc.py:172
#, python-format
msgid "Model %(name)r not found in app %(label)r"
-msgstr "Modelo %(name)r no encontrado en aplicacin %(label)r"
+msgstr "Modelo %(name)r no encontrado en aplicación %(label)r"
-#: contrib/admin/views/doc.py:183
+#: contrib/admin/views/doc.py:184
#, python-format
msgid "the related `%(label)s.%(type)s` object"
-msgstr "el objeto relacionado `%(label)s%(type)s`"
+msgstr "el objeto `%(label)s.%(type)s` relacionado"
-#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
-#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
msgid "model:"
msgstr "modelo:"
-#: contrib/admin/views/doc.py:214
+#: contrib/admin/views/doc.py:215
#, python-format
msgid "related `%(label)s.%(name)s` objects"
-msgstr "objetos relacionados `%(label)s.%(name)s`"
+msgstr "objetos `%(label)s.%(name)s` relacionados"
-#: contrib/admin/views/doc.py:219
+#: contrib/admin/views/doc.py:220
#, python-format
msgid "all %s"
-msgstr "todos %s"
+msgstr "todos los %s"
-#: contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:225
#, python-format
msgid "number of %s"
-msgstr "nmero de %s"
+msgstr "número de %s"
-#: contrib/admin/views/doc.py:229
+#: contrib/admin/views/doc.py:230
#, python-format
msgid "Fields on %s objects"
-msgstr "Campos en %s objetos"
+msgstr "Campos en objetos %s"
-#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301
-#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309
-#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
msgid "Integer"
msgstr "Entero"
-#: contrib/admin/views/doc.py:292
+#: contrib/admin/views/doc.py:293
msgid "Boolean (Either True or False)"
msgstr "Booleano (Verdadero o Falso)"
-#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
#, python-format
msgid "String (up to %(maxlength)s)"
-msgstr "Cadena (mximo %(maxlength)s)"
+msgstr "Cadena (máximo %(maxlength)s)"
-#: contrib/admin/views/doc.py:294
+#: contrib/admin/views/doc.py:295
msgid "Comma-separated integers"
msgstr "Enteros separados por comas"
-#: contrib/admin/views/doc.py:295
+#: contrib/admin/views/doc.py:296
msgid "Date (without time)"
msgstr "Fecha (sin hora)"
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:297
msgid "Date (with time)"
msgstr "Fecha (con hora)"
-#: contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:298
+msgid "Decimal number"
+msgstr "Número decimal"
+
+#: contrib/admin/views/doc.py:299
msgid "E-mail address"
-msgstr "Direccin de correo electrnico"
+msgstr "Dirección de correo electrónico"
-#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299
-#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
msgid "File path"
msgstr "Ruta de archivo"
-#: contrib/admin/views/doc.py:300
-msgid "Decimal number"
-msgstr "Nmero decimal"
-
-#: contrib/admin/views/doc.py:304 contrib/comments/models.py:85
-msgid "IP address"
-msgstr "Direccin IP"
+#: contrib/admin/views/doc.py:302
+msgid "Floating point number"
+msgstr "Número de punto flotante"
-#: contrib/admin/views/doc.py:306
+#: contrib/admin/views/doc.py:308
msgid "Boolean (Either True, False or None)"
msgstr "Booleano (Verdadero, Falso o Nulo)"
-#: contrib/admin/views/doc.py:307
+#: contrib/admin/views/doc.py:309
msgid "Relation to parent model"
-msgstr "Relacin con el modelo padre"
+msgstr "Relación con el modelo padre"
-#: contrib/admin/views/doc.py:308
+#: contrib/admin/views/doc.py:310
msgid "Phone number"
-msgstr "Nmero de telfono"
+msgstr "Número de teléfono"
-#: contrib/admin/views/doc.py:313
+#: contrib/admin/views/doc.py:315
msgid "Text"
msgstr "Texto"
-#: contrib/admin/views/doc.py:314
+#: contrib/admin/views/doc.py:316
msgid "Time"
msgstr "Hora"
-#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
-#: contrib/admin/views/doc.py:316
+#: contrib/admin/views/doc.py:318
msgid "U.S. state (two uppercase letters)"
-msgstr "Estado de los EE.UU. (dos letras maysculas)"
+msgstr "Estado de los EE.UU. (dos letras mayúsculas)"
-#: contrib/admin/views/doc.py:317
+#: contrib/admin/views/doc.py:319
msgid "XML text"
msgstr "Texto XML"
-#: contrib/admin/views/doc.py:343
+#: contrib/admin/views/doc.py:345
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s no parece ser un objeto urlpattern"
-#: contrib/admin/views/main.py:223
+#: contrib/admin/views/decorators.py:24
+#: contrib/admin/templates/admin/login.html:25
+msgid "Log in"
+msgstr "Identificarse"
+
+#: contrib/admin/views/decorators.py:62
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+"Por favor, identifíquese de nuevo porque su sesión ha caducado. No se "
+"preocupe: se ha guardado su envío."
+
+#: contrib/admin/views/decorators.py:69
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr ""
+"Parece que su navegador no está configurado para aceptar cookies. Actívelas "
+"por favor, recargue esta página, e inténtelo de nuevo."
+
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr "Los nombres de usuario no pueden contener el carácter '@'."
+
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr ""
+"Su dirección de correo no es su nombre de usuario. Intente nuevamente usando "
+"'%s'."
+
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully."
+msgstr "Se agregó con éxito %(name)s \"%(obj)s\"."
+
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
+#: contrib/admin/views/main.py:354
+msgid "You may edit it again below."
+msgstr "Puede modificarlo nuevamente abajo."
+
+#: contrib/admin/views/auth.py:31
+msgid "Add user"
+msgstr "Agregar usuario"
+
+#: contrib/admin/views/auth.py:58
+msgid "Password changed successfully."
+msgstr "Cambio de contraseña exitoso"
+
+#: contrib/admin/views/auth.py:65
+#, python-format
+msgid "Change password: %s"
+msgstr "Cambiar contraseña: %s"
+
+#: contrib/admin/views/main.py:230
msgid "Site administration"
-msgstr "Sitio administrativo"
+msgstr "Administración de sitio"
-#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
#, python-format
msgid "You may add another %s below."
msgstr "Puede agregar otro %s abajo."
-#: contrib/admin/views/main.py:289
+#: contrib/admin/views/main.py:296
#, python-format
msgid "Add %s"
msgstr "Agregar %s"
-#: contrib/admin/views/main.py:335
+#: contrib/admin/views/main.py:342
#, python-format
msgid "Added %s."
msgstr "Agregado %s."
-#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337
-#: contrib/admin/views/main.py:339 db/models/manipulators.py:308
-msgid "and"
-msgstr "y"
-
-#: contrib/admin/views/main.py:337
+#: contrib/admin/views/main.py:344
#, python-format
msgid "Changed %s."
msgstr "Modifica %s."
-#: contrib/admin/views/main.py:339
+#: contrib/admin/views/main.py:346
#, python-format
msgid "Deleted %s."
msgstr "Elimina %s."
-#: contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:349
msgid "No fields changed."
-msgstr "No ha modificado ningn campo."
+msgstr "No ha modificado ningún campo."
-#: contrib/admin/views/main.py:345
+#: contrib/admin/views/main.py:352
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
-msgstr "Se modific con xito %(name)s \"%(obj)s\"."
+msgstr "Se modificó con éxito %(name)s \"%(obj)s\"."
-#: contrib/admin/views/main.py:353
+#: contrib/admin/views/main.py:360
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr ""
-"Se agreg con xito %(name)s \"%(obj)s\". Puede modificarlo nuevamente abajo."
+"Se agregó con éxito %(name)s \"%(obj)s\". Puede modificarlo nuevamente abajo."
-#: contrib/admin/views/main.py:391
+#: contrib/admin/views/main.py:398
#, python-format
msgid "Change %s"
msgstr "Modificar %s"
-#: contrib/admin/views/main.py:476
+#: contrib/admin/views/main.py:483
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
-msgstr "Uno o ms %(fieldname)s en %(name)s: %(obj)s"
+msgstr "Uno o más %(fieldname)s en %(name)s: %(obj)s"
-#: contrib/admin/views/main.py:481
+#: contrib/admin/views/main.py:488
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
-msgstr "Uno o ms %(fieldname)s en %(name)s:"
+msgstr "Uno o más %(fieldname)s en %(name)s:"
-#: contrib/admin/views/main.py:514
+#: contrib/admin/views/main.py:520
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
-msgstr "Se elimin con xito %(name)s \"%(obj)s\"."
+msgstr "Se eliminó con éxito %(name)s \"%(obj)s\"."
-#: contrib/admin/views/main.py:517
+#: contrib/admin/views/main.py:523
msgid "Are you sure?"
-msgstr "Est seguro?"
+msgstr "¿Está seguro?"
-#: contrib/admin/views/main.py:539
+#: contrib/admin/views/main.py:545
#, python-format
msgid "Change history: %s"
msgstr "Historia de modificaciones: %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s"
msgstr "Seleccione %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s to change"
msgstr "Seleccione %s a modificar"
-#: contrib/admin/views/main.py:768
+#: contrib/admin/views/main.py:780
msgid "Database error"
msgstr "Error de base de datos"
-#: contrib/admin/templatetags/admin_list.py:247
-msgid "All dates"
-msgstr "Todas las fechas"
-
-#: contrib/admin/templates/widget/date_time.html:3
-msgid "Date:"
-msgstr "Fecha:"
-
-#: contrib/admin/templates/widget/date_time.html:4
-msgid "Time:"
-msgstr "Hora:"
-
-#: contrib/admin/templates/widget/file.html:2
-msgid "Currently:"
-msgstr "Actualmente"
-
-#: contrib/admin/templates/widget/file.html:3
-msgid "Change:"
-msgstr "Modificar:"
-
-#: contrib/admin/templates/admin/index.html:17
-#, python-format
-msgid "Models available in the %(name)s application."
-msgstr "Modelos disponibles en la aplicacin %(name)s."
-
-#: contrib/admin/templates/admin/index.html:18
-#, python-format
-msgid "%(name)s"
-msgstr "%(name)s"
-
-#: contrib/admin/templates/admin/index.html:28
-#: contrib/admin/templates/admin/change_form.html:15
-msgid "Add"
-msgstr "Agregar"
-
-#: contrib/admin/templates/admin/index.html:34
-msgid "Change"
-msgstr "Modificar"
-
-#: contrib/admin/templates/admin/index.html:44
-msgid "You don't have permission to edit anything."
-msgstr "No tiene permiso para editar nada."
-
-#: contrib/admin/templates/admin/index.html:52
-msgid "Recent Actions"
-msgstr "Acciones recientes"
-
-#: contrib/admin/templates/admin/index.html:53
-msgid "My Actions"
-msgstr "Mis acciones"
-
-#: contrib/admin/templates/admin/index.html:57
-msgid "None available"
-msgstr "Ninguna disponible"
-
-#: contrib/admin/templates/admin/filters.html:4
-msgid "Filter"
-msgstr "Filtrar"
-
-#: contrib/admin/templates/admin/search_form.html:8
-msgid "Go"
-msgstr "Buscar"
-
-#: contrib/admin/templates/admin/search_form.html:10
-#, python-format
-msgid "1 result"
-msgid_plural "%(counter)s results"
-msgstr[0] "un resultado"
-msgstr[1] "%(counter)s resultados"
-
-#: contrib/admin/templates/admin/search_form.html:10
-#, python-format
-msgid "%(full_result_count)s total"
-msgstr "total: %(full_result_count)s"
-
-#: contrib/admin/templates/admin/filter.html:2
-#, python-format
-msgid " By %(filter_title)s "
-msgstr " Por %(filter_title)s "
-
-#: contrib/admin/templates/admin/pagination.html:10
-msgid "Show all"
-msgstr "Mostrar todos/as"
-
-#: contrib/admin/templates/admin/change_form.html:10
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Documentation"
-msgstr "Documentacin"
+msgstr "Documentación"
-#: contrib/admin/templates/admin/change_form.html:10
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin/auth/user/change_password.html:15
#: contrib/admin/templates/admin/auth/user/change_password.html:46
-#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-msgid "Change password"
-msgstr "Cambiar contrasea"
-
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:25
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/auth/user/change_password.html:9
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_detail.html:3
#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/model_index.html:5
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/view_index.html:5
#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/comments/templates/comments/form.html:6
-msgid "Log out"
-msgstr "Cerrar sesin"
+msgid "Change password"
+msgstr "Cambiar contraseña"
-#: contrib/admin/templates/admin/change_form.html:13
#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/base.html:30
#: contrib/admin/templates/admin/object_history.html:5
#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/base.html:30
#: contrib/admin/templates/admin/delete_confirmation.html:6
#: contrib/admin/templates/admin/invalid_setup.html:4
#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/registration/logged_out.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_reset_done.html:4
#: contrib/admin/templates/registration/password_change_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
-#: contrib/admin/templates/registration/password_reset_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/logged_out.html:4
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Home"
msgstr "Inicio"
-#: contrib/admin/templates/admin/change_form.html:21
+#: contrib/admin/templates/admin/change_list.html:12
+#, python-format
+msgid "Add %(name)s"
+msgstr "Agregar %(name)s"
+
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr "Página no encontrada"
+
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr "Lo sentimos, pero no se encuentra la página solicitada."
+
#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/change_form.html:21
msgid "History"
msgstr "Historia"
+#: contrib/admin/templates/admin/object_history.html:18
+msgid "Date/time"
+msgstr "Fecha/hora"
+
+#: contrib/admin/templates/admin/object_history.html:19
+msgid "User"
+msgstr "Usuario"
+
+#: contrib/admin/templates/admin/object_history.html:20
+msgid "Action"
+msgstr "Acción"
+
+#: contrib/admin/templates/admin/object_history.html:26
+msgid "DATE_WITH_TIME_FULL"
+msgstr "j M Y P"
+
+#: contrib/admin/templates/admin/object_history.html:36
+msgid ""
+"This object doesn't have a change history. It probably wasn't added via this "
+"admin site."
+msgstr ""
+"Este objeto no tiene historia de modificaciones. Probablemente no fué "
+"añadido usando este sitio de administración."
+
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "Error del servidor"
+
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr "Error del servidor (500)"
+
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr "Error de servidor <em>(500)</em>"
+
+#: contrib/admin/templates/admin/500.html:10
+msgid ""
+"There's been an error. It's been reported to the site administrators via e-"
+"mail and should be fixed shortly. Thanks for your patience."
+msgstr ""
+"Ha ocurrido un error. Se ha informado a los administradores del sitio "
+"mediante correo electrónico y debería ser solucionado en breve. Gracias por "
+"su paciencia."
+
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr "Sitio de administración de Django"
+
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr "Administración de Django"
+
+#: contrib/admin/templates/admin/filter.html:2
+#, python-format
+msgid " By %(filter_title)s "
+msgstr " Por %(filter_title)s "
+
+#: contrib/admin/templates/admin/index.html:17
+#, python-format
+msgid "Models available in the %(name)s application."
+msgstr "Modelos disponibles en la aplicación %(name)s."
+
+#: contrib/admin/templates/admin/index.html:18
+#, python-format
+msgid "%(name)s"
+msgstr "%(name)s"
+
+#: contrib/admin/templates/admin/index.html:28
+#: contrib/admin/templates/admin/change_form.html:15
+msgid "Add"
+msgstr "Agregar"
+
+#: contrib/admin/templates/admin/index.html:34
+msgid "Change"
+msgstr "Modificar"
+
+#: contrib/admin/templates/admin/index.html:44
+msgid "You don't have permission to edit anything."
+msgstr "No tiene permiso para editar nada."
+
+#: contrib/admin/templates/admin/index.html:52
+msgid "Recent Actions"
+msgstr "Acciones recientes"
+
+#: contrib/admin/templates/admin/index.html:53
+msgid "My Actions"
+msgstr "Mis acciones"
+
+#: contrib/admin/templates/admin/index.html:57
+msgid "None available"
+msgstr "Ninguna disponible"
+
#: contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
msgstr "Ver en el sitio"
@@ -1101,44 +1659,15 @@ msgstr[1] "Por favor, corrija los siguientes errores."
#: contrib/admin/templates/admin/change_form.html:50
msgid "Ordering"
-msgstr "Ordenacin"
+msgstr "Ordenación"
#: contrib/admin/templates/admin/change_form.html:53
msgid "Order:"
msgstr "Orden:"
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
-msgid "Page not found"
-msgstr "Pgina no encontrada"
-
-#: contrib/admin/templates/admin/404.html:10
-msgid "We're sorry, but the requested page could not be found."
-msgstr "Lo sentimos, pero no se encuentra la pgina solicitada."
-
-#: contrib/admin/templates/admin/base_site.html:4
-msgid "Django site admin"
-msgstr "Sitio de administracin de Django"
-
-#: contrib/admin/templates/admin/base_site.html:7
-msgid "Django administration"
-msgstr "Administracin de Django"
-
-#: contrib/admin/templates/admin/change_list.html:12
-#, python-format
-msgid "Add %(name)s"
-msgstr "Agregar %(name)s"
-
-#: contrib/admin/templates/admin/login.html:17
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
-msgid "Username:"
-msgstr "Usuario:"
-
-#: contrib/admin/templates/admin/login.html:20
-#: contrib/comments/templates/comments/form.html:8
-msgid "Password:"
-msgstr "Contrasea:"
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Mostrar todos/as"
#: contrib/admin/templates/admin/base.html:25
msgid "Welcome,"
@@ -1155,7 +1684,7 @@ msgstr "Grabar como nuevo"
#: contrib/admin/templates/admin/submit_line.html:5
msgid "Save and add another"
-msgstr "Grabar y aadir otro"
+msgstr "Grabar y añadir otro"
#: contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing"
@@ -1165,50 +1694,25 @@ msgstr "Grabar y continuar editando"
msgid "Save"
msgstr "Grabar"
-#: contrib/admin/templates/admin/object_history.html:18
-msgid "Date/time"
-msgstr "Fecha/hora"
-
-#: contrib/admin/templates/admin/object_history.html:19
-msgid "User"
-msgstr "Usuario"
-
-#: contrib/admin/templates/admin/object_history.html:20
-msgid "Action"
-msgstr "Accin"
-
-#: contrib/admin/templates/admin/object_history.html:26
-msgid "DATE_WITH_TIME_FULL"
-msgstr "j M Y P"
-
-#: contrib/admin/templates/admin/object_history.html:36
-msgid ""
-"This object doesn't have a change history. It probably wasn't added via this "
-"admin site."
-msgstr ""
-"Este objeto no tiene historia de modificaciones. Probablemente no fu "
-"aadido usando este sitio de administracin."
-
-#: contrib/admin/templates/admin/500.html:4
-msgid "Server error"
-msgstr "Error del servidor"
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr "Buscar"
-#: contrib/admin/templates/admin/500.html:6
-msgid "Server error (500)"
-msgstr "Error del servidor (500)"
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "un resultado"
+msgstr[1] "%(counter)s resultados"
-#: contrib/admin/templates/admin/500.html:9
-msgid "Server Error <em>(500)</em>"
-msgstr "Error de servidor <em>(500)</em>"
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr "total: %(full_result_count)s"
-#: contrib/admin/templates/admin/500.html:10
-msgid ""
-"There's been an error. It's been reported to the site administrators via e-"
-"mail and should be fixed shortly. Thanks for your patience."
-msgstr ""
-"Ha ocurrido un error. Se ha informado a los administradores del sitio "
-"mediante correo electrnico y debera ser solucionado en breve. Gracias por "
-"su paciencia."
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filtrar"
#: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format
@@ -1217,7 +1721,7 @@ msgid ""
"related objects, but your account doesn't have permission to delete the "
"following types of objects:"
msgstr ""
-"Eliminar el %(object_name)s '%(escaped_object)s' provocara la eliminacin "
+"Eliminar el %(object_name)s '%(escaped_object)s' provocaría la eliminación "
"de objetos relacionados, pero su cuenta no tiene permiso para eliminar los "
"siguientes tipos de objetos:"
@@ -1227,12 +1731,12 @@ msgid ""
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
"All of the following related items will be deleted:"
msgstr ""
-"Est seguro de que quiere eliminar los %(object_name)s \"%(escaped_object)s"
-"\"? Se eliminarn los siguientes objetos relacionados:"
+"¿Está seguro de que quiere eliminar los %(object_name)s \"%(escaped_object)s"
+"\"? Se eliminarán los siguientes objetos relacionados:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
-msgstr "S, estoy seguro"
+msgstr "Sí, estoy seguro"
#: contrib/admin/templates/admin/invalid_setup.html:8
msgid ""
@@ -1240,125 +1744,124 @@ msgid ""
"database tables have been created, and make sure the database is readable by "
"the appropriate user."
msgstr ""
-"Hay algn problema con su instalacin de base de datos. Asegrese de que las "
-"tablas de la misma hayan sido creadas, y asegrese de que el usuario "
+"Hay algún problema con su instalación de base de datos. Asegúrese de que las "
+"tablas de la misma hayan sido creadas, y asegúrese de que el usuario "
"apropiado tenga permisos de lectura en la base de datos."
#: contrib/admin/templates/admin/auth/user/change_password.html:28
#, python-format
msgid "Enter a new password for the user <strong>%(username)s</strong>."
msgstr ""
-"Introduzca una nueva contrasea para el usuario <strong>%(username)s</"
+"Introduzca una nueva contraseña para el usuario <strong>%(username)s</"
"strong>."
#: contrib/admin/templates/admin/auth/user/change_password.html:34
#: contrib/admin/templates/admin/auth/user/add_form.html:18
msgid "Password"
-msgstr "Contrasea:"
+msgstr "Contraseña:"
#: contrib/admin/templates/admin/auth/user/change_password.html:39
#: contrib/admin/templates/admin/auth/user/add_form.html:23
msgid "Password (again)"
-msgstr "Contrasea (de nuevo)"
+msgstr "Contraseña (de nuevo)"
#: contrib/admin/templates/admin/auth/user/change_password.html:40
#: contrib/admin/templates/admin/auth/user/add_form.html:24
msgid "Enter the same password as above, for verification."
-msgstr "Para verificacin, introduzca la misma contrasea que ingres arriba."
+msgstr "Para verificación, introduzca la misma contraseña que ingresó arriba."
#: contrib/admin/templates/admin/auth/user/add_form.html:6
msgid ""
"First, enter a username and password. Then, you'll be able to edit more user "
"options."
msgstr ""
-"Primero, introduzca un nombre de usuario y una contrasea. Luego podr "
+"Primero, introduzca un nombre de usuario y una contraseña. Luego podrá "
"configurar opciones adicionales."
#: contrib/admin/templates/admin/auth/user/add_form.html:12
msgid "Username"
msgstr "Nombre de usuario:"
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_form.html:6
-#: contrib/admin/templates/registration/password_change_form.html:10
-msgid "Password change"
-msgstr "Cambio de contrasea"
-
-#: contrib/admin/templates/registration/password_change_done.html:6
-#: contrib/admin/templates/registration/password_change_done.html:10
-msgid "Password change successful"
-msgstr "Cambio de contrasea exitoso"
-
-#: contrib/admin/templates/registration/password_change_done.html:12
-msgid "Your password was changed."
-msgstr "Su contrasea ha sido cambiada."
+#: contrib/admin/templates/widget/file.html:2
+msgid "Currently:"
+msgstr "Actualmente"
-#: contrib/admin/templates/registration/password_reset_form.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:6
-#: contrib/admin/templates/registration/password_reset_form.html:10
-#: contrib/admin/templates/registration/password_reset_done.html:4
-msgid "Password reset"
-msgstr "Recuperar contrasea"
+#: contrib/admin/templates/widget/file.html:3
+msgid "Change:"
+msgstr "Modificar:"
-#: contrib/admin/templates/registration/password_reset_form.html:12
-msgid ""
-"Forgotten your password? Enter your e-mail address below, and we'll reset "
-"your password and e-mail the new one to you."
-msgstr ""
-"Ha olvidado su contrasea? Introduzca su direccin de correo electrnico, y "
-"crearemos una nueva que le enviaremos por correo."
+#: contrib/admin/templates/widget/date_time.html:3
+msgid "Date:"
+msgstr "Fecha:"
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "E-mail address:"
-msgstr "Direccin de correo electrnico:"
+#: contrib/admin/templates/widget/date_time.html:4
+msgid "Time:"
+msgstr "Hora:"
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "Reset my password"
-msgstr "Recuperar mi contrasea"
+#: contrib/admin/templates/registration/logged_out.html:8
+msgid "Thanks for spending some quality time with the Web site today."
+msgstr "Gracias por el tiempo que ha dedicado al sitio web hoy."
-#: contrib/admin/templates/registration/password_reset_done.html:6
-#: contrib/admin/templates/registration/password_reset_done.html:10
-msgid "Password reset successful"
-msgstr "Recuperacin de contrasea exitosa"
+#: contrib/admin/templates/registration/logged_out.html:10
+msgid "Log in again"
+msgstr "Identificarse de nuevo"
-#: contrib/admin/templates/registration/password_reset_done.html:12
-msgid ""
-"We've e-mailed a new password to the e-mail address you submitted. You "
-"should be receiving it shortly."
-msgstr ""
-"Le hemos enviado una nueva contrasea a la direccin que ha suministrado. "
-"Debera recibirla en breve."
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+#: contrib/admin/templates/registration/password_change_done.html:4
+msgid "Password change"
+msgstr "Cambio de contraseña"
#: contrib/admin/templates/registration/password_change_form.html:12
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
-"Por favor, por razones de seguridad, introduzca su contrasea antigua, y "
-"luego introduzca la nueva contrasea dos veces para verificar que la ha "
+"Por favor, por razones de seguridad, introduzca su contraseña antigua, y "
+"luego introduzca la nueva contraseña dos veces para verificar que la ha "
"escrito correctamente."
#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
-msgstr "Contrasea antigua:"
+msgstr "Contraseña antigua:"
#: contrib/admin/templates/registration/password_change_form.html:19
msgid "New password:"
-msgstr "Contrasea nueva:"
+msgstr "Contraseña nueva:"
#: contrib/admin/templates/registration/password_change_form.html:21
msgid "Confirm password:"
-msgstr "Confirme contrasea:"
+msgstr "Confirme contraseña:"
#: contrib/admin/templates/registration/password_change_form.html:23
msgid "Change my password"
-msgstr "Cambiar mi contrasea"
+msgstr "Cambiar mi contraseña"
+
+#: contrib/admin/templates/registration/password_reset_done.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:6
+#: contrib/admin/templates/registration/password_reset_form.html:10
+msgid "Password reset"
+msgstr "Recuperar contraseña"
+
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr "Recuperación de contraseña exitosa"
+
+#: contrib/admin/templates/registration/password_reset_done.html:12
+msgid ""
+"We've e-mailed a new password to the e-mail address you submitted. You "
+"should be receiving it shortly."
+msgstr ""
+"Le hemos enviado una nueva contraseña a la dirección que ha suministrado. "
+"Debería recibirla en breve."
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
msgstr ""
-"Est recibiendo este mensaje debido a que solicit recuperar la contrasea"
+"Está recibiendo este mensaje debido a que solicitó recuperar la contraseña"
#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
@@ -1368,11 +1871,11 @@ msgstr "de su cuenta de usuario en %(site_name)s."
#: contrib/admin/templates/registration/password_reset_email.html:5
#, python-format
msgid "Your new password is: %(new_password)s"
-msgstr "Su nueva contrasea es: %(new_password)s"
+msgstr "Su nueva contraseña es: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
-msgstr "Puede cambiarla accediendo a esta pgina:"
+msgstr "Puede cambiarla accediendo a esta página:"
#: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:"
@@ -1380,20 +1883,37 @@ msgstr "Su nombre de usuario, en caso de haberlo olvidado:"
#: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!"
-msgstr "Gracias por usar nuestro sitio!"
+msgstr "¡Gracias por usar nuestro sitio!"
#: contrib/admin/templates/registration/password_reset_email.html:15
#, python-format
msgid "The %(site_name)s team"
msgstr "El equipo de %(site_name)s"
-#: contrib/admin/templates/registration/logged_out.html:8
-msgid "Thanks for spending some quality time with the Web site today."
-msgstr "Gracias por el tiempo que ha dedicado al sitio web hoy."
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr "Cambio de contraseña exitoso"
-#: contrib/admin/templates/registration/logged_out.html:10
-msgid "Log in again"
-msgstr "Identificarse de nuevo"
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr "Su contraseña ha sido cambiada."
+
+#: contrib/admin/templates/registration/password_reset_form.html:12
+msgid ""
+"Forgotten your password? Enter your e-mail address below, and we'll reset "
+"your password and e-mail the new one to you."
+msgstr ""
+"¿Ha olvidado su contraseña? Introduzca su dirección de correo electrónico, y "
+"crearemos una nueva que le enviaremos por correo."
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "E-mail address:"
+msgstr "Dirección de correo electrónico:"
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "Reset my password"
+msgstr "Recuperar mi contraseña"
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets"
@@ -1401,7 +1921,7 @@ msgstr "Bookmarklets"
#: contrib/admin/templates/admin_doc/bookmarklets.html:5
msgid "Documentation bookmarklets"
-msgstr "Bookmarklets de documentacin"
+msgstr "Bookmarklets de documentación"
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
msgid ""
@@ -1415,24 +1935,24 @@ msgid ""
msgstr ""
"\n"
"<p class=\"help\">Para instalar bookmarklets, arrastre el enlace a su barra\n"
-"de favoritos, o pulse con el botn derecho el enlace y adalo a sus "
+"de favoritos, o pulse con el botón derecho el enlace y añádalo a sus "
"favoritos.\n"
-"Ahora puede seleccionar el bookmarklet desde cualquier pgina en el sitio.\n"
-"Tenga en cuenta que algunos de estos bookmarklets precisan que est viendo\n"
-"el sitio desde un equipo sealado como \"interno\" (hable\n"
-"con su administrador de sistemas si no est seguro de si el suyo lo es).</"
+"Ahora puede seleccionar el bookmarklet desde cualquier página en el sitio.\n"
+"Tenga en cuenta que algunos de estos bookmarklets precisan que esté viendo\n"
+"el sitio desde un equipo señalado como \"interno\" (hable\n"
+"con su administrador de sistemas si no está seguro de si el suyo lo es).</"
"p>\n"
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
msgid "Documentation for this page"
-msgstr "Documentacin de esta pgina"
+msgstr "Documentación de esta página"
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
msgid ""
"Jumps you from any page to the documentation for the view that generates "
"that page."
msgstr ""
-"Le lleva desde cualquier pgina a la documentacin de la vista que la genera."
+"Le lleva desde cualquier página a la documentación de la vista que la genera."
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
msgid "Show object ID"
@@ -1443,8 +1963,8 @@ msgid ""
"Shows the content-type and unique ID for pages that represent a single "
"object."
msgstr ""
-"Muestra el tipo de contenido e ID unvoco de las pginas que representan un "
-"nico objeto."
+"Muestra el tipo de contenido e ID unívoco de las páginas que representan un "
+"único objeto."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)"
@@ -1453,7 +1973,7 @@ msgstr "Editar este objeto (ventana actual)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object."
msgstr ""
-"Le lleva a la pgina de administracin de pginas que representan un nico "
+"Le lleva a la página de administración de páginas que representan un único "
"objeto."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
@@ -1463,110 +1983,273 @@ msgstr "Editar este objeto (nueva ventana)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
msgid "As above, but opens the admin page in a new window."
msgstr ""
-"Como antes, pero abre la pgina de administracin en una nueva ventana."
+"Como antes, pero abre la página de administración en una nueva ventana."
-#: contrib/sites/models.py:10
-msgid "domain name"
-msgstr "nombre de dominio"
+#: contrib/admin/templatetags/admin_list.py:254
+msgid "All dates"
+msgstr "Todas las fechas"
-#: contrib/sites/models.py:11
-msgid "display name"
-msgstr "nombre para visualizar"
+#: contrib/localflavor/is_/forms.py:17
+msgid ""
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr ""
+"Introduzca un número de identificación islandés válido. El formato es XXXXXX-"
+"XXXX."
-#: contrib/sites/models.py:15
-msgid "site"
-msgstr "sitio"
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr "El número de identificación islandés no es válido."
-#: contrib/sites/models.py:16
-msgid "sites"
-msgstr "sitios"
+#: contrib/localflavor/fi/forms.py:14 contrib/localflavor/de/forms.py:16
+#: contrib/localflavor/fr/forms.py:17
+msgid "Enter a zip code in the format XXXXX."
+msgstr "Introduzca un zip code en formato XXXXX."
-#: contrib/sessions/models.py:68
-msgid "session key"
-msgstr "clave de sesin"
+#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
+msgid "Enter a valid Finnish social security number."
+msgstr "Introduzca un número de seguridad social finlandés válido."
-#: contrib/sessions/models.py:69
-msgid "session data"
-msgstr "datos de sesin"
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr "Introduzca un zip code en formato XXXXX-XXX."
-#: contrib/sessions/models.py:70
-msgid "expire date"
-msgstr "fecha de caducidad"
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr "Los números telefónicos deben respetar el formato XX-XXXX-XXXX."
-#: contrib/sessions/models.py:74
-msgid "session"
-msgstr "sesin"
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr "Este campo permite sólo valores numéricos."
-#: contrib/sessions/models.py:75
-msgid "sessions"
-msgstr "sesiones"
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr "Este campo requiere como máximo 11 dígitos o 14 caracteres."
-#: contrib/contenttypes/models.py:36
-msgid "python model class name"
-msgstr "nombre de la clase python del modelo"
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr "Número CPF inválido."
-#: contrib/contenttypes/models.py:39
-msgid "content type"
-msgstr "tipo de contenido"
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr "Este campo requiere al menos 14 dígitos."
-#: contrib/contenttypes/models.py:40
-msgid "content types"
-msgstr "tipos de contenido"
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr "Número CNPJ inválido."
-#: contrib/flatpages/models.py:8
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Introduzca un zip code válido."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Introduzca un número de Seguridad Social válido."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Introduzca un número VAT válido."
+
+#: contrib/localflavor/de/de_states.py:5
+msgid "Baden-Wuerttemberg"
+msgstr "Baden-Wuerttemberg"
+
+#: contrib/localflavor/de/de_states.py:6
+msgid "Bavaria"
+msgstr "Bavaria"
+
+#: contrib/localflavor/de/de_states.py:7
+msgid "Berlin"
+msgstr "Berlin"
+
+#: contrib/localflavor/de/de_states.py:8
+msgid "Brandenburg"
+msgstr "Brandenburg"
+
+#: contrib/localflavor/de/de_states.py:9
+msgid "Bremen"
+msgstr "Bremen"
+
+#: contrib/localflavor/de/de_states.py:10
+msgid "Hamburg"
+msgstr "Hamburg"
+
+#: contrib/localflavor/de/de_states.py:11
+msgid "Hessen"
+msgstr "Hessen"
+
+#: contrib/localflavor/de/de_states.py:12
+msgid "Mecklenburg-Western Pomerania"
+msgstr "Mecklenburg-Western Pomerania"
+
+#: contrib/localflavor/de/de_states.py:13
+msgid "Lower Saxony"
+msgstr "Lower Saxony"
+
+#: contrib/localflavor/de/de_states.py:14
+msgid "North Rhine-Westphalia"
+msgstr "North Rhine-Westphalia"
+
+#: contrib/localflavor/de/de_states.py:15
+msgid "Rhineland-Palatinate"
+msgstr "Rhineland-Palatinate"
+
+#: contrib/localflavor/de/de_states.py:16
+msgid "Saarland"
+msgstr "Saarland"
+
+#: contrib/localflavor/de/de_states.py:17
+msgid "Saxony"
+msgstr "Saxony"
+
+#: contrib/localflavor/de/de_states.py:18
+msgid "Saxony-Anhalt"
+msgstr "Saxony-Anhalt"
+
+#: contrib/localflavor/de/de_states.py:19
+msgid "Schleswig-Holstein"
+msgstr "Schleswig-Holstein"
+
+#: contrib/localflavor/de/de_states.py:20
+msgid "Thuringia"
+msgstr "Thuringia"
+
+#: contrib/localflavor/de/forms.py:60
msgid ""
-"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
+"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
+"format."
msgstr ""
-"Ejemplo: '/about/contact/'. Asegrese de que pone barras al principio y al "
-"final."
+"Introduzca un número de tarjeta de identidad alemán válido en formato "
+"XXXXXXXXXXX-XXXXXXX-XXXXXXX-X."
-#: contrib/flatpages/models.py:9
-msgid "title"
-msgstr "ttulo"
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr ""
+"Introduzca un postcode. Se requiere un espacio entre las dos secciones del "
+"mismo."
-#: contrib/flatpages/models.py:10
-msgid "content"
-msgstr "contenido"
+#: contrib/localflavor/cl/forms.py:32
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Introduzca un RUT chileno válido. EL formato es XX.XXX.XXX-X."
-#: contrib/flatpages/models.py:11
-msgid "enable comments"
-msgstr "activar comentarios"
+#: contrib/localflavor/cl/forms.py:37
+msgid "Enter valid a Chilean RUT"
+msgstr "Introduzca un RUT chileno válido."
-#: contrib/flatpages/models.py:12
-msgid "template name"
-msgstr "nombre de plantilla"
+#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:14
+msgid "Enter a zip code in the format XXXX."
+msgstr "Introduzca un zip code en formato XXX."
-#: contrib/flatpages/models.py:13
+#: contrib/localflavor/ch/forms.py:90
msgid ""
-"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
-"will use 'flatpages/default.html'."
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
msgstr ""
-"Ejemplo: 'flatpages/contact_page.html'. Si no lo proporciona, el sistema "
-"usar 'flatpages/default.html'."
+"Introduzca un número válido de tarjeta de identidad o pasaporte Suizos en "
+"formato X1234567<0 o 1234567890."
-#: contrib/flatpages/models.py:14
-msgid "registration required"
-msgstr "debe estar registrado"
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr "Aargau"
-#: contrib/flatpages/models.py:14
-msgid "If this is checked, only logged-in users will be able to view the page."
-msgstr "Si est marcado, slo los usuarios registrados podrn ver la pgina."
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
+msgstr "Appenzell Innerrhoden"
-#: contrib/flatpages/models.py:18
-msgid "flat page"
-msgstr "pgina esttica"
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr "Appenzell Ausserrhoden"
-#: contrib/flatpages/models.py:19
-msgid "flat pages"
-msgstr "pginas estticas"
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr "Basel-Stadt"
-#: contrib/localflavor/no/forms.py:15 contrib/localflavor/ch/forms.py:18
-msgid "Enter a zip code in the format XXXX."
-msgstr "Introduzca un zip code en formato XXX."
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
+msgstr "Basel-Land"
-#: contrib/localflavor/no/forms.py:36
-msgid "Enter a valid Norwegian social security number."
-msgstr "Introduzca un nmero de seguridad social Noruego vlido."
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr "Berne"
+
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr "Fribourg"
+
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr "Geneva"
+
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr "Glarus"
+
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr "Graubuenden"
+
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr "Jura"
+
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr "Lucerne"
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
+msgstr "Neuchatel"
+
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr "Nidwalden"
+
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr "Obwalden"
+
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr "Schaffhausen"
+
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr "Schwyz"
+
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr "Solothurn"
+
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr "St. Gallen"
+
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr "Thurgau"
+
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr "Ticino"
+
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr "Uri"
+
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr "Valais"
+
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
+msgstr "Vaud"
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr "Zug"
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr "Zurich"
#: contrib/localflavor/us/forms.py:18
msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
@@ -1574,779 +2257,308 @@ msgstr "Introduzca un zip code en el formato XXXXX o XXXXX-XXXX."
#: contrib/localflavor/us/forms.py:51
msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
-msgstr "Introduzca un Nmero de Seguridad Social en formato XXX-XX-XXXX."
+msgstr "Introduzca un Número de Seguridad Social en formato XXX-XX-XXXX."
+
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr "Introduzca un post code de 4 dígitos."
#: contrib/localflavor/jp/jp_prefectures.py:4
msgid "Hokkaido"
-msgstr ""
+msgstr "Hokkaido"
#: contrib/localflavor/jp/jp_prefectures.py:5
msgid "Aomori"
-msgstr ""
+msgstr "Aomori"
#: contrib/localflavor/jp/jp_prefectures.py:6
msgid "Iwate"
-msgstr ""
+msgstr "Iwate"
#: contrib/localflavor/jp/jp_prefectures.py:7
msgid "Miyagi"
-msgstr ""
+msgstr "Miyagi"
#: contrib/localflavor/jp/jp_prefectures.py:8
msgid "Akita"
-msgstr ""
+msgstr "Akita"
#: contrib/localflavor/jp/jp_prefectures.py:9
msgid "Yamagata"
-msgstr ""
+msgstr "Yamagata"
#: contrib/localflavor/jp/jp_prefectures.py:10
msgid "Fukushima"
-msgstr ""
+msgstr "Fukushima"
#: contrib/localflavor/jp/jp_prefectures.py:11
msgid "Ibaraki"
-msgstr ""
+msgstr "Ibaraki"
#: contrib/localflavor/jp/jp_prefectures.py:12
msgid "Tochigi"
-msgstr ""
+msgstr "Tochigi"
#: contrib/localflavor/jp/jp_prefectures.py:13
msgid "Gunma"
-msgstr ""
+msgstr "Gunma"
#: contrib/localflavor/jp/jp_prefectures.py:14
msgid "Saitama"
-msgstr ""
+msgstr "Saitama"
#: contrib/localflavor/jp/jp_prefectures.py:15
msgid "Chiba"
-msgstr ""
+msgstr "Chiba"
#: contrib/localflavor/jp/jp_prefectures.py:16
msgid "Tokyo"
-msgstr ""
+msgstr "Tokyo"
#: contrib/localflavor/jp/jp_prefectures.py:17
msgid "Kanagawa"
-msgstr ""
+msgstr "Kanagawa"
#: contrib/localflavor/jp/jp_prefectures.py:18
msgid "Yamanashi"
-msgstr ""
+msgstr "Yamanashi"
#: contrib/localflavor/jp/jp_prefectures.py:19
msgid "Nagano"
-msgstr ""
+msgstr "Nagano"
#: contrib/localflavor/jp/jp_prefectures.py:20
msgid "Niigata"
-msgstr ""
+msgstr "Niigata"
#: contrib/localflavor/jp/jp_prefectures.py:21
msgid "Toyama"
-msgstr ""
+msgstr "Toyama"
#: contrib/localflavor/jp/jp_prefectures.py:22
msgid "Ishikawa"
-msgstr ""
+msgstr "Ishikawa"
#: contrib/localflavor/jp/jp_prefectures.py:23
msgid "Fukui"
-msgstr ""
+msgstr "Fukui"
#: contrib/localflavor/jp/jp_prefectures.py:24
msgid "Gifu"
-msgstr ""
+msgstr "Gifu"
#: contrib/localflavor/jp/jp_prefectures.py:25
msgid "Shizuoka"
-msgstr ""
+msgstr "Shizuoka"
#: contrib/localflavor/jp/jp_prefectures.py:26
msgid "Aichi"
-msgstr ""
+msgstr "Aichi"
#: contrib/localflavor/jp/jp_prefectures.py:27
msgid "Mie"
-msgstr ""
+msgstr "Mie"
#: contrib/localflavor/jp/jp_prefectures.py:28
msgid "Shiga"
-msgstr ""
+msgstr "Shiga"
#: contrib/localflavor/jp/jp_prefectures.py:29
msgid "Kyoto"
-msgstr ""
+msgstr "Kyoto"
#: contrib/localflavor/jp/jp_prefectures.py:30
msgid "Osaka"
-msgstr ""
+msgstr "Osaka"
#: contrib/localflavor/jp/jp_prefectures.py:31
msgid "Hyogo"
-msgstr ""
+msgstr "Hyogo"
#: contrib/localflavor/jp/jp_prefectures.py:32
msgid "Nara"
-msgstr ""
+msgstr "Nara"
#: contrib/localflavor/jp/jp_prefectures.py:33
msgid "Wakayama"
-msgstr ""
+msgstr "Wakayama"
#: contrib/localflavor/jp/jp_prefectures.py:34
msgid "Tottori"
-msgstr ""
+msgstr "Tottori"
#: contrib/localflavor/jp/jp_prefectures.py:35
msgid "Shimane"
-msgstr ""
+msgstr "Shimane"
#: contrib/localflavor/jp/jp_prefectures.py:36
msgid "Okayama"
-msgstr ""
+msgstr "Okayama"
#: contrib/localflavor/jp/jp_prefectures.py:37
msgid "Hiroshima"
-msgstr ""
+msgstr "Hiroshima"
#: contrib/localflavor/jp/jp_prefectures.py:38
msgid "Yamaguchi"
-msgstr ""
+msgstr "Yamaguchi"
#: contrib/localflavor/jp/jp_prefectures.py:39
msgid "Tokushima"
-msgstr ""
+msgstr "Tokushima"
#: contrib/localflavor/jp/jp_prefectures.py:40
msgid "Kagawa"
-msgstr ""
+msgstr "Kagawa"
#: contrib/localflavor/jp/jp_prefectures.py:41
msgid "Ehime"
-msgstr ""
+msgstr "Ehime"
#: contrib/localflavor/jp/jp_prefectures.py:42
msgid "Kochi"
-msgstr ""
+msgstr "Kochi"
#: contrib/localflavor/jp/jp_prefectures.py:43
msgid "Fukuoka"
-msgstr ""
+msgstr "Fukuoka"
#: contrib/localflavor/jp/jp_prefectures.py:44
msgid "Saga"
-msgstr ""
+msgstr "Saga"
#: contrib/localflavor/jp/jp_prefectures.py:45
msgid "Nagasaki"
-msgstr ""
+msgstr "Nagasaki"
#: contrib/localflavor/jp/jp_prefectures.py:46
msgid "Kumamoto"
-msgstr ""
+msgstr "Kumamoto"
#: contrib/localflavor/jp/jp_prefectures.py:47
msgid "Oita"
-msgstr ""
+msgstr "Oita"
#: contrib/localflavor/jp/jp_prefectures.py:48
msgid "Miyazaki"
-msgstr ""
+msgstr "Miyazaki"
#: contrib/localflavor/jp/jp_prefectures.py:49
msgid "Kagoshima"
-msgstr ""
+msgstr "Kagoshima"
#: contrib/localflavor/jp/jp_prefectures.py:50
msgid "Okinawa"
-msgstr ""
+msgstr "Okinawa"
#: contrib/localflavor/jp/forms.py:21
msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
-msgstr "Introduzca un cdigo postal en formato XXXXXX o XXX-XXXX."
-
-#: contrib/localflavor/ch/forms.py:90
-msgid ""
-"Enter a valid Swiss identity or passport card number in X1234567<0 or "
-"1234567890 format."
-msgstr ""
-"Introduzca un nmero vlido de tarjeta de identidad o pasaporte Suizos en "
-"formato X1234567<0 o 1234567890."
-
-#: contrib/localflavor/ch/ch_states.py:5
-msgid "Aargau"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:6
-msgid "Appenzell Innerrhoden"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:7
-msgid "Appenzell Ausserrhoden"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:8
-msgid "Basel-Stadt"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:9
-msgid "Basel-Land"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:10
-msgid "Berne"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:11
-msgid "Fribourg"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:12
-msgid "Geneva"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:13
-msgid "Glarus"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:14
-msgid "Graubuenden"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:15
-msgid "Jura"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:16
-msgid "Lucerne"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:17
-msgid "Neuchatel"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:18
-msgid "Nidwalden"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:19
-msgid "Obwalden"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:20
-msgid "Schaffhausen"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:21
-msgid "Schwyz"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:22
-msgid "Solothurn"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:23
-msgid "St. Gallen"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:24
-msgid "Thurgau"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:25
-msgid "Ticino"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:26
-msgid "Uri"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:27
-msgid "Valais"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:28
-msgid "Vaud"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:29
-msgid "Zug"
-msgstr ""
-
-#: contrib/localflavor/ch/ch_states.py:30
-msgid "Zurich"
-msgstr ""
-
-#: contrib/localflavor/fi/forms.py:14 contrib/localflavor/de/forms.py:16
-#: contrib/localflavor/fr/forms.py:17
-msgid "Enter a zip code in the format XXXXX."
-msgstr "Introduzca un zip code en formato XXXXX."
-
-#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
-msgid "Enter a valid Finnish social security number."
-msgstr "Introduzca un nmero de seguridad social finlands vlido."
-
-#: contrib/localflavor/au/forms.py:18
-msgid "Enter a 4 digit post code."
-msgstr "Introduzca un post code de 4 dgitos."
-
-#: contrib/localflavor/is_/forms.py:16
-msgid ""
-"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
-msgstr ""
-"Introduzca un nmero de identificacin islands vlido. El formato es XXXXXX-"
-"XXXX."
-
-#: contrib/localflavor/is_/forms.py:30
-msgid "The Icelandic identification number is not valid."
-msgstr "El nmero de identificacin islands no es vlido."
-
-#: contrib/localflavor/uk/forms.py:18
-msgid "Enter a postcode. A space is required between the two postcode parts."
-msgstr ""
-"Introduzca un postcode. Se requiere un espacio entre las dos secciones del "
-"mismo."
-
-#: contrib/localflavor/de/de_states.py:5
-msgid "Baden-Wuerttemberg"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:6
-msgid "Bavaria"
-msgstr ""
+msgstr "Introduzca un código postal en formato XXXXXX o XXX-XXXX."
-#: contrib/localflavor/de/de_states.py:7
-msgid "Berlin"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:8
-msgid "Brandenburg"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:9
-msgid "Bremen"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:10
-msgid "Hamburg"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:11
-msgid "Hessen"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:12
-msgid "Mecklenburg-Western Pomerania"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:13
-msgid "Lower Saxony"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:14
-msgid "North Rhine-Westphalia"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:15
-msgid "Rhineland-Palatinate"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:16
-msgid "Saarland"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:17
-msgid "Saxony"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:18
-msgid "Saxony-Anhalt"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:19
-msgid "Schleswig-Holstein"
-msgstr ""
-
-#: contrib/localflavor/de/de_states.py:20
-msgid "Thuringia"
-msgstr ""
-
-#: contrib/localflavor/de/forms.py:60
-msgid ""
-"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
-"format."
-msgstr ""
-"Introduzca un nmero de tarjeta de identidad alemn vlido en formato "
-"XXXXXXXXXXX-XXXXXXX-XXXXXXX-X."
-
-#: contrib/localflavor/br/forms.py:18
-msgid "Enter a zip code in the format XXXXX-XXX."
-msgstr "Introduzca un zip code en formato XXXXX-XXX."
-
-#: contrib/localflavor/br/forms.py:30
-msgid "Phone numbers must be in XX-XXXX-XXXX format."
-msgstr "Los nmeros telefnicos deben respetar el formato XX-XXXX-XXXX."
-
-#: contrib/localflavor/br/forms.py:72
-msgid "This field requires only numbers."
-msgstr "Este campo permite slo valores numricos."
-
-#: contrib/localflavor/br/forms.py:74
-msgid "This field requires at most 11 digits or 14 characters."
-msgstr "Este campo requiere como mximo 11 dgitos o 14 caracteres."
-
-#: contrib/localflavor/br/forms.py:84
-msgid "Invalid CPF number."
-msgstr "Nmero CPF invlido."
-
-#: contrib/localflavor/br/forms.py:106
-msgid "This field requires at least 14 digits"
-msgstr "Este campo requiere al menos 14 dgitos."
-
-#: contrib/localflavor/br/forms.py:116
-msgid "Invalid CNPJ number."
-msgstr "Nmero CNPJ invlido."
-
-#: contrib/localflavor/cl/forms.py:21
-msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
-msgstr "Introduzca un RUT chileno vlido. EL formato es XX.XXX.XXX-X."
-
-#: contrib/localflavor/cl/forms.py:26
-msgid "Enter valid a Chilean RUT"
-msgstr "Introduzca un RUT chileno vlido."
-
-#: contrib/localflavor/it/forms.py:16
-msgid "Enter a valid zip code."
-msgstr "Introduzca un zip code vlido."
-
-#: contrib/localflavor/it/forms.py:41
-msgid "Enter a valid Social Security number."
-msgstr "Introduzca un nmero de Seguridad Social vlido."
-
-#: contrib/localflavor/it/forms.py:68
-msgid "Enter a valid VAT number."
-msgstr "Introduzca un nmero VAT vlido."
-
-#: contrib/comments/models.py:67 contrib/comments/models.py:166
-msgid "object ID"
-msgstr "ID de objeto"
-
-#: contrib/comments/models.py:68
-msgid "headline"
-msgstr "encabezado"
-
-#: contrib/comments/models.py:69 contrib/comments/models.py:90
-#: contrib/comments/models.py:167
-msgid "comment"
-msgstr "comentario"
-
-#: contrib/comments/models.py:70
-msgid "rating #1"
-msgstr "calificacin 1"
-
-#: contrib/comments/models.py:71
-msgid "rating #2"
-msgstr "calificacin 2"
-
-#: contrib/comments/models.py:72
-msgid "rating #3"
-msgstr "calificacin 3"
-
-#: contrib/comments/models.py:73
-msgid "rating #4"
-msgstr "calificacin 4"
-
-#: contrib/comments/models.py:74
-msgid "rating #5"
-msgstr "calificacin 5"
-
-#: contrib/comments/models.py:75
-msgid "rating #6"
-msgstr "calificacin 6"
-
-#: contrib/comments/models.py:76
-msgid "rating #7"
-msgstr "calificacin 7"
-
-#: contrib/comments/models.py:77
-msgid "rating #8"
-msgstr "calificacin 8"
-
-#: contrib/comments/models.py:82
-msgid "is valid rating"
-msgstr "es calificacin vlida"
-
-#: contrib/comments/models.py:83 contrib/comments/models.py:169
-msgid "date/time submitted"
-msgstr "fecha/hora de envo"
-
-#: contrib/comments/models.py:84 contrib/comments/models.py:170
-msgid "is public"
-msgstr "es pblico"
-
-#: contrib/comments/models.py:86
-msgid "is removed"
-msgstr "est eliminado"
-
-#: contrib/comments/models.py:86
-msgid ""
-"Check this box if the comment is inappropriate. A \"This comment has been "
-"removed\" message will be displayed instead."
-msgstr ""
-"Marque esta caja si el comentario es inapropiado. En su lugar se mostrar "
-"\"Este comentario ha sido eliminado\"."
-
-#: contrib/comments/models.py:91
-msgid "comments"
-msgstr "comentarios"
-
-#: contrib/comments/models.py:131 contrib/comments/models.py:207
-msgid "Content object"
-msgstr "Objeto contenido"
-
-#: contrib/comments/models.py:159
-#, python-format
-msgid ""
-"Posted by %(user)s at %(date)s\n"
-"\n"
-"%(comment)s\n"
-"\n"
-"http://%(domain)s%(url)s"
-msgstr ""
-"Enviado por %(user)s el %(date)s\n"
-"\n"
-"%(comment)s\n"
-"\n"
-"http://%(domain)s%(url)s"
-
-#: contrib/comments/models.py:168
-msgid "person's name"
-msgstr "nombre de la persona"
-
-#: contrib/comments/models.py:171
-msgid "ip address"
-msgstr "direccin ip"
-
-#: contrib/comments/models.py:173
-msgid "approved by staff"
-msgstr "aprobado por el staff"
-
-#: contrib/comments/models.py:176
-msgid "free comment"
-msgstr "comentario libre"
-
-#: contrib/comments/models.py:177
-msgid "free comments"
-msgstr "comentarios libres"
-
-#: contrib/comments/models.py:233
-msgid "score"
-msgstr "puntuacin"
-
-#: contrib/comments/models.py:234
-msgid "score date"
-msgstr "fecha de la puntuacin"
+#: contrib/localflavor/no/forms.py:35
+msgid "Enter a valid Norwegian social security number."
+msgstr "Introduzca un número de seguridad social Noruego válido."
-#: contrib/comments/models.py:237
-msgid "karma score"
-msgstr "punto karma"
+#: contrib/contenttypes/models.py:37
+msgid "python model class name"
+msgstr "nombre de la clase python del modelo"
-#: contrib/comments/models.py:238
-msgid "karma scores"
-msgstr "puntos karma"
+#: contrib/contenttypes/models.py:40
+msgid "content type"
+msgstr "tipo de contenido"
-#: contrib/comments/models.py:242
-#, python-format
-msgid "%(score)d rating by %(user)s"
-msgstr "puntuado %(score)d por %(user)s"
+#: contrib/contenttypes/models.py:41
+msgid "content types"
+msgstr "tipos de contenido"
-#: contrib/comments/models.py:258
-#, python-format
+#: contrib/flatpages/models.py:8
msgid ""
-"This comment was flagged by %(user)s:\n"
-"\n"
-"%(text)s"
+"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr ""
-"Este comentario fue marcado por %(user)s:\n"
-"\n"
-"%(text)s"
-
-#: contrib/comments/models.py:265
-msgid "flag date"
-msgstr "fecha de la marca"
-
-#: contrib/comments/models.py:268
-msgid "user flag"
-msgstr "marca de usuario"
-
-#: contrib/comments/models.py:269
-msgid "user flags"
-msgstr "marcas de usuario"
-
-#: contrib/comments/models.py:273
-#, python-format
-msgid "Flag by %r"
-msgstr "Marca de %r"
-
-#: contrib/comments/models.py:278
-msgid "deletion date"
-msgstr "fecha de eliminacin"
-
-#: contrib/comments/models.py:280
-msgid "moderator deletion"
-msgstr "Eliminacin por moderador"
-
-#: contrib/comments/models.py:281
-msgid "moderator deletions"
-msgstr "eliminaciones por moderador"
-
-#: contrib/comments/models.py:285
-#, python-format
-msgid "Moderator deletion by %r"
-msgstr "Eliminacin del moderador %r"
-
-#: contrib/comments/views/karma.py:19
-msgid "Anonymous users cannot vote"
-msgstr "Los usuarios annimos no pueden votar"
-
-#: contrib/comments/views/karma.py:23
-msgid "Invalid comment ID"
-msgstr "ID de comentario no vlido"
-
-#: contrib/comments/views/karma.py:25
-msgid "No voting for yourself"
-msgstr "Ud. no puede votarse a s mismo"
-
-#: contrib/comments/views/comments.py:27
-msgid ""
-"This rating is required because you've entered at least one other rating."
-msgstr "Se precisa esta puntuacin porque ha introducido al menos otra ms."
-
-#: contrib/comments/views/comments.py:111
-#, python-format
-msgid ""
-"This comment was posted by a user who has posted fewer than %(count)s "
-"comment:\n"
-"\n"
-"%(text)s"
-msgid_plural ""
-"This comment was posted by a user who has posted fewer than %(count)s "
-"comments:\n"
-"\n"
-"%(text)s"
-msgstr[0] ""
-"Este comentario lo envi un usuario que ha enviado menos de %(count)s "
-"comentario:\n"
-"\n"
-"%(text)s"
-msgstr[1] ""
-"Este comentario lo envi un usuario que ha enviado menos de %(count)s "
-"comentarios:\n"
-"\n"
-"%(text)s"
+"Ejemplo: '/about/contact/'. Asegúrese de usar barras '/' al principio y al "
+"final."
-#: contrib/comments/views/comments.py:116
-#, python-format
-msgid ""
-"This comment was posted by a sketchy user:\n"
-"\n"
-"%(text)s"
-msgstr ""
-"Este comentario ha sido enviado por un usuario 'semi-annimo':\n"
-"\n"
-"%(text)s"
+#: contrib/flatpages/models.py:9
+msgid "title"
+msgstr "título"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
-msgid "Only POSTs are allowed"
-msgstr "Slo se admiten POSTs"
+#: contrib/flatpages/models.py:10
+msgid "content"
+msgstr "contenido"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
-msgid "One or more of the required fields wasn't submitted"
-msgstr "No se proporcion uno o ms de los siguientes campos requeridos"
+#: contrib/flatpages/models.py:11
+msgid "enable comments"
+msgstr "activar comentarios"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
-msgid "Somebody tampered with the comment form (security violation)"
-msgstr ""
-"Alguien est jugando con el formulario de comentarios (violacin de "
-"seguridad)"
+#: contrib/flatpages/models.py:12
+msgid "template name"
+msgstr "nombre de plantilla"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/flatpages/models.py:13
msgid ""
-"The comment form had an invalid 'target' parameter -- the object ID was "
-"invalid"
+"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
+"will use 'flatpages/default.html'."
msgstr ""
-"El formulario de comentarios tiene un parmetro 'target' no vlido (el ID de "
-"objeto era invlido)"
+"Ejemplo: 'flatpages/contact_page.html'. Si no lo proporciona, el sistema "
+"usará 'flatpages/default.html'."
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
-msgid "The comment form didn't provide either 'preview' or 'post'"
-msgstr "El formulario de comentario no proporcion 'previsualizar' ni 'enviar'"
+#: contrib/flatpages/models.py:14
+msgid "registration required"
+msgstr "debe estar registrado"
-#: contrib/comments/templates/comments/form.html:8
-msgid "Forgotten your password?"
-msgstr "Olvid su contrasea?"
+#: contrib/flatpages/models.py:14
+msgid "If this is checked, only logged-in users will be able to view the page."
+msgstr "Si está marcado, sólo los usuarios registrados podrán ver la página."
-#: contrib/comments/templates/comments/form.html:12
-msgid "Ratings"
-msgstr "Calificaciones"
+#: contrib/flatpages/models.py:18
+msgid "flat page"
+msgstr "página estática"
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Required"
-msgstr "Requerido"
+#: contrib/flatpages/models.py:19
+msgid "flat pages"
+msgstr "páginas estáticas"
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Optional"
-msgstr "Opcional"
+#: contrib/sessions/models.py:68
+msgid "session key"
+msgstr "clave de sesión"
-#: contrib/comments/templates/comments/form.html:23
-msgid "Post a photo"
-msgstr "Enviar una foto"
+#: contrib/sessions/models.py:69
+msgid "session data"
+msgstr "datos de sesión"
-#: contrib/comments/templates/comments/form.html:28
-#: contrib/comments/templates/comments/freeform.html:5
-msgid "Comment:"
-msgstr "Comentario:"
+#: contrib/sessions/models.py:70
+msgid "expire date"
+msgstr "fecha de caducidad"
-#: contrib/comments/templates/comments/form.html:35
-#: contrib/comments/templates/comments/freeform.html:10
-msgid "Preview comment"
-msgstr "Previsualizar comentario"
+#: contrib/sessions/models.py:74
+msgid "session"
+msgstr "sesión"
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "Su nombre:"
+#: contrib/sessions/models.py:75
+msgid "sessions"
+msgstr "sesiones"
#: contrib/humanize/templatetags/humanize.py:17
msgid "th"
-msgstr ""
+msgstr "th"
#: contrib/humanize/templatetags/humanize.py:17
msgid "st"
-msgstr ""
+msgstr "st"
#: contrib/humanize/templatetags/humanize.py:17
msgid "nd"
-msgstr ""
+msgstr "nd"
#: contrib/humanize/templatetags/humanize.py:17
msgid "rd"
-msgstr ""
+msgstr "rd"
#: contrib/humanize/templatetags/humanize.py:47
#, python-format
msgid "%(value).1f million"
msgid_plural "%(value).1f million"
-msgstr[0] "%(value).1f milln"
+msgstr[0] "%(value).1f millón"
msgstr[1] "%(value).1f millones"
#: contrib/humanize/templatetags/humanize.py:50
@@ -2360,7 +2572,7 @@ msgstr[1] "%(value).1f millardos"
#, python-format
msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion"
-msgstr[0] "%(value).1f billn"
+msgstr[0] "%(value).1f billón"
msgstr[1] "%(value).1f billones"
#: contrib/humanize/templatetags/humanize.py:68
@@ -2399,624 +2611,471 @@ msgstr "ocho"
msgid "nine"
msgstr "nueve"
-#: db/models/manipulators.py:307
-#, python-format
-msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "Ya existe un(a) %(object)s con este/a %(type)s para %(field)s."
-
-#: db/models/fields/__init__.py:42
-#, python-format
-msgid "%(optname)s with this %(fieldname)s already exists."
-msgstr "Ya existe %(optname)s con este %(fieldname)s."
-
-#: db/models/fields/__init__.py:369
-msgid "This value must be an integer."
-msgstr "Este valor debe ser un nmero entero."
-
-#: db/models/fields/__init__.py:404
-msgid "This value must be either True or False."
-msgstr "Este valor debe ser True o False."
-
-#: db/models/fields/__init__.py:425
-msgid "This field cannot be null."
-msgstr "Este campo no puede ser nulo."
-
-#: db/models/fields/__init__.py:459 core/validators.py:148
-msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "Introduzca una fecha vlida en formato AAAA-MM-DD."
-
-#: db/models/fields/__init__.py:528 core/validators.py:157
-msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Introduzca una fecha/hora vlida en formato AAAA-MM-DD HH:MM."
-
-#: db/models/fields/__init__.py:632
-msgid "Enter a valid filename."
-msgstr "Introduzca un nombre de archivo vlido."
-
-#: db/models/fields/__init__.py:753
-msgid "This value must be either None, True or False."
-msgstr "Este valor debe ser None, True o False."
-
-#: db/models/fields/related.py:53
-#, python-format
-msgid "Please enter a valid %s."
-msgstr "Por favor, introduzca un %s vlido."
-
-#: db/models/fields/related.py:642
-msgid "Separate multiple IDs with commas."
-msgstr " Separe mltiples identificadores con comas."
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr "redirigir desde"
-#: db/models/fields/related.py:644
+#: contrib/redirects/models.py:8
msgid ""
-"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
-msgstr ""
-"Mantenga presionada \"Control\" (\"Command\" en una Mac) para seleccionar "
-"ms de uno."
-
-#: db/models/fields/related.py:691
-#, python-format
-msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural ""
-"Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] ""
-"Por favor, introduzca IDs de %(self)s vlidos. El valor %(value)r no es "
-"vlido."
-msgstr[1] ""
-"Por favor, introduzca IDs de %(self)s vlidos. Los valores %(value)r no son "
-"vlidos."
-
-#: oldforms/__init__.py:392
-#, python-format
-msgid "Ensure your text is less than %s character."
-msgid_plural "Ensure your text is less than %s characters."
-msgstr[0] "Asegrese de que su texto tiene menos de %s caracter."
-msgstr[1] "Asegrese de que su texto tiene menos de %s caracteres."
-
-#: oldforms/__init__.py:397
-msgid "Line breaks are not allowed here."
-msgstr "No se permiten saltos de lnea."
-
-#: oldforms/__init__.py:498 oldforms/__init__.py:571 oldforms/__init__.py:610
-#, python-format
-msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "Seleccione una opcin vlida; '%(data)s' no est en %(choices)s."
-
-#: oldforms/__init__.py:672 core/validators.py:174 core/validators.py:445
-msgid "No file was submitted. Check the encoding type on the form."
+"This should be an absolute path, excluding the domain name. Example: '/"
+"events/search/'."
msgstr ""
-"No se envi un archivo. Verifique el tipo de codificacin en el formulario."
-
-#: oldforms/__init__.py:674
-msgid "The submitted file is empty."
-msgstr "El archivo enviado est vaco."
-
-#: oldforms/__init__.py:730
-msgid "Enter a whole number between -32,768 and 32,767."
-msgstr "Introduzca un nmero entero entre -32.768 y 32.767."
-
-#: oldforms/__init__.py:740
-msgid "Enter a positive number."
-msgstr "Introduzca un nmero positivo."
-
-#: oldforms/__init__.py:750
-msgid "Enter a whole number between 0 and 32,767."
-msgstr "Introduzca un nmero entero entre 0 y 32.767."
-
-#: views/generic/create_update.py:43
-#, python-format
-msgid "The %(verbose_name)s was created successfully."
-msgstr "Se cre con xito %(verbose_name)s."
-
-#: views/generic/create_update.py:117
-#, python-format
-msgid "The %(verbose_name)s was updated successfully."
-msgstr "Se actualiz con xito %(verbose_name)s."
-
-#: views/generic/create_update.py:184
-#, python-format
-msgid "The %(verbose_name)s was deleted."
-msgstr "Se elimin %(verbose_name)s."
-
-#: conf/global_settings.py:39
-msgid "Arabic"
-msgstr "rabe"
-
-#: conf/global_settings.py:40
-msgid "Bengali"
-msgstr "Bengal"
-
-#: conf/global_settings.py:41
-msgid "Bulgarian"
-msgstr "Blgaro"
-
-#: conf/global_settings.py:42
-msgid "Catalan"
-msgstr "Cataln"
-
-#: conf/global_settings.py:43
-msgid "Czech"
-msgstr "Checo"
-
-#: conf/global_settings.py:44
-msgid "Welsh"
-msgstr "Gals"
-
-#: conf/global_settings.py:45
-msgid "Danish"
-msgstr "Dans"
-
-#: conf/global_settings.py:46
-msgid "German"
-msgstr "Alemn"
-
-#: conf/global_settings.py:47
-msgid "Greek"
-msgstr "Griego"
-
-#: conf/global_settings.py:48
-msgid "English"
-msgstr "Ingls"
-
-#: conf/global_settings.py:49
-msgid "Spanish"
-msgstr "Espaol"
-
-#: conf/global_settings.py:50
-msgid "Argentinean Spanish"
-msgstr "Espaol Argentino"
-
-#: conf/global_settings.py:51
-msgid "Finnish"
-msgstr "Finlands"
-
-#: conf/global_settings.py:52
-msgid "French"
-msgstr "Francs"
-
-#: conf/global_settings.py:53
-msgid "Galician"
-msgstr "Gallego"
-
-#: conf/global_settings.py:54
-msgid "Hungarian"
-msgstr "Hngaro"
-
-#: conf/global_settings.py:55
-msgid "Hebrew"
-msgstr "Hebreo"
-
-#: conf/global_settings.py:56
-msgid "Icelandic"
-msgstr "Islands"
-
-#: conf/global_settings.py:57
-msgid "Italian"
-msgstr "Italiano"
-
-#: conf/global_settings.py:58
-msgid "Japanese"
-msgstr "Japons"
-
-#: conf/global_settings.py:59
-msgid "Korean"
-msgstr "Koreano"
-
-#: conf/global_settings.py:60
-msgid "Kannada"
-msgstr "Canars"
-
-#: conf/global_settings.py:61
-msgid "Latvian"
-msgstr "Letn"
-
-#: conf/global_settings.py:62
-msgid "Macedonian"
-msgstr "Macedonio"
-
-#: conf/global_settings.py:63
-msgid "Dutch"
-msgstr "Holands"
-
-#: conf/global_settings.py:64
-msgid "Norwegian"
-msgstr "Noruego"
-
-#: conf/global_settings.py:65
-msgid "Polish"
-msgstr "Polaco"
-
-#: conf/global_settings.py:66
-msgid "Portugese"
-msgstr "Portugus"
-
-#: conf/global_settings.py:67
-msgid "Brazilian"
-msgstr "Brasileo"
-
-#: conf/global_settings.py:68
-msgid "Romanian"
-msgstr "Rumano"
-
-#: conf/global_settings.py:69
-msgid "Russian"
-msgstr "Ruso"
-
-#: conf/global_settings.py:70
-msgid "Slovak"
-msgstr "Eslovaco"
-
-#: conf/global_settings.py:71
-msgid "Slovenian"
-msgstr "Esloveno"
-
-#: conf/global_settings.py:72
-msgid "Serbian"
-msgstr "Serbio"
-
-#: conf/global_settings.py:73
-msgid "Swedish"
-msgstr "Sueco"
-
-#: conf/global_settings.py:74
-msgid "Tamil"
-msgstr "Tamil"
-
-#: conf/global_settings.py:75
-msgid "Telugu"
-msgstr "Telugu"
-
-#: conf/global_settings.py:76
-msgid "Turkish"
-msgstr "Turco"
-
-#: conf/global_settings.py:77
-msgid "Ukrainian"
-msgstr "Ucraniano"
-
-#: conf/global_settings.py:78
-msgid "Simplified Chinese"
-msgstr "Chino simplificado"
-
-#: conf/global_settings.py:79
-msgid "Traditional Chinese"
-msgstr "Chino tradicional"
-
-#: template/defaultfilters.py:491
-msgid "yes,no,maybe"
-msgstr "si,no,talvez"
+"Esta ruta debería ser absoluta, excluyendo el nombre de dominio. Ejemplo: '/"
+"events/search/'."
-#: template/defaultfilters.py:520
-#, python-format
-msgid "%(size)d byte"
-msgid_plural "%(size)d bytes"
-msgstr[0] ""
-msgstr[1] ""
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr "redirigir a"
-#: template/defaultfilters.py:522
-#, python-format
-msgid "%.1f KB"
+#: contrib/redirects/models.py:10
+msgid ""
+"This can be either an absolute path (as above) or a full URL starting with "
+"'http://'."
msgstr ""
+"Esto puede ser bien una ruta absoluta (como arriba) o una URL completa que "
+"empiece con 'http://'."
-#: template/defaultfilters.py:524
-#, python-format
-msgid "%.1f MB"
-msgstr ""
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr "redirección"
-#: template/defaultfilters.py:525
-#, python-format
-msgid "%.1f GB"
-msgstr ""
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr "redirecciones"
-#: core/validators.py:64
+#: core/validators.py:71
msgid "This value must contain only letters, numbers and underscores."
-msgstr "Este valor debe contener slo letras, nmeros y guiones bajos."
+msgstr "Este valor debe contener sólo letras, números y guiones bajos."
-#: core/validators.py:68
+#: core/validators.py:75
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
msgstr ""
-"Este valor debe contener slo letras, nmeros, guiones bajos, guiones o "
+"Este valor debe contener sólo letras, números, guiones bajos, guiones o "
"barras (/)"
-#: core/validators.py:72
+#: core/validators.py:79
msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr ""
-"Este valor debe contener slo letras, nmeros, guiones bajos o guiones."
+"Este valor debe contener sólo letras, números, guiones bajos o guiones."
-#: core/validators.py:76
+#: core/validators.py:83
msgid "Uppercase letters are not allowed here."
-msgstr "No se admiten letras maysculas."
+msgstr "No se admiten letras mayúsculas."
-#: core/validators.py:80
+#: core/validators.py:87
msgid "Lowercase letters are not allowed here."
-msgstr "No se admiten letras minsculas."
+msgstr "No se admiten letras minúsculas."
-#: core/validators.py:87
+#: core/validators.py:94
msgid "Enter only digits separated by commas."
-msgstr "Introduzca slo dgitos separados por comas."
+msgstr "Introduzca sólo dígitos separados por comas."
-#: core/validators.py:99
+#: core/validators.py:106
msgid "Enter valid e-mail addresses separated by commas."
-msgstr "Introduzca direcciones de correo vlidas separadas por comas."
+msgstr "Introduzca direcciones de correo válidas separadas por comas."
-#: core/validators.py:103
+#: core/validators.py:110
msgid "Please enter a valid IP address."
-msgstr "Por favor introduzca una direccin IP vlida."
+msgstr "Por favor introduzca una dirección IP válida."
-#: core/validators.py:107
+#: core/validators.py:114
msgid "Empty values are not allowed here."
-msgstr "No se admiten valores vacos."
+msgstr "No se admiten valores vacíos."
-#: core/validators.py:111
+#: core/validators.py:118
msgid "Non-numeric characters aren't allowed here."
-msgstr "No se admiten caracteres no numricos."
+msgstr "No se admiten caracteres no numéricos."
-#: core/validators.py:115
+#: core/validators.py:122
msgid "This value can't be comprised solely of digits."
-msgstr "Este valor no puede estar formado slo por dgitos."
+msgstr "Este valor no puede estar formado sólo por dígitos."
+
+#: core/validators.py:127 newforms/fields.py:141
+msgid "Enter a whole number."
+msgstr "Introduzca un número entero."
-#: core/validators.py:124
+#: core/validators.py:131
msgid "Only alphabetical characters are allowed here."
-msgstr "Slo se admiten caracteres alfabticos."
+msgstr "Sólo se admiten caracteres alfabéticos."
-#: core/validators.py:139
+#: core/validators.py:146
msgid "Year must be 1900 or later."
-msgstr "El ao debe ser 1900 o posterior."
+msgstr "El año debe ser 1900 o posterior."
-#: core/validators.py:143
+#: core/validators.py:150
#, python-format
msgid "Invalid date: %s"
-msgstr "Fecha no vlida: %s"
+msgstr "Fecha no válida: %s"
-#: core/validators.py:153
+#: core/validators.py:160
msgid "Enter a valid time in HH:MM format."
-msgstr "Introduzca una hora vlida en formato HH:MM."
+msgstr "Introduzca una hora válida en formato HH:MM."
+
+#: core/validators.py:169 newforms/fields.py:335
+msgid "Enter a valid e-mail address."
+msgstr "Introduzca una dirección de correo electrónico válida"
-#: core/validators.py:178
+#: core/validators.py:185
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
-"Enve una imagen vlida. El archivo que ha enviado no era una imagen o se "
+"Envíe una imagen válida. El archivo que ha enviado no era una imagen o se "
"trataba de una imagen corrupta."
-#: core/validators.py:185
+#: core/validators.py:192
#, python-format
msgid "The URL %s does not point to a valid image."
-msgstr "La URL %s no apunta a una imagen vlida."
+msgstr "La URL %s no apunta a una imagen válida."
-#: core/validators.py:189
+#: core/validators.py:196
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr ""
-"Los nmeros telefnicos deben respetar el formato XXX-XXX-XXXX. \"%s\" no es "
-"vlido."
+"Los números telefónicos deben respetar el formato XXX-XXX-XXXX. \"%s\" no es "
+"válido."
-#: core/validators.py:197
+#: core/validators.py:204
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
-msgstr "La URL %s no apunta a un vdeo QuickTime vlido."
+msgstr "La URL %s no apunta a un vídeo QuickTime válido."
-#: core/validators.py:201
+#: core/validators.py:208
msgid "A valid URL is required."
-msgstr "Se precisa una URL vlida."
+msgstr "Se precisa una URL válida."
-#: core/validators.py:215
+#: core/validators.py:222
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
"%s"
msgstr ""
-"Se precisa HTML vlido. Los errores especficos son:\n"
+"Se precisa HTML válido. Los errores específicos son:\n"
"%s"
-#: core/validators.py:222
+#: core/validators.py:229
#, python-format
msgid "Badly formed XML: %s"
msgstr "XML mal formado: %s"
-#: core/validators.py:239
+#: core/validators.py:246
#, python-format
msgid "Invalid URL: %s"
-msgstr "URL no vlida: %s"
+msgstr "URL no válida: %s"
-#: core/validators.py:244 core/validators.py:246
+#: core/validators.py:251 core/validators.py:253
#, python-format
msgid "The URL %s is a broken link."
msgstr "La URL %s es un enlace roto."
-#: core/validators.py:252
+#: core/validators.py:259
msgid "Enter a valid U.S. state abbreviation."
-msgstr "Introduzca una abreviatura vlida de estado de los EE.UU."
+msgstr "Introduzca una abreviatura válida de estado de los EE.UU."
-#: core/validators.py:266
+#: core/validators.py:273
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
-msgstr[0] "Vigila tu boca! Aqu no admitimos la palabra %s."
-msgstr[1] "Vigila tu boca! Aqu no admitimos las palabras %s."
+msgstr[0] "¡Vigila tu boca! Aquí no admitimos la palabra %s."
+msgstr[1] "¡Vigila tu boca! Aquí no admitimos las palabras %s."
-#: core/validators.py:273
+#: core/validators.py:280
#, python-format
msgid "This field must match the '%s' field."
msgstr "Este campo debe concordar con el campo '%s'."
-#: core/validators.py:292
+#: core/validators.py:299
msgid "Please enter something for at least one field."
msgstr "Por favor, introduzca algo en al menos un campo."
-#: core/validators.py:301 core/validators.py:312
+#: core/validators.py:308 core/validators.py:319
msgid "Please enter both fields or leave them both empty."
-msgstr "Por favor, rellene ambos campos o deje ambos vacos."
+msgstr "Por favor, rellene ambos campos o deje ambos vacíos."
-#: core/validators.py:320
+#: core/validators.py:327
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "Se debe proporcionar este campo si %(field)s es %(value)s"
-#: core/validators.py:333
+#: core/validators.py:340
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Se debe proporcionar este campo si %(field)s no es %(value)s"
-#: core/validators.py:352
+#: core/validators.py:359
msgid "Duplicate values are not allowed."
msgstr "No se admiten valores duplicados."
-#: core/validators.py:367
+#: core/validators.py:374
#, python-format
msgid "This value must be between %(lower)s and %(upper)s."
msgstr "Este valor debe estar entre %(lower)s y %(upper)s."
-#: core/validators.py:369
+#: core/validators.py:376
#, python-format
msgid "This value must be at least %s."
msgstr "Este valor debe ser al menos %s."
-#: core/validators.py:371
+#: core/validators.py:378
#, python-format
msgid "This value must be no more than %s."
msgstr "Este valor debe ser no mayor que %s."
-#: core/validators.py:407
+#: core/validators.py:414
#, python-format
msgid "This value must be a power of %s."
msgstr "Este valor debe ser una potencia de %s."
-#: core/validators.py:418
+#: core/validators.py:424
msgid "Please enter a valid decimal number."
-msgstr "Por favor, introduzca un nmero decimal vlido."
+msgstr "Por favor, introduzca un número decimal válido."
-#: core/validators.py:422
+#: core/validators.py:431
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con un mximo de un dgito en "
+"Por favor, introduzca un número decimal válido con un máximo de un dígito en "
"total."
msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con un maximo de %s dgitos "
+"Por favor, introduzca un número decimal válido con un maximo de %s dígitos "
"en total."
-#: core/validators.py:425
+#: core/validators.py:434
#, python-format
msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit."
msgid_plural ""
"Please enter a valid decimal number with a whole part of at most %s digits."
msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con un dgito entero como "
-"mximo."
+"Por favor, introduzca un número decimal válido con un dígito entero como "
+"máximo."
msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con un mximo de %s dgitos "
+"Por favor, introduzca un número decimal válido con un máximo de %s dígitos "
"enteros."
-#: core/validators.py:428
+#: core/validators.py:437
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places."
msgstr[0] ""
-"Por favor, introduzca un nmero decimal vlido con un mximo de una posicin "
+"Por favor, introduzca un número decimal válido con un máximo de una posición "
"decimal."
msgstr[1] ""
-"Por favor, introduzca un nmero decimal vlido con un mximo de %s "
+"Por favor, introduzca un número decimal válido con un máximo de %s "
"posiciones decimales."
-#: core/validators.py:438
+#: core/validators.py:445
+msgid "Please enter a valid floating point number."
+msgstr "Por favor introduzca un número de punto flotante válido."
+
+#: core/validators.py:454
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr ""
-"Asegrese de que el archivo que enva es de un tamao mnimo de %s bytes."
+"Asegúrese de que el archivo que envía es de un tamaño mínimo de %s bytes."
-#: core/validators.py:439
+#: core/validators.py:455
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr ""
-"Asegrese de que el archivo que enva es de un tamao mximo de %s bytes."
+"Asegúrese de que el archivo que envía es de un tamaño máximo de %s bytes."
-#: core/validators.py:456
+#: core/validators.py:472
msgid "The format for this field is wrong."
msgstr "El formato de este campo es incorrecto."
-#: core/validators.py:471
+#: core/validators.py:487
msgid "This field is invalid."
-msgstr "Este campo no es vlido."
+msgstr "Este campo no es válido."
-#: core/validators.py:507
+#: core/validators.py:523
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "No se pudo obtener nada de %s."
-#: core/validators.py:510
+#: core/validators.py:526
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr ""
-"La URL %(url)s devolvi la cabecera Content-Type '%(contenttype)s', que no "
-"es vlida."
+"La URL %(url)s devolvió la cabecera Content-Type '%(contenttype)s', que no "
+"es válida."
-#: core/validators.py:543
+#: core/validators.py:559
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
"\"%(start)s\".)"
msgstr ""
-"Por favor, cierre la etiqueta %(tag)s de la lnea %(line)s. (La lnea "
+"Por favor, cierre la etiqueta %(tag)s de la línea %(line)s. (La línea "
"empieza con \"%(start)s\".)"
-#: core/validators.py:547
+#: core/validators.py:563
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
"starts with \"%(start)s\".)"
msgstr ""
-"Parte del texto que comienza en la lnea %(line)s no est permitido en ese "
-"contexto. (La lnea empieza con \"%(start)s\".)"
+"Parte del texto que comienza en la línea %(line)s no está permitido en ese "
+"contexto. (La línea empieza con \"%(start)s\".)"
-#: core/validators.py:552
+#: core/validators.py:568
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
"(start)s\".)"
msgstr ""
-"El \"%(attr)s\" de la lnea %(line)s no es un atributo vlido. (La lnea "
+"El \"%(attr)s\" de la línea %(line)s no es un atributo válido. (La línea "
"empieza con \"%(start)s\".)"
-#: core/validators.py:557
+#: core/validators.py:573
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
"(start)s\".)"
msgstr ""
-"La \"<%(tag)s>\" de la lnea %(line)s no es una etiqueta vlida. (La lnea "
+"La \"<%(tag)s>\" de la línea %(line)s no es una etiqueta válida. (La línea "
"empieza con \"%(start)s\".)"
-#: core/validators.py:561
+#: core/validators.py:577
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
"starts with \"%(start)s\".)"
msgstr ""
-"A una etiqueta de la lnea %(line)s le faltan uno o ms atributos "
-"requeridos. (La lnea empieza con \"%(start)s\".)"
+"A una etiqueta de la línea %(line)s le faltan uno o más atributos "
+"requeridos. (La línea empieza con \"%(start)s\".)"
-#: core/validators.py:566
+#: core/validators.py:582
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
"starts with \"%(start)s\".)"
msgstr ""
-"El atributo \"%(attr)s\" de la lnea %(line)s tiene un valor que no es "
-"vlido. (La lnea empieza con \"%(start)s\".)"
+"El atributo \"%(attr)s\" de la línea %(line)s tiene un valor que no es "
+"válido. (La línea empieza con \"%(start)s\".)"
+
+#: newforms/fields.py:116
+#, python-format
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr "Asegúrese de que este valor tenga como máximo %(max)d caracteres (tiene %(length)d)."
+
+#: newforms/fields.py:118
+#, python-format
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr "Asegúrese de que este valor tenga al menos %(min)d caracteres (tiene %(length)d)."
+
+#: newforms/fields.py:143 newforms/fields.py:166 newforms/fields.py:196
+#, python-format
+msgid "Ensure this value is less than or equal to %s."
+msgstr "Asegúrese de que este valor sea menor o igual a %s."
+
+#: newforms/fields.py:145 newforms/fields.py:168 newforms/fields.py:198
+#, python-format
+msgid "Ensure this value is greater than or equal to %s."
+msgstr "Asegúrese de que este valor sea mayor o igual a %s."
+
+#: newforms/fields.py:164 newforms/fields.py:191
+msgid "Enter a number."
+msgstr "Introduzca un número."
+
+#: newforms/fields.py:200
+#, python-format
+msgid "Ensure that there are no more than %s digits in total."
+msgstr "Asegúrese de que no existan en total mas de %s dígitos."
+
+#: newforms/fields.py:202
+#, python-format
+msgid "Ensure that there are no more than %s decimal places."
+msgstr "Asegúrese de que no existan mas de %s lugares decimales."
+
+#: newforms/fields.py:204
+#, python-format
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr "Asegúrese de que no existan mas de %s dígitos antes del punto decimal."
+
+#: newforms/fields.py:237 newforms/fields.py:560
+msgid "Enter a valid date."
+msgstr "Introduzca una fecha válida."
+
+#: newforms/fields.py:264 newforms/fields.py:562
+msgid "Enter a valid time."
+msgstr "Introduzca una hora válida."
+
+#: newforms/fields.py:300
+msgid "Enter a valid date/time."
+msgstr "Introduzca una fecha/hora válida."
+
+#: newforms/fields.py:313
+msgid "Enter a valid value."
+msgstr "Introduzca un valor válido."
+
+#: newforms/fields.py:353 newforms/fields.py:375
+msgid "Enter a valid URL."
+msgstr "Introduzca una URL válida."
+
+#: newforms/fields.py:377
+msgid "This URL appears to be a broken link."
+msgstr "La URL parece ser un enlace roto."
+
+#: newforms/fields.py:428 newforms/models.py:174
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr ""
+"Seleccione una opción válida. Esa opción no es una de las opciones "
+"disponibles."
+
+#: newforms/fields.py:444 newforms/fields.py:520 newforms/models.py:191
+msgid "Enter a list of values."
+msgstr "Introduzca una lista de valores."
+
+#: newforms/fields.py:450 newforms/models.py:197
+#, python-format
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr ""
+"Seleccione una opción válida. %s no es una de las opciones disponibles."
+
+#: template/defaultfilters.py:485
+msgid "yes,no,maybe"
+msgstr "si,no,talvez"
+
+#: template/defaultfilters.py:514
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: template/defaultfilters.py:516
+#, python-format
+msgid "%.1f KB"
+msgstr "%.1f KB"
+
+#: template/defaultfilters.py:518
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: template/defaultfilters.py:519
+#, python-format
+msgid "%.1f GB"
+msgstr "%.1f GB"
+
+#~ msgid "%d milliseconds"
+#~ msgstr "%d milisegundos"
+
+#~ msgid "AnonymousUser"
+#~ msgstr "UsuarioAnonimo"
#~ msgid "Use '[algo]$[salt]$[hexdigest]'"
#~ msgstr "Use '[algoritmo]$[salt]$[hexdigest]'"
#~ msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
-#~ msgstr "Ha <a href=\"/password_reset/\">olvidado su contrasea</a>?"
+#~ msgstr "¿Ha <a href=\"/password_reset/\">olvidado su contraseña</a>?"
#~ msgid "%(content_type_name)s"
#~ msgstr "tipos de contenido"
@@ -3033,7 +3092,7 @@ msgstr ""
#~ msgstr "Comentarios"
#~ msgid "String (up to 50)"
-#~ msgstr "Cadena (mximo 50)"
+#~ msgstr "Cadena (máximo 50)"
#~ msgid "label"
#~ msgstr "etiqueta"
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
index d8e3cc6fd6..b055405fbf 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
index 91ecb09eed..4c81e7e3f1 100644
--- a/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
@@ -1,17 +1,17 @@
-# Argentinean spanish translation for the django-admin JS files, based on
-# Spanish translation work by Jorge Gajon.
-# This file is distributed under the same license as the Django package.
-# Copyright (C) Ramiro Morales <rm0@gmx.net>, 2006,2007.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
#
msgid ""
msgstr ""
-"Project-Id-Version: Django JavaScript 1.0\n"
+"Project-Id-Version: Django Javascript 1.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-02-25 17:48-0300\n"
-"PO-Revision-Date: 2007-02-25 17:55-0300\n"
+"POT-Creation-Date: 2007-07-14 13:45-0300\n"
+"PO-Revision-Date: 2007-07-14 14:36-0300\n"
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
+"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
@@ -55,7 +55,7 @@ msgstr ""
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
-msgstr "Domingo Lunes Martes Mircoles Jueves Viernes Sbado"
+msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
@@ -93,7 +93,7 @@ msgstr "6 a.m."
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
-msgstr "Medioda"
+msgstr "Mediodía"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
@@ -115,4 +115,4 @@ msgstr "Ayer"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
-msgstr "Maana"
+msgstr "Mañana"
diff --git a/django/conf/locale/fr/LC_MESSAGES/django.mo b/django/conf/locale/fr/LC_MESSAGES/django.mo
index b96306cabd..55e4e57f5a 100644
--- a/django/conf/locale/fr/LC_MESSAGES/django.mo
+++ b/django/conf/locale/fr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/fr/LC_MESSAGES/django.po b/django/conf/locale/fr/LC_MESSAGES/django.po
index 2e525466b1..ba335f5eae 100644
--- a/django/conf/locale/fr/LC_MESSAGES/django.po
+++ b/django/conf/locale/fr/LC_MESSAGES/django.po
@@ -7,128 +7,132 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-04-22 09:06+0200\n"
+"POT-Creation-Date: 2007-07-08 16:03+0200\n"
"PO-Revision-Date: 2006-05-08 15:12+0200\n"
-"Last-Translator: Baptiste Goupil <baptiste.goupil_at_google_email.com>\n"
+"Last-Translator: Baptiste <baptiste.goupil_at_google_email.com>\n"
"Language-Team: français <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: oldforms/__init__.py:357 db/models/fields/__init__.py:114
-#: db/models/fields/__init__.py:271 db/models/fields/__init__.py:607
-#: db/models/fields/__init__.py:618 newforms/models.py:178
-#: newforms/fields.py:80 newforms/fields.py:376 newforms/fields.py:452
-#: newforms/fields.py:463
+#: oldforms/__init__.py:369 db/models/fields/__init__.py:125
+#: db/models/fields/__init__.py:282 db/models/fields/__init__.py:679
+#: db/models/fields/__init__.py:690 newforms/models.py:188
+#: newforms/fields.py:87 newforms/fields.py:444 newforms/fields.py:523
+#: newforms/fields.py:534
msgid "This field is required."
msgstr "Ce champ est obligatoire."
-#: oldforms/__init__.py:392
+#: oldforms/__init__.py:404
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Assurez-vous que votre texte fait moins de %s caractère."
msgstr[1] "Assurez-vous que votre texte fait moins de %s caractères."
-#: oldforms/__init__.py:397
+#: oldforms/__init__.py:409
msgid "Line breaks are not allowed here."
msgstr "Les retours à la ligne ne sont pas autorisés ici."
-#: oldforms/__init__.py:498 oldforms/__init__.py:571 oldforms/__init__.py:610
+#: oldforms/__init__.py:507 oldforms/__init__.py:581 oldforms/__init__.py:620
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Sélectionnez un choix valide ; '%(data)s' n'est pas dans %(choices)s."
-#: oldforms/__init__.py:577 newforms/widgets.py:180
-#: contrib/admin/filterspecs.py:150
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:152
msgid "Unknown"
msgstr "Inconnu"
-#: oldforms/__init__.py:577 newforms/widgets.py:180
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "Yes"
msgstr "Oui"
-#: oldforms/__init__.py:577 newforms/widgets.py:180
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "No"
msgstr "Non"
-#: oldforms/__init__.py:672 core/validators.py:174 core/validators.py:445
+#: oldforms/__init__.py:682 core/validators.py:178 core/validators.py:456
msgid "No file was submitted. Check the encoding type on the form."
msgstr ""
-#: oldforms/__init__.py:674
+#: oldforms/__init__.py:684
msgid "The submitted file is empty."
msgstr "Le fichier soumis est vide."
-#: oldforms/__init__.py:730
+#: oldforms/__init__.py:740
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Entrez un nombre entier entre -32 768 et 32 767."
-#: oldforms/__init__.py:740
+#: oldforms/__init__.py:750
msgid "Enter a positive number."
msgstr "Entrez un nombre entier positif."
-#: oldforms/__init__.py:750
+#: oldforms/__init__.py:760
msgid "Enter a whole number between 0 and 32,767."
msgstr "Entrez un nombre entier entre 0 et 32 767."
-#: db/models/manipulators.py:302
+#: db/models/manipulators.py:304
#, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr ""
-#: db/models/manipulators.py:303
+#: db/models/manipulators.py:305
msgid "and"
msgstr "et"
-#: db/models/fields/__init__.py:41
+#: db/models/fields/__init__.py:46
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(optname)s avec le champ %(fieldname)s existe déjà."
-#: db/models/fields/__init__.py:364
+#: db/models/fields/__init__.py:377
msgid "This value must be an integer."
msgstr "Cette valeur doit être un entier."
-#: db/models/fields/__init__.py:399
+#: db/models/fields/__init__.py:412
msgid "This value must be either True or False."
msgstr "Cette valeur doit être soit Vraie soit Fausse."
-#: db/models/fields/__init__.py:420
+#: db/models/fields/__init__.py:433
msgid "This field cannot be null."
msgstr "Ce champ ne peut pas être vide."
-#: db/models/fields/__init__.py:454 core/validators.py:148
+#: db/models/fields/__init__.py:467 core/validators.py:152
msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Entrez une date valide au format AAAA-MM-JJ."
-#: db/models/fields/__init__.py:523 core/validators.py:157
+#: db/models/fields/__init__.py:536 core/validators.py:161
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Entrez une date et une heure valide au format AAAA-MM-JJ HH:MM."
-#: db/models/fields/__init__.py:627
+#: db/models/fields/__init__.py:596
+msgid "This value must be a decimal number."
+msgstr "Cette valeur doit être un nombre décimal."
+
+#: db/models/fields/__init__.py:699
msgid "Enter a valid filename."
msgstr "Entrez un nom de fichier valide."
-#: db/models/fields/__init__.py:748
+#: db/models/fields/__init__.py:824
msgid "This value must be either None, True or False."
msgstr "Cette valeur doit être Nulle, Vraie ou Fausse."
-#: db/models/fields/related.py:53
+#: db/models/fields/related.py:55
#, python-format
msgid "Please enter a valid %s."
msgstr "Entrez un %s valide."
-#: db/models/fields/related.py:624
+#: db/models/fields/related.py:623
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
"Maintenez \"Contrôle (ctrl)\", ou \"Commande (touche pomme)\" sur un Mac, "
"pour en sélectionner plusieurs."
-#: db/models/fields/related.py:668
+#: db/models/fields/related.py:667
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
@@ -146,366 +150,376 @@ msgid "Bengali"
msgstr "Indien"
#: conf/global_settings.py:41
+msgid "Bulgarian"
+msgstr "Bulgare"
+
+#: conf/global_settings.py:42
msgid "Catalan"
msgstr "Catalan"
-#: conf/global_settings.py:42
+#: conf/global_settings.py:43
msgid "Czech"
msgstr "Tchèque"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:44
msgid "Welsh"
msgstr "Gallois"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:45
msgid "Danish"
msgstr "Dannois"
-#: conf/global_settings.py:45
+#: conf/global_settings.py:46
msgid "German"
msgstr "Allemand"
-#: conf/global_settings.py:46
+#: conf/global_settings.py:47
msgid "Greek"
msgstr "Grec"
-#: conf/global_settings.py:47
+#: conf/global_settings.py:48
msgid "English"
msgstr "Anglais"
-#: conf/global_settings.py:48
+#: conf/global_settings.py:49
msgid "Spanish"
msgstr "Espagnol"
-#: conf/global_settings.py:49
+#: conf/global_settings.py:50
msgid "Argentinean Spanish"
msgstr "Espagnol Argentin"
-#: conf/global_settings.py:50
+#: conf/global_settings.py:51
+msgid "Persian"
+msgstr "Perse"
+
+#: conf/global_settings.py:52
msgid "Finnish"
-msgstr "Dannois"
+msgstr "Finlandais"
-#: conf/global_settings.py:51
+#: conf/global_settings.py:53
msgid "French"
msgstr "Français"
-#: conf/global_settings.py:52
+#: conf/global_settings.py:54
msgid "Galician"
msgstr "Galicien"
-#: conf/global_settings.py:53
+#: conf/global_settings.py:55
msgid "Hungarian"
msgstr "Hongrois"
-#: conf/global_settings.py:54
+#: conf/global_settings.py:56
msgid "Hebrew"
-msgstr "Israélien"
+msgstr "Hébreu"
-#: conf/global_settings.py:55
+#: conf/global_settings.py:57
msgid "Icelandic"
msgstr "Islandais"
-#: conf/global_settings.py:56
+#: conf/global_settings.py:58
msgid "Italian"
msgstr "Italien"
-#: conf/global_settings.py:57
+#: conf/global_settings.py:59
msgid "Japanese"
msgstr "Japonais"
-#: conf/global_settings.py:58
+#: conf/global_settings.py:60
+msgid "Korean"
+msgstr "Coréen"
+
+#: conf/global_settings.py:61
msgid "Kannada"
msgstr "Kannada"
-#: conf/global_settings.py:59
+#: conf/global_settings.py:62
msgid "Latvian"
msgstr "Letton"
-#: conf/global_settings.py:60
+#: conf/global_settings.py:63
msgid "Macedonian"
msgstr "Macédonien"
-#: conf/global_settings.py:61
+#: conf/global_settings.py:64
msgid "Dutch"
-msgstr "Néerlandais"
+msgstr "Hollandais"
-#: conf/global_settings.py:62
+#: conf/global_settings.py:65
msgid "Norwegian"
msgstr "Norvégien"
-#: conf/global_settings.py:63
+#: conf/global_settings.py:66
msgid "Polish"
msgstr "Polonais"
-#: conf/global_settings.py:64
+#: conf/global_settings.py:67
msgid "Portugese"
-msgstr ""
+msgstr "Portugais"
-#: conf/global_settings.py:65
+#: conf/global_settings.py:68
msgid "Brazilian"
msgstr "Brésilien"
-#: conf/global_settings.py:66
+#: conf/global_settings.py:69
msgid "Romanian"
msgstr "Roumain"
-#: conf/global_settings.py:67
+#: conf/global_settings.py:70
msgid "Russian"
msgstr "Russe"
-#: conf/global_settings.py:68
+#: conf/global_settings.py:71
msgid "Slovak"
msgstr "Slovaque"
-#: conf/global_settings.py:69
+#: conf/global_settings.py:72
msgid "Slovenian"
msgstr "Slovaque"
-#: conf/global_settings.py:70
+#: conf/global_settings.py:73
msgid "Serbian"
msgstr "Serbe"
-#: conf/global_settings.py:71
+#: conf/global_settings.py:74
msgid "Swedish"
msgstr "Suédois"
-#: conf/global_settings.py:72
+#: conf/global_settings.py:75
msgid "Tamil"
msgstr "Tamoul"
-#: conf/global_settings.py:73
+#: conf/global_settings.py:76
msgid "Telugu"
msgstr "Télougou"
-#: conf/global_settings.py:74
+#: conf/global_settings.py:77
msgid "Turkish"
msgstr "Turc"
-#: conf/global_settings.py:75
+#: conf/global_settings.py:78
msgid "Ukrainian"
msgstr "Ukrainien"
-#: conf/global_settings.py:76
+#: conf/global_settings.py:79
msgid "Simplified Chinese"
msgstr "Chinois simplifié"
-#: conf/global_settings.py:77
+#: conf/global_settings.py:80
msgid "Traditional Chinese"
msgstr "Chinois traditionnel"
-#: core/validators.py:64
+#: core/validators.py:68
msgid "This value must contain only letters, numbers and underscores."
-msgstr ""
-"Ce champ ne doit contenir que des lettres, des nombres et des tirets bas "
-"('_')."
+msgstr "Ce champ ne doit contenir que des lettres, des nombres et des"
+"tirets bas _."
-#: core/validators.py:68
+#: core/validators.py:72
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
msgstr ""
-"Ce champ ne doit contenir que des lettres, des nombres, des tirets bas ('_') "
-"et des '/'."
+"Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _,"
+"des traits d'union, et des '/'."
-#: core/validators.py:72
+#: core/validators.py:76
msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr ""
-"Ce champ ne doit contenir que des lettres, des nombres, des tirets bas ('_') "
-"et des '-'."
+"Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _"
+"et des traits d'union."
-#: core/validators.py:76
+#: core/validators.py:80
msgid "Uppercase letters are not allowed here."
msgstr "Les lettres majuscules ne sont pas autorisées ici."
-#: core/validators.py:80
+#: core/validators.py:84
msgid "Lowercase letters are not allowed here."
msgstr "Les lettres minuscules ne sont pas autorisées ici."
-#: core/validators.py:87
+#: core/validators.py:91
msgid "Enter only digits separated by commas."
msgstr "Saisissez uniquement des chiffres séparés par des virgules."
-#: core/validators.py:99
+#: core/validators.py:103
msgid "Enter valid e-mail addresses separated by commas."
msgstr "Entrez des adresses de courriel valides séparées par des virgules."
-#: core/validators.py:103
+#: core/validators.py:107
msgid "Please enter a valid IP address."
msgstr "Entrez une adresse IP valide."
-#: core/validators.py:107
+#: core/validators.py:111
msgid "Empty values are not allowed here."
msgstr "Vous ne pouvez pas laisser ce champ vide."
-#: core/validators.py:111
+#: core/validators.py:115
msgid "Non-numeric characters aren't allowed here."
msgstr "Les caractères non numériques ne sont pas autorisés ici."
-#: core/validators.py:115
+#: core/validators.py:119
msgid "This value can't be comprised solely of digits."
msgstr "Cette valeur ne peut pas être composé uniquement de chiffres."
-#: core/validators.py:120 newforms/fields.py:128
+#: core/validators.py:124 newforms/fields.py:135
msgid "Enter a whole number."
msgstr "Entrez un nombre entier."
-#: core/validators.py:124
+#: core/validators.py:128
msgid "Only alphabetical characters are allowed here."
msgstr "Seules les lettres de l'alphabet sont autorisées ici."
-#: core/validators.py:139
+#: core/validators.py:143
msgid "Year must be 1900 or later."
msgstr "L'année doit être supérieure à 1900."
-#: core/validators.py:143
+#: core/validators.py:147
#, python-format
msgid "Invalid date: %s"
-msgstr "Date invalide&amp;nbsp;: %s"
+msgstr "Date invalide : %s"
-#: core/validators.py:153
+#: core/validators.py:157
msgid "Enter a valid time in HH:MM format."
msgstr "Entrez une heure valide au format HH:MM."
-#: core/validators.py:162 newforms/fields.py:271
+#: core/validators.py:166 newforms/fields.py:339
msgid "Enter a valid e-mail address."
msgstr "Entrez une adresse de courriel valide."
-#: core/validators.py:178
+#: core/validators.py:182
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
"Envoyez une image valide. Le fichier que vous avez transferé n'est pas une "
-"image ou bien est une image corrompue."
+"image ou bien est corrompu."
-#: core/validators.py:185
+#: core/validators.py:189
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "L'URL %s ne pointe pas vers une image valide."
-#: core/validators.py:189
+#: core/validators.py:193
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr ""
"Les numéros de téléphone doivent être au format XXX-XXX-XXXX. \"%s\" est "
"incorrect."
-#: core/validators.py:197
+#: core/validators.py:201
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "L'URL %s ne pointe pas vers une vidéo QuickTime valide."
-#: core/validators.py:201
+#: core/validators.py:205
msgid "A valid URL is required."
msgstr "Une URL valide est requise."
-#: core/validators.py:215
+#: core/validators.py:219
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
"%s"
msgstr ""
-"Du HTML valide est requis. Les erreurs sont les suivantes&amp;nbsp;:\n"
+"Du HTML valide est requis. Les erreurs sont les suivantes :\n"
"%s"
-#: core/validators.py:222
+#: core/validators.py:226
#, python-format
msgid "Badly formed XML: %s"
-msgstr "XML mal formé&amp;nbsp;: %s"
+msgstr "XML mal formé : %s"
-#: core/validators.py:239
+#: core/validators.py:243
#, python-format
msgid "Invalid URL: %s"
-msgstr "URL invalide&amp;nbsp;: %s"
+msgstr "URL invalide : %s"
-#: core/validators.py:244 core/validators.py:246
+#: core/validators.py:248 core/validators.py:250
#, python-format
msgid "The URL %s is a broken link."
msgstr "L'URL %s est un lien cassé."
-#: core/validators.py:252
+#: core/validators.py:256
msgid "Enter a valid U.S. state abbreviation."
-msgstr "Entrez une abréviation d'état américain valide."
+msgstr "Entrez une abréviation d'État Américain valide."
-#: core/validators.py:266
+#: core/validators.py:270
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Attention à votre langage ! Le mot %s n'est pas autorisé ici."
msgstr[1] "Attention à votre langage ! Les mots %s ne sont pas autorisés ici."
-#: core/validators.py:273
+#: core/validators.py:277
#, python-format
msgid "This field must match the '%s' field."
msgstr "Ce champ doit correspondre au champ '%s'."
-#: core/validators.py:292
+#: core/validators.py:296
msgid "Please enter something for at least one field."
-msgstr "Saisissez au moins une valeur dans un des champs s'il vous plaît."
+msgstr "Veuillez saisir quelque chose dans au moins un des champs."
-#: core/validators.py:301 core/validators.py:312
+#: core/validators.py:305 core/validators.py:316
msgid "Please enter both fields or leave them both empty."
-msgstr ""
-"Renseignez chacun des champs ou laissez les deux vides s'il vous plaît."
+msgstr "Veuillez renseigner les deux champs ou les laisser tous les deux vides."
-#: core/validators.py:320
+#: core/validators.py:324
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "Ce champ doit être renseigné si %(field)s vaut %(value)s"
-#: core/validators.py:333
+#: core/validators.py:337
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Ce champ doit être renseigné si %(field)s ne vaut pas %(value)s"
-#: core/validators.py:352
+#: core/validators.py:356
msgid "Duplicate values are not allowed."
-msgstr "Des valeurs identiques ne sont pas autorisées."
+msgstr "Les valeurs identiques ne sont pas autorisées."
-#: core/validators.py:367
+#: core/validators.py:371
#, python-format
msgid "This value must be between %(lower)s and %(upper)s."
msgstr "Cette valeur doit être comprise entre %(lower)s et %(upper)s."
-#: core/validators.py:369
+#: core/validators.py:373
#, python-format
msgid "This value must be at least %s."
msgstr "Cette valeur doit être au moins %s."
-#: core/validators.py:371
+#: core/validators.py:375
#, python-format
msgid "This value must be no more than %s."
msgstr "Cette valeur ne doit pas dépasser %s."
-#: core/validators.py:407
+#: core/validators.py:411
#, python-format
msgid "This value must be a power of %s."
msgstr "Cette valeur doit être une puissance de %s."
-#: core/validators.py:418
+#: core/validators.py:420
msgid "Please enter a valid decimal number."
-msgstr "Saisissez un nombre décimal valide s'il vous plaît."
+msgstr "Veuillez saisir un nombre décimal valide."
-#: core/validators.py:422
+#: core/validators.py:426
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
msgstr[0] ""
-"Saisissez un nombre décimal valide avec au plus %s chiffre s'il vous plaît."
+"Veuillez saisir un nombre décimal valide avec au plus %s chiffre."
msgstr[1] ""
-"Saisissez un nombre décimal valide avec au plus %s chiffres s'il vous plaît."
+"Veuillez saisir un nombre décimal valide avec au plus %s chiffres."
-#: core/validators.py:425
+#: core/validators.py:429
#, python-format
msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit."
msgid_plural ""
"Please enter a valid decimal number with a whole part of at most %s digits."
-msgstr[0] "Veuillez saisir un nombre décimal valide avec au plus %s chiffre."
-msgstr[1] "Veuillez saisir un nombre décimal valide avec au plus %s chiffres."
+msgstr[0] "Veuillez saisir un nombre décimal valide avec une partie entière de %s chiffre au plus."
+msgstr[1] "Veuillez saisir un nombre décimal valide avec une partie entière de %s chiffres au plus."
-#: core/validators.py:428
+#: core/validators.py:432
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
@@ -513,32 +527,36 @@ msgid_plural ""
msgstr[0] "Veuillez saisir un nombre décimal valide avec au plus %s décimale."
msgstr[1] "Veuillez saisir un nombre décimal valide avec au plus %s décimales."
-#: core/validators.py:438
+#: core/validators.py:440
+msgid "Please enter a valid floating point number."
+msgstr "Veuillez entrer un nombre à virgule flottante valide."
+
+#: core/validators.py:449
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr ""
-"Vérifiez que le fichier transféré fait au moins une taille de %s octets."
+"Vérifiez que le fichier transféré fait au moins %s octets."
-#: core/validators.py:439
+#: core/validators.py:450
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr ""
-"Vérifiez que le fichier transféré fait au plus une taille de %s octets."
+"Vérifiez que le fichier transféré fait au plus %s octets."
-#: core/validators.py:456
+#: core/validators.py:467
msgid "The format for this field is wrong."
msgstr "Le format de ce champ est mauvais."
-#: core/validators.py:471
+#: core/validators.py:482
msgid "This field is invalid."
msgstr "Ce champ est invalide."
-#: core/validators.py:507
+#: core/validators.py:518
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "Impossible de récupérer quoi que ce soit depuis %s."
-#: core/validators.py:510
+#: core/validators.py:521
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
@@ -546,16 +564,16 @@ msgstr ""
"L'entête Content-Type '%(contenttype)s', renvoyée par l'url %(url)s n'est "
"pas valide."
-#: core/validators.py:543
+#: core/validators.py:554
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
"\"%(start)s\".)"
msgstr ""
-"Veuillez fermer le tag %(tag)s de la ligne %(line)s. (La ligne débutant par "
+"Veuillez fermer le tag %(tag)s à la ligne %(line)s. (Ligne débutant par "
"\"%(start)s\".)"
-#: core/validators.py:547
+#: core/validators.py:558
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
@@ -564,7 +582,7 @@ msgstr ""
"Du texte commençant à la ligne %(line)s n'est pas autorisé dans ce contexte. "
"(Ligne débutant par \"%(start)s\".)"
-#: core/validators.py:552
+#: core/validators.py:563
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
@@ -573,7 +591,7 @@ msgstr ""
"\"%(attr)s\" ligne %(line)s n'est pas un attribut valide. (Ligne débutant "
"par \"%(start)s\".)"
-#: core/validators.py:557
+#: core/validators.py:568
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
@@ -582,7 +600,7 @@ msgstr ""
"\"<%(tag)s>\" ligne %(line)s n'est pas un tag valide. (Ligne débutant par \"%"
"(start)s\".)"
-#: core/validators.py:561
+#: core/validators.py:572
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
@@ -591,7 +609,7 @@ msgstr ""
"Un tag, ou un ou plusieurs attributs, de la ligne %(line)s est manquant. "
"(Ligne débutant par \"%(start)s\".)"
-#: core/validators.py:566
+#: core/validators.py:577
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
@@ -615,64 +633,83 @@ msgstr "L'objet %(verbose_name)s a été mis à jour avec succès."
msgid "The %(verbose_name)s was deleted."
msgstr "L'objet %(verbose_name)s a été supprimé."
-#: newforms/models.py:165 newforms/fields.py:362
+#: newforms/models.py:175 newforms/fields.py:432
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr ""
"Sélectionnez un choix valide. Ce choix ne fait pas partie de ceux "
"disponibles."
-#: newforms/models.py:182 newforms/fields.py:380 newforms/fields.py:456
+#: newforms/models.py:192 newforms/fields.py:448 newforms/fields.py:527
msgid "Enter a list of values."
-msgstr "Entrez une liste de valeur."
+msgstr "Entrez une liste de valeurs."
-#: newforms/models.py:188 newforms/fields.py:389
+#: newforms/models.py:198 newforms/fields.py:457
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
-msgstr "Sélectionnez un choix valide ; %s n'en fait pas partie."
+msgstr "Sélectionnez un choix valide; %s n'en fait pas partie."
-#: newforms/fields.py:103 newforms/fields.py:256
+#: newforms/fields.py:110 newforms/fields.py:324
#, python-format
msgid "Ensure this value has at most %d characters."
-msgstr "Assurez-vous que cette valeur fait moins de %d caractère."
+msgstr "Assurez-vous que cette valeur fait moins de %d caractères."
-#: newforms/fields.py:105 newforms/fields.py:258
+#: newforms/fields.py:112 newforms/fields.py:326
#, python-format
msgid "Ensure this value has at least %d characters."
-msgstr "Assurez-vous que cette valeur fait au moins %d caractère."
+msgstr "Assurez-vous que cette valeur fait plus de %d caractères."
-#: newforms/fields.py:130
+#: newforms/fields.py:137 newforms/fields.py:160 newforms/fields.py:192
#, python-format
msgid "Ensure this value is less than or equal to %s."
-msgstr "Assurez-vous que cette valeur soit plus petite ou égale à %s."
+msgstr "Assurez-vous que cette valeur soit inférieure ou égale à %s."
-#: newforms/fields.py:132
+#: newforms/fields.py:139 newforms/fields.py:162 newforms/fields.py:194
#, python-format
msgid "Ensure this value is greater than or equal to %s."
-msgstr "Assurez-vous que cette valeur soit plus grande ou égale à %s."
+msgstr "Assurez-vous que cette valeur soit supérieure ou égale à %s."
+
+#: newforms/fields.py:158 newforms/fields.py:186
+msgid "Enter a number."
+msgstr "Entrez un nombre."
+
+#: newforms/fields.py:196
+#, python-format
+msgid "Ensure that there are no more than %s digits in total."
+msgstr "Assurez-vous qu'il n'y a pas plus de %s chiffres au total."
+
+#: newforms/fields.py:198
+#, python-format
+msgid "Ensure that there are no more than %s decimal places."
+msgstr "Assurez-vous qu'il n'y a pas plus de %s chiffres après la virgule."
+
+#: newforms/fields.py:200
+#, python-format
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr "Assurez-vous qu'il n'y a pas plus de %s chiffres avant la virgule."
-#: newforms/fields.py:165
+#: newforms/fields.py:233 newforms/fields.py:567
msgid "Enter a valid date."
msgstr "Entrez une date valide."
-#: newforms/fields.py:192
+#: newforms/fields.py:260 newforms/fields.py:569
msgid "Enter a valid time."
msgstr "Entrez une heure valide."
-#: newforms/fields.py:228
+#: newforms/fields.py:296
msgid "Enter a valid date/time."
msgstr "Entrez une date et une heure valides."
-#: newforms/fields.py:242
+#: newforms/fields.py:310
msgid "Enter a valid value."
msgstr "Entrez une valeur valide."
-#: newforms/fields.py:289 newforms/fields.py:311
+#: newforms/fields.py:357 newforms/fields.py:379
msgid "Enter a valid URL."
msgstr "Entrez une URL valide."
-#: newforms/fields.py:313
+#: newforms/fields.py:381
msgid "This URL appears to be a broken link."
-msgstr "L'URL est un lien cassé."
+msgstr "Cette URL semble être cassée."
#: contrib/humanize/templatetags/humanize.py:17
msgid "th"
@@ -756,8 +793,8 @@ msgid ""
"This should be an absolute path, excluding the domain name. Example: '/"
"events/search/'."
msgstr ""
-"Ceci doit être un chemin absolu, sans nom de domaine. Par exemple: '/events/"
-"search/'."
+"Ceci doit être un chemin absolu, sans nom de domaine. Par exemple: '/evenements/"
+"rechercher/'."
#: contrib/redirects/models.py:9
msgid "redirect to"
@@ -836,7 +873,7 @@ msgstr "date et heure soumises"
msgid "is public"
msgstr "est public"
-#: contrib/comments/models.py:85 contrib/admindocs/views.py:304
+#: contrib/comments/models.py:85 contrib/admindocs/views.py:305
msgid "IP address"
msgstr "adresse IP"
@@ -877,7 +914,7 @@ msgstr ""
#: contrib/comments/models.py:158
msgid "person's name"
-msgstr "nom"
+msgstr "nom de la personne"
#: contrib/comments/models.py:161
msgid "ip address"
@@ -961,25 +998,25 @@ msgstr "suppressions de modérateur"
msgid "Moderator deletion by %r"
msgstr "Suppression de modérateur par %r"
-#: contrib/comments/views/karma.py:19
+#: contrib/comments/views/karma.py:20
msgid "Anonymous users cannot vote"
msgstr "Les utilisateurs anonymes ne peuvent pas voter"
-#: contrib/comments/views/karma.py:23
+#: contrib/comments/views/karma.py:24
msgid "Invalid comment ID"
-msgstr "ID de commentaire invalide"
+msgstr "Identifiant de commentaire invalide"
-#: contrib/comments/views/karma.py:25
+#: contrib/comments/views/karma.py:26
msgid "No voting for yourself"
msgstr "Impossible de voter pour soi-même"
-#: contrib/comments/views/comments.py:27
+#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr ""
-"Ce votre est nécéssaire parceque vous avez saisi au moins un autre vote."
+"Ce vote est nécessaire car vous avez saisi au moins un autre vote."
-#: contrib/comments/views/comments.py:111
+#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
@@ -993,67 +1030,67 @@ msgid_plural ""
"%(text)s"
msgstr[0] ""
"Ce commentaire a été posté par un utilisateur qui a posté moins de %(count)s "
-"commentaire&amp;nbsp;:\n"
+"commentaire :\n"
"\n"
"%(text)s"
msgstr[1] ""
"Ce commentaire a été posté par un utilisateur qui a posté moins de %(count)s "
-"commentaires&amp;nbsp;:\n"
+"commentaires :\n"
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:116
+#: contrib/comments/views/comments.py:117
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
"\n"
"%(text)s"
msgstr ""
-"Ce commentaire a été posté par un utilisateur imprécis&amp;nbsp;:\n"
+"Ce commentaire a été posté par un utilisateur imprécis :\n"
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
msgid "Only POSTs are allowed"
msgstr "Seuls les POSTs sont autorisés"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
msgid "One or more of the required fields wasn't submitted"
msgstr "Un ou plusieurs champs requis n'ont pas été remplis"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
msgid "Somebody tampered with the comment form (security violation)"
msgstr ""
"Quelqu'un a trafiqué le formulaire de commentaire (violation des règles de "
"sécurité)"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
msgstr ""
-"Ce formulaire de commentaire avait un paramètre cible invalide ; l'ID de "
+"Ce formulaire de commentaire avait un paramètre cible invalide; l'identifiant de "
"l'objet était invalide"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr ""
-"Le formulaire de commentaire ne proposait ni les options de prévisualisation "
-"ni d'envoi"
+"Le formulaire de commentaire ne proposait ni la prévisualisation "
+"ni l'envoi"
#: contrib/comments/templates/comments/freeform.html:4
msgid "Your name:"
-msgstr "Votre nom&amp;nbsp;:"
+msgstr "Votre nom :"
#: contrib/comments/templates/comments/freeform.html:5
#: contrib/comments/templates/comments/form.html:28
msgid "Comment:"
-msgstr "Commentaire&amp;nbsp;:"
+msgstr "Commentaire :"
#: contrib/comments/templates/comments/freeform.html:10
#: contrib/comments/templates/comments/form.html:35
@@ -1095,7 +1132,7 @@ msgstr "Mot de passe"
#: contrib/comments/templates/comments/form.html:8
msgid "Forgotten your password?"
-msgstr "Mot de passe oublié?"
+msgstr "Mot de passe oublié ?"
#: contrib/comments/templates/comments/form.html:12
msgid "Ratings"
@@ -1131,65 +1168,65 @@ msgstr "site"
msgid "sites"
msgstr "sites"
-#: contrib/admin/filterspecs.py:40
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
"<ul>\n"
msgstr ""
-"<h3>Par %s&amp;nbsp;:</h3>\n"
+"<h3>Par %s&nbsp;:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Tout"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Toutes les dates"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Aujourd'hui"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
msgstr "Les 7 derniers jours"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Ce mois-ci"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
msgstr "Cette année"
-#: contrib/admin/options.py:307 contrib/admin/views/auth.py:19
+#: contrib/admin/options.py:323 contrib/admin/views/auth.py:20
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "L'objet %(name)s \"%(obj)s\" a été ajouté avec succès."
-#: contrib/admin/options.py:311 contrib/admin/options.py:363
-#: contrib/admin/views/auth.py:24
+#: contrib/admin/options.py:327 contrib/admin/options.py:385
+#: contrib/admin/views/auth.py:25
msgid "You may edit it again below."
msgstr "Vous pouvez continuez de l'éditez ci-dessous."
-#: contrib/admin/options.py:321 contrib/admin/options.py:372
+#: contrib/admin/options.py:337 contrib/admin/options.py:394
#, python-format
msgid "You may add another %s below."
msgstr "Vous pouvez ajouter un autre %s ci-dessous."
-#: contrib/admin/options.py:358
+#: contrib/admin/options.py:380
msgid "No fields changed."
msgstr "Aucun champ modifié."
-#: contrib/admin/options.py:361
+#: contrib/admin/options.py:383
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "L'objet %(name)s \"%(obj)s\" a été modifié avec succès."
-#: contrib/admin/options.py:369
+#: contrib/admin/options.py:391
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
@@ -1197,69 +1234,69 @@ msgstr ""
"L'objet %(name)s \"%(obj)s\" a été ajouté avec succès.Vous pouvez continuez "
"de l'éditez ci-dessous."
-#: contrib/admin/options.py:408
+#: contrib/admin/options.py:437
#, python-format
msgid "Add %s"
msgstr "Ajouter %s"
-#: contrib/admin/options.py:468
+#: contrib/admin/options.py:504
#, python-format
msgid "Change %s"
msgstr "Changement %s"
-#: contrib/admin/options.py:494
+#: contrib/admin/options.py:531
msgid "Database error"
msgstr "Erreur de base de données"
-#: contrib/admin/options.py:539
+#: contrib/admin/options.py:576
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "L'objet %(name)s \"%(obj)s\" a été supprimé avec succès."
-#: contrib/admin/options.py:542
+#: contrib/admin/options.py:579
msgid "Are you sure?"
msgstr "Êtes-vous sûr ?"
-#: contrib/admin/options.py:564
+#: contrib/admin/options.py:601
#, python-format
msgid "Change history: %s"
-msgstr "Historique des changements&amp;nbsp;: %s"
+msgstr "Historique des changements : %s"
-#: contrib/admin/models.py:16
+#: contrib/admin/models.py:17
msgid "action time"
msgstr "heure de l'action"
-#: contrib/admin/models.py:19
+#: contrib/admin/models.py:20
msgid "object id"
msgstr "id de l'objet"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object repr"
msgstr "représentation de l'objet"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "action flag"
msgstr "indicateur de l'action"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "change message"
msgstr "message de modification"
-#: contrib/admin/models.py:25
+#: contrib/admin/models.py:26
msgid "log entry"
msgstr "entrée d'historique"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entries"
msgstr "entrées d'historique"
-#: contrib/admin/widgets.py:43
+#: contrib/admin/widgets.py:44
msgid "Date:"
-msgstr "Date&amp;nbsp;:"
+msgstr "Date :"
-#: contrib/admin/widgets.py:43
+#: contrib/admin/widgets.py:44
msgid "Time:"
-msgstr "Heure&amp;nbsp;:"
+msgstr "Heure :"
#: contrib/admin/sites.py:13 contrib/admin/views/decorators.py:10
#: contrib/auth/forms.py:60
@@ -1267,7 +1304,7 @@ msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgstr ""
-"Saisissez s'il vous plaît un nom d'utilisateur et un mot de passe valide. "
+"Veuillez saisir un nom d'utilisateur et un mot de passe valide. "
"Remarquez que chacun de ces champs est sensible à la casse (différenciation "
"des majuscules/minuscules)."
@@ -1281,16 +1318,16 @@ msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
msgstr ""
-"Votre session a expiré, connectez-vous de nouveau s'il vous plaît. Ne vous "
-"inquiétez pas, votre travail précédement éffectué a été sauvé."
+"Veuillez vous reconnecter, car votre session a expiré. Ne vous "
+"inquiétez pas, votre soumission a été enregistrée."
#: contrib/admin/sites.py:193 contrib/admin/views/decorators.py:69
msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
msgstr ""
-"Il semblerait que votre navigateur n'accepte pas les cookies. Activez-les, "
-"rechargez cette page et rééssayez s'il vous plaît."
+"Il semblerait que votre navigateur n'accepte pas les cookies. Veuillez"
+"les activer, recharger cette page, puis rééssayer."
#: contrib/admin/sites.py:207 contrib/admin/views/decorators.py:83
msgid "Usernames cannot contain the '@' character."
@@ -1302,54 +1339,54 @@ msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr ""
"Votre courriel n'est pas votre nom d'utilisateur. Essayez '%s' à la place."
-#: contrib/admin/sites.py:263 contrib/admin/views/main.py:136
+#: contrib/admin/sites.py:276 contrib/admin/views/main.py:143
msgid "Site administration"
msgstr "Gestion du site"
-#: contrib/admin/templatetags/admin_list.py:247
+#: contrib/admin/templatetags/admin_list.py:252
msgid "All dates"
msgstr "Toutes les dates"
-#: contrib/admin/views/auth.py:30
+#: contrib/admin/views/auth.py:31
msgid "Add user"
msgstr "Ajouter l'utilisateur"
-#: contrib/admin/views/auth.py:55
+#: contrib/admin/views/auth.py:56
msgid "Password changed successfully."
msgstr "Mot de passe modifié avec succés"
-#: contrib/admin/views/auth.py:62
+#: contrib/admin/views/auth.py:63
#, python-format
msgid "Change password: %s"
-msgstr "Modifier le mot de passe&amp;nbsp;: %s"
+msgstr "Modifier le mot de passe : %s"
-#: contrib/admin/views/main.py:215
+#: contrib/admin/views/main.py:222
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
-msgstr "Un ou plusieurs %(fieldname)s dans %(name)s&amp;nbsp;: %(obj)s"
+msgstr "Un ou plusieurs %(fieldname)s dans %(name)s : %(obj)s"
-#: contrib/admin/views/main.py:220
+#: contrib/admin/views/main.py:227
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
-msgstr "Un ou plusieurs %(fieldname)s dans %(name)s&amp;nbsp;: "
+msgstr "Un ou plusieurs %(fieldname)s dans %(name)s :"
-#: contrib/admin/views/main.py:262
+#: contrib/admin/views/main.py:269
#, python-format
msgid "Select %s"
msgstr "Sélectionnez %s"
-#: contrib/admin/views/main.py:262
+#: contrib/admin/views/main.py:269
#, python-format
msgid "Select %s to change"
msgstr "Sélectionnez %s pour changer"
#: contrib/admin/templates/widget/file.html:2
msgid "Currently:"
-msgstr "Actuellement&amp;nbsp;:"
+msgstr "Actuellement :"
#: contrib/admin/templates/widget/file.html:3
msgid "Change:"
-msgstr "Modification&amp;nbsp;:"
+msgstr "Modification :"
#: contrib/admin/templates/admin/object_history.html:4
#: contrib/admin/templates/admin/change_list.html:8
@@ -1465,7 +1502,7 @@ msgid ""
msgstr ""
"Une erreur est survenue. Elle a été transmise par courriel aux "
"administrateurs du site et sera corrigée dans les meilleurs délais. Merci "
-"pour votre patience."
+"de votre patience."
#: contrib/admin/templates/admin/invalid_setup.html:7
msgid ""
@@ -1473,8 +1510,8 @@ msgid ""
"database tables have been created, and make sure the database is readable by "
"the appropriate user."
msgstr ""
-"Quelque chose ne va pas avec votre base de données. Vérifiez que lesbonnes "
-"bases ont été créées, et qu'elle est lisible par le bon utilisateur."
+"Quelque chose ne va pas avec votre base de données. Vérifiez que les bonnes "
+"tables ont été créées, et que la base est lisible par le bon utilisateur."
#: contrib/admin/templates/admin/search_form.html:8
msgid "Go"
@@ -1577,7 +1614,7 @@ msgid ""
msgstr ""
"Supprimer l'objet %(object_name)s '%(escaped_object)s' provoquerait la "
"suppression des objets qui lui sont liés mais votre compte ne possède pas la "
-"permission de supprimer les types d'objets suivants&amp;nbsp;:"
+"permission de supprimer les types d'objets suivants :"
#: contrib/admin/templates/admin/delete_confirmation.html:24
#, python-format
@@ -1587,7 +1624,7 @@ msgid ""
msgstr ""
"Êtes vous certain de vouloir supprimer l'objet %(object_name)s \"%"
"(escaped_object)s\" ? Les éléments suivant sont liés à celui-ci et seront "
-"aussi supprimés&amp;nbsp;:"
+"aussi supprimés :"
#: contrib/admin/templates/admin/delete_confirmation.html:29
msgid "Yes, I'm sure"
@@ -1636,7 +1673,7 @@ msgid ""
"First, enter a username and password. Then, you'll be able to edit more user "
"options."
msgstr ""
-"Entrez tout d'abord un nom d'utilisateur et un mot de passe.Vous pourrez "
+"Entrez tout d'abord un nom d'utilisateur et un mot de passe. Vous pourrez "
"ensuite modifier plus d'options."
#: contrib/admin/templates/admin/auth/user/add_form.html:12
@@ -1677,7 +1714,7 @@ msgstr ""
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
-msgstr "Courriel&amp;nbsp;:"
+msgstr "Courriel :"
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "Reset my password"
@@ -1715,15 +1752,15 @@ msgstr ""
#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
-msgstr "Ancien mot de passe&amp;nbsp;:"
+msgstr "Ancien mot de passe :"
#: contrib/admin/templates/registration/password_change_form.html:19
msgid "New password:"
-msgstr "Nouveau mot de passe&amp;nbsp;:"
+msgstr "Nouveau mot de passe :"
#: contrib/admin/templates/registration/password_change_form.html:21
msgid "Confirm password:"
-msgstr "Confirmation du nouveau mot de passe"
+msgstr "Confirmation du mot de passe"
#: contrib/admin/templates/registration/password_change_form.html:23
msgid "Change my password"
@@ -1742,15 +1779,15 @@ msgstr "pour votre compte au site %(site_name)s"
#: contrib/admin/templates/registration/password_reset_email.html:5
#, python-format
msgid "Your new password is: %(new_password)s"
-msgstr "Votre nouveau mot de passe est&amp;nbsp;: %(new_password)s"
+msgstr "Votre nouveau mot de passe est : %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
-msgstr "Vous pouvez modifier ce mot de passe à l'adresse suivante&amp;nbsp;:"
+msgstr "Vous pouvez modifier ce mot de passe à l'adresse suivante :"
#: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:"
-msgstr "Votre nom d'utilisateur, en cas d'oubli&amp;nbsp;:"
+msgstr "Votre nom d'utilisateur, en cas d'oubli :"
#: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!"
@@ -1780,10 +1817,9 @@ msgid ""
"your computer is \"internal\").</p>\n"
msgstr ""
"\n"
-"<p class=\"help\">Pour installer des bookmarklets, faîtes glisser le lien "
-"vers\n"
+"<p class=\"help\">Pour installer des signets, faîtes glisser le lien vers\n"
"votre barre de marques-pages, ou cliquez droit dessus et ajoutez-y le.\n"
-"Maintenant vous pouvez le sélectionner depuis n'importe quelle page\n"
+"Maintenant, vous pouvez le sélectionner depuis n'importe quelle page\n"
"du site. Notez que certains d'entre eux nécessitent que vous visionniez\n"
"le site depuis un ordinateur dit \"interne\" (veuillez contacter votre\n"
"administrateur système si vous n'êtes pas sûr que votre ordinateur le soit)."
@@ -1803,14 +1839,14 @@ msgstr ""
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
msgid "Show object ID"
-msgstr "Afficher l'ID de l'objet"
+msgstr "Afficher l'identifiant de l'objet"
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
msgid ""
"Shows the content-type and unique ID for pages that represent a single "
"object."
msgstr ""
-"Montre le content-type et l'ID unique pour les pages qui représente un objet "
+"Montre le content-type et l'identifiant unique pour les pages qui représentent un objet "
"unique."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
@@ -1831,75 +1867,75 @@ msgstr ""
"Comme ci-dessus, mais ouvre la page d'administration dans une nouvelle "
"fenêtre."
-#: contrib/contenttypes/models.py:36
+#: contrib/contenttypes/models.py:37
msgid "python model class name"
msgstr "nom du module python"
-#: contrib/contenttypes/models.py:39
+#: contrib/contenttypes/models.py:40
msgid "content type"
msgstr "type de contenu"
-#: contrib/contenttypes/models.py:40
+#: contrib/contenttypes/models.py:41
msgid "content types"
msgstr "types de contenu"
-#: contrib/auth/views.py:39
+#: contrib/auth/views.py:41
msgid "Logged out"
msgstr "Déconnecté"
-#: contrib/auth/models.py:38 contrib/auth/models.py:58
+#: contrib/auth/models.py:51 contrib/auth/models.py:71
msgid "name"
msgstr "nom"
-#: contrib/auth/models.py:40
+#: contrib/auth/models.py:53
msgid "codename"
msgstr "nom de code"
-#: contrib/auth/models.py:43
+#: contrib/auth/models.py:56
msgid "permission"
msgstr "permission"
-#: contrib/auth/models.py:44 contrib/auth/models.py:59
+#: contrib/auth/models.py:57 contrib/auth/models.py:72
msgid "permissions"
msgstr "permissions"
-#: contrib/auth/models.py:62
+#: contrib/auth/models.py:75
msgid "group"
msgstr "groupe"
-#: contrib/auth/models.py:63 contrib/auth/models.py:100
+#: contrib/auth/models.py:76 contrib/auth/models.py:113
msgid "groups"
msgstr "groupes"
-#: contrib/auth/models.py:90
+#: contrib/auth/models.py:103
msgid "username"
msgstr "nom d'utilisateur"
-#: contrib/auth/models.py:90
+#: contrib/auth/models.py:103
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
msgstr ""
"Requis. 30 caractères maximum, alphanumériques uniquement (lettres, "
-"chiffres, et tirets bas '_')."
+"chiffres, et tirets bas _)."
-#: contrib/auth/models.py:91
+#: contrib/auth/models.py:104
msgid "first name"
msgstr "prénom"
-#: contrib/auth/models.py:92
+#: contrib/auth/models.py:105
msgid "last name"
msgstr "nom"
-#: contrib/auth/models.py:93
+#: contrib/auth/models.py:106
msgid "e-mail address"
msgstr "courriel"
-#: contrib/auth/models.py:94
+#: contrib/auth/models.py:107
msgid "password"
msgstr "mot de passe"
-#: contrib/auth/models.py:94
+#: contrib/auth/models.py:107
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
@@ -1907,31 +1943,31 @@ msgstr ""
"Utilisez [algo]$[salt]$[hexdigest]' ou le <a href=\"password/\">formulaire "
"de changement de mot de passe</a>."
-#: contrib/auth/models.py:95
+#: contrib/auth/models.py:108
msgid "staff status"
msgstr "statut équipe"
-#: contrib/auth/models.py:95
+#: contrib/auth/models.py:108
msgid "Designates whether the user can log into this admin site."
msgstr "Précise si l'utilisateur peut se connecter à ce site d'administration."
-#: contrib/auth/models.py:96
+#: contrib/auth/models.py:109
msgid "active"
msgstr "actif"
-#: contrib/auth/models.py:96
+#: contrib/auth/models.py:109
msgid ""
"Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts."
msgstr ""
"Précise si l'utilisateur peut se connecter à l'administration. "
-"Déselectionnezceci plutôt que supprimer le compte."
+"Déselectionnez ceci plutôt que supprimer le compte."
-#: contrib/auth/models.py:97
+#: contrib/auth/models.py:110
msgid "superuser status"
msgstr "statut super-utilisateur"
-#: contrib/auth/models.py:97
+#: contrib/auth/models.py:110
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
@@ -1939,15 +1975,15 @@ msgstr ""
"Précise que l'utilisateur possède toutes les permissions sans les assigner "
"explicitement."
-#: contrib/auth/models.py:98
+#: contrib/auth/models.py:111
msgid "last login"
msgstr "dernière connexion"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:112
msgid "date joined"
msgstr "date d'inscription"
-#: contrib/auth/models.py:101
+#: contrib/auth/models.py:114
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@@ -1956,39 +1992,35 @@ msgstr ""
"recevra aussi toutes les permissions de tous les groupes auquels il "
"appartient. "
-#: contrib/auth/models.py:102
+#: contrib/auth/models.py:115
msgid "user permissions"
msgstr "permissions de l'utilisateur"
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:119
msgid "user"
msgstr "utilisateur"
-#: contrib/auth/models.py:107
+#: contrib/auth/models.py:120
msgid "users"
msgstr "utilisateurs"
-#: contrib/auth/models.py:248
+#: contrib/auth/models.py:259
msgid "message"
msgstr "message"
-#: contrib/auth/models.py:261
-msgid "AnonymousUser"
-msgstr "Anonyme"
-
-#: contrib/auth/models.py:320
+#: contrib/auth/models.py:334
msgid "Personal info"
msgstr "Information personnelle"
-#: contrib/auth/models.py:321
+#: contrib/auth/models.py:335
msgid "Permissions"
msgstr "Permissions"
-#: contrib/auth/models.py:322
+#: contrib/auth/models.py:336
msgid "Important dates"
msgstr "Dates importantes"
-#: contrib/auth/models.py:323
+#: contrib/auth/models.py:337
msgid "Groups"
msgstr "Groupes"
@@ -2012,7 +2044,7 @@ msgstr ""
msgid "This account is inactive."
msgstr "Ce compte est inactif."
-#: contrib/auth/forms.py:85
+#: contrib/auth/forms.py:84
msgid ""
"That e-mail address doesn't have an associated user account. Are you sure "
"you've registered?"
@@ -2022,140 +2054,140 @@ msgstr ""
#: contrib/auth/forms.py:117
msgid "The two 'new password' fields didn't match."
-msgstr "Les deux nouveaux mots de passe ne correspondent pas."
+msgstr "Les deux champs \"nouveau mot de passe\" ne correspondent pas."
#: contrib/auth/forms.py:124
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr "Votre ancien mot de passe est incorrect. Veuillez le rectifier."
-#: contrib/admindocs/views.py:46 contrib/admindocs/views.py:48
-#: contrib/admindocs/views.py:50
+#: contrib/admindocs/views.py:47 contrib/admindocs/views.py:49
+#: contrib/admindocs/views.py:51
msgid "tag:"
-msgstr "mot-clé&amp;nbsp;:"
+msgstr "mot-clé :"
-#: contrib/admindocs/views.py:77 contrib/admindocs/views.py:79
-#: contrib/admindocs/views.py:81
+#: contrib/admindocs/views.py:78 contrib/admindocs/views.py:80
+#: contrib/admindocs/views.py:82
msgid "filter:"
-msgstr "filtre&amp;nbsp;:"
+msgstr "filtre :"
-#: contrib/admindocs/views.py:135 contrib/admindocs/views.py:137
-#: contrib/admindocs/views.py:139
+#: contrib/admindocs/views.py:136 contrib/admindocs/views.py:138
+#: contrib/admindocs/views.py:140
msgid "view:"
-msgstr "vue&amp;nbsp;:"
+msgstr "vue :"
-#: contrib/admindocs/views.py:164
+#: contrib/admindocs/views.py:165
#, python-format
msgid "App %r not found"
msgstr "L'application %r n'a pas été trouvée."
-#: contrib/admindocs/views.py:171
+#: contrib/admindocs/views.py:172
#, python-format
msgid "Model %(name)r not found in app %(app)r"
msgstr "Le modèle %(name)r n'a pas été trouvé dans l'application %(app)r"
-#: contrib/admindocs/views.py:183
+#: contrib/admindocs/views.py:184
#, python-format
msgid "the related `%(app)s.%(type)s` object"
-msgstr "l'objet `%(app)s.%(type)s en relation "
+msgstr "l'objet `%(app)s.%(type)s` en relation "
-#: contrib/admindocs/views.py:183 contrib/admindocs/views.py:205
-#: contrib/admindocs/views.py:219 contrib/admindocs/views.py:224
+#: contrib/admindocs/views.py:184 contrib/admindocs/views.py:206
+#: contrib/admindocs/views.py:220 contrib/admindocs/views.py:225
msgid "model:"
-msgstr "modèle&amp;nbsp;:"
+msgstr "modèle :"
-#: contrib/admindocs/views.py:214
+#: contrib/admindocs/views.py:215
#, python-format
msgid "related `%(app)s.%(name)s` objects"
-msgstr "les objets `%(app)s.%(name)s en relation"
+msgstr "les objets `%(app)s.%(name)s` en relation"
-#: contrib/admindocs/views.py:219
+#: contrib/admindocs/views.py:220
#, python-format
msgid "all %s"
msgstr "tous les %s"
-#: contrib/admindocs/views.py:224
+#: contrib/admindocs/views.py:225
#, python-format
msgid "number of %s"
msgstr "nombre de %s"
-#: contrib/admindocs/views.py:229
+#: contrib/admindocs/views.py:230
#, python-format
msgid "Fields on %s objects"
msgstr "Champs sur les objets %s"
-#: contrib/admindocs/views.py:291 contrib/admindocs/views.py:301
-#: contrib/admindocs/views.py:303 contrib/admindocs/views.py:309
-#: contrib/admindocs/views.py:310 contrib/admindocs/views.py:312
+#: contrib/admindocs/views.py:292 contrib/admindocs/views.py:302
+#: contrib/admindocs/views.py:304 contrib/admindocs/views.py:310
+#: contrib/admindocs/views.py:311 contrib/admindocs/views.py:313
msgid "Integer"
msgstr "Entier"
-#: contrib/admindocs/views.py:292
+#: contrib/admindocs/views.py:293
msgid "Boolean (Either True or False)"
msgstr "Booléen (Vrai ou Faux)"
-#: contrib/admindocs/views.py:293 contrib/admindocs/views.py:311
+#: contrib/admindocs/views.py:294 contrib/admindocs/views.py:312
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "Chaîne de caractère (jusqu'à %(maxlength)s)"
-#: contrib/admindocs/views.py:294
+#: contrib/admindocs/views.py:295
msgid "Comma-separated integers"
msgstr "Des entiers séparés par une virgule"
-#: contrib/admindocs/views.py:295
+#: contrib/admindocs/views.py:296
msgid "Date (without time)"
msgstr "Date (sans l'heure)"
-#: contrib/admindocs/views.py:296
+#: contrib/admindocs/views.py:297
msgid "Date (with time)"
msgstr "Date (avec l'heure)"
-#: contrib/admindocs/views.py:297
+#: contrib/admindocs/views.py:298
msgid "E-mail address"
-msgstr "Courriel&amp;nbsp;:"
+msgstr "Courriel"
-#: contrib/admindocs/views.py:298 contrib/admindocs/views.py:299
-#: contrib/admindocs/views.py:302
+#: contrib/admindocs/views.py:299 contrib/admindocs/views.py:300
+#: contrib/admindocs/views.py:303
msgid "File path"
msgstr "Chemin vers le fichier"
-#: contrib/admindocs/views.py:300
+#: contrib/admindocs/views.py:301
msgid "Decimal number"
msgstr "Nombre décimal"
-#: contrib/admindocs/views.py:306
+#: contrib/admindocs/views.py:307
msgid "Boolean (Either True, False or None)"
msgstr "Booléen (Vrai, Faux ou None)"
-#: contrib/admindocs/views.py:307
+#: contrib/admindocs/views.py:308
msgid "Relation to parent model"
msgstr "Relation au modèle parent"
-#: contrib/admindocs/views.py:308
+#: contrib/admindocs/views.py:309
msgid "Phone number"
msgstr "Numéro de téléphone"
-#: contrib/admindocs/views.py:313
+#: contrib/admindocs/views.py:314
msgid "Text"
msgstr "Texte"
-#: contrib/admindocs/views.py:314
+#: contrib/admindocs/views.py:315
msgid "Time"
msgstr "Heure"
-#: contrib/admindocs/views.py:315 contrib/flatpages/models.py:7
+#: contrib/admindocs/views.py:316 contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
-#: contrib/admindocs/views.py:316
+#: contrib/admindocs/views.py:317
msgid "U.S. state (two uppercase letters)"
-msgstr "État U.S. (deux lettres majuscules)"
+msgstr "État Américain (deux lettres majuscules)"
-#: contrib/admindocs/views.py:317
+#: contrib/admindocs/views.py:318
msgid "XML text"
msgstr "Texte XML"
-#: contrib/admindocs/views.py:343
+#: contrib/admindocs/views.py:344
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s ne semble pas être un objet urlpattern"
@@ -2170,7 +2202,7 @@ msgid "Enter a 4 digit post code."
msgstr "Entrez un code postal Australien (4 chiffres)."
#: contrib/localflavor/fr/forms.py:17 contrib/localflavor/de/forms.py:16
-#: contrib/localflavor/it/forms.py:14 contrib/localflavor/fi/forms.py:14
+#: contrib/localflavor/fi/forms.py:14
msgid "Enter a zip code in the format XXXXX."
msgstr "Entrez un code postal (format XXXXX)."
@@ -2374,6 +2406,26 @@ msgstr "Entrez un code postal Brésilien (format XXXXX-XXX)."
msgid "Phone numbers must be in XX-XXXX-XXXX format."
msgstr "Les numéros de téléphone doivent être au format XX-XXXX-XXXX."
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr "Ce champ ne doit contenir que des nombres."
+
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr "Ce champ requiert au plus 11 chiffres ou 14 caractères."
+
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr "Numéro CPF invalide."
+
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr "Ce champ requiert au minimum 14 chiffres."
+
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr "Numéro CNPJ invalide."
+
#: contrib/localflavor/de/de_states.py:5
msgid "Baden-Wuerttemberg"
msgstr "Bade-Wurtemberg"
@@ -2446,7 +2498,19 @@ msgstr ""
"Entrez un numéro de carte d'identité Allemand (format XXXXXXXXXXX-XXXXXXX-"
"XXXXXXX-X)."
-#: contrib/localflavor/no/forms.py:15
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Entrez un code postal valide."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Entrez un numéro valide de Sécurité Sociale."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Entrez une TVA valide."
+
+#: contrib/localflavor/no/forms.py:15 contrib/localflavor/ch/forms.py:18
msgid "Enter a zip code in the format XXXX."
msgstr "Entrez un code postal Norvégien (format XXXX)."
@@ -2454,7 +2518,7 @@ msgstr "Entrez un code postal Norvégien (format XXXX)."
msgid "Enter a valid Norwegian social security number."
msgstr "Entrez un numéro de sécurité sociale Norvégien."
-#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:46
+#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
msgid "Enter a valid Finnish social security number."
msgstr "Entrez un numéro de sécurité sociale Finlandais."
@@ -2466,13 +2530,142 @@ msgstr "Entrez un code postal Américain (format XXXXX ou XXXXX-XXXX)."
msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
msgstr "Entrez un numéro de sécurité sociale Américain (format XXX-XX-XXXX)."
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr "Argovie"
+
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
+msgstr "Appenzell Rhodes-Intérieures"
+
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr "Appenzell Rhodes-Extérieures"
+
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr "Bâle-Ville"
+
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
+msgstr "Bâle-Campagne"
+
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr "Berne"
+
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr "Fribourg"
+
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr "Genève"
+
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr "Glaris"
+
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr "Grisons"
+
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr "Jura"
+
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr "Lucerne"
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
+msgstr "Neuchâtel"
+
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr "Nidwald"
+
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr "Obwald"
+
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr "Schaffhouse"
+
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr "Suisse"
+
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr "Soleure"
+
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr "Saint Gall"
+
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr "Thuringe"
+
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr "Tessin"
+
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr "Uri"
+
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr "Valais"
+
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
+msgstr "Vaud"
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr "Zoug"
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr "Zurich"
+
+#: contrib/localflavor/ch/forms.py:90
+msgid ""
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
+msgstr ""
+"Entrez un numéro de passeport ou de carte d'identité valide au format "
+"X1234567<0 ou 1234567890."
+
+#: contrib/localflavor/is_/forms.py:17
+msgid ""
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr "Entrez un code postal islandais valide (format XXXXXX-XXXX)."
+
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr "Le numéro d'identification Islandais est invalide."
+
+#: contrib/localflavor/cl/forms.py:22
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Entrez un RUT Chilien valide (format XX.XXX.XXX-X)."
+
+#: contrib/localflavor/cl/forms.py:27
+msgid "Enter valid a Chilean RUT"
+msgstr "Entrez un RUT Chilien valide."
+
#: contrib/sessions/models.py:68
msgid "session key"
msgstr "clé de session"
#: contrib/sessions/models.py:69
msgid "session data"
-msgstr "donnée de session"
+msgstr "données de session"
#: contrib/sessions/models.py:70
msgid "expire date"
@@ -2490,7 +2683,7 @@ msgstr "sessions"
msgid ""
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr ""
-"Par exemple&amp;nbsp;: '/about/contact/'. Vérifiez la présence du caractère "
+"Par exemple : '/a_propos/contact/'. Vérifiez la présence du caractère "
"'/' en début et en fin de chaine."
#: contrib/flatpages/models.py:9
@@ -2529,11 +2722,11 @@ msgstr ""
#: contrib/flatpages/models.py:19
msgid "flat page"
-msgstr "page à plat"
+msgstr "page statique"
#: contrib/flatpages/models.py:20
msgid "flat pages"
-msgstr "pages à plat"
+msgstr "pages statiques"
#: utils/dates.py:6
msgid "Monday"
@@ -2563,127 +2756,155 @@ msgstr "Samedi"
msgid "Sunday"
msgstr "Dimanche"
-#: utils/dates.py:14
+#: utils/dates.py:10
+msgid "Mon"
+msgstr "Lun"
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr "Mar"
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr "Mer"
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr "Jeu"
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr "Ven"
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr "Sam"
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr "Dim"
+
+#: utils/dates.py:18
msgid "January"
msgstr "Janvier"
-#: utils/dates.py:14
+#: utils/dates.py:18
msgid "February"
msgstr "Février"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "Mars"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "Avril"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Mai"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Juin"
-#: utils/dates.py:15 utils/dates.py:27
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Juillet"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "August"
msgstr "Août"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "September"
msgstr "Septembre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "October"
msgstr "Octobre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "November"
msgstr "Novembre"
-#: utils/dates.py:16
+#: utils/dates.py:20
msgid "December"
msgstr "Décembre"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jan"
msgstr "jan"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "feb"
msgstr "fév"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "mar"
msgstr "mar"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "apr"
msgstr "avr"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "may"
msgstr "mai"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jun"
msgstr "jui"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "jul"
msgstr "jul"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "aug"
-msgstr "aout"
+msgstr "août"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "sep"
msgstr "sep"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "oct"
msgstr "oct"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "nov"
msgstr "nov"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "dec"
msgstr "déc"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Jan."
msgstr "Jan."
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Feb."
msgstr "Fév."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Aug."
-msgstr "Aôut"
+msgstr "Août"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Sept."
msgstr "Sept."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Oct."
msgstr "Oct."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Nov."
msgstr "Nov."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Dec."
msgstr "Déc."
@@ -2723,78 +2944,96 @@ msgid_plural "minutes"
msgstr[0] "minute"
msgstr[1] "minutes"
-#: utils/dateformat.py:40
+#: utils/timesince.py:40
+#, python-format
+msgid "%d milliseconds"
+msgstr "%d millisecondes"
+
+#: utils/timesince.py:41
+#, python-format
+msgid "%(number)d %(type)s"
+msgstr "%(number)d %(type)s"
+
+#: utils/timesince.py:47
+#, python-format
+msgid ", %(number)d %(type)s"
+msgstr ", %(number)d %(type)s"
+
+#: utils/dateformat.py:41
msgid "p.m."
msgstr "après-midi"
-#: utils/dateformat.py:41
+#: utils/dateformat.py:42
msgid "a.m."
msgstr "matin"
-#: utils/dateformat.py:46
+#: utils/dateformat.py:47
msgid "PM"
msgstr "Matin"
-#: utils/dateformat.py:47
+#: utils/dateformat.py:48
msgid "AM"
msgstr "Après-midi"
-#: utils/dateformat.py:95
+#: utils/dateformat.py:97
msgid "midnight"
msgstr "minuit"
-#: utils/dateformat.py:97
+#: utils/dateformat.py:99
msgid "noon"
msgstr "midi"
-#: utils/translation/trans_real.py:358
+#: utils/translation/trans_real.py:391
msgid "DATE_FORMAT"
msgstr "j F Y"
-#: utils/translation/trans_real.py:359
+#: utils/translation/trans_real.py:392
msgid "DATETIME_FORMAT"
msgstr "j F Y, G:i"
-#: utils/translation/trans_real.py:360
+#: utils/translation/trans_real.py:393
msgid "TIME_FORMAT"
msgstr "G:i:s"
-#: utils/translation/trans_real.py:376
+#: utils/translation/trans_real.py:409
msgid "YEAR_MONTH_FORMAT"
msgstr "F Y"
-#: utils/translation/trans_real.py:377
+#: utils/translation/trans_real.py:410
msgid "MONTH_DAY_FORMAT"
msgstr "j F"
-#: template/defaultfilters.py:491
+#: template/defaultfilters.py:485
msgid "yes,no,maybe"
-msgstr "oui,non,peut-être"
+msgstr "oui, non, peut-être"
-#: template/defaultfilters.py:520
+#: template/defaultfilters.py:514
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] "%(size)d octet"
msgstr[1] "%(size)d octets"
-#: template/defaultfilters.py:522
+#: template/defaultfilters.py:516
#, python-format
msgid "%.1f KB"
msgstr "%.1f Ko"
-#: template/defaultfilters.py:524
+#: template/defaultfilters.py:518
#, python-format
msgid "%.1f MB"
msgstr "%.1f Mo"
-#: template/defaultfilters.py:525
+#: template/defaultfilters.py:519
#, python-format
msgid "%.1f GB"
msgstr "%.1f Go"
-#~ msgid "One or more %(fieldname)s in %(name)s&amp;nbsp;:"
-#~ msgstr "Un ou plusieurs %(fieldname)s dans %(name)s&amp;nbsp;:"
+#~ msgid "AnonymousUser"
+#~ msgstr "Anonyme"
+
+#~ msgid "One or more %(fieldname)s in %(name)s :"
+#~ msgstr "Un ou plusieurs %(fieldname)s dans %(name)s :"
#~ msgid "Separate multiple IDs with commas."
#~ msgstr "Séparez les ID par des virgules."
@@ -2812,7 +3051,7 @@ msgstr "%.1f Go"
#~ msgstr "Tri"
#~ msgid "Order:"
-#~ msgstr "Ordre&amp;nbsp;:"
+#~ msgstr "Ordre :"
#~ msgid "%dth"
#~ msgstr "%de"
diff --git a/django/conf/locale/fr/LC_MESSAGES/djangojs.mo b/django/conf/locale/fr/LC_MESSAGES/djangojs.mo
index 12a53b39e2..44f04e3b7e 100644
--- a/django/conf/locale/fr/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/fr/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/fr/LC_MESSAGES/djangojs.po b/django/conf/locale/fr/LC_MESSAGES/djangojs.po
index 8cf467187e..3d6a2aaca3 100644
--- a/django/conf/locale/fr/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/fr/LC_MESSAGES/djangojs.po
@@ -1,7 +1,7 @@
# French translation for js.
-# Copyright (C) 2005 Mikal Barbero
+# Copyright (C) 2005 Mikaël Barbero
# This file is distributed under the same license as the PACKAGE package.
-# Mikal Barbero <mikael.barbero nospam at nospam free.fr>, 2005.
+# Mikaël Barbero <mikael.barbero nospam at nospam free.fr>, 2005.
#
msgid ""
msgstr ""
@@ -9,10 +9,10 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-24 16:39+0100\n"
"PO-Revision-Date: 2005-12-24 16:39+0100\n"
-"Last-Translator: Mikal Barbero <mikael.barbero nospam at nospam free.fr>\n"
+"Last-Translator: Mikaël Barbero <mikael.barbero nospam at nospam free.fr>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/calendar.js:24
@@ -21,8 +21,8 @@ msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
-"Janvier Fvrier Mars Avril Mai Juin Juillet Aot Septembre Octobre Novembre "
-"Dcembre"
+"Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre "
+"Décembre"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
@@ -35,7 +35,7 @@ msgstr "Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
-msgstr "Disponible %s"
+msgstr "%s disponible(s)"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
@@ -52,11 +52,11 @@ msgstr "Enlever"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
-msgstr "Choisi %s"
+msgstr "%s choisi(es)"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
-msgstr "Slectionnez un ou plusieurs choix et cliquez "
+msgstr "Sélectionnez un ou plusieurs choix et cliquez "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
diff --git a/django/conf/locale/hr/LC_MESSAGES/django.mo b/django/conf/locale/hr/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..e7f4d6bf2f
--- /dev/null
+++ b/django/conf/locale/hr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/hr/LC_MESSAGES/django.po b/django/conf/locale/hr/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..79850d176e
--- /dev/null
+++ b/django/conf/locale/hr/LC_MESSAGES/django.po
@@ -0,0 +1,3282 @@
+# translation of django.po to Hrvatski jezik
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: django\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-08-06 23:19+0200\n"
+"PO-Revision-Date: 2007-08-12 23:05+0200\n"
+"Last-Translator: Aljosa Mohorovic <aljosa.mohorovic@gmail.com>\n"
+"Language-Team: Hrvatski jezik\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: oldforms/__init__.py:373 db/models/fields/__init__.py:156
+#: db/models/fields/__init__.py:313 db/models/fields/__init__.py:721
+#: db/models/fields/__init__.py:732 newforms/models.py:193
+#: newforms/fields.py:92 newforms/fields.py:490 newforms/fields.py:566
+#: newforms/fields.py:577
+msgid "This field is required."
+msgstr "Unos za ovo polje je obavezan."
+
+#: oldforms/__init__.py:408
+#, python-format
+msgid "Ensure your text is less than %s character."
+msgid_plural "Ensure your text is less than %s characters."
+msgstr[0] "Uneseni tekst mora sadržavati manje od %s znaka."
+msgstr[1] "Uneseni tekst mora sadržavati manje od %s znakova."
+
+#: oldforms/__init__.py:413
+msgid "Line breaks are not allowed here."
+msgstr "Unos u novi red ovdje nije dozvoljen."
+
+#: oldforms/__init__.py:511 oldforms/__init__.py:585 oldforms/__init__.py:624
+#, python-format
+msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
+msgstr "Odaberite iz ponuđenog; '%(data)s' nije u %(choices)s."
+
+#: oldforms/__init__.py:591 newforms/widgets.py:188
+#: contrib/admin/filterspecs.py:152
+msgid "Unknown"
+msgstr "Nepoznat pojam."
+
+#: oldforms/__init__.py:591 newforms/widgets.py:188
+#: contrib/admin/filterspecs.py:145
+msgid "Yes"
+msgstr "Da"
+
+#: oldforms/__init__.py:591 newforms/widgets.py:188
+#: contrib/admin/filterspecs.py:145
+msgid "No"
+msgstr "Ne"
+
+#: oldforms/__init__.py:686 core/validators.py:181 core/validators.py:461
+#: newforms/fields.py:376
+msgid "No file was submitted. Check the encoding type on the form."
+msgstr "Datoteka nije poslana. Provjerite 'encoding type' forme."
+
+#: oldforms/__init__.py:688 newforms/fields.py:380
+msgid "The submitted file is empty."
+msgstr "Poslana datoteka je prazna."
+
+#: oldforms/__init__.py:744
+msgid "Enter a whole number between -32,768 and 32,767."
+msgstr "Unesite cijeli broj između -32,768 i 32,767."
+
+#: oldforms/__init__.py:754
+msgid "Enter a positive number."
+msgstr "Unesite pozitivan broj."
+
+#: oldforms/__init__.py:764
+msgid "Enter a whole number between 0 and 32,767."
+msgstr "Unesite cijeli broj između 0 i 32,767."
+
+#: db/models/manipulators.py:309
+#, python-format
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "%(object)s sa %(type)s već postoji za navedeno %(field)s."
+
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+msgid "and"
+msgstr "i"
+
+#: db/models/fields/__init__.py:49
+#, python-format
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "%(optname)s sa navedenim %(fieldname)s već postoji."
+
+#: db/models/fields/__init__.py:411
+msgid "This value must be an integer."
+msgstr "Vrijednost mora biti interger."
+
+#: db/models/fields/__init__.py:446
+msgid "This value must be either True or False."
+msgstr "Vrijednost mora biti True ili False."
+
+#: db/models/fields/__init__.py:467
+msgid "This field cannot be null."
+msgstr "Ovo polje ne može biti null."
+
+#: db/models/fields/__init__.py:501 core/validators.py:155
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "Unesite validan datum u formatu YYYY-MM-DD."
+
+#: db/models/fields/__init__.py:570 core/validators.py:164
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "Unesite validan datum/vrijeme u formatu YYYY-MM-DD HH:MM."
+
+#: db/models/fields/__init__.py:631
+msgid "This value must be a decimal number."
+msgstr "Vrijednost mora biti decimalan broj."
+
+#: db/models/fields/__init__.py:741
+msgid "Enter a valid filename."
+msgstr "Unesite ime datoteke koja postoji."
+
+#: db/models/fields/__init__.py:883
+msgid "This value must be either None, True or False."
+msgstr "Vrijednost mora biti None, True ili False."
+
+#: db/models/fields/related.py:55
+#, python-format
+msgid "Please enter a valid %s."
+msgstr "Molim unesite validan %s."
+
+#: db/models/fields/related.py:661
+msgid "Separate multiple IDs with commas."
+msgstr "Odvojite više ID-a zarezom."
+
+#: db/models/fields/related.py:663
+msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr "Držite \"Control\", ili \"Command\" na Mac-u, da bi odabravili više od jednog objekta."
+
+#: db/models/fields/related.py:710
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] "Molim unesite ispravan %(self)s ID. Vrijednost %(value)r je neispravna."
+msgstr[1] ""
+
+#: conf/global_settings.py:38
+msgid "Arabic"
+msgstr ""
+
+#: conf/global_settings.py:39
+msgid "Bengali"
+msgstr ""
+
+#: conf/global_settings.py:40
+msgid "Bulgarian"
+msgstr ""
+
+#: conf/global_settings.py:41
+msgid "Catalan"
+msgstr ""
+
+#: conf/global_settings.py:42
+msgid "Czech"
+msgstr ""
+
+#: conf/global_settings.py:43
+msgid "Welsh"
+msgstr ""
+
+#: conf/global_settings.py:44
+msgid "Danish"
+msgstr ""
+
+#: conf/global_settings.py:45
+msgid "German"
+msgstr ""
+
+#: conf/global_settings.py:46
+msgid "Greek"
+msgstr ""
+
+#: conf/global_settings.py:47
+msgid "English"
+msgstr ""
+
+#: conf/global_settings.py:48
+msgid "Spanish"
+msgstr ""
+
+#: conf/global_settings.py:49
+msgid "Argentinean Spanish"
+msgstr ""
+
+#: conf/global_settings.py:50
+msgid "Persian"
+msgstr ""
+
+#: conf/global_settings.py:51
+msgid "Finnish"
+msgstr ""
+
+#: conf/global_settings.py:52
+msgid "French"
+msgstr ""
+
+#: conf/global_settings.py:53
+msgid "Galician"
+msgstr ""
+
+#: conf/global_settings.py:54
+msgid "Hungarian"
+msgstr ""
+
+#: conf/global_settings.py:55
+msgid "Hebrew"
+msgstr ""
+
+#: conf/global_settings.py:56
+msgid "Icelandic"
+msgstr ""
+
+#: conf/global_settings.py:57
+msgid "Italian"
+msgstr ""
+
+#: conf/global_settings.py:58
+msgid "Japanese"
+msgstr ""
+
+#: conf/global_settings.py:59
+msgid "Korean"
+msgstr ""
+
+#: conf/global_settings.py:60
+msgid "Kannada"
+msgstr ""
+
+#: conf/global_settings.py:61
+msgid "Latvian"
+msgstr ""
+
+#: conf/global_settings.py:62
+msgid "Macedonian"
+msgstr ""
+
+#: conf/global_settings.py:63
+msgid "Dutch"
+msgstr ""
+
+#: conf/global_settings.py:64
+msgid "Norwegian"
+msgstr ""
+
+#: conf/global_settings.py:65
+msgid "Polish"
+msgstr ""
+
+#: conf/global_settings.py:66
+msgid "Portugese"
+msgstr ""
+
+#: conf/global_settings.py:67
+msgid "Brazilian"
+msgstr ""
+
+#: conf/global_settings.py:68
+msgid "Romanian"
+msgstr ""
+
+#: conf/global_settings.py:69
+msgid "Russian"
+msgstr ""
+
+#: conf/global_settings.py:70
+msgid "Slovak"
+msgstr ""
+
+#: conf/global_settings.py:71
+msgid "Slovenian"
+msgstr ""
+
+#: conf/global_settings.py:72
+msgid "Serbian"
+msgstr ""
+
+#: conf/global_settings.py:73
+msgid "Swedish"
+msgstr ""
+
+#: conf/global_settings.py:74
+msgid "Tamil"
+msgstr ""
+
+#: conf/global_settings.py:75
+msgid "Telugu"
+msgstr ""
+
+#: conf/global_settings.py:76
+msgid "Turkish"
+msgstr ""
+
+#: conf/global_settings.py:77
+msgid "Ukrainian"
+msgstr ""
+
+#: conf/global_settings.py:78
+msgid "Simplified Chinese"
+msgstr ""
+
+#: conf/global_settings.py:79
+msgid "Traditional Chinese"
+msgstr ""
+
+#: core/validators.py:71
+msgid "This value must contain only letters, numbers and underscores."
+msgstr "Ova vrijednost može sadržavati samo slova, brojeve i povlaku."
+
+#: core/validators.py:75
+msgid ""
+"This value must contain only letters, numbers, underscores, dashes or "
+"slashes."
+msgstr ""
+"Ova vrijednost može sadržavati samo slova, brojeve, povlaku, crtice ili "
+"slashes (/)."
+
+#: core/validators.py:79
+msgid "This value must contain only letters, numbers, underscores or hyphens."
+msgstr "Ova vrijednost može sadržavati samo slova, brojeve, povlake ili hyphens."
+
+#: core/validators.py:83
+msgid "Uppercase letters are not allowed here."
+msgstr "Velika slova ovdje nisu dopuštena."
+
+#: core/validators.py:87
+msgid "Lowercase letters are not allowed here."
+msgstr "Mala slova ovdje nisu dopuštena"
+
+#: core/validators.py:94
+msgid "Enter only digits separated by commas."
+msgstr "Unesite samo brojeve razdvojene zarezom."
+
+#: core/validators.py:106
+msgid "Enter valid e-mail addresses separated by commas."
+msgstr "Unesite ispravne e-mail adrese odvojene zarezom."
+
+#: core/validators.py:110
+msgid "Please enter a valid IP address."
+msgstr "Unesite ispravnu IP adresu."
+
+#: core/validators.py:114
+msgid "Empty values are not allowed here."
+msgstr "Prazne vrijednosti nisu ispravne ovdje."
+
+#: core/validators.py:118
+msgid "Non-numeric characters aren't allowed here."
+msgstr "Dozvoljeni su samo numerički znakovi."
+
+#: core/validators.py:122
+msgid "This value can't be comprised solely of digits."
+msgstr "Ova vrijednost ne može sadržavati samo brojeve."
+
+#: core/validators.py:127 newforms/fields.py:142
+msgid "Enter a whole number."
+msgstr "Unesite cijeli broj."
+
+#: core/validators.py:131
+msgid "Only alphabetical characters are allowed here."
+msgstr "Dozvoljena su samo slova abecede."
+
+#: core/validators.py:146
+msgid "Year must be 1900 or later."
+msgstr "Godina mora biti poslije 1900."
+
+#: core/validators.py:150
+#, python-format
+msgid "Invalid date: %s"
+msgstr "Neispravan datum: %s"
+
+#: core/validators.py:160
+msgid "Enter a valid time in HH:MM format."
+msgstr "Unesite ispravno vrijeme u HH:MM formatu."
+
+#: core/validators.py:169 newforms/fields.py:336
+msgid "Enter a valid e-mail address."
+msgstr "Unesite ispravnu e-mail adresu."
+
+#: core/validators.py:185 newforms/fields.py:397
+msgid ""
+"Upload a valid image. The file you uploaded was either not an image or a "
+"corrupted image."
+msgstr "Upload-ajte ispravnu sliku. Datoteka koju ste upload-ali ili nije slika ili je oštečena."
+
+#: core/validators.py:192
+#, python-format
+msgid "The URL %s does not point to a valid image."
+msgstr "URL %s ne prikazuje ispravnu sliku."
+
+#: core/validators.py:196
+#, python-format
+msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
+msgstr ""
+
+#: core/validators.py:204
+#, python-format
+msgid "The URL %s does not point to a valid QuickTime video."
+msgstr ""
+
+#: core/validators.py:208
+msgid "A valid URL is required."
+msgstr ""
+
+#: core/validators.py:222
+#, python-format
+msgid ""
+"Valid HTML is required. Specific errors are:\n"
+"%s"
+msgstr ""
+
+#: core/validators.py:229
+#, python-format
+msgid "Badly formed XML: %s"
+msgstr ""
+
+#: core/validators.py:246
+#, python-format
+msgid "Invalid URL: %s"
+msgstr ""
+
+#: core/validators.py:251 core/validators.py:253
+#, python-format
+msgid "The URL %s is a broken link."
+msgstr ""
+
+#: core/validators.py:259
+msgid "Enter a valid U.S. state abbreviation."
+msgstr ""
+
+#: core/validators.py:273
+#, python-format
+msgid "Watch your mouth! The word %s is not allowed here."
+msgid_plural "Watch your mouth! The words %s are not allowed here."
+msgstr[0] ""
+msgstr[1] ""
+
+#: core/validators.py:280
+#, python-format
+msgid "This field must match the '%s' field."
+msgstr ""
+
+#: core/validators.py:299
+msgid "Please enter something for at least one field."
+msgstr ""
+
+#: core/validators.py:308 core/validators.py:319
+msgid "Please enter both fields or leave them both empty."
+msgstr ""
+
+#: core/validators.py:327
+#, python-format
+msgid "This field must be given if %(field)s is %(value)s"
+msgstr ""
+
+#: core/validators.py:340
+#, python-format
+msgid "This field must be given if %(field)s is not %(value)s"
+msgstr ""
+
+#: core/validators.py:359
+msgid "Duplicate values are not allowed."
+msgstr ""
+
+#: core/validators.py:374
+#, python-format
+#, fuzzy
+msgid "This value must be between %(lower)s and %(upper)s."
+msgstr "i."
+
+#: core/validators.py:376
+#, python-format
+msgid "This value must be at least %s."
+msgstr ""
+
+#: core/validators.py:378
+#, python-format
+msgid "This value must be no more than %s."
+msgstr ""
+
+#: core/validators.py:414
+#, python-format
+msgid "This value must be a power of %s."
+msgstr ""
+
+#: core/validators.py:424
+msgid "Please enter a valid decimal number."
+msgstr ""
+
+#: core/validators.py:431
+#, python-format
+msgid "Please enter a valid decimal number with at most %s total digit."
+msgid_plural "Please enter a valid decimal number with at most %s total digits."
+msgstr[0] ""
+msgstr[1] ""
+
+#: core/validators.py:434
+#, python-format
+msgid "Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] ""
+msgstr[1] ""
+
+#: core/validators.py:437
+#, python-format
+msgid "Please enter a valid decimal number with at most %s decimal place."
+msgid_plural "Please enter a valid decimal number with at most %s decimal places."
+msgstr[0] ""
+msgstr[1] ""
+
+#: core/validators.py:445
+msgid "Please enter a valid floating point number."
+msgstr ""
+
+#: core/validators.py:454
+#, python-format
+msgid "Make sure your uploaded file is at least %s bytes big."
+msgstr ""
+
+#: core/validators.py:455
+#, python-format
+msgid "Make sure your uploaded file is at most %s bytes big."
+msgstr ""
+
+#: core/validators.py:472
+msgid "The format for this field is wrong."
+msgstr ""
+
+#: core/validators.py:487
+msgid "This field is invalid."
+msgstr ""
+
+#: core/validators.py:523
+#, python-format
+msgid "Could not retrieve anything from %s."
+msgstr ""
+
+#: core/validators.py:526
+#, python-format
+msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+msgstr ""
+
+#: core/validators.py:559
+#, python-format
+msgid ""
+"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
+"\"%(start)s\".)"
+msgstr ""
+
+#: core/validators.py:563
+#, python-format
+msgid ""
+"Some text starting on line %(line)s is not allowed in that context. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+
+#: core/validators.py:568
+#, python-format
+msgid ""
+"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+
+#: core/validators.py:573
+#, python-format
+msgid ""
+"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+
+#: core/validators.py:577
+#, python-format
+msgid ""
+"A tag on line %(line)s is missing one or more required attributes. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+
+#: core/validators.py:582
+#, python-format
+msgid ""
+"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+
+#: views/generic/create_update.py:43
+#, python-format
+msgid "The %(verbose_name)s was created successfully."
+msgstr ""
+
+#: views/generic/create_update.py:117
+#, python-format
+msgid "The %(verbose_name)s was updated successfully."
+msgstr ""
+
+#: views/generic/create_update.py:184
+#, python-format
+msgid "The %(verbose_name)s was deleted."
+msgstr ""
+
+#: newforms/models.py:180 newforms/fields.py:478
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr ""
+
+#: newforms/models.py:197 newforms/fields.py:494 newforms/fields.py:570
+msgid "Enter a list of values."
+msgstr ""
+
+#: newforms/models.py:203 newforms/fields.py:500
+#, python-format
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr ""
+
+#: newforms/fields.py:116
+#, python-format
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr ""
+
+#: newforms/fields.py:118
+#, python-format
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr ""
+
+#: newforms/fields.py:144 newforms/fields.py:167 newforms/fields.py:197
+#, python-format
+msgid "Ensure this value is less than or equal to %s."
+msgstr ""
+
+#: newforms/fields.py:146 newforms/fields.py:169 newforms/fields.py:199
+#, python-format
+msgid "Ensure this value is greater than or equal to %s."
+msgstr ""
+
+#: newforms/fields.py:165 newforms/fields.py:192
+msgid "Enter a number."
+msgstr ""
+
+#: newforms/fields.py:201
+#, python-format
+msgid "Ensure that there are no more than %s digits in total."
+msgstr ""
+
+#: newforms/fields.py:203
+#, python-format
+msgid "Ensure that there are no more than %s decimal places."
+msgstr ""
+
+#: newforms/fields.py:205
+#, python-format
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr ""
+
+#: newforms/fields.py:238 newforms/fields.py:610
+msgid "Enter a valid date."
+msgstr ""
+
+#: newforms/fields.py:265 newforms/fields.py:612
+msgid "Enter a valid time."
+msgstr ""
+
+#: newforms/fields.py:301
+msgid "Enter a valid date/time."
+msgstr ""
+
+#: newforms/fields.py:314
+msgid "Enter a valid value."
+msgstr ""
+
+#: newforms/fields.py:378
+#, fuzzy
+msgid "No file was submitted."
+msgstr "Ne."
+
+#: newforms/fields.py:403 newforms/fields.py:425
+msgid "Enter a valid URL."
+msgstr ""
+
+#: newforms/fields.py:427
+msgid "This URL appears to be a broken link."
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "th"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "st"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "nd"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "rd"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:47
+#, python-format
+msgid "%(value).1f million"
+msgid_plural "%(value).1f million"
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/humanize/templatetags/humanize.py:50
+#, python-format
+msgid "%(value).1f billion"
+msgid_plural "%(value).1f billion"
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/humanize/templatetags/humanize.py:53
+#, python-format
+msgid "%(value).1f trillion"
+msgid_plural "%(value).1f trillion"
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "one"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "two"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "three"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "four"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "five"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "six"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "seven"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "eight"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "nine"
+msgstr ""
+
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr ""
+
+#: contrib/redirects/models.py:8
+msgid ""
+"This should be an absolute path, excluding the domain name. Example: '/"
+"events/search/'."
+msgstr ""
+
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr ""
+
+#: contrib/redirects/models.py:10
+msgid ""
+"This can be either an absolute path (as above) or a full URL starting with "
+"'http://'."
+msgstr ""
+
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr ""
+
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr ""
+
+#: contrib/comments/models.py:67 contrib/comments/models.py:166
+msgid "object ID"
+msgstr ""
+
+#: contrib/comments/models.py:68
+msgid "headline"
+msgstr ""
+
+#: contrib/comments/models.py:69 contrib/comments/models.py:90
+#: contrib/comments/models.py:167
+msgid "comment"
+msgstr ""
+
+#: contrib/comments/models.py:70
+msgid "rating #1"
+msgstr ""
+
+#: contrib/comments/models.py:71
+msgid "rating #2"
+msgstr ""
+
+#: contrib/comments/models.py:72
+msgid "rating #3"
+msgstr ""
+
+#: contrib/comments/models.py:73
+msgid "rating #4"
+msgstr ""
+
+#: contrib/comments/models.py:74
+msgid "rating #5"
+msgstr ""
+
+#: contrib/comments/models.py:75
+msgid "rating #6"
+msgstr ""
+
+#: contrib/comments/models.py:76
+msgid "rating #7"
+msgstr ""
+
+#: contrib/comments/models.py:77
+msgid "rating #8"
+msgstr ""
+
+#: contrib/comments/models.py:82
+msgid "is valid rating"
+msgstr ""
+
+#: contrib/comments/models.py:83 contrib/comments/models.py:169
+msgid "date/time submitted"
+msgstr ""
+
+#: contrib/comments/models.py:84 contrib/comments/models.py:170
+msgid "is public"
+msgstr ""
+
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:306
+msgid "IP address"
+msgstr ""
+
+#: contrib/comments/models.py:86
+msgid "is removed"
+msgstr ""
+
+#: contrib/comments/models.py:86
+msgid ""
+"Check this box if the comment is inappropriate. A \"This comment has been "
+"removed\" message will be displayed instead."
+msgstr ""
+
+#: contrib/comments/models.py:91
+msgid "comments"
+msgstr ""
+
+#: contrib/comments/models.py:131 contrib/comments/models.py:207
+msgid "Content object"
+msgstr ""
+
+#: contrib/comments/models.py:159
+#, python-format
+msgid ""
+"Posted by %(user)s at %(date)s\n"
+"\n"
+"%(comment)s\n"
+"\n"
+"http://%(domain)s%(url)s"
+msgstr ""
+
+#: contrib/comments/models.py:168
+msgid "person's name"
+msgstr ""
+
+#: contrib/comments/models.py:171
+msgid "ip address"
+msgstr ""
+
+#: contrib/comments/models.py:173
+msgid "approved by staff"
+msgstr ""
+
+#: contrib/comments/models.py:176
+msgid "free comment"
+msgstr ""
+
+#: contrib/comments/models.py:177
+msgid "free comments"
+msgstr ""
+
+#: contrib/comments/models.py:233
+msgid "score"
+msgstr ""
+
+#: contrib/comments/models.py:234
+msgid "score date"
+msgstr ""
+
+#: contrib/comments/models.py:237
+msgid "karma score"
+msgstr ""
+
+#: contrib/comments/models.py:238
+msgid "karma scores"
+msgstr ""
+
+#: contrib/comments/models.py:242
+#, python-format
+msgid "%(score)d rating by %(user)s"
+msgstr ""
+
+#: contrib/comments/models.py:258
+#, python-format
+msgid ""
+"This comment was flagged by %(user)s:\n"
+"\n"
+"%(text)s"
+msgstr ""
+
+#: contrib/comments/models.py:265
+msgid "flag date"
+msgstr ""
+
+#: contrib/comments/models.py:268
+msgid "user flag"
+msgstr ""
+
+#: contrib/comments/models.py:269
+msgid "user flags"
+msgstr ""
+
+#: contrib/comments/models.py:273
+#, python-format
+msgid "Flag by %r"
+msgstr ""
+
+#: contrib/comments/models.py:278
+msgid "deletion date"
+msgstr ""
+
+#: contrib/comments/models.py:280
+msgid "moderator deletion"
+msgstr ""
+
+#: contrib/comments/models.py:281
+msgid "moderator deletions"
+msgstr ""
+
+#: contrib/comments/models.py:285
+#, python-format
+msgid "Moderator deletion by %r"
+msgstr ""
+
+#: contrib/comments/views/karma.py:20
+msgid "Anonymous users cannot vote"
+msgstr ""
+
+#: contrib/comments/views/karma.py:24
+msgid "Invalid comment ID"
+msgstr ""
+
+#: contrib/comments/views/karma.py:26
+#, fuzzy
+msgid "No voting for yourself"
+msgstr "Ne"
+
+#: contrib/comments/views/comments.py:28
+msgid "This rating is required because you've entered at least one other rating."
+msgstr ""
+
+#: contrib/comments/views/comments.py:112
+#, python-format
+msgid ""
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comment:\n"
+"\n"
+"%(text)s"
+msgid_plural ""
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comments:\n"
+"\n"
+"%(text)s"
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/comments/views/comments.py:117
+#, python-format
+msgid ""
+"This comment was posted by a sketchy user:\n"
+"\n"
+"%(text)s"
+msgstr ""
+
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
+msgid "Only POSTs are allowed"
+msgstr ""
+
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
+msgid "One or more of the required fields wasn't submitted"
+msgstr ""
+
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
+msgid "Somebody tampered with the comment form (security violation)"
+msgstr ""
+
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
+msgid ""
+"The comment form had an invalid 'target' parameter -- the object ID was "
+"invalid"
+msgstr ""
+
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
+msgid "The comment form didn't provide either 'preview' or 'post'"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:17
+msgid "Username:"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+msgid "Log out"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:20
+msgid "Password:"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:28
+#: contrib/comments/templates/comments/freeform.html:5
+msgid "Comment:"
+msgstr ""
+
+#: contrib/comments/templates/comments/form.html:35
+#: contrib/comments/templates/comments/freeform.html:10
+msgid "Preview comment"
+msgstr ""
+
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr ""
+
+#: contrib/sites/models.py:15
+msgid "domain name"
+msgstr ""
+
+#: contrib/sites/models.py:16
+msgid "display name"
+msgstr ""
+
+#: contrib/sites/models.py:20
+msgid "site"
+msgstr ""
+
+#: contrib/sites/models.py:21
+msgid "sites"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:42
+#, python-format
+msgid ""
+"<h3>By %s:</h3>\n"
+"<ul>\n"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
+msgid "All"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:111
+msgid "Any date"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:112
+msgid "Today"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:115
+msgid "Past 7 days"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:117
+msgid "This month"
+msgstr ""
+
+#: contrib/admin/filterspecs.py:119
+msgid "This year"
+msgstr ""
+
+#: contrib/admin/models.py:17
+msgid "action time"
+msgstr ""
+
+#: contrib/admin/models.py:20
+msgid "object id"
+msgstr ""
+
+#: contrib/admin/models.py:21
+msgid "object repr"
+msgstr ""
+
+#: contrib/admin/models.py:22
+msgid "action flag"
+msgstr ""
+
+#: contrib/admin/models.py:23
+msgid "change message"
+msgstr ""
+
+#: contrib/admin/models.py:26
+msgid "log entry"
+msgstr ""
+
+#: contrib/admin/models.py:27
+msgid "log entries"
+msgstr ""
+
+#: contrib/admin/templatetags/admin_list.py:254
+msgid "All dates"
+msgstr ""
+
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully."
+msgstr ""
+
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
+#: contrib/admin/views/main.py:354
+msgid "You may edit it again below."
+msgstr ""
+
+#: contrib/admin/views/auth.py:31
+msgid "Add user"
+msgstr ""
+
+#: contrib/admin/views/auth.py:58
+msgid "Password changed successfully."
+msgstr ""
+
+#: contrib/admin/views/auth.py:65
+#, python-format
+msgid "Change password: %s"
+msgstr ""
+
+#: contrib/admin/views/main.py:230
+msgid "Site administration"
+msgstr ""
+
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
+#, python-format
+msgid "You may add another %s below."
+msgstr ""
+
+#: contrib/admin/views/main.py:296
+#, python-format
+msgid "Add %s"
+msgstr ""
+
+#: contrib/admin/views/main.py:342
+#, python-format
+msgid "Added %s."
+msgstr ""
+
+#: contrib/admin/views/main.py:344
+#, python-format
+msgid "Changed %s."
+msgstr ""
+
+#: contrib/admin/views/main.py:346
+#, python-format
+msgid "Deleted %s."
+msgstr ""
+
+#: contrib/admin/views/main.py:349
+#, fuzzy
+msgid "No fields changed."
+msgstr "Ne."
+
+#: contrib/admin/views/main.py:352
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was changed successfully."
+msgstr ""
+
+#: contrib/admin/views/main.py:360
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
+msgstr ""
+
+#: contrib/admin/views/main.py:398
+#, python-format
+msgid "Change %s"
+msgstr ""
+
+#: contrib/admin/views/main.py:483
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
+msgstr ""
+
+#: contrib/admin/views/main.py:488
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s:"
+msgstr ""
+
+#: contrib/admin/views/main.py:520
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was deleted successfully."
+msgstr ""
+
+#: contrib/admin/views/main.py:523
+msgid "Are you sure?"
+msgstr ""
+
+#: contrib/admin/views/main.py:545
+#, python-format
+msgid "Change history: %s"
+msgstr ""
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s"
+msgstr ""
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s to change"
+msgstr ""
+
+#: contrib/admin/views/main.py:780
+msgid "Database error"
+msgstr ""
+
+#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
+#, fuzzy
+msgid ""
+"Please enter a correct username and password. Note that both fields are case-"
+"sensitive."
+msgstr "i."
+
+#: contrib/admin/views/decorators.py:24
+#: contrib/admin/templates/admin/login.html:25
+msgid "Log in"
+msgstr ""
+
+#: contrib/admin/views/decorators.py:62
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+
+#: contrib/admin/views/decorators.py:69
+#, fuzzy
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr "i."
+
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr ""
+
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr ""
+
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
+msgid "tag:"
+msgstr ""
+
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
+msgid "filter:"
+msgstr ""
+
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
+msgid "view:"
+msgstr ""
+
+#: contrib/admin/views/doc.py:165
+#, python-format
+msgid "App %r not found"
+msgstr ""
+
+#: contrib/admin/views/doc.py:172
+#, python-format
+msgid "Model %(name)r not found in app %(label)r"
+msgstr ""
+
+#: contrib/admin/views/doc.py:184
+#, python-format
+msgid "the related `%(label)s.%(type)s` object"
+msgstr ""
+
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
+msgid "model:"
+msgstr ""
+
+#: contrib/admin/views/doc.py:215
+#, python-format
+msgid "related `%(label)s.%(name)s` objects"
+msgstr ""
+
+#: contrib/admin/views/doc.py:220
+#, python-format
+msgid "all %s"
+msgstr ""
+
+#: contrib/admin/views/doc.py:225
+#, python-format
+msgid "number of %s"
+msgstr ""
+
+#: contrib/admin/views/doc.py:230
+#, python-format
+msgid "Fields on %s objects"
+msgstr ""
+
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
+msgid "Integer"
+msgstr ""
+
+#: contrib/admin/views/doc.py:293
+msgid "Boolean (Either True or False)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
+#, python-format
+msgid "String (up to %(max_length)s)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:295
+msgid "Comma-separated integers"
+msgstr ""
+
+#: contrib/admin/views/doc.py:296
+msgid "Date (without time)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:297
+msgid "Date (with time)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:298
+msgid "Decimal number"
+msgstr ""
+
+#: contrib/admin/views/doc.py:299
+msgid "E-mail address"
+msgstr ""
+
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
+msgid "File path"
+msgstr ""
+
+#: contrib/admin/views/doc.py:302
+msgid "Floating point number"
+msgstr ""
+
+#: contrib/admin/views/doc.py:308
+msgid "Boolean (Either True, False or None)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:309
+msgid "Relation to parent model"
+msgstr ""
+
+#: contrib/admin/views/doc.py:310
+msgid "Phone number"
+msgstr ""
+
+#: contrib/admin/views/doc.py:315
+msgid "Text"
+msgstr ""
+
+#: contrib/admin/views/doc.py:316
+msgid "Time"
+msgstr ""
+
+#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
+msgid "URL"
+msgstr ""
+
+#: contrib/admin/views/doc.py:318
+msgid "U.S. state (two uppercase letters)"
+msgstr ""
+
+#: contrib/admin/views/doc.py:319
+msgid "XML text"
+msgstr ""
+
+#: contrib/admin/views/doc.py:345
+#, python-format
+msgid "%s does not appear to be a urlpattern object"
+msgstr ""
+
+#: contrib/admin/templates/widget/file.html:2
+msgid "Currently:"
+msgstr ""
+
+#: contrib/admin/templates/widget/file.html:3
+msgid "Change:"
+msgstr ""
+
+#: contrib/admin/templates/widget/date_time.html:3
+msgid "Date:"
+msgstr ""
+
+#: contrib/admin/templates/widget/date_time.html:4
+msgid "Time:"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Documentation"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/admin/auth/user/change_password.html:15
+#: contrib/admin/templates/admin/auth/user/change_password.html:46
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+msgid "Change password"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_list.html:6
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/invalid_setup.html:4
+#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/base.html:30
+#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/logged_out.html:4
+#: contrib/admin/templates/registration/password_reset_done.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Home"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_list.html:12
+#, python-format
+msgid "Add %(name)s"
+msgstr ""
+
+#: contrib/admin/templates/admin/filter.html:2
+#, python-format
+msgid " By %(filter_title)s "
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/change_form.html:21
+msgid "History"
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:18
+msgid "Date/time"
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:19
+msgid "User"
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:20
+msgid "Action"
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:26
+msgid "DATE_WITH_TIME_FULL"
+msgstr ""
+
+#: contrib/admin/templates/admin/object_history.html:36
+msgid ""
+"This object doesn't have a change history. It probably wasn't added via this "
+"admin site."
+msgstr ""
+
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr ""
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr ""
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr ""
+
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr ""
+
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr ""
+
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr ""
+
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr ""
+
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr ""
+
+#: contrib/admin/templates/admin/500.html:10
+#, fuzzy
+msgid ""
+"There's been an error. It's been reported to the site administrators via e-"
+"mail and should be fixed shortly. Thanks for your patience."
+msgstr "i."
+
+#: contrib/admin/templates/admin/invalid_setup.html:8
+#, fuzzy
+msgid ""
+"Something's wrong with your database installation. Make sure the appropriate "
+"database tables have been created, and make sure the database is readable by "
+"the appropriate user."
+msgstr "i."
+
+#: contrib/admin/templates/admin/index.html:17
+#, python-format
+msgid "Models available in the %(name)s application."
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:18
+#, python-format
+msgid "%(name)s"
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:28
+#: contrib/admin/templates/admin/change_form.html:15
+msgid "Add"
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:34
+msgid "Change"
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:44
+msgid "You don't have permission to edit anything."
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:52
+msgid "Recent Actions"
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:53
+msgid "My Actions"
+msgstr ""
+
+#: contrib/admin/templates/admin/index.html:57
+msgid "None available"
+msgstr ""
+
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr ""
+
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr ""
+
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_form.html:22
+msgid "View on site"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_form.html:32
+#: contrib/admin/templates/admin/auth/user/change_password.html:24
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+msgstr[1] ""
+
+#: contrib/admin/templates/admin/change_form.html:50
+msgid "Ordering"
+msgstr ""
+
+#: contrib/admin/templates/admin/change_form.html:53
+msgid "Order:"
+msgstr ""
+
+#: contrib/admin/templates/admin/delete_confirmation.html:9
+#: contrib/admin/templates/admin/submit_line.html:3
+msgid "Delete"
+msgstr ""
+
+#: contrib/admin/templates/admin/delete_confirmation.html:14
+#, python-format
+msgid ""
+"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
+"related objects, but your account doesn't have permission to delete the "
+"following types of objects:"
+msgstr ""
+
+#: contrib/admin/templates/admin/delete_confirmation.html:21
+#, python-format
+msgid ""
+"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
+"All of the following related items will be deleted:"
+msgstr ""
+
+#: contrib/admin/templates/admin/delete_confirmation.html:26
+#, fuzzy
+msgid "Yes, I'm sure"
+msgstr "Da"
+
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr ""
+
+#: contrib/admin/templates/admin/submit_line.html:4
+msgid "Save as new"
+msgstr ""
+
+#: contrib/admin/templates/admin/submit_line.html:5
+#, fuzzy
+msgid "Save and add another"
+msgstr "i"
+
+#: contrib/admin/templates/admin/submit_line.html:6
+#, fuzzy
+msgid "Save and continue editing"
+msgstr "i"
+
+#: contrib/admin/templates/admin/submit_line.html:7
+msgid "Save"
+msgstr ""
+
+#: contrib/admin/templates/admin/auth/user/change_password.html:28
+#, python-format
+msgid "Enter a new password for the user <strong>%(username)s</strong>."
+msgstr ""
+
+#: contrib/admin/templates/admin/auth/user/change_password.html:34
+#: contrib/admin/templates/admin/auth/user/add_form.html:18
+msgid "Password"
+msgstr ""
+
+#: contrib/admin/templates/admin/auth/user/change_password.html:39
+#: contrib/admin/templates/admin/auth/user/add_form.html:23
+msgid "Password (again)"
+msgstr ""
+
+#: contrib/admin/templates/admin/auth/user/change_password.html:40
+#: contrib/admin/templates/admin/auth/user/add_form.html:24
+msgid "Enter the same password as above, for verification."
+msgstr ""
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:6
+#, fuzzy
+msgid ""
+"First, enter a username and password. Then, you'll be able to edit more user "
+"options."
+msgstr "i."
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:12
+msgid "Username"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+msgid "Password change"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:6
+#: contrib/admin/templates/registration/password_reset_form.html:10
+#: contrib/admin/templates/registration/password_reset_done.html:4
+msgid "Password reset"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_form.html:12
+#, fuzzy
+msgid ""
+"Forgotten your password? Enter your e-mail address below, and we'll reset "
+"your password and e-mail the new one to you."
+msgstr "i i."
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "E-mail address:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "Reset my password"
+msgstr ""
+
+#: contrib/admin/templates/registration/logged_out.html:8
+msgid "Thanks for spending some quality time with the Web site today."
+msgstr ""
+
+#: contrib/admin/templates/registration/logged_out.html:10
+msgid "Log in again"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_done.html:12
+msgid ""
+"We've e-mailed a new password to the e-mail address you submitted. You "
+"should be receiving it shortly."
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_form.html:12
+#, fuzzy
+msgid ""
+"Please enter your old password, for security's sake, and then enter your new "
+"password twice so we can verify you typed it in correctly."
+msgstr "i."
+
+#: contrib/admin/templates/registration/password_change_form.html:17
+msgid "Old password:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_form.html:19
+msgid "New password:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_form.html:21
+msgid "Confirm password:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_change_form.html:23
+msgid "Change my password"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:2
+msgid "You're receiving this e-mail because you requested a password reset"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:3
+#, python-format
+msgid "for your user account at %(site_name)s"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:5
+#, python-format
+msgid "Your new password is: %(new_password)s"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:7
+msgid "Feel free to change this password by going to this page:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:11
+msgid "Your username, in case you've forgotten:"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:13
+msgid "Thanks for using our site!"
+msgstr ""
+
+#: contrib/admin/templates/registration/password_reset_email.html:15
+#, python-format
+msgid "The %(site_name)s team"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Bookmarklets"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:5
+msgid "Documentation bookmarklets"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:9
+#, fuzzy
+msgid ""
+"\n"
+"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
+"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
+"select the bookmarklet from any page in the site. Note that some of these\n"
+"bookmarklets require you to be viewing the site from a computer designated\n"
+"as \"internal\" (talk to your system administrator if you aren't sure if\n"
+"your computer is \"internal\").</p>\n"
+msgstr ""
+"\n"
+"<p class=\"help\"> i</p>"
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:19
+msgid "Documentation for this page"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:20
+msgid ""
+"Jumps you from any page to the documentation for the view that generates "
+"that page."
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:22
+msgid "Show object ID"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:23
+#, fuzzy
+msgid ""
+"Shows the content-type and unique ID for pages that represent a single "
+"object."
+msgstr "i."
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:25
+msgid "Edit this object (current window)"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:26
+msgid "Jumps to the admin page for pages that represent a single object."
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:28
+msgid "Edit this object (new window)"
+msgstr ""
+
+#: contrib/admin/templates/admin_doc/bookmarklets.html:29
+msgid "As above, but opens the admin page in a new window."
+msgstr ""
+
+#: contrib/contenttypes/models.py:37
+msgid "python model class name"
+msgstr ""
+
+#: contrib/contenttypes/models.py:40
+msgid "content type"
+msgstr ""
+
+#: contrib/contenttypes/models.py:41
+msgid "content types"
+msgstr ""
+
+#: contrib/auth/views.py:41
+msgid "Logged out"
+msgstr ""
+
+#: contrib/auth/models.py:53 contrib/auth/models.py:73
+msgid "name"
+msgstr ""
+
+#: contrib/auth/models.py:55
+msgid "codename"
+msgstr ""
+
+#: contrib/auth/models.py:58
+msgid "permission"
+msgstr ""
+
+#: contrib/auth/models.py:59 contrib/auth/models.py:74
+msgid "permissions"
+msgstr ""
+
+#: contrib/auth/models.py:77
+msgid "group"
+msgstr ""
+
+#: contrib/auth/models.py:78 contrib/auth/models.py:121
+msgid "groups"
+msgstr ""
+
+#: contrib/auth/models.py:111
+msgid "username"
+msgstr ""
+
+#: contrib/auth/models.py:111
+#, fuzzy
+msgid ""
+"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
+"digits and underscores)."
+msgstr "i."
+
+#: contrib/auth/models.py:112
+msgid "first name"
+msgstr ""
+
+#: contrib/auth/models.py:113
+msgid "last name"
+msgstr ""
+
+#: contrib/auth/models.py:114
+msgid "e-mail address"
+msgstr ""
+
+#: contrib/auth/models.py:115
+msgid "password"
+msgstr ""
+
+#: contrib/auth/models.py:115
+msgid ""
+"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
+"password form</a>."
+msgstr ""
+
+#: contrib/auth/models.py:116
+msgid "staff status"
+msgstr ""
+
+#: contrib/auth/models.py:116
+msgid "Designates whether the user can log into this admin site."
+msgstr ""
+
+#: contrib/auth/models.py:117
+msgid "active"
+msgstr ""
+
+#: contrib/auth/models.py:117
+msgid ""
+"Designates whether this user can log into the Django admin. Unselect this "
+"instead of deleting accounts."
+msgstr ""
+
+#: contrib/auth/models.py:118
+msgid "superuser status"
+msgstr ""
+
+#: contrib/auth/models.py:118
+msgid ""
+"Designates that this user has all permissions without explicitly assigning "
+"them."
+msgstr ""
+
+#: contrib/auth/models.py:119
+msgid "last login"
+msgstr ""
+
+#: contrib/auth/models.py:120
+msgid "date joined"
+msgstr ""
+
+#: contrib/auth/models.py:122
+msgid ""
+"In addition to the permissions manually assigned, this user will also get "
+"all permissions granted to each group he/she is in."
+msgstr ""
+
+#: contrib/auth/models.py:123
+msgid "user permissions"
+msgstr ""
+
+#: contrib/auth/models.py:127
+msgid "user"
+msgstr ""
+
+#: contrib/auth/models.py:128
+msgid "users"
+msgstr ""
+
+#: contrib/auth/models.py:134
+msgid "Personal info"
+msgstr ""
+
+#: contrib/auth/models.py:135
+msgid "Permissions"
+msgstr ""
+
+#: contrib/auth/models.py:136
+msgid "Important dates"
+msgstr ""
+
+#: contrib/auth/models.py:137
+msgid "Groups"
+msgstr ""
+
+#: contrib/auth/models.py:287
+msgid "message"
+msgstr ""
+
+#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
+msgid "The two password fields didn't match."
+msgstr ""
+
+#: contrib/auth/forms.py:25
+msgid "A user with that username already exists."
+msgstr ""
+
+#: contrib/auth/forms.py:53
+msgid ""
+"Your Web browser doesn't appear to have cookies enabled. Cookies are "
+"required for logging in."
+msgstr ""
+
+#: contrib/auth/forms.py:62
+msgid "This account is inactive."
+msgstr ""
+
+#: contrib/auth/forms.py:84
+msgid ""
+"That e-mail address doesn't have an associated user account. Are you sure "
+"you've registered?"
+msgstr ""
+
+#: contrib/auth/forms.py:117
+msgid "The two 'new password' fields didn't match."
+msgstr ""
+
+#: contrib/auth/forms.py:124
+msgid "Your old password was entered incorrectly. Please enter it again."
+msgstr ""
+
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr ""
+
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr ""
+
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr ""
+
+#: contrib/localflavor/fr/forms.py:17 contrib/localflavor/de/forms.py:16
+#: contrib/localflavor/fi/forms.py:14
+msgid "Enter a zip code in the format XXXXX."
+msgstr ""
+
+#: contrib/localflavor/us/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr ""
+
+#: contrib/localflavor/us/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:5
+msgid "Baden-Wuerttemberg"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:6
+msgid "Bavaria"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:7
+msgid "Berlin"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:8
+msgid "Brandenburg"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:9
+msgid "Bremen"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:10
+msgid "Hamburg"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:11
+msgid "Hessen"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:12
+msgid "Mecklenburg-Western Pomerania"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:13
+msgid "Lower Saxony"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:14
+msgid "North Rhine-Westphalia"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:15
+msgid "Rhineland-Palatinate"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:16
+msgid "Saarland"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:17
+msgid "Saxony"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:18
+msgid "Saxony-Anhalt"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:19
+msgid "Schleswig-Holstein"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:20
+msgid "Thuringia"
+msgstr ""
+
+#: contrib/localflavor/de/forms.py:60
+msgid ""
+"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
+"format."
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:4
+msgid "Hokkaido"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:5
+msgid "Aomori"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:6
+msgid "Iwate"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:7
+msgid "Miyagi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:8
+msgid "Akita"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:9
+msgid "Yamagata"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:10
+msgid "Fukushima"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:11
+msgid "Ibaraki"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:12
+msgid "Tochigi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:13
+msgid "Gunma"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:14
+msgid "Saitama"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:15
+msgid "Chiba"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:16
+msgid "Tokyo"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:17
+msgid "Kanagawa"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:18
+msgid "Yamanashi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:19
+msgid "Nagano"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:20
+msgid "Niigata"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:21
+msgid "Toyama"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:22
+msgid "Ishikawa"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:23
+msgid "Fukui"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:24
+msgid "Gifu"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:25
+msgid "Shizuoka"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:26
+msgid "Aichi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:27
+msgid "Mie"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:28
+msgid "Shiga"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:29
+msgid "Kyoto"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:30
+msgid "Osaka"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:31
+msgid "Hyogo"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:32
+msgid "Nara"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:33
+msgid "Wakayama"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:34
+msgid "Tottori"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:35
+msgid "Shimane"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:36
+msgid "Okayama"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:37
+msgid "Hiroshima"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:38
+msgid "Yamaguchi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:39
+msgid "Tokushima"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:40
+msgid "Kagawa"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:41
+msgid "Ehime"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:42
+msgid "Kochi"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:43
+msgid "Fukuoka"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:44
+msgid "Saga"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:45
+msgid "Nagasaki"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:46
+msgid "Kumamoto"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:47
+msgid "Oita"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:48
+msgid "Miyazaki"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:49
+msgid "Kagoshima"
+msgstr ""
+
+#: contrib/localflavor/jp/jp_prefectures.py:50
+msgid "Okinawa"
+msgstr ""
+
+#: contrib/localflavor/jp/forms.py:21
+msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr ""
+
+#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:14
+msgid "Enter a zip code in the format XXXX."
+msgstr ""
+
+#: contrib/localflavor/ch/forms.py:90
+msgid ""
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
+msgstr ""
+
+#: contrib/localflavor/is_/forms.py:17
+msgid "Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr ""
+
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr ""
+
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr ""
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr ""
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr ""
+
+#: contrib/localflavor/no/forms.py:35
+msgid "Enter a valid Norwegian social security number."
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:8
+msgid "Banska Bystrica region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:9
+msgid "Bratislava region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:10
+msgid "Kosice region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:11
+msgid "Nitra region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:12
+msgid "Presov region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:13
+msgid "Trencin region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:14
+msgid "Trnava region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:15
+msgid "Zilina region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:8
+msgid "Banska Bystrica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:9
+msgid "Banska Stiavnica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:10
+msgid "Bardejov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:11
+msgid "Banovce nad Bebravou"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:12
+msgid "Brezno"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:13
+msgid "Bratislava I"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:14
+msgid "Bratislava II"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:15
+msgid "Bratislava III"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:16
+msgid "Bratislava IV"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:17
+msgid "Bratislava V"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:18
+msgid "Bytca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:19
+msgid "Cadca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:20
+msgid "Detva"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:21
+msgid "Dolny Kubin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:22
+msgid "Dunajska Streda"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:23
+msgid "Galanta"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:24
+msgid "Gelnica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:25
+msgid "Hlohovec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:26
+msgid "Humenne"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:27
+msgid "Ilava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:28
+msgid "Kezmarok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:29
+msgid "Komarno"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:30
+msgid "Kosice I"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:31
+msgid "Kosice II"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:32
+msgid "Kosice III"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:33
+msgid "Kosice IV"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:34
+msgid "Kosice - okolie"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:35
+msgid "Krupina"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:36
+msgid "Kysucke Nove Mesto"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:37
+msgid "Levice"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:38
+msgid "Levoca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:39
+msgid "Liptovsky Mikulas"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:40
+msgid "Lucenec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:41
+msgid "Malacky"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:42
+msgid "Martin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:43
+msgid "Medzilaborce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:44
+msgid "Michalovce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:45
+msgid "Myjava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:46
+msgid "Namestovo"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:47
+msgid "Nitra"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:48
+msgid "Nove Mesto nad Vahom"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:49
+msgid "Nove Zamky"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:50
+msgid "Partizanske"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:51
+msgid "Pezinok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:52
+msgid "Piestany"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:53
+msgid "Poltar"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:54
+msgid "Poprad"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:55
+msgid "Povazska Bystrica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:56
+msgid "Presov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:57
+msgid "Prievidza"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:58
+msgid "Puchov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:59
+msgid "Revuca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:60
+msgid "Rimavska Sobota"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:61
+msgid "Roznava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:62
+msgid "Ruzomberok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:63
+msgid "Sabinov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:64
+msgid "Senec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:65
+msgid "Senica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:66
+msgid "Skalica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:67
+msgid "Snina"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:68
+msgid "Sobrance"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:69
+msgid "Spisska Nova Ves"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:70
+msgid "Stara Lubovna"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:71
+msgid "Stropkov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:72
+msgid "Svidnik"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:73
+msgid "Sala"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:74
+msgid "Topolcany"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:75
+msgid "Trebisov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:76
+msgid "Trencin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:77
+msgid "Trnava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:78
+msgid "Turcianske Teplice"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:79
+msgid "Tvrdosin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:80
+msgid "Velky Krtis"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:81
+msgid "Vranov nad Toplou"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:82
+msgid "Zlate Moravce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:83
+msgid "Zvolen"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:84
+msgid "Zarnovica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:85
+msgid "Ziar nad Hronom"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:86
+msgid "Zilina"
+msgstr ""
+
+#: contrib/localflavor/sk/forms.py:32
+msgid "Enter a postal code in the format XXXXX or XXX XX."
+msgstr ""
+
+#: contrib/localflavor/cl/forms.py:32
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr ""
+
+#: contrib/localflavor/cl/forms.py:37
+msgid "Enter valid a Chilean RUT"
+msgstr ""
+
+#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
+msgid "Enter a valid Finnish social security number."
+msgstr ""
+
+#: contrib/sessions/models.py:68
+msgid "session key"
+msgstr ""
+
+#: contrib/sessions/models.py:69
+msgid "session data"
+msgstr ""
+
+#: contrib/sessions/models.py:70
+msgid "expire date"
+msgstr ""
+
+#: contrib/sessions/models.py:74
+msgid "session"
+msgstr ""
+
+#: contrib/sessions/models.py:75
+msgid "sessions"
+msgstr ""
+
+#: contrib/flatpages/models.py:8
+#, fuzzy
+msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
+msgstr "i."
+
+#: contrib/flatpages/models.py:9
+msgid "title"
+msgstr ""
+
+#: contrib/flatpages/models.py:10
+msgid "content"
+msgstr ""
+
+#: contrib/flatpages/models.py:11
+msgid "enable comments"
+msgstr ""
+
+#: contrib/flatpages/models.py:12
+msgid "template name"
+msgstr ""
+
+#: contrib/flatpages/models.py:13
+msgid ""
+"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
+"will use 'flatpages/default.html'."
+msgstr ""
+
+#: contrib/flatpages/models.py:14
+msgid "registration required"
+msgstr ""
+
+#: contrib/flatpages/models.py:14
+msgid "If this is checked, only logged-in users will be able to view the page."
+msgstr ""
+
+#: contrib/flatpages/models.py:18
+msgid "flat page"
+msgstr ""
+
+#: contrib/flatpages/models.py:19
+msgid "flat pages"
+msgstr ""
+
+#: utils/dates.py:6
+msgid "Monday"
+msgstr ""
+
+#: utils/dates.py:6
+msgid "Tuesday"
+msgstr ""
+
+#: utils/dates.py:6
+msgid "Wednesday"
+msgstr ""
+
+#: utils/dates.py:6
+msgid "Thursday"
+msgstr ""
+
+#: utils/dates.py:6
+msgid "Friday"
+msgstr ""
+
+#: utils/dates.py:7
+msgid "Saturday"
+msgstr ""
+
+#: utils/dates.py:7
+msgid "Sunday"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Mon"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr ""
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr ""
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr ""
+
+#: utils/dates.py:18
+msgid "January"
+msgstr ""
+
+#: utils/dates.py:18
+msgid "February"
+msgstr ""
+
+#: utils/dates.py:18 utils/dates.py:31
+msgid "March"
+msgstr ""
+
+#: utils/dates.py:18 utils/dates.py:31
+msgid "April"
+msgstr ""
+
+#: utils/dates.py:18 utils/dates.py:31
+msgid "May"
+msgstr ""
+
+#: utils/dates.py:18 utils/dates.py:31
+msgid "June"
+msgstr ""
+
+#: utils/dates.py:19 utils/dates.py:31
+msgid "July"
+msgstr ""
+
+#: utils/dates.py:19
+msgid "August"
+msgstr ""
+
+#: utils/dates.py:19
+msgid "September"
+msgstr ""
+
+#: utils/dates.py:19
+msgid "October"
+msgstr ""
+
+#: utils/dates.py:19
+msgid "November"
+msgstr ""
+
+#: utils/dates.py:20
+msgid "December"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "jan"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "feb"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "mar"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "apr"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "may"
+msgstr ""
+
+#: utils/dates.py:23
+msgid "jun"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "jul"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "aug"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "sep"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "oct"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "nov"
+msgstr ""
+
+#: utils/dates.py:24
+msgid "dec"
+msgstr ""
+
+#: utils/dates.py:31
+msgid "Jan."
+msgstr ""
+
+#: utils/dates.py:31
+msgid "Feb."
+msgstr ""
+
+#: utils/dates.py:32
+msgid "Aug."
+msgstr ""
+
+#: utils/dates.py:32
+msgid "Sept."
+msgstr ""
+
+#: utils/dates.py:32
+msgid "Oct."
+msgstr ""
+
+#: utils/dates.py:32
+msgid "Nov."
+msgstr ""
+
+#: utils/dates.py:32
+msgid "Dec."
+msgstr ""
+
+#: utils/timesince.py:12
+msgid "year"
+msgid_plural "years"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:13
+msgid "month"
+msgid_plural "months"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:14
+msgid "week"
+msgid_plural "weeks"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:15
+msgid "day"
+msgid_plural "days"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:16
+msgid "hour"
+msgid_plural "hours"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:17
+msgid "minute"
+msgid_plural "minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: utils/timesince.py:39
+#, python-format
+msgid "%(number)d %(type)s"
+msgstr ""
+
+#: utils/timesince.py:45
+#, python-format
+msgid ", %(number)d %(type)s"
+msgstr ""
+
+#: utils/dateformat.py:41
+msgid "p.m."
+msgstr ""
+
+#: utils/dateformat.py:42
+msgid "a.m."
+msgstr ""
+
+#: utils/dateformat.py:47
+msgid "PM"
+msgstr ""
+
+#: utils/dateformat.py:48
+msgid "AM"
+msgstr ""
+
+#: utils/dateformat.py:97
+msgid "midnight"
+msgstr ""
+
+#: utils/dateformat.py:99
+msgid "noon"
+msgstr ""
+
+#: utils/translation/trans_real.py:391
+msgid "DATE_FORMAT"
+msgstr ""
+
+#: utils/translation/trans_real.py:392
+msgid "DATETIME_FORMAT"
+msgstr ""
+
+#: utils/translation/trans_real.py:393
+msgid "TIME_FORMAT"
+msgstr ""
+
+#: utils/translation/trans_real.py:409
+msgid "YEAR_MONTH_FORMAT"
+msgstr ""
+
+#: utils/translation/trans_real.py:410
+msgid "MONTH_DAY_FORMAT"
+msgstr ""
+
+#: template/defaultfilters.py:485
+msgid "yes,no,maybe"
+msgstr ""
+
+#: template/defaultfilters.py:514
+#, python-format
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: template/defaultfilters.py:516
+#, python-format
+msgid "%.1f KB"
+msgstr ""
+
+#: template/defaultfilters.py:518
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: template/defaultfilters.py:519
+#, python-format
+msgid "%.1f GB"
+msgstr ""
+
diff --git a/django/conf/locale/hr/LC_MESSAGES/djangojs.mo b/django/conf/locale/hr/LC_MESSAGES/djangojs.mo
new file mode 100644
index 0000000000..823d8dbf10
--- /dev/null
+++ b/django/conf/locale/hr/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/hr/LC_MESSAGES/djangojs.po b/django/conf/locale/hr/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000..7fd1654913
--- /dev/null
+++ b/django/conf/locale/hr/LC_MESSAGES/djangojs.po
@@ -0,0 +1,118 @@
+# 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 <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-08-13 11:13+1000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: contrib/admin/media/js/SelectFilter2.js:33
+#, perl-format
+msgid "Available %s"
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:41
+msgid "Choose all"
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:46
+msgid "Add"
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:48
+msgid "Remove"
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:53
+#, perl-format
+msgid "Chosen %s"
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:54
+msgid "Select your choice(s) and click "
+msgstr ""
+
+#: contrib/admin/media/js/SelectFilter2.js:59
+msgid "Clear all"
+msgstr ""
+
+#: contrib/admin/media/js/dateparse.js:32
+#: contrib/admin/media/js/calendar.js:24
+msgid ""
+"January February March April May June July August September October November "
+"December"
+msgstr ""
+
+#: contrib/admin/media/js/dateparse.js:33
+msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+msgstr ""
+
+#: contrib/admin/media/js/calendar.js:25
+msgid "S M T W T F S"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+msgid "Now"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
+msgid "Clock"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
+msgid "Choose a time"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+msgid "Midnight"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+msgid "6 a.m."
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
+msgid "Noon"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
+msgid "Cancel"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
+msgid "Today"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
+msgid "Calendar"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
+msgid "Yesterday"
+msgstr ""
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
+msgid "Tomorrow"
+msgstr ""
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
+msgid "Show"
+msgstr ""
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
+msgid "Hide"
+msgstr ""
diff --git a/django/conf/locale/it/LC_MESSAGES/django.mo b/django/conf/locale/it/LC_MESSAGES/django.mo
index e0d5e0442d..42f69d30bf 100644
--- a/django/conf/locale/it/LC_MESSAGES/django.mo
+++ b/django/conf/locale/it/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/it/LC_MESSAGES/django.po b/django/conf/locale/it/LC_MESSAGES/django.po
index 2c9060a076..96ca9650d6 100644
--- a/django/conf/locale/it/LC_MESSAGES/django.po
+++ b/django/conf/locale/it/LC_MESSAGES/django.po
@@ -7,9 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-04-11 17:39+0200\n"
-"PO-Revision-Date: 2007-03-14 19:29+0100\n"
-"Last-Translator: Flavio Curella <flavio.curella@gmail.com>\n"
+"POT-Creation-Date: 2007-08-11 19:17+0200\n"
+"PO-Revision-Date: 2007-08-11 19:39+0100\n"
+"Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
"Language-Team: Italiano\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -17,13 +17,97 @@ msgstr ""
"X-Generator: KBabel 1.11.2\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: conf/global_settings.py:39
+#: db/models/manipulators.py:309
+#, python-format
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "Un %(object)s·con questo·%(type)s·esiste già per questo·%(field)s."
+
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+msgid "and"
+msgstr "e"
+
+#: db/models/fields/related.py:55
+#, python-format
+msgid "Please enter a valid %s."
+msgstr "Inserire un %s valido."
+
+#: db/models/fields/related.py:661
+msgid "Separate multiple IDs with commas."
+msgstr "Separare gli ID multipli con virgole."
+
+#: db/models/fields/related.py:663
+msgid ""
+"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr ""
+"Tenere premuto \"Control\", o \"Command\" su Mac, per selezionarne più di "
+"uno."
+
+#: db/models/fields/related.py:710
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural ""
+"Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] ""
+"Inserire un ID valido per %(self)s. Il valore %(value)r non è valido."
+msgstr[1] ""
+"Inserire ID validi per %(self)s. I valori %(value)r non sono validi."
+
+#: db/models/fields/__init__.py:49
+#, python-format
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "Un %(optname)s·con questo·%(fieldname)s·esiste già."
+
+#: db/models/fields/__init__.py:156 db/models/fields/__init__.py:313
+#: db/models/fields/__init__.py:721 db/models/fields/__init__.py:732
+#: oldforms/__init__.py:373 newforms/fields.py:92 newforms/fields.py:490
+#: newforms/fields.py:566 newforms/fields.py:577 newforms/models.py:193
+msgid "This field is required."
+msgstr "Questo campo è obbligatorio."
+
+#: db/models/fields/__init__.py:411
+msgid "This value must be an integer."
+msgstr "Questo valore deve essere un intero."
+
+#: db/models/fields/__init__.py:446
+msgid "This value must be either True or False."
+msgstr "Questo valore deve essere True o False."
+
+#: db/models/fields/__init__.py:467
+msgid "This field cannot be null."
+msgstr "Questo campo non può essere nullo."
+
+#: db/models/fields/__init__.py:501 core/validators.py:155
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "Inserire una data valida in formato AAAA-MM-GG."
+
+#: db/models/fields/__init__.py:570 core/validators.py:164
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "Inserire una data/ora valida in formato AAAA-MM-GG OO:MM."
+
+#: db/models/fields/__init__.py:631
+msgid "This value must be a decimal number."
+msgstr "Questo valore deve essere un numero decimale."
+
+#: db/models/fields/__init__.py:741
+msgid "Enter a valid filename."
+msgstr "Inserire un nome di file valido."
+
+#: db/models/fields/__init__.py:883
+msgid "This value must be either None, True or False."
+msgstr "Questo valore deve essere None, True o False."
+
+#: conf/global_settings.py:38
msgid "Arabic"
msgstr "Arabo"
-#: conf/global_settings.py:40
+#: conf/global_settings.py:39
msgid "Bengali"
-msgstr "Bengali"
+msgstr ""
+
+#: conf/global_settings.py:40
+msgid "Bulgarian"
+msgstr "Bulgaro"
#: conf/global_settings.py:41
msgid "Catalan"
@@ -62,313 +146,1105 @@ msgid "Argentinean Spanish"
msgstr "Spagnolo argentino"
#: conf/global_settings.py:50
+msgid "Persian"
+msgstr "Persiano"
+
+#: conf/global_settings.py:51
msgid "Finnish"
msgstr "Finlandese"
-#: conf/global_settings.py:51
+#: conf/global_settings.py:52
msgid "French"
msgstr "Francese"
-#: conf/global_settings.py:52
+#: conf/global_settings.py:53
msgid "Galician"
msgstr "Galiziano"
-#: conf/global_settings.py:53
+#: conf/global_settings.py:54
msgid "Hungarian"
msgstr "Ungherese"
-#: conf/global_settings.py:54
+#: conf/global_settings.py:55
msgid "Hebrew"
msgstr "Ebraico"
-#: conf/global_settings.py:55
+#: conf/global_settings.py:56
msgid "Icelandic"
msgstr "Islandese"
-#: conf/global_settings.py:56
+#: conf/global_settings.py:57
msgid "Italian"
msgstr "Italiano"
-#: conf/global_settings.py:57
+#: conf/global_settings.py:58
msgid "Japanese"
msgstr "Giapponese"
-#: conf/global_settings.py:58
-#, fuzzy
+#: conf/global_settings.py:59
msgid "Korean"
-msgstr "Norvegese"
+msgstr "Coreano"
-#: conf/global_settings.py:59
+#: conf/global_settings.py:60
msgid "Kannada"
-msgstr "Kannada"
+msgstr ""
-#: conf/global_settings.py:60
+#: conf/global_settings.py:61
msgid "Latvian"
msgstr "Lettone"
-#: conf/global_settings.py:61
+#: conf/global_settings.py:62
msgid "Macedonian"
msgstr "Macedone"
-#: conf/global_settings.py:62
+#: conf/global_settings.py:63
msgid "Dutch"
msgstr "Olandese"
-#: conf/global_settings.py:63
+#: conf/global_settings.py:64
msgid "Norwegian"
msgstr "Norvegese"
-#: conf/global_settings.py:64
+#: conf/global_settings.py:65
msgid "Polish"
msgstr "Polacco"
-#: conf/global_settings.py:65
+#: conf/global_settings.py:66
msgid "Portugese"
msgstr "Portoghese"
-#: conf/global_settings.py:66
+#: conf/global_settings.py:67
msgid "Brazilian"
msgstr "Brasiliano"
-#: conf/global_settings.py:67
+#: conf/global_settings.py:68
msgid "Romanian"
msgstr "Rumeno"
-#: conf/global_settings.py:68
+#: conf/global_settings.py:69
msgid "Russian"
msgstr "Russo"
-#: conf/global_settings.py:69
+#: conf/global_settings.py:70
msgid "Slovak"
msgstr "Slovacco"
-#: conf/global_settings.py:70
+#: conf/global_settings.py:71
msgid "Slovenian"
msgstr "Sloveno"
-#: conf/global_settings.py:71
+#: conf/global_settings.py:72
msgid "Serbian"
msgstr "Serbo"
-#: conf/global_settings.py:72
+#: conf/global_settings.py:73
msgid "Swedish"
msgstr "Svedese"
-#: conf/global_settings.py:73
+#: conf/global_settings.py:74
msgid "Tamil"
-msgstr "Tamil"
+msgstr ""
-#: conf/global_settings.py:74
+#: conf/global_settings.py:75
msgid "Telugu"
msgstr ""
-#: conf/global_settings.py:75
+#: conf/global_settings.py:76
msgid "Turkish"
msgstr "Turco"
-#: conf/global_settings.py:76
+#: conf/global_settings.py:77
msgid "Ukrainian"
msgstr "Ucraino"
-#: conf/global_settings.py:77
+#: conf/global_settings.py:78
msgid "Simplified Chinese"
msgstr "Cinese semplificato"
-#: conf/global_settings.py:78
+#: conf/global_settings.py:79
msgid "Traditional Chinese"
msgstr "Cinese tradizionale"
-#: contrib/admin/filterspecs.py:40
+#: core/validators.py:71
+msgid "This value must contain only letters, numbers and underscores."
+msgstr "Questo valore può contenere solo lettere, cifre e sottolineati."
+
+#: core/validators.py:75
+msgid ""
+"This value must contain only letters, numbers, underscores, dashes or "
+"slashes."
+msgstr ""
+"Questo valore può contenere solo lettere, cifre, sottolineati, trattini e "
+"barre diagonali."
+
+#: core/validators.py:79
+msgid "This value must contain only letters, numbers, underscores or hyphens."
+msgstr ""
+"Questo valore può contenere solo lettere, cifre, sottolineati e trattini."
+
+#: core/validators.py:83
+msgid "Uppercase letters are not allowed here."
+msgstr "Non sono ammesse lettere maiuscole."
+
+#: core/validators.py:87
+msgid "Lowercase letters are not allowed here."
+msgstr "Non sono ammesse lettere minuscole."
+
+#: core/validators.py:94
+msgid "Enter only digits separated by commas."
+msgstr "Inserire solo cifre separate da virgole."
+
+#: core/validators.py:106
+msgid "Enter valid e-mail addresses separated by commas."
+msgstr "Inserire indirizzi e-mail validi separati da virgole."
+
+#: core/validators.py:110
+msgid "Please enter a valid IP address."
+msgstr "Inserire un indirizzo IP valido."
+
+#: core/validators.py:114
+msgid "Empty values are not allowed here."
+msgstr "È necessario inserire un valore."
+
+#: core/validators.py:118
+msgid "Non-numeric characters aren't allowed here."
+msgstr "Sono ammessi soltanto caratteri numerici."
+
+#: core/validators.py:122
+msgid "This value can't be comprised solely of digits."
+msgstr "Questo valore non può essere composto solo da cifre."
+
+#: core/validators.py:127 newforms/fields.py:142
+msgid "Enter a whole number."
+msgstr "Inserire un numero intero."
+
+#: core/validators.py:131
+msgid "Only alphabetical characters are allowed here."
+msgstr "Sono ammessi solo caratteri alfabetici."
+
+#: core/validators.py:146
+msgid "Year must be 1900 or later."
+msgstr "L'anno deve essere 1900 o successivo."
+
+#: core/validators.py:150
+#, python-format
+msgid "Invalid date: %s"
+msgstr "Data non valida: %s"
+
+#: core/validators.py:160
+msgid "Enter a valid time in HH:MM format."
+msgstr "Inserire un ora valida in formato OO:MM."
+
+#: core/validators.py:169 newforms/fields.py:336
+msgid "Enter a valid e-mail address."
+msgstr "Inserire un indirizzo e-mail valido."
+
+#: core/validators.py:181 core/validators.py:461 oldforms/__init__.py:686
+#: newforms/fields.py:376
+msgid "No file was submitted. Check the encoding type on the form."
+msgstr ""
+"Non è stato inviato alcun file. Verificare il tipo di codifica della form."
+
+#: core/validators.py:185 newforms/fields.py:397
+msgid ""
+"Upload a valid image. The file you uploaded was either not an image or a "
+"corrupted image."
+msgstr ""
+"Caricare un'immagine valida. Il file caricato non è un'immagine o è corrotto."
+
+#: core/validators.py:192
+#, python-format
+msgid "The URL %s does not point to a valid image."
+msgstr "La URL %s non punta ad un'immagine valida."
+
+#: core/validators.py:196
+#, python-format
+msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
+msgstr ""
+"I numeri di telefono devono essere in formato XXX-XXX-XXXX . \"%s\" non è "
+"valido."
+
+#: core/validators.py:204
+#, python-format
+msgid "The URL %s does not point to a valid QuickTime video."
+msgstr "La URL %s non punta ad un video QuickTime valido."
+
+#: core/validators.py:208
+msgid "A valid URL is required."
+msgstr "Inserire una URL valida."
+
+#: core/validators.py:222
+#, python-format
+msgid ""
+"Valid HTML is required. Specific errors are:\n"
+"%s"
+msgstr ""
+"È richiesto HTML valido. Gli errori sono i seguenti:\n"
+"%s"
+
+#: core/validators.py:229
+#, python-format
+msgid "Badly formed XML: %s"
+msgstr "XML malformato: %s"
+
+#: core/validators.py:246
+#, python-format
+msgid "Invalid URL: %s"
+msgstr "URL non valida: %s"
+
+#: core/validators.py:251 core/validators.py:253
+#, python-format
+msgid "The URL %s is a broken link."
+msgstr "La URL %s è un link non funzionante."
+
+#: core/validators.py:259
+msgid "Enter a valid U.S. state abbreviation."
+msgstr "Inserire un valido nome di stato USA abbreviato."
+
+#: core/validators.py:273
+#, python-format
+msgid "Watch your mouth! The word %s is not allowed here."
+msgid_plural "Watch your mouth! The words %s are not allowed here."
+msgstr[0] "Moderare i termini: la parola %s non è ammessa."
+msgstr[1] "Moderare i termini: le parole %s non sono ammesse."
+
+#: core/validators.py:280
+#, python-format
+msgid "This field must match the '%s' field."
+msgstr "Questo campo deve corrispondere al campo '%s'."
+
+#: core/validators.py:299
+msgid "Please enter something for at least one field."
+msgstr "Inserire qualcosa in almeno un campo."
+
+#: core/validators.py:308 core/validators.py:319
+msgid "Please enter both fields or leave them both empty."
+msgstr "Inserire entrambi i campi o lasciarli entrambi vuoti."
+
+#: core/validators.py:327
+#, python-format
+msgid "This field must be given if %(field)s is %(value)s"
+msgstr "Questo campo è obbligatorio se %(field)s è %(value)s"
+
+#: core/validators.py:340
+#, python-format
+msgid "This field must be given if %(field)s is not %(value)s"
+msgstr "Questo campo è obbligatorio se %(field)s non è %(value)s"
+
+#: core/validators.py:359
+msgid "Duplicate values are not allowed."
+msgstr "Non sono ammessi valori duplicati."
+
+#: core/validators.py:374
+#, fuzzy, python-format
+msgid "This value must be between %(lower)s and %(upper)s."
+msgstr "Questo valore deve essere compreso tra %s e %s."
+
+#: core/validators.py:376
+#, python-format
+msgid "This value must be at least %s."
+msgstr "Questo valore deve essere almeno pari a %s."
+
+#: core/validators.py:378
+#, python-format
+msgid "This value must be no more than %s."
+msgstr "Questo valore non deve essere maggiore di %s."
+
+#: core/validators.py:414
+#, python-format
+msgid "This value must be a power of %s."
+msgstr "Questo valore deve essere una potenza di %s."
+
+#: core/validators.py:424
+msgid "Please enter a valid decimal number."
+msgstr "Inserire un numero decimale valido."
+
+#: core/validators.py:431
+#, python-format
+msgid "Please enter a valid decimal number with at most %s total digit."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s total digits."
+msgstr[0] "Inserire un numero decimale con non più di %s cifra in totale."
+msgstr[1] "Inserire un numero decimale con non più di %s cifre in totale."
+
+#: core/validators.py:434
+#, python-format
+msgid ""
+"Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural ""
+"Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] ""
+"Inserire un numero decimale la cui parte intera sia composta da non più di "
+"%s cifra."
+msgstr[1] ""
+"Inserire un numero decimale la cui parte intera sia composta da non più di "
+"%s cifre."
+
+#: core/validators.py:437
+#, python-format
+msgid "Please enter a valid decimal number with at most %s decimal place."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s decimal places."
+msgstr[0] "Inserire un decimale con non più di %s cifra decimale."
+msgstr[1] "Inserire un decimale con non più di %s cifre decimali."
+
+#: core/validators.py:445
+msgid "Please enter a valid floating point number."
+msgstr "Inserire un numero decimale valido."
+
+#: core/validators.py:454
+#, python-format
+msgid "Make sure your uploaded file is at least %s bytes big."
+msgstr "Verificare che il file caricato sia grande almeno %s byte."
+
+#: core/validators.py:455
+#, python-format
+msgid "Make sure your uploaded file is at most %s bytes big."
+msgstr "Verificare che il file caricato non sia più grande di %s byte."
+
+#: core/validators.py:472
+msgid "The format for this field is wrong."
+msgstr "Il formato di questo campo non è valido."
+
+#: core/validators.py:487
+msgid "This field is invalid."
+msgstr "Questo campo non è valido."
+
+#: core/validators.py:523
+#, python-format
+msgid "Could not retrieve anything from %s."
+msgstr "Impossibile recuperare alcunché da %s."
+
+#: core/validators.py:526
+#, python-format
+msgid ""
+"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+msgstr ""
+"La URL %(url)s ha restituito un header Content-Type non valido: "
+"'%(contenttype)s'."
+
+#: core/validators.py:559
+#, python-format
+msgid ""
+"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
+"\"%(start)s\".)"
+msgstr ""
+"Chiudere il tag %(tag)s a linea %(line)s. (La linea inizia con \"%(start)s"
+"\".)"
+
+#: core/validators.py:563
+#, python-format
+msgid ""
+"Some text starting on line %(line)s is not allowed in that context. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"Il testo che comincia a linea %(line)s non e' ammesso in quel contesto. "
+"(La linea comincia con \"%(start)s\".)"
+
+#: core/validators.py:568
+#, python-format
+msgid ""
+"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"\"%(attr)s\" a linea %(line)s non è un attributo valido. (La linea comincia "
+"con \"%(start)s\".)"
+
+#: core/validators.py:573
+#, python-format
+msgid ""
+"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"\"<%(tag)s>\" a linea %(line)s non è un tag valido. (La linea comincia con "
+"\"%(start)s\".)"
+
+#: core/validators.py:577
+#, python-format
+msgid ""
+"A tag on line %(line)s is missing one or more required attributes. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"Un tag a linea %(line)s manca di uno o più attributi richiesti. (La linea "
+"comincia con \"%(start)s\".)"
+
+#: core/validators.py:582
+#, python-format
+msgid ""
+"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"L'attributo \"%(attr)s\" a linea %(line)s ha un valore non valido. (La linea "
+"comincia con \"%(start)s\".)"
+
+#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
+msgid "The two password fields didn't match."
+msgstr "I due campi password non corrispondono."
+
+#: contrib/auth/forms.py:25
+msgid "A user with that username already exists."
+msgstr "Un utente con questo nome·è già presente."
+
+#: contrib/auth/forms.py:53
+msgid ""
+"Your Web browser doesn't appear to have cookies enabled. Cookies are "
+"required for logging in."
+msgstr ""
+"Il browser web sembra non avere i cookie abilitati. I cookie sono necessari "
+"per poter accedere."
+
+#: contrib/auth/forms.py:60 contrib/admin/views/decorators.py:10
+msgid ""
+"Please enter a correct username and password. Note that both fields are case-"
+"sensitive."
+msgstr ""
+"Inserire nome utente e password corretti. Entrambi i campi sono case "
+"sensitive."
+
+#: contrib/auth/forms.py:62
+msgid "This account is inactive."
+msgstr "Questo account non è attivo."
+
+#: contrib/auth/forms.py:84
+msgid ""
+"That e-mail address doesn't have an associated user account. Are you sure "
+"you've registered?"
+msgstr ""
+"Questo indirizzo email non è associato ad alcun account utente. Sei sicuro "
+"di esserti registrato?"
+
+#: contrib/auth/forms.py:117
+msgid "The two 'new password' fields didn't match."
+msgstr "I due campi 'nuova password' non corrispondono."
+
+#: contrib/auth/forms.py:124
+msgid "Your old password was entered incorrectly. Please enter it again."
+msgstr ""
+"La vecchia password non è stata inserita correttamente: va inserita di nuovo."
+
+#: contrib/auth/models.py:53 contrib/auth/models.py:73
+msgid "name"
+msgstr "nome"
+
+#: contrib/auth/models.py:55
+msgid "codename"
+msgstr "nome in codice"
+
+#: contrib/auth/models.py:58
+msgid "permission"
+msgstr "permesso"
+
+#: contrib/auth/models.py:59 contrib/auth/models.py:74
+msgid "permissions"
+msgstr "permessi"
+
+#: contrib/auth/models.py:77
+msgid "group"
+msgstr "gruppo"
+
+#: contrib/auth/models.py:78 contrib/auth/models.py:121
+msgid "groups"
+msgstr "gruppi"
+
+#: contrib/auth/models.py:111
+msgid "username"
+msgstr "nome utente"
+
+#: contrib/auth/models.py:111
+msgid ""
+"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
+"digits and underscores)."
+msgstr ""
+"Obbligatorio. 30 caratteri o meno. Solo caratteri alfanumerici (lettere, "
+"cifre e sottolineati)."
+
+#: contrib/auth/models.py:112
+msgid "first name"
+msgstr "nome"
+
+#: contrib/auth/models.py:113
+msgid "last name"
+msgstr "cognome"
+
+#: contrib/auth/models.py:114
+msgid "e-mail address"
+msgstr "indirizzo e-mail"
+
+#: contrib/auth/models.py:115
+msgid "password"
+msgstr "password"
+
+#: contrib/auth/models.py:115
+msgid ""
+"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
+"password form</a>."
+msgstr ""
+"Usare '[algo]$[salt]$[hexdigest]' oppure la <a href=\"password/\">maschera "
+"di cambio password</a>."
+
+#: contrib/auth/models.py:116
+msgid "staff status"
+msgstr "privilegi di staff"
+
+#: contrib/auth/models.py:116
+msgid "Designates whether the user can log into this admin site."
+msgstr "Indica se l'utente può accedere a questo sito di amministrazione."
+
+#: contrib/auth/models.py:117
+msgid "active"
+msgstr "attivo"
+
+#: contrib/auth/models.py:117
+msgid ""
+"Designates whether this user can log into the Django admin. Unselect this "
+"instead of deleting accounts."
+msgstr ""
+"Indica se l'utente può accedere all'amministrazione di Django. Deselezionare "
+"qui, piuttosto che cancellare gli account."
+
+#: contrib/auth/models.py:118
+msgid "superuser status"
+msgstr "privilegi di superutente"
+
+#: contrib/auth/models.py:118
+msgid ""
+"Designates that this user has all permissions without explicitly assigning "
+"them."
+msgstr ""
+"Indica che l'utente ha tutti i privilegi, senza che siano stati assegnati "
+"esplicitamente."
+
+#: contrib/auth/models.py:119
+msgid "last login"
+msgstr "ultimo accesso"
+
+#: contrib/auth/models.py:120
+msgid "date joined"
+msgstr "iscritto in data"
+
+#: contrib/auth/models.py:122
+msgid ""
+"In addition to the permissions manually assigned, this user will also get "
+"all permissions granted to each group he/she is in."
+msgstr ""
+"In aggiunta ai privilegi assegnati manualmente, l'utente riceverà anche "
+"tutti i privilegi assegnati ad ogni gruppo cui appartiene."
+
+#: contrib/auth/models.py:123
+msgid "user permissions"
+msgstr "privilegi utente"
+
+#: contrib/auth/models.py:127
+msgid "user"
+msgstr "utente"
+
+#: contrib/auth/models.py:128
+msgid "users"
+msgstr "utenti"
+
+#: contrib/auth/models.py:134
+msgid "Personal info"
+msgstr "Informazioni personali"
+
+#: contrib/auth/models.py:135
+msgid "Permissions"
+msgstr "Permessi"
+
+#: contrib/auth/models.py:136
+msgid "Important dates"
+msgstr "Date importanti"
+
+#: contrib/auth/models.py:137
+msgid "Groups"
+msgstr "Gruppi"
+
+#: contrib/auth/models.py:287
+msgid "message"
+msgstr "messaggio"
+
+#: contrib/auth/views.py:41
+msgid "Logged out"
+msgstr "Accesso annullato"
+
+#: contrib/admin/models.py:17
+msgid "action time"
+msgstr "momento dell'azione"
+
+#: contrib/admin/models.py:20
+msgid "object id"
+msgstr "id dell'oggetto"
+
+#: contrib/admin/models.py:21
+msgid "object repr"
+msgstr "rappresentazione dell'oggetto"
+
+#: contrib/admin/models.py:22
+msgid "action flag"
+msgstr "flag di azione"
+
+#: contrib/admin/models.py:23
+msgid "change message"
+msgstr "messaggio di modifica"
+
+#: contrib/admin/models.py:26
+msgid "log entry"
+msgstr "voce di log"
+
+#: contrib/admin/models.py:27
+msgid "log entries"
+msgstr "voci di log"
+
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
"<ul>\n"
msgstr ""
-"<h3>Da %s:</h3>\n"
+"<h3>Di %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Tutti"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Qualsiasi data"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Oggi"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
msgstr "Ultimi 7 giorni"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Questo mese"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
msgstr "Quest'anno"
-#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:145 oldforms/__init__.py:591
+#: newforms/widgets.py:188
msgid "Yes"
msgstr "Sì"
-#: contrib/admin/filterspecs.py:143 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:145 oldforms/__init__.py:591
+#: newforms/widgets.py:188
msgid "No"
msgstr "No"
-#: contrib/admin/filterspecs.py:150 newforms/widgets.py:180
-#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:152 oldforms/__init__.py:591
+#: newforms/widgets.py:188
msgid "Unknown"
msgstr "Sconosciuto"
-#: contrib/admin/models.py:16
-msgid "action time"
-msgstr "data azione"
+#: contrib/admin/views/decorators.py:24
+#: contrib/admin/templates/admin/login.html:25
+msgid "Log in"
+msgstr "Accedi"
-#: contrib/admin/models.py:19
-msgid "object id"
-msgstr "ID oggetto"
+#: contrib/admin/views/decorators.py:62
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+"La sessione è scaduta: occorre accedere nuovamente. I dati inseriti sono "
+"stati comunque salvati."
-#: contrib/admin/models.py:20
-msgid "object repr"
-msgstr "rappresentazione oggetto"
+#: contrib/admin/views/decorators.py:69
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr ""
+"Il browser non sembra configurato per accettare i cookie. Una volta "
+"abilitati, ricaricare la pagina e riprovare."
-#: contrib/admin/models.py:21
-msgid "action flag"
-msgstr "flag azione"
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr "I nomi utente non possono contenere il carattere '@'."
-#: contrib/admin/models.py:22
-msgid "change message"
-msgstr "messaggio di modifica"
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr ""
+"Il nome utente non è costituito dall'indirizzo e-mail. Provare con '%s'."
-#: contrib/admin/models.py:25
-msgid "log entry"
-msgstr "voce di log"
+#: contrib/admin/views/main.py:230
+msgid "Site administration"
+msgstr "Amministrazione sito"
-#: contrib/admin/models.py:26
-msgid "log entries"
-msgstr "voci di log"
+#: contrib/admin/views/main.py:264 contrib/admin/views/auth.py:20
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully."
+msgstr "Lo %(name)s \"%(obj)s\" è stato aggiunto correttamente."
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
-msgid "Page not found"
-msgstr "Pagina non trovata"
+#: contrib/admin/views/main.py:268 contrib/admin/views/main.py:354
+#: contrib/admin/views/auth.py:25
+msgid "You may edit it again below."
+msgstr "È possibile modificarlo nuovamente qui sotto."
-#: contrib/admin/templates/admin/404.html:10
-msgid "We're sorry, but the requested page could not be found."
-msgstr "Spiacenti, ma la pagina richiesta non è stata trovata."
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
+#, python-format
+msgid "You may add another %s below."
+msgstr "È possibile aggiungere un altro %s qui sotto."
-#: contrib/admin/templates/admin/500.html:4
-#: contrib/admin/templates/admin/base.html:30
-#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/delete_confirmation.html:6
-#: contrib/admin/templates/admin/invalid_setup.html:4
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/auth/user/change_password.html:12
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/registration/logged_out.html:4
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_reset_done.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:4
-msgid "Home"
-msgstr "Pagina iniziale"
+#: contrib/admin/views/main.py:296
+#, python-format
+msgid "Add %s"
+msgstr "Aggiungi %s"
-#: contrib/admin/templates/admin/500.html:4
-msgid "Server error"
-msgstr "Errore del server"
+#: contrib/admin/views/main.py:342
+#, python-format
+msgid "Added %s."
+msgstr "%s aggiunto."
-#: contrib/admin/templates/admin/500.html:6
-msgid "Server error (500)"
-msgstr "Errore del server (500)"
+#: contrib/admin/views/main.py:344
+#, python-format
+msgid "Changed %s."
+msgstr "%s modificato."
-#: contrib/admin/templates/admin/500.html:9
-msgid "Server Error <em>(500)</em>"
-msgstr "Errore del server <em>(500)</em>"
+#: contrib/admin/views/main.py:346
+#, python-format
+msgid "Deleted %s."
+msgstr "%s cancellato."
-#: contrib/admin/templates/admin/500.html:10
+#: contrib/admin/views/main.py:349
+msgid "No fields changed."
+msgstr "Nessun campo modificato."
+
+#: contrib/admin/views/main.py:352
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was changed successfully."
+msgstr "Lo %(name)s \"%(obj)s\" è stato modificato correttamente."
+
+#: contrib/admin/views/main.py:360
+#, fuzzy, python-format
msgid ""
-"There's been an error. It's been reported to the site administrators via e-"
-"mail and should be fixed shortly. Thanks for your patience."
+"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr ""
-"Si è verificato un errore. È stato riportato agli amministratori del sito "
-"via e-mail e verrà corretto a breve. Grazie per la tua pazienza."
+"%Lo (name)s \"%(obj)s\" è stato aggiunto correttamente. È possibile "
+"modificarlo nuovamente qui sotto."
-#: contrib/admin/templates/admin/base.html:25
-msgid "Welcome,"
-msgstr "Benvenuto,"
+#: contrib/admin/views/main.py:398
+#, python-format
+msgid "Change %s"
+msgstr "Modifica %s"
-#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/views/main.py:483
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
+msgstr "Uno o più %(fieldname)s in %(name)s: %(obj)s"
+
+#: contrib/admin/views/main.py:488
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s:"
+msgstr "Uno o più %(fieldname)s in %(name)s:"
+
+#: contrib/admin/views/main.py:520
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was deleted successfully."
+msgstr "Lo %(name)s \"%(obj)s\" è stato cancellato correttamente."
+
+#: contrib/admin/views/main.py:523
+msgid "Are you sure?"
+msgstr "Sei sicuro?"
+
+#: contrib/admin/views/main.py:545
+#, python-format
+msgid "Change history: %s"
+msgstr "Tracciato delle modifiche: %s"
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s"
+msgstr "Scegli %s"
+
+#: contrib/admin/views/main.py:579
+#, python-format
+msgid "Select %s to change"
+msgstr "Scegli %s da modificare"
+
+#: contrib/admin/views/main.py:780
+msgid "Database error"
+msgstr "Errore nel database"
+
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
+msgid "tag:"
+msgstr "tag:"
+
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
+msgid "filter:"
+msgstr "filtro:"
+
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
+msgid "view:"
+msgstr "view:"
+
+#: contrib/admin/views/doc.py:165
+#, python-format
+msgid "App %r not found"
+msgstr "Appl. %r non trovata"
+
+#: contrib/admin/views/doc.py:172
+#, python-format
+msgid "Model %(name)r not found in app %(label)r"
+msgstr "Modello %(name)r non trovato nell'appl. %(label)r"
+
+#: contrib/admin/views/doc.py:184
+#, python-format
+msgid "the related `%(label)s.%(type)s` object"
+msgstr "l'oggetto `%(label)s.%(type)s` collegato"
+
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
+msgid "model:"
+msgstr "modello:"
+
+#: contrib/admin/views/doc.py:215
+#, python-format
+msgid "related `%(label)s.%(name)s` objects"
+msgstr "oggetti `%(label)s.%(name)s` collegati"
+
+#: contrib/admin/views/doc.py:220
+#, python-format
+msgid "all %s"
+msgstr "tutti %s"
+
+#: contrib/admin/views/doc.py:225
+#, python-format
+msgid "number of %s"
+msgstr "numero di %s"
+
+#: contrib/admin/views/doc.py:230
+#, python-format
+msgid "Fields on %s objects"
+msgstr "Campi sugli oggetti %s"
+
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
+msgid "Integer"
+msgstr "Intero"
+
+#: contrib/admin/views/doc.py:293
+msgid "Boolean (Either True or False)"
+msgstr "Booleano (True o False)"
+
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
+#, python-format
+msgid "String (up to %(max_length)s)"
+msgstr "Stringa (fino a %(max_length)s)"
+
+#: contrib/admin/views/doc.py:295
+msgid "Comma-separated integers"
+msgstr "Interi separati da virgola"
+
+#: contrib/admin/views/doc.py:296
+msgid "Date (without time)"
+msgstr "Data (senza ora)"
+
+#: contrib/admin/views/doc.py:297
+msgid "Date (with time)"
+msgstr "Data (con ora)"
+
+#: contrib/admin/views/doc.py:298
+msgid "Decimal number"
+msgstr "Numero decimale"
+
+#: contrib/admin/views/doc.py:299
+msgid "E-mail address"
+msgstr "Indirizzo e-mail"
+
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
+msgid "File path"
+msgstr "Percorso di file"
+
+#: contrib/admin/views/doc.py:302
+msgid "Floating point number"
+msgstr "Numero decimale"
+
+#: contrib/admin/views/doc.py:306 contrib/comments/models.py:85
+msgid "IP address"
+msgstr "indirizzo IP"
+
+#: contrib/admin/views/doc.py:308
+msgid "Boolean (Either True, False or None)"
+msgstr "Booleano (True, False o None)"
+
+#: contrib/admin/views/doc.py:309
+msgid "Relation to parent model"
+msgstr "Collegamento a modello padre"
+
+#: contrib/admin/views/doc.py:310
+msgid "Phone number"
+msgstr "Numero di telefono"
+
+#: contrib/admin/views/doc.py:315
+msgid "Text"
+msgstr "Testo"
+
+#: contrib/admin/views/doc.py:316
+msgid "Time"
+msgstr "Ora"
+
+#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
+msgid "URL"
+msgstr "URL"
+
+#: contrib/admin/views/doc.py:318
+msgid "U.S. state (two uppercase letters)"
+msgstr "Stato USA (due lettere maiuscole)"
+
+#: contrib/admin/views/doc.py:319
+msgid "XML text"
+msgstr "Testo XML"
+
+#: contrib/admin/views/doc.py:345
+#, python-format
+msgid "%s does not appear to be a urlpattern object"
+msgstr "%s non sembra essere un oggetto urlpattern"
+
+#: contrib/admin/views/auth.py:31
+msgid "Add user"
+msgstr "Aggiungi utente"
+
+#: contrib/admin/views/auth.py:58
+msgid "Password changed successfully."
+msgstr "La password è stata cambiata correttamente."
+
+#: contrib/admin/views/auth.py:65
+#, python-format
+msgid "Change password: %s"
+msgstr "Cambia la password: %s"
+
+#: contrib/admin/templatetags/admin_list.py:254
+msgid "All dates"
+msgstr "Tutte le date"
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Mostra tutto"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/change_form.html:10
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
msgid "Documentation"
msgstr "Documentazione"
-#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/change_form.html:10
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin/auth/user/change_password.html:15
#: contrib/admin/templates/admin/auth/user/change_password.html:46
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
msgid "Change password"
msgstr "Cambia la password"
-#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/change_form.html:10
#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/comments/templates/comments/form.html:6
msgid "Log out"
msgstr "Esci"
-#: contrib/admin/templates/admin/base_site.html:4
-msgid "Django site admin"
-msgstr "Amministrazione sito Django"
+#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/change_list.html:6
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/invalid_setup.html:4
+#: contrib/admin/templates/admin/base.html:30
+#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/logged_out.html:4
+#: contrib/admin/templates/registration/password_reset_done.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_done.html:4
+msgid "Home"
+msgstr "Pagina iniziale"
-#: contrib/admin/templates/admin/base_site.html:7
-msgid "Django administration"
-msgstr "Amministrazione Django"
+#: contrib/admin/templates/admin/delete_confirmation.html:9
+#: contrib/admin/templates/admin/submit_line.html:3
+msgid "Delete"
+msgstr "Cancella"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:14
+#, python-format
+msgid ""
+"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
+"related objects, but your account doesn't have permission to delete the "
+"following types of objects:"
+msgstr ""
+"La cancellazione di %(object_name)s '%(escaped_object)s' causerebbe la "
+"cancellazione di oggetti collegati, ma questo account non ha i permessi per "
+"cancellare gli oggetti dei seguenti tipi:"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:21
+#, python-format
+msgid ""
+"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
+"All of the following related items will be deleted:"
+msgstr ""
+"Sei sicuro di voler cancellare gli %(object_name)s \"%(escaped_object)s\"? "
+"Tutti i seguenti oggetti collegati saranno cancellati:"
+
+#: contrib/admin/templates/admin/delete_confirmation.html:26
+msgid "Yes, I'm sure"
+msgstr "Sì, sono sicuro"
+
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr "Pagina non trovata"
+
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr "Spiacenti, ma la pagina richiesta non è stata trovata."
#: contrib/admin/templates/admin/change_form.html:15
#: contrib/admin/templates/admin/index.html:28
@@ -399,48 +1275,31 @@ msgstr "Ordinamento"
msgid "Order:"
msgstr "Ordine:"
-#: contrib/admin/templates/admin/change_list.html:12
+#: contrib/admin/templates/admin/filter.html:2
#, python-format
-msgid "Add %(name)s"
-msgstr "Aggiungi %(name)s"
+msgid " By %(filter_title)s "
+msgstr " Per %(filter_title)s "
-#: contrib/admin/templates/admin/delete_confirmation.html:9
-#: contrib/admin/templates/admin/submit_line.html:3
-msgid "Delete"
-msgstr "Cancella"
+#: contrib/admin/templates/admin/submit_line.html:4
+msgid "Save as new"
+msgstr "Salva come nuovo"
-#: contrib/admin/templates/admin/delete_confirmation.html:14
-#, python-format
-msgid ""
-"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
-"related objects, but your account doesn't have permission to delete the "
-"following types of objects:"
-msgstr ""
-"La cancellazione di %(object_name)s '%(escaped_object)s' causerebbe la "
-"cancellazione di oggetti collegati, ma questo account non ha i permessi per "
-"cancellare gli oggetti dei seguenti tipi:"
+#: contrib/admin/templates/admin/submit_line.html:5
+msgid "Save and add another"
+msgstr "Salva e aggiungi un altro"
-#: contrib/admin/templates/admin/delete_confirmation.html:21
-#, python-format
-msgid ""
-"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
-"All of the following related items will be deleted:"
-msgstr ""
-"Sei sicuro di voler rimuovere %(object_name)s \"%(escaped_object)s\"? Tutti "
-"i seguenti oggetti collegati saranno cancellati:"
+#: contrib/admin/templates/admin/submit_line.html:6
+msgid "Save and continue editing"
+msgstr "Salva e continua le modifiche"
-#: contrib/admin/templates/admin/delete_confirmation.html:26
-msgid "Yes, I'm sure"
-msgstr "Sì, sono sicuro"
+#: contrib/admin/templates/admin/submit_line.html:7
+msgid "Save"
+msgstr "Salva"
-#: contrib/admin/templates/admin/filter.html:2
+#: contrib/admin/templates/admin/change_list.html:12
#, python-format
-msgid " By %(filter_title)s "
-msgstr " Per %(filter_title)s "
-
-#: contrib/admin/templates/admin/filters.html:4
-msgid "Filter"
-msgstr "Filtro"
+msgid "Add %(name)s"
+msgstr "Aggiungi %(name)s"
#: contrib/admin/templates/admin/index.html:17
#, python-format
@@ -472,35 +1331,17 @@ msgstr "Azioni Proprie"
msgid "None available"
msgstr "Nessuno disponibile"
-#: contrib/admin/templates/admin/invalid_setup.html:8
-msgid ""
-"Something's wrong with your database installation. Make sure the appropriate "
-"database tables have been created, and make sure the database is readable by "
-"the appropriate user."
-msgstr ""
-"Ci sono problemi nell'installazione del database. Assicurarsi che le tabelle "
-"appropriate del database siano state create, e che il database sia leggibile "
-"dall'utente appropriato."
-
-#: contrib/admin/templates/admin/login.html:17
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
-msgid "Username:"
-msgstr "Nome utente:"
-
-#: contrib/admin/templates/admin/login.html:20
-#: contrib/comments/templates/comments/form.html:8
-msgid "Password:"
-msgstr "Password:"
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr "Amministrazione sito Django"
-#: contrib/admin/templates/admin/login.html:25
-#: contrib/admin/views/decorators.py:24
-msgid "Log in"
-msgstr "Accedi"
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr "Amministrazione Django"
#: contrib/admin/templates/admin/object_history.html:18
msgid "Date/time"
-msgstr "Data/orario"
+msgstr "Data/ora"
#: contrib/admin/templates/admin/object_history.html:19
msgid "User"
@@ -522,9 +1363,35 @@ msgstr ""
"Questo oggetto non ha cambiamenti registrati. Probabilmente non è stato "
"creato con questo sito di amministrazione."
-#: contrib/admin/templates/admin/pagination.html:10
-msgid "Show all"
-msgstr "Mostra tutto"
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "Errore del server"
+
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr "Errore del server (500)"
+
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr "Errore del server <em>(500)</em>"
+
+#: contrib/admin/templates/admin/500.html:10
+msgid ""
+"There's been an error. It's been reported to the site administrators via e-"
+"mail and should be fixed shortly. Thanks for your patience."
+msgstr ""
+"Si è verificato un errore. È stato riportato agli amministratori del sito "
+"via e-mail e verrà corretto a breve. Grazie per la tua pazienza."
+
+#: contrib/admin/templates/admin/invalid_setup.html:8
+msgid ""
+"Something's wrong with your database installation. Make sure the appropriate "
+"database tables have been created, and make sure the database is readable by "
+"the appropriate user."
+msgstr ""
+"Ci sono problemi nell'installazione del database. Assicurarsi che le tabelle "
+"appropriate del database siano state create, e che il database sia leggibile "
+"dall'utente appropriato."
#: contrib/admin/templates/admin/search_form.html:8
msgid "Go"
@@ -542,21 +1409,24 @@ msgstr[1] "%(counter)s risultati"
msgid "%(full_result_count)s total"
msgstr "%(full_result_count)s totali"
-#: contrib/admin/templates/admin/submit_line.html:4
-msgid "Save as new"
-msgstr "Salva come nuovo"
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filtro"
-#: contrib/admin/templates/admin/submit_line.html:5
-msgid "Save and add another"
-msgstr "Salva e aggiungi un altro"
+#: contrib/admin/templates/admin/login.html:17
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+msgid "Username:"
+msgstr "Nome utente:"
-#: contrib/admin/templates/admin/submit_line.html:6
-msgid "Save and continue editing"
-msgstr "Salva e continua le modifiche"
+#: contrib/admin/templates/admin/login.html:20
+#: contrib/comments/templates/comments/form.html:8
+msgid "Password:"
+msgstr "Password:"
-#: contrib/admin/templates/admin/submit_line.html:7
-msgid "Save"
-msgstr "Salva"
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr "Benvenuto,"
#: contrib/admin/templates/admin/auth/user/add_form.html:6
msgid ""
@@ -614,7 +1484,7 @@ msgstr ""
"barra \n"
"dei bookmark, o cliccare il link con il tasto destro e aggiungerlo ai "
"bookmark.\n"
-"Sarà quindi possibile selezionare un bookmarklet in qualsiasi pagina del "
+"Sarà quindi possibile scegliere un bookmarklet in qualsiasi pagina del "
"sito.\n"
"Si noti che alcuni di questi bookmarklet richiedono l'accesso al sito "
"tramite un\n"
@@ -664,73 +1534,44 @@ msgid "As above, but opens the admin page in a new window."
msgstr ""
"Come sopra, ma apre la pagina di amministrazione in una nuova finestra."
-#: contrib/admin/templates/registration/logged_out.html:8
-msgid "Thanks for spending some quality time with the Web site today."
-msgstr "Grazie per aver speso il tuo tempo prezioso su questo sito oggi."
-
-#: contrib/admin/templates/registration/logged_out.html:10
-msgid "Log in again"
-msgstr "Accedi di nuovo"
-
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_form.html:6
-#: contrib/admin/templates/registration/password_change_form.html:10
-msgid "Password change"
-msgstr "Cambio password"
-
-#: contrib/admin/templates/registration/password_change_done.html:6
-#: contrib/admin/templates/registration/password_change_done.html:10
-msgid "Password change successful"
-msgstr "Cambio di password avvenuto correttamente"
-
-#: contrib/admin/templates/registration/password_change_done.html:12
-msgid "Your password was changed."
-msgstr "La password è stata cambiata."
-
-#: contrib/admin/templates/registration/password_change_form.html:12
-msgid ""
-"Please enter your old password, for security's sake, and then enter your new "
-"password twice so we can verify you typed it in correctly."
-msgstr ""
-"Inserire l'attuale password, per ragioni di sicurezza, e poi la nuova "
-"password due volte, per verificare di averla scritta correttamente."
-
-#: contrib/admin/templates/registration/password_change_form.html:17
-msgid "Old password:"
-msgstr "Password attuale:"
+#: contrib/admin/templates/widget/date_time.html:3
+msgid "Date:"
+msgstr "Data:"
-#: contrib/admin/templates/registration/password_change_form.html:19
-msgid "New password:"
-msgstr "Nuova password:"
+#: contrib/admin/templates/widget/date_time.html:4
+msgid "Time:"
+msgstr "Ora:"
-#: contrib/admin/templates/registration/password_change_form.html:21
-msgid "Confirm password:"
-msgstr "Confermare la password:"
+#: contrib/admin/templates/widget/file.html:2
+msgid "Currently:"
+msgstr "Attualmente:"
-#: contrib/admin/templates/registration/password_change_form.html:23
-msgid "Change my password"
-msgstr "Modifica la mia password"
+#: contrib/admin/templates/widget/file.html:3
+msgid "Change:"
+msgstr "Modifica:"
-#: contrib/admin/templates/registration/password_reset_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/password_reset_form.html:6
#: contrib/admin/templates/registration/password_reset_form.html:10
+#: contrib/admin/templates/registration/password_reset_done.html:4
msgid "Password reset"
msgstr "Reimposta la password"
-#: contrib/admin/templates/registration/password_reset_done.html:6
-#: contrib/admin/templates/registration/password_reset_done.html:10
-msgid "Password reset successful"
-msgstr "Password reimpostata correttamente"
-
-#: contrib/admin/templates/registration/password_reset_done.html:12
+#: contrib/admin/templates/registration/password_reset_form.html:12
msgid ""
-"We've e-mailed a new password to the e-mail address you submitted. You "
-"should be receiving it shortly."
+"Forgotten your password? Enter your e-mail address below, and we'll reset "
+"your password and e-mail the new one to you."
msgstr ""
-"La nuova password è stata inviata all'indirizzo e-mail inserito. Arriverà a "
-"breve."
+"Dimenticata la password? Inserire il proprio indirizzo e-mail qui sotto: la "
+"password sarà reimpostata, e la nuova ti verrà inviata per e-mail."
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "E-mail address:"
+msgstr "Indirizzo e-mail:"
+
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "Reset my password"
+msgstr "Reimposta la mia password"
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
@@ -764,511 +1605,238 @@ msgstr "Grazie per aver usato il nostro sito!"
msgid "The %(site_name)s team"
msgstr "Il team di %(site_name)s"
-#: contrib/admin/templates/registration/password_reset_form.html:12
-msgid ""
-"Forgotten your password? Enter your e-mail address below, and we'll reset "
-"your password and e-mail the new one to you."
-msgstr ""
-"Dimenticata la password? Inserire il proprio indirizzo e-mail qui sotto: la "
-"password sarà reimpostata, e la nuova ti verrà inviata per e-mail."
-
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "E-mail address:"
-msgstr "Indirizzo e-mail:"
-
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "Reset my password"
-msgstr "Reimposta la mia password"
-
-#: contrib/admin/templates/widget/date_time.html:3
-msgid "Date:"
-msgstr "Data:"
-
-#: contrib/admin/templates/widget/date_time.html:4
-msgid "Time:"
-msgstr "Orario:"
-
-#: contrib/admin/templates/widget/file.html:2
-msgid "Currently:"
-msgstr "Attualmente:"
-
-#: contrib/admin/templates/widget/file.html:3
-msgid "Change:"
-msgstr "Modifica:"
-
-#: contrib/admin/templatetags/admin_list.py:247
-msgid "All dates"
-msgstr "Tutte le date"
-
-#: contrib/admin/views/auth.py:19 contrib/admin/views/main.py:257
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully."
-msgstr "%(name)s \"%(obj)s\" è stato aggiunto correttamente."
-
-#: contrib/admin/views/auth.py:24 contrib/admin/views/main.py:261
-#: contrib/admin/views/main.py:347
-msgid "You may edit it again below."
-msgstr "È possibile modificarlo nuovamente qui sotto."
-
-#: contrib/admin/views/auth.py:30
-msgid "Add user"
-msgstr "Aggiungi utente"
+#: contrib/admin/templates/registration/logged_out.html:8
+msgid "Thanks for spending some quality time with the Web site today."
+msgstr "Grazie per aver speso il tuo tempo prezioso su questo sito oggi."
-#: contrib/admin/views/auth.py:57
-msgid "Password changed successfully."
-msgstr "La password è stata cambiata correttamente."
+#: contrib/admin/templates/registration/logged_out.html:10
+msgid "Log in again"
+msgstr "Accedi di nuovo"
-#: contrib/admin/views/auth.py:64
-#, python-format
-msgid "Change password: %s"
-msgstr "Cambia la password: %s"
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr "Password reimpostata correttamente"
-#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
+#: contrib/admin/templates/registration/password_reset_done.html:12
msgid ""
-"Please enter a correct username and password. Note that both fields are case-"
-"sensitive."
+"We've e-mailed a new password to the e-mail address you submitted. You "
+"should be receiving it shortly."
msgstr ""
-"Inserire nome utente e password corretti. Entrambi i campi sono case "
-"sensitive."
+"La nuova password è stata inviata all'indirizzo e-mail inserito. Arriverà a "
+"breve."
-#: contrib/admin/views/decorators.py:62
-msgid ""
-"Please log in again, because your session has expired. Don't worry: Your "
-"submission has been saved."
-msgstr ""
-"La sessione è scaduta: occorre accedere nuovamente. I dati inseriti sono "
-"stati comunquesalvati."
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+#: contrib/admin/templates/registration/password_change_done.html:4
+msgid "Password change"
+msgstr "Cambio password"
-#: contrib/admin/views/decorators.py:69
+#: contrib/admin/templates/registration/password_change_form.html:12
msgid ""
-"Looks like your browser isn't configured to accept cookies. Please enable "
-"cookies, reload this page, and try again."
-msgstr ""
-"Il browser non sembra configurato per accettare i cookie. Una volta "
-"abilitati, ricaricare la pagina e riprovare."
-
-#: contrib/admin/views/decorators.py:83
-msgid "Usernames cannot contain the '@' character."
-msgstr "I nomi utente non possono contenere il carattere '@'."
-
-#: contrib/admin/views/decorators.py:85
-#, python-format
-msgid "Your e-mail address is not your username. Try '%s' instead."
+"Please enter your old password, for security's sake, and then enter your new "
+"password twice so we can verify you typed it in correctly."
msgstr ""
-"Il nome utente non è costituito dall'indirizzo e-mail. Provare con '%s'."
-
-#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
-msgid "tag:"
-msgstr "tag:"
-
-#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
-msgid "filter:"
-msgstr "filtro:"
-
-#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
-msgid "view:"
-msgstr "view:"
-
-#: contrib/admin/views/doc.py:164
-#, python-format
-msgid "App %r not found"
-msgstr "Appl. %r non trovata"
-
-#: contrib/admin/views/doc.py:171
-#, fuzzy, python-format
-msgid "Model %(name)r not found in app %(label)r"
-msgstr "Modello %r non trovato nell'appl. %r"
-
-#: contrib/admin/views/doc.py:183
-#, fuzzy, python-format
-msgid "the related `%(label)s.%(type)s` object"
-msgstr "l'oggetto `%s.%s` collegato"
-
-#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
-#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
-msgid "model:"
-msgstr "modello:"
-
-#: contrib/admin/views/doc.py:214
-#, fuzzy, python-format
-msgid "related `%(label)s.%(name)s` objects"
-msgstr "oggetti `%s.%s` collegati"
-
-#: contrib/admin/views/doc.py:219
-#, python-format
-msgid "all %s"
-msgstr "tutti %s"
-
-#: contrib/admin/views/doc.py:224
-#, python-format
-msgid "number of %s"
-msgstr "numero di %s"
-
-#: contrib/admin/views/doc.py:229
-#, python-format
-msgid "Fields on %s objects"
-msgstr "Campi sugli oggetti %s"
-
-#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301
-#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309
-#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312
-msgid "Integer"
-msgstr "Intero"
-
-#: contrib/admin/views/doc.py:292
-msgid "Boolean (Either True or False)"
-msgstr "Booleano (True o False)"
-
-#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311
-#, python-format
-msgid "String (up to %(maxlength)s)"
-msgstr "Stringa (fino a %(maxlength)s caratteri)"
-
-#: contrib/admin/views/doc.py:294
-msgid "Comma-separated integers"
-msgstr "Interi separati da virgola"
-
-#: contrib/admin/views/doc.py:295
-msgid "Date (without time)"
-msgstr "Data (senza orario)"
-
-#: contrib/admin/views/doc.py:296
-msgid "Date (with time)"
-msgstr "Data (con orario)"
-
-#: contrib/admin/views/doc.py:297
-msgid "E-mail address"
-msgstr "Indirizzo e-mail"
-
-#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299
-#: contrib/admin/views/doc.py:302
-msgid "File path"
-msgstr "Percorso di file"
-
-#: contrib/admin/views/doc.py:300
-msgid "Decimal number"
-msgstr "Numero decimale"
-
-#: contrib/admin/views/doc.py:304 contrib/comments/models.py:85
-msgid "IP address"
-msgstr "indirizzo IP"
-
-#: contrib/admin/views/doc.py:306
-msgid "Boolean (Either True, False or None)"
-msgstr "Booleano (True, False o None)"
-
-#: contrib/admin/views/doc.py:307
-msgid "Relation to parent model"
-msgstr "Collegamento a modello padre"
-
-#: contrib/admin/views/doc.py:308
-msgid "Phone number"
-msgstr "Numero di telefono"
-
-#: contrib/admin/views/doc.py:313
-msgid "Text"
-msgstr "Testo"
-
-#: contrib/admin/views/doc.py:314
-msgid "Time"
-msgstr "Orario"
-
-#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7
-msgid "URL"
-msgstr "URL"
+"Inserire l'attuale password, per ragioni di sicurezza, e poi la nuova "
+"password due volte, per verificare di averla scritta correttamente."
-#: contrib/admin/views/doc.py:316
-msgid "U.S. state (two uppercase letters)"
-msgstr "Stato USA (due lettere maiuscole)"
+#: contrib/admin/templates/registration/password_change_form.html:17
+msgid "Old password:"
+msgstr "Password attuale:"
-#: contrib/admin/views/doc.py:317
-msgid "XML text"
-msgstr "Testo XML"
+#: contrib/admin/templates/registration/password_change_form.html:19
+msgid "New password:"
+msgstr "Nuova password:"
-#: contrib/admin/views/doc.py:343
-#, python-format
-msgid "%s does not appear to be a urlpattern object"
-msgstr "%s non sembra essere un oggetto urlpattern"
+#: contrib/admin/templates/registration/password_change_form.html:21
+msgid "Confirm password:"
+msgstr "Confermare la password:"
-#: contrib/admin/views/main.py:223
-msgid "Site administration"
-msgstr "Amministrazione sito"
+#: contrib/admin/templates/registration/password_change_form.html:23
+msgid "Change my password"
+msgstr "Modifica la mia password"
-#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
-#, python-format
-msgid "You may add another %s below."
-msgstr "È possibile aggiungere un altro %s qui sotto."
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr "Cambio di password avvenuto correttamente"
-#: contrib/admin/views/main.py:289
-#, python-format
-msgid "Add %s"
-msgstr "Aggiungere %s"
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr "La password è stata cambiata."
-#: contrib/admin/views/main.py:335
-#, python-format
-msgid "Added %s."
-msgstr "Aggiunto %s"
+#: contrib/sites/models.py:15
+msgid "domain name"
+msgstr "nome di dominio"
-#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337
-#: contrib/admin/views/main.py:339 db/models/manipulators.py:308
-msgid "and"
-msgstr "e"
+#: contrib/sites/models.py:16
+msgid "display name"
+msgstr "nome visualizzato"
-#: contrib/admin/views/main.py:337
-#, python-format
-msgid "Changed %s."
-msgstr "Modificato %s."
+#: contrib/sites/models.py:20
+msgid "site"
+msgstr "sito"
-#: contrib/admin/views/main.py:339
-#, python-format
-msgid "Deleted %s."
-msgstr "Cancellato %s"
+#: contrib/sites/models.py:21
+msgid "sites"
+msgstr "siti"
-#: contrib/admin/views/main.py:342
-msgid "No fields changed."
-msgstr "Nessun campo modificato."
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "th"
+msgstr "º"
-#: contrib/admin/views/main.py:345
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was changed successfully."
-msgstr "%(name)s \"%(obj)s\" è stato modificato correttamente."
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "st"
+msgstr "º"
-#: contrib/admin/views/main.py:353
-#, python-format
-msgid ""
-"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
-msgstr ""
-"%(name)s \"%(obj)s\" è stato aggiunto correttamente. È possibile modificarlo "
-"nuovamente qui sotto."
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "nd"
+msgstr "º"
-#: contrib/admin/views/main.py:391
-#, python-format
-msgid "Change %s"
-msgstr "Modificare %s"
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "rd"
+msgstr "º"
-#: contrib/admin/views/main.py:476
+#: contrib/humanize/templatetags/humanize.py:47
#, python-format
-msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
-msgstr "Uno o più %(fieldname)s in %(name)s: %(obj)s"
+msgid "%(value).1f million"
+msgid_plural "%(value).1f million"
+msgstr[0] "%(value).1f milione"
+msgstr[1] "%(value).1f milioni"
-#: contrib/admin/views/main.py:481
+#: contrib/humanize/templatetags/humanize.py:50
#, python-format
-msgid "One or more %(fieldname)s in %(name)s:"
-msgstr "Uno o più %(fieldname)s in %(name)s:"
+msgid "%(value).1f billion"
+msgid_plural "%(value).1f billion"
+msgstr[0] "%(value).1f miliardo"
+msgstr[1] "%(value).1f miliardi"
-#: contrib/admin/views/main.py:514
+#: contrib/humanize/templatetags/humanize.py:53
#, python-format
-msgid "The %(name)s \"%(obj)s\" was deleted successfully."
-msgstr "%(name)s \"%(obj)s\" è stato cancellato correttamente."
+msgid "%(value).1f trillion"
+msgid_plural "%(value).1f trillion"
+msgstr[0] "%(value).1f migliaio di miliardi"
+msgstr[1] "%(value).1f migliaia di miliardi"
-#: contrib/admin/views/main.py:517
-msgid "Are you sure?"
-msgstr "Sei sicuro?"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "one"
+msgstr "uno"
-#: contrib/admin/views/main.py:539
-#, python-format
-msgid "Change history: %s"
-msgstr "Tracciato delle modifiche: %s"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "two"
+msgstr "due"
-#: contrib/admin/views/main.py:573
-#, python-format
-msgid "Select %s"
-msgstr "Seleziona %s"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "three"
+msgstr "tre"
-#: contrib/admin/views/main.py:573
-#, python-format
-msgid "Select %s to change"
-msgstr "Seleziona %s per modificare"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "four"
+msgstr "quattro"
-#: contrib/admin/views/main.py:768
-msgid "Database error"
-msgstr "Errore nel database"
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "five"
+msgstr "cinque"
-#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
-msgid "The two password fields didn't match."
-msgstr "I due campi password non corrispondono."
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "six"
+msgstr "sei"
-#: contrib/auth/forms.py:25
-msgid "A user with that username already exists."
-msgstr "Un utente con questo nome·è già presente."
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "seven"
+msgstr "sette"
-#: contrib/auth/forms.py:53
-msgid ""
-"Your Web browser doesn't appear to have cookies enabled. Cookies are "
-"required for logging in."
-msgstr ""
-"Il browser web sembra non avere i cookie abilitati. I cookie sono necessari "
-"per poter accedere."
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "eight"
+msgstr "otto"
-#: contrib/auth/forms.py:62
-msgid "This account is inactive."
-msgstr "Questo account non è attivo."
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "nine"
+msgstr "nove"
-#: contrib/auth/forms.py:85
+#: contrib/flatpages/models.py:8
msgid ""
-"That e-mail address doesn't have an associated user account. Are you sure "
-"you've registered?"
-msgstr ""
-"Questo indirizzo email non è associato ad alcun account utente. Sei sicuro "
-"di esserti registrato?"
-
-#: contrib/auth/forms.py:117
-msgid "The two 'new password' fields didn't match."
-msgstr "I due campi 'nuova password' non corrispondono."
-
-#: contrib/auth/forms.py:124
-msgid "Your old password was entered incorrectly. Please enter it again."
+"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr ""
-"La vecchia password non è stata inserita correttamente: va inserita di nuovo."
-
-#: contrib/auth/models.py:38 contrib/auth/models.py:58
-msgid "name"
-msgstr "nome"
-
-#: contrib/auth/models.py:40
-msgid "codename"
-msgstr "nome in codice"
-
-#: contrib/auth/models.py:43
-msgid "permission"
-msgstr "permesso"
+"Esempio: '/about/contact/'. Assicurarsi di inserire le barre diagonali "
+"iniziali e finali."
-#: contrib/auth/models.py:44 contrib/auth/models.py:59
-msgid "permissions"
-msgstr "permessi"
+#: contrib/flatpages/models.py:9
+msgid "title"
+msgstr "titolo"
-#: contrib/auth/models.py:62
-msgid "group"
-msgstr "gruppo"
+#: contrib/flatpages/models.py:10
+msgid "content"
+msgstr "contenuto"
-#: contrib/auth/models.py:63 contrib/auth/models.py:103
-msgid "groups"
-msgstr "gruppi"
+#: contrib/flatpages/models.py:11
+msgid "enable comments"
+msgstr "abilita commenti"
-#: contrib/auth/models.py:93
-msgid "username"
-msgstr "nome utente"
+#: contrib/flatpages/models.py:12
+msgid "template name"
+msgstr "nome modello"
-#: contrib/auth/models.py:93
+#: contrib/flatpages/models.py:13
msgid ""
-"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
-"digits and underscores)."
+"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
+"will use 'flatpages/default.html'."
msgstr ""
-"Obbligatorio. 30 caratteri o meno. Solo caratteri alfanumerici (lettere, "
-"cifre e sottolineature)."
-
-#: contrib/auth/models.py:94
-msgid "first name"
-msgstr "nome"
-
-#: contrib/auth/models.py:95
-msgid "last name"
-msgstr "cognome"
-
-#: contrib/auth/models.py:96
-msgid "e-mail address"
-msgstr "indirizzo e-mail"
+"Esempio: 'flatpages/contact_page.html'. Se non specificato, il sistema userà "
+"'flatpages/default.html'."
-#: contrib/auth/models.py:97
-msgid "password"
-msgstr "password"
+#: contrib/flatpages/models.py:14
+msgid "registration required"
+msgstr "registrazione obbligatoria"
-#: contrib/auth/models.py:97
-msgid ""
-"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
-"password form</a>."
+#: contrib/flatpages/models.py:14
+msgid "If this is checked, only logged-in users will be able to view the page."
msgstr ""
-"Usare '[algo]$[salt]$[hexdigest]' oppure la maschera di <a href=\"password/"
-"\">cambio password</a>."
-
-#: contrib/auth/models.py:98
-msgid "staff status"
-msgstr "privilegi di staff"
-
-#: contrib/auth/models.py:98
-msgid "Designates whether the user can log into this admin site."
-msgstr "Indica se l'utente può accedere a questo sito di amministrazione."
+"Se selezionato, solo gli utenti che hanno effettuato l'accesso potranno "
+"vedere la pagina."
-#: contrib/auth/models.py:99
-msgid "active"
-msgstr "attivo"
+#: contrib/flatpages/models.py:18
+msgid "flat page"
+msgstr "pagina statica"
-#: contrib/auth/models.py:99
-msgid ""
-"Designates whether this user can log into the Django admin. Unselect this "
-"instead of deleting accounts."
-msgstr ""
-"Indica se l'utente può accedere all'amministrazione di Django. Deselezionare "
-"qui, piuttosto che cancellare gli account."
+#: contrib/flatpages/models.py:19
+msgid "flat pages"
+msgstr "pagine statiche"
-#: contrib/auth/models.py:100
-msgid "superuser status"
-msgstr "privilegi di superutente"
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr "redirezione da"
-#: contrib/auth/models.py:100
+#: contrib/redirects/models.py:8
msgid ""
-"Designates that this user has all permissions without explicitly assigning "
-"them."
+"This should be an absolute path, excluding the domain name. Example: '/"
+"events/search/'."
msgstr ""
-"Indica che l'utente ha tutti i privilegi, senza che siano stati assegnati "
-"esplicitamente."
-
-#: contrib/auth/models.py:101
-msgid "last login"
-msgstr "ultimo accesso"
+"Deve essere un percorso assoluto, senza nome di dominio. Esempio: '/events/"
+"search/'."
-#: contrib/auth/models.py:102
-msgid "date joined"
-msgstr "iscritto in data"
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr "redirezione verso"
-#: contrib/auth/models.py:104
+#: contrib/redirects/models.py:10
msgid ""
-"In addition to the permissions manually assigned, this user will also get "
-"all permissions granted to each group he/she is in."
+"This can be either an absolute path (as above) or a full URL starting with "
+"'http://'."
msgstr ""
-"In aggiunta ai privilegi assegnati manualmente, l'utente riceverà anche "
-"tutti i privilegi assegnati ad ogni gruppo cui appartiene."
-
-#: contrib/auth/models.py:105
-msgid "user permissions"
-msgstr "privilegi utente"
-
-#: contrib/auth/models.py:109
-msgid "user"
-msgstr "utente"
-
-#: contrib/auth/models.py:110
-msgid "users"
-msgstr "utenti"
-
-#: contrib/auth/models.py:116
-msgid "Personal info"
-msgstr "Informazioni personali"
-
-#: contrib/auth/models.py:117
-msgid "Permissions"
-msgstr "Privilegi"
-
-#: contrib/auth/models.py:118
-msgid "Important dates"
-msgstr "Date importanti"
-
-#: contrib/auth/models.py:119
-msgid "Groups"
-msgstr "Gruppi"
+"Può essere un percorso assoluto (come sopra) o una URL completa che inizia "
+"con 'http://'."
-#: contrib/auth/models.py:263
-msgid "message"
-msgstr "messaggio"
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr "redirezione"
-#: contrib/auth/views.py:39
-msgid "Logged out"
-msgstr "Accesso annullato"
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr "redirezioni"
-#: contrib/comments/models.py:67 contrib/comments/models.py:166
+#: contrib/comments/models.py:67 contrib/comments/models.py:169
msgid "object ID"
msgstr "ID dell'oggetto"
@@ -1277,7 +1845,7 @@ msgid "headline"
msgstr "intestazione"
#: contrib/comments/models.py:69 contrib/comments/models.py:90
-#: contrib/comments/models.py:167
+#: contrib/comments/models.py:170
msgid "comment"
msgstr "commento"
@@ -1317,11 +1885,11 @@ msgstr "valutazione #8"
msgid "is valid rating"
msgstr "è una valutazione valida"
-#: contrib/comments/models.py:83 contrib/comments/models.py:169
+#: contrib/comments/models.py:83 contrib/comments/models.py:172
msgid "date/time submitted"
-msgstr "data/orario di inserimento"
+msgstr "data/ora di inserimento"
-#: contrib/comments/models.py:84 contrib/comments/models.py:170
+#: contrib/comments/models.py:84 contrib/comments/models.py:173
msgid "is public"
msgstr "è pubblico"
@@ -1341,11 +1909,11 @@ msgstr ""
msgid "comments"
msgstr "commenti"
-#: contrib/comments/models.py:131 contrib/comments/models.py:207
+#: contrib/comments/models.py:134 contrib/comments/models.py:213
msgid "Content object"
msgstr "Oggetto con contenuto"
-#: contrib/comments/models.py:159
+#: contrib/comments/models.py:162
#, python-format
msgid ""
"Posted by %(user)s at %(date)s\n"
@@ -1360,48 +1928,48 @@ msgstr ""
"\n"
"http://%(domain)s%(url)s"
-#: contrib/comments/models.py:168
+#: contrib/comments/models.py:171
msgid "person's name"
msgstr "nome della persona"
-#: contrib/comments/models.py:171
+#: contrib/comments/models.py:174
msgid "ip address"
msgstr "indirizzo IP"
-#: contrib/comments/models.py:173
+#: contrib/comments/models.py:176
msgid "approved by staff"
msgstr "approvato dallo staff"
-#: contrib/comments/models.py:176
+#: contrib/comments/models.py:179
msgid "free comment"
msgstr "commento libero"
-#: contrib/comments/models.py:177
+#: contrib/comments/models.py:180
msgid "free comments"
msgstr "commenti liberi"
-#: contrib/comments/models.py:233
+#: contrib/comments/models.py:239
msgid "score"
msgstr "punteggio"
-#: contrib/comments/models.py:234
+#: contrib/comments/models.py:240
msgid "score date"
msgstr "data punteggio"
-#: contrib/comments/models.py:237
+#: contrib/comments/models.py:243
msgid "karma score"
msgstr "livello karma"
-#: contrib/comments/models.py:238
+#: contrib/comments/models.py:244
msgid "karma scores"
msgstr "livelli karma"
-#: contrib/comments/models.py:242
+#: contrib/comments/models.py:248
#, python-format
msgid "%(score)d rating by %(user)s"
msgstr "valutazione: %(score)d da %(user)s"
-#: contrib/comments/models.py:258
+#: contrib/comments/models.py:264
#, python-format
msgid ""
"This comment was flagged by %(user)s:\n"
@@ -1412,84 +1980,60 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/models.py:265
+#: contrib/comments/models.py:271
msgid "flag date"
msgstr "data flag"
-#: contrib/comments/models.py:268
+#: contrib/comments/models.py:274
msgid "user flag"
msgstr "flag utente"
-#: contrib/comments/models.py:269
+#: contrib/comments/models.py:275
msgid "user flags"
msgstr "flag utente"
-#: contrib/comments/models.py:273
+#: contrib/comments/models.py:279
#, python-format
msgid "Flag by %r"
msgstr "Flag da %r"
-#: contrib/comments/models.py:278
+#: contrib/comments/models.py:284
msgid "deletion date"
msgstr "data cancellazione"
-#: contrib/comments/models.py:280
+#: contrib/comments/models.py:286
msgid "moderator deletion"
msgstr "cancellazione da moderatore"
-#: contrib/comments/models.py:281
+#: contrib/comments/models.py:287
msgid "moderator deletions"
msgstr "cancellazioni da moderatore"
-#: contrib/comments/models.py:285
+#: contrib/comments/models.py:291
#, python-format
msgid "Moderator deletion by %r"
msgstr "Cancellazione da moderatore %r"
-#: contrib/comments/templates/comments/form.html:8
-msgid "Forgotten your password?"
-msgstr "Hai dimenticato la password?"
-
-#: contrib/comments/templates/comments/form.html:12
-msgid "Ratings"
-msgstr "Valutazioni"
-
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Required"
-msgstr "Obbligatorio"
-
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Optional"
-msgstr "Facoltativo"
-
-#: contrib/comments/templates/comments/form.html:23
-msgid "Post a photo"
-msgstr "Invia una foto"
-
-#: contrib/comments/templates/comments/form.html:28
-#: contrib/comments/templates/comments/freeform.html:5
-msgid "Comment:"
-msgstr "Commento:"
+#: contrib/comments/views/karma.py:20
+msgid "Anonymous users cannot vote"
+msgstr "Gli utenti anonimi non possono votare"
-#: contrib/comments/templates/comments/form.html:35
-#: contrib/comments/templates/comments/freeform.html:10
-msgid "Preview comment"
-msgstr "Anteprima commento"
+#: contrib/comments/views/karma.py:24
+msgid "Invalid comment ID"
+msgstr "ID commento non valido"
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "Il suo nome:"
+#: contrib/comments/views/karma.py:26
+msgid "No voting for yourself"
+msgstr "Impossibile votare per se stessi"
-#: contrib/comments/views/comments.py:27
+#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr ""
"Questa valutazione è obbligatoria perché hai inserito almeno un'altra "
"valutazione."
-#: contrib/comments/views/comments.py:111
+#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
@@ -1512,7 +2056,7 @@ msgstr[1] ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:116
+#: contrib/comments/views/comments.py:117
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
@@ -1523,23 +2067,23 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
msgid "Only POSTs are allowed"
msgstr "Sono ammessi solo POST"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
msgid "One or more of the required fields wasn't submitted"
msgstr "Uno o più campi richiesti non sono stati inseriti"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
msgid "Somebody tampered with the comment form (security violation)"
msgstr "Qualcuno ha alterato il modulo di commento (violazione di sicurezza)"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
@@ -1547,176 +2091,215 @@ msgstr ""
"Il modulo di commento ha un parametro 'target' non valido -- l'ID "
"dell'oggetto non è valido"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr "Il modulo di commento non fornisce né 'anteprima' né 'invia'"
-#: contrib/comments/views/karma.py:19
-msgid "Anonymous users cannot vote"
-msgstr "Gli utenti anonimi non possono votare"
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr "Hai dimenticato la password?"
-#: contrib/comments/views/karma.py:23
-msgid "Invalid comment ID"
-msgstr "ID commento non valido"
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr "Valutazioni"
-#: contrib/comments/views/karma.py:25
-msgid "No voting for yourself"
-msgstr "Impossibile votare per se stessi"
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr "Obbligatorio"
-#: contrib/contenttypes/models.py:36
-msgid "python model class name"
-msgstr "nome della classe modello in Python"
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr "Facoltativo"
-#: contrib/contenttypes/models.py:39
-msgid "content type"
-msgstr "content type"
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr "Inserisci una foto"
-#: contrib/contenttypes/models.py:40
-msgid "content types"
-msgstr "content type"
+#: contrib/comments/templates/comments/form.html:28
+#: contrib/comments/templates/comments/freeform.html:5
+msgid "Comment:"
+msgstr "Commento:"
-#: contrib/flatpages/models.py:8
-msgid ""
-"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
-msgstr ""
-"Esempio: '/about/contact/'. Assicurarsi di inserire le barre diagonali "
-"iniziali e finali."
+#: contrib/comments/templates/comments/form.html:35
+#: contrib/comments/templates/comments/freeform.html:10
+msgid "Preview comment"
+msgstr "Anteprima commento"
-#: contrib/flatpages/models.py:9
-msgid "title"
-msgstr "titolo"
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "Il tuo nome:"
-#: contrib/flatpages/models.py:10
-msgid "content"
-msgstr "contenuto"
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr "Inserire un codice postale di 4 cifre."
-#: contrib/flatpages/models.py:11
-msgid "enable comments"
-msgstr "abilita commenti"
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr "Inserire un codice postale nel formato XXXXX-XXX ."
-#: contrib/flatpages/models.py:12
-msgid "template name"
-msgstr "nome modello"
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr "I numeri di telefono devono essere in formato XX-XXXX-XXXX ."
-#: contrib/flatpages/models.py:13
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr "In questo campo possono essere solo presenti numeri."
+
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr "Questo campo richiede non più di 11 cifre, o 14 caratteri."
+
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr "Numero CPF non valido."
+
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr "Questo campo richiede almeno 14 cifre."
+
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr "Numero CNPJ non valido."
+
+#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:14
+msgid "Enter a zip code in the format XXXX."
+msgstr "Inserire un codice postale nel formato XXXXX ."
+
+#: contrib/localflavor/ch/forms.py:90
msgid ""
-"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
-"will use 'flatpages/default.html'."
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
msgstr ""
-"Esempio: 'flatpages/contact_page.html'. Se non specificato, il sistema userà "
-"'flatpages/default.html'."
+"Inserire un numero di carta d'identità o passaporto svizzeri validi, in "
+"formato X1234567<0 o 1234567890 ."
-#: contrib/flatpages/models.py:14
-msgid "registration required"
-msgstr "registrazione obbligatoria"
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr ""
-#: contrib/flatpages/models.py:14
-msgid "If this is checked, only logged-in users will be able to view the page."
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
msgstr ""
-"Se selezionato, solo gli utenti che hanno effettuato l'accesso potranno "
-"vedere la pagina."
-#: contrib/flatpages/models.py:18
-msgid "flat page"
-msgstr "pagina statica"
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr ""
-#: contrib/flatpages/models.py:19
-msgid "flat pages"
-msgstr "pagine statiche"
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:17
-msgid "th"
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
msgstr ""
-#: contrib/humanize/templatetags/humanize.py:17
-#, fuzzy
-msgid "st"
-msgstr "º"
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr "Berna"
-#: contrib/humanize/templatetags/humanize.py:17
-#, fuzzy
-msgid "nd"
-msgstr "º"
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr "Friburgo"
-#: contrib/humanize/templatetags/humanize.py:17
-msgid "rd"
-msgstr "º"
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr "Ginevra"
-#: contrib/humanize/templatetags/humanize.py:47
-#, python-format
-msgid "%(value).1f million"
-msgid_plural "%(value).1f million"
-msgstr[0] "%(value).1f milione"
-msgstr[1] "%(value).1f milioni"
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:50
-#, python-format
-msgid "%(value).1f billion"
-msgid_plural "%(value).1f billion"
-msgstr[0] "%(value).1f miliardo"
-msgstr[1] "%(value).1f miliardi"
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:53
-#, python-format
-msgid "%(value).1f trillion"
-msgid_plural "%(value).1f trillion"
-msgstr[0] ""
-msgstr[1] ""
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "one"
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr "Lucerna"
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "two"
-msgstr "due"
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "three"
-msgstr "tre"
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-#, fuzzy
-msgid "four"
-msgstr "quattro"
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "five"
-msgstr "cinque"
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "six"
-msgstr "sei"
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "seven"
-msgstr "sette"
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "eight"
-msgstr "otto"
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr ""
-#: contrib/humanize/templatetags/humanize.py:68
-msgid "nine"
-msgstr "nove"
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr ""
-#: contrib/localflavor/au/forms.py:18
-#, fuzzy
-msgid "Enter a 4 digit post code."
-msgstr "Inserire una codici postale di 4 cifre."
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr ""
-#: contrib/localflavor/br/forms.py:18
-#, fuzzy
-msgid "Enter a zip code in the format XXXXX-XXX."
-msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX."
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr ""
-#: contrib/localflavor/br/forms.py:30
-#, fuzzy
-msgid "Phone numbers must be in XX-XXXX-XXXX format."
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
msgstr ""
-"I numeri di telefono devono essere in formato XXX-XXX-XXXX. \"%s\" non è "
-"valido."
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr ""
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr "Zurigo"
+
+#: contrib/localflavor/cl/forms.py:32
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Inserire un RUT cileno valido. Il formato è XX.XXX.XXX-X ."
+
+#: contrib/localflavor/cl/forms.py:37
+msgid "Enter valid a Chilean RUT"
+msgstr "Inserire un RUT cileno valido."
+
+#: contrib/localflavor/de/forms.py:16 contrib/localflavor/fi/forms.py:14
+#: contrib/localflavor/fr/forms.py:17
+msgid "Enter a zip code in the format XXXXX."
+msgstr "Inserire un codice postale nel formato XXXXX ."
+
+#: contrib/localflavor/de/forms.py:60
+msgid ""
+"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
+"format."
+msgstr ""
+"Inserire un numero di carta d'identità tedesco valido nel formato "
+"XXXXXXXXXXX-XXXXXXX-XXXXXXX-X ."
#: contrib/localflavor/de/de_states.py:5
msgid "Baden-Wuerttemberg"
@@ -1724,10 +2307,9 @@ msgstr ""
#: contrib/localflavor/de/de_states.py:6
msgid "Bavaria"
-msgstr ""
+msgstr "Baviera"
#: contrib/localflavor/de/de_states.py:7
-#, fuzzy
msgid "Berlin"
msgstr "Berlino"
@@ -1744,7 +2326,6 @@ msgid "Hamburg"
msgstr "Amburgo"
#: contrib/localflavor/de/de_states.py:11
-#, fuzzy
msgid "Hessen"
msgstr ""
@@ -1765,7 +2346,6 @@ msgid "Rhineland-Palatinate"
msgstr ""
#: contrib/localflavor/de/de_states.py:16
-#, fuzzy
msgid "Saarland"
msgstr ""
@@ -1785,27 +2365,25 @@ msgstr ""
msgid "Thuringia"
msgstr ""
-#: contrib/localflavor/de/forms.py:16 contrib/localflavor/fi/forms.py:14
-#: contrib/localflavor/fr/forms.py:17 contrib/localflavor/it/forms.py:14
-#, fuzzy
-msgid "Enter a zip code in the format XXXXX."
-msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX."
-
-#: contrib/localflavor/de/forms.py:60
-msgid ""
-"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
-"format."
-msgstr "Inserire un numero tedesco di carta d'identità valido nel formato XXXXXXXXXXX-XXXXXXX-XXXXXXX-X."
-
#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
-#, fuzzy
msgid "Enter a valid Finnish social security number."
-msgstr "Inserire un numero valido di assisstenza sociale finlandese."
+msgstr "Inserire un numero di assistenza sociale finlandese valido."
+
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Inserire un codice postale valido."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Inserire un numero di assistenza sociale valido."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Inserire una partita IVA valida."
#: contrib/localflavor/jp/forms.py:21
-#, fuzzy
msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
-msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX."
+msgstr "Inserire un codice postale nel formato XXXXXXX o XXX-XXXX ."
#: contrib/localflavor/jp/jp_prefectures.py:4
msgid "Hokkaido"
@@ -1860,9 +2438,8 @@ msgid "Tokyo"
msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:17
-#, fuzzy
msgid "Kanagawa"
-msgstr "Kannada"
+msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:18
msgid "Yamanashi"
@@ -1933,9 +2510,8 @@ msgid "Tottori"
msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:35
-#, fuzzy
msgid "Shimane"
-msgstr "Modifica"
+msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:36
msgid "Okayama"
@@ -1954,14 +2530,12 @@ msgid "Tokushima"
msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:40
-#, fuzzy
msgid "Kagawa"
-msgstr "Kannada"
+msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:41
-#, fuzzy
msgid "Ehime"
-msgstr "Orario"
+msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:42
msgid "Kochi"
@@ -1999,595 +2573,467 @@ msgstr ""
msgid "Okinawa"
msgstr ""
-#: contrib/localflavor/no/forms.py:15
-#, fuzzy
-msgid "Enter a zip code in the format XXXX."
-msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX."
-
-#: contrib/localflavor/no/forms.py:36
-#, fuzzy
+#: contrib/localflavor/no/forms.py:35
msgid "Enter a valid Norwegian social security number."
-msgstr "Inserire un numero decimale valido."
+msgstr "Inserire un numero di assistenza sociale norvegese valido."
-#: contrib/localflavor/uk/forms.py:18
-msgid "Enter a postcode. A space is required between the two postcode parts."
+#: contrib/localflavor/sk/forms.py:32
+msgid "Enter a postal code in the format XXXXX or XXX XX."
+msgstr "Inserire un codice postale nel formato XXXXX o XXX XX ."
+
+#: contrib/localflavor/sk/sk_districts.py:8
+msgid "Banska Bystrica"
msgstr ""
-"Inserire un codice postale. È obbligatorio uno spazio tra le due parti del "
-"codice postale."
-#: contrib/localflavor/us/forms.py:18
-msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
-msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX."
+#: contrib/localflavor/sk/sk_districts.py:9
+msgid "Banska Stiavnica"
+msgstr ""
-#: contrib/localflavor/us/forms.py:51
-msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
-msgstr "Inserire un numero di assistenza sociale statunitense valido, nel formato XXX-XX-XXXX."
+#: contrib/localflavor/sk/sk_districts.py:10
+msgid "Bardejov"
+msgstr ""
-#: contrib/redirects/models.py:7
-msgid "redirect from"
-msgstr "redirigi da"
+#: contrib/localflavor/sk/sk_districts.py:11
+msgid "Banovce nad Bebravou"
+msgstr ""
-#: contrib/redirects/models.py:8
-msgid ""
-"This should be an absolute path, excluding the domain name. Example: '/"
-"events/search/'."
+#: contrib/localflavor/sk/sk_districts.py:12
+msgid "Brezno"
msgstr ""
-"Deve essere un percorso assoluto, senza nome di dominio. Esempio: '/events/"
-"search/'."
-#: contrib/redirects/models.py:9
-msgid "redirect to"
-msgstr "redirigi verso"
+#: contrib/localflavor/sk/sk_districts.py:13
+msgid "Bratislava I"
+msgstr ""
-#: contrib/redirects/models.py:10
-msgid ""
-"This can be either an absolute path (as above) or a full URL starting with "
-"'http://'."
+#: contrib/localflavor/sk/sk_districts.py:14
+msgid "Bratislava II"
msgstr ""
-"Può essere un percorso assoluto (come sopra) o una URL completa che inizia "
-"con 'http://'."
-#: contrib/redirects/models.py:13
-msgid "redirect"
-msgstr "redirezione"
+#: contrib/localflavor/sk/sk_districts.py:15
+msgid "Bratislava III"
+msgstr ""
-#: contrib/redirects/models.py:14
-msgid "redirects"
-msgstr "redirezioni"
+#: contrib/localflavor/sk/sk_districts.py:16
+msgid "Bratislava IV"
+msgstr ""
-#: contrib/sessions/models.py:68
-msgid "session key"
-msgstr "chiave di sessione"
+#: contrib/localflavor/sk/sk_districts.py:17
+msgid "Bratislava V"
+msgstr ""
-#: contrib/sessions/models.py:69
-msgid "session data"
-msgstr "dati di sessione"
+#: contrib/localflavor/sk/sk_districts.py:18
+msgid "Bytca"
+msgstr ""
-#: contrib/sessions/models.py:70
-msgid "expire date"
-msgstr "data di scadenza"
+#: contrib/localflavor/sk/sk_districts.py:19
+msgid "Cadca"
+msgstr ""
-#: contrib/sessions/models.py:74
-msgid "session"
-msgstr "sessione"
+#: contrib/localflavor/sk/sk_districts.py:20
+msgid "Detva"
+msgstr ""
-#: contrib/sessions/models.py:75
-msgid "sessions"
-msgstr "sessioni"
+#: contrib/localflavor/sk/sk_districts.py:21
+msgid "Dolny Kubin"
+msgstr ""
-#: contrib/sites/models.py:10
-msgid "domain name"
-msgstr "nome di dominio"
+#: contrib/localflavor/sk/sk_districts.py:22
+msgid "Dunajska Streda"
+msgstr ""
-#: contrib/sites/models.py:11
-msgid "display name"
-msgstr "nome visualizzato"
+#: contrib/localflavor/sk/sk_districts.py:23
+msgid "Galanta"
+msgstr ""
-#: contrib/sites/models.py:15
-msgid "site"
-msgstr "sito"
+#: contrib/localflavor/sk/sk_districts.py:24
+msgid "Gelnica"
+msgstr ""
-#: contrib/sites/models.py:16
-msgid "sites"
-msgstr "siti"
+#: contrib/localflavor/sk/sk_districts.py:25
+msgid "Hlohovec"
+msgstr ""
-#: core/validators.py:64
-msgid "This value must contain only letters, numbers and underscores."
-msgstr "Questo valore può contenere solo lettere, cifre e sottolineature."
+#: contrib/localflavor/sk/sk_districts.py:26
+msgid "Humenne"
+msgstr ""
-#: core/validators.py:68
-msgid ""
-"This value must contain only letters, numbers, underscores, dashes or "
-"slashes."
+#: contrib/localflavor/sk/sk_districts.py:27
+msgid "Ilava"
msgstr ""
-"Questo valore può contenere solo lettere, cifre, sottolineature, trattini e "
-"barre diagonali."
-#: core/validators.py:72
-msgid "This value must contain only letters, numbers, underscores or hyphens."
+#: contrib/localflavor/sk/sk_districts.py:28
+msgid "Kezmarok"
msgstr ""
-"Questo valore può contenere solo lettere, cifre, sottolineature e trattini."
-#: core/validators.py:76
-msgid "Uppercase letters are not allowed here."
-msgstr "Non sono ammesse lettere maiuscole."
+#: contrib/localflavor/sk/sk_districts.py:29
+msgid "Komarno"
+msgstr ""
-#: core/validators.py:80
-msgid "Lowercase letters are not allowed here."
-msgstr "Non sono ammesse lettere minuscole."
+#: contrib/localflavor/sk/sk_districts.py:30
+msgid "Kosice I"
+msgstr ""
-#: core/validators.py:87
-msgid "Enter only digits separated by commas."
-msgstr "Inserire solo cifre separate da virgole."
+#: contrib/localflavor/sk/sk_districts.py:31
+msgid "Kosice II"
+msgstr ""
-#: core/validators.py:99
-msgid "Enter valid e-mail addresses separated by commas."
-msgstr "Inserire indirizzi e-mail validi separati da virgole."
+#: contrib/localflavor/sk/sk_districts.py:32
+msgid "Kosice III"
+msgstr ""
-#: core/validators.py:103
-msgid "Please enter a valid IP address."
-msgstr "Inserire un indirizzo IP valido."
+#: contrib/localflavor/sk/sk_districts.py:33
+msgid "Kosice IV"
+msgstr ""
-#: core/validators.py:107
-msgid "Empty values are not allowed here."
-msgstr "È necessario inserire un valore."
+#: contrib/localflavor/sk/sk_districts.py:34
+msgid "Kosice - okolie"
+msgstr ""
-#: core/validators.py:111
-msgid "Non-numeric characters aren't allowed here."
-msgstr "Sono ammessi soltanto caratteri numerici."
+#: contrib/localflavor/sk/sk_districts.py:35
+msgid "Krupina"
+msgstr ""
-#: core/validators.py:115
-msgid "This value can't be comprised solely of digits."
-msgstr "Questo valore non può essere composto solo da cifre."
+#: contrib/localflavor/sk/sk_districts.py:36
+msgid "Kysucke Nove Mesto"
+msgstr ""
-#: core/validators.py:120 newforms/fields.py:128
-msgid "Enter a whole number."
-msgstr "Inserire un numero intero."
+#: contrib/localflavor/sk/sk_districts.py:37
+msgid "Levice"
+msgstr ""
-#: core/validators.py:124
-msgid "Only alphabetical characters are allowed here."
-msgstr "Sono ammessi solo caratteri alfabetici."
+#: contrib/localflavor/sk/sk_districts.py:38
+msgid "Levoca"
+msgstr ""
-#: core/validators.py:139
-msgid "Year must be 1900 or later."
-msgstr "L'anno deve essere 1900 o successivo."
+#: contrib/localflavor/sk/sk_districts.py:39
+msgid "Liptovsky Mikulas"
+msgstr ""
-#: core/validators.py:143
-#, fuzzy, python-format
-msgid "Invalid date: %s"
-msgstr "Data non valida: %s."
+#: contrib/localflavor/sk/sk_districts.py:40
+msgid "Lucenec"
+msgstr ""
-#: core/validators.py:148 db/models/fields/__init__.py:457
-msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "Inserire una data valida in formato AAAA-MM-GG."
+#: contrib/localflavor/sk/sk_districts.py:41
+msgid "Malacky"
+msgstr ""
-#: core/validators.py:153
-msgid "Enter a valid time in HH:MM format."
-msgstr "Inserire un orario valido in formato OO:MM."
+#: contrib/localflavor/sk/sk_districts.py:42
+msgid "Martin"
+msgstr ""
-#: core/validators.py:157 db/models/fields/__init__.py:526
-msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Inserire una data/ora valida in formato AAAA-MM-GG OO:MM."
+#: contrib/localflavor/sk/sk_districts.py:43
+msgid "Medzilaborce"
+msgstr ""
-#: core/validators.py:162 newforms/fields.py:271
-msgid "Enter a valid e-mail address."
-msgstr "Inserire un indirizzo e-mail valido."
+#: contrib/localflavor/sk/sk_districts.py:44
+msgid "Michalovce"
+msgstr ""
-#: core/validators.py:174 core/validators.py:445 oldforms/__init__.py:672
-msgid "No file was submitted. Check the encoding type on the form."
+#: contrib/localflavor/sk/sk_districts.py:45
+msgid "Myjava"
msgstr ""
-"Non è stato inviato alcun file. Verificare il tipo di codifica della form."
-#: core/validators.py:178
-msgid ""
-"Upload a valid image. The file you uploaded was either not an image or a "
-"corrupted image."
+#: contrib/localflavor/sk/sk_districts.py:46
+msgid "Namestovo"
msgstr ""
-"Caricare un'immagine valida. Il file caricato non è un'immagine o è corrotto."
-#: core/validators.py:185
-#, python-format
-msgid "The URL %s does not point to a valid image."
-msgstr "La URL %s non punta ad un'immagine valida."
+#: contrib/localflavor/sk/sk_districts.py:47
+msgid "Nitra"
+msgstr ""
-#: core/validators.py:189
-#, python-format
-msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
+#: contrib/localflavor/sk/sk_districts.py:48
+msgid "Nove Mesto nad Vahom"
msgstr ""
-"I numeri di telefono devono essere in formato XXX-XXX-XXXX. \"%s\" non è "
-"valido."
-#: core/validators.py:197
-#, python-format
-msgid "The URL %s does not point to a valid QuickTime video."
-msgstr "La URL %s non punta ad un video QuickTime valido."
+#: contrib/localflavor/sk/sk_districts.py:49
+msgid "Nove Zamky"
+msgstr ""
-#: core/validators.py:201
-msgid "A valid URL is required."
-msgstr "Inserire una URL valida."
+#: contrib/localflavor/sk/sk_districts.py:50
+msgid "Partizanske"
+msgstr ""
-#: core/validators.py:215
-#, python-format
-msgid ""
-"Valid HTML is required. Specific errors are:\n"
-"%s"
+#: contrib/localflavor/sk/sk_districts.py:51
+msgid "Pezinok"
msgstr ""
-"È richiesto HTML valido. Gli errori sono i seguenti:\n"
-"%s"
-#: core/validators.py:222
-#, python-format
-msgid "Badly formed XML: %s"
-msgstr "XML malformato: %s"
+#: contrib/localflavor/sk/sk_districts.py:52
+msgid "Piestany"
+msgstr ""
-#: core/validators.py:239
-#, python-format
-msgid "Invalid URL: %s"
-msgstr "URL non valida: %s"
+#: contrib/localflavor/sk/sk_districts.py:53
+msgid "Poltar"
+msgstr ""
-#: core/validators.py:244 core/validators.py:246
-#, python-format
-msgid "The URL %s is a broken link."
-msgstr "La URL %s è un link non funzionante."
+#: contrib/localflavor/sk/sk_districts.py:54
+msgid "Poprad"
+msgstr ""
-#: core/validators.py:252
-msgid "Enter a valid U.S. state abbreviation."
-msgstr "Inserire un valido nome di stato USA abbreviato."
+#: contrib/localflavor/sk/sk_districts.py:55
+msgid "Povazska Bystrica"
+msgstr ""
-#: core/validators.py:266
-#, python-format
-msgid "Watch your mouth! The word %s is not allowed here."
-msgid_plural "Watch your mouth! The words %s are not allowed here."
-msgstr[0] "Moderare i termini: la parola %s non è ammessa."
-msgstr[1] "Moderare i termini: le parole %s non sono ammesse."
+#: contrib/localflavor/sk/sk_districts.py:56
+msgid "Presov"
+msgstr ""
-#: core/validators.py:273
-#, python-format
-msgid "This field must match the '%s' field."
-msgstr "Questo campo deve corrispondere al campo '%s'."
+#: contrib/localflavor/sk/sk_districts.py:57
+msgid "Prievidza"
+msgstr ""
-#: core/validators.py:292
-msgid "Please enter something for at least one field."
-msgstr "Inserire qualcosa in almeno un campo."
+#: contrib/localflavor/sk/sk_districts.py:58
+msgid "Puchov"
+msgstr ""
-#: core/validators.py:301 core/validators.py:312
-msgid "Please enter both fields or leave them both empty."
-msgstr "Inserire entrambi i campi o lasciarli entrambi vuoti."
+#: contrib/localflavor/sk/sk_districts.py:59
+msgid "Revuca"
+msgstr ""
-#: core/validators.py:320
-#, python-format
-msgid "This field must be given if %(field)s is %(value)s"
-msgstr "Questo campo è obbligatorio se %(field)s è %(value)s"
+#: contrib/localflavor/sk/sk_districts.py:60
+msgid "Rimavska Sobota"
+msgstr ""
-#: core/validators.py:333
-#, python-format
-msgid "This field must be given if %(field)s is not %(value)s"
-msgstr "Questo campo è obbligatorio se %(field)s non è %(value)s"
+#: contrib/localflavor/sk/sk_districts.py:61
+msgid "Roznava"
+msgstr ""
-#: core/validators.py:352
-msgid "Duplicate values are not allowed."
-msgstr "Non sono ammessi valori duplicati."
+#: contrib/localflavor/sk/sk_districts.py:62
+msgid "Ruzomberok"
+msgstr ""
-#: core/validators.py:367
-#, fuzzy, python-format
-msgid "This value must be between %(lower)s and %(upper)s."
-msgstr "Questo valore deve essere compreso tra %s e %s."
+#: contrib/localflavor/sk/sk_districts.py:63
+msgid "Sabinov"
+msgstr ""
-#: core/validators.py:369
-#, python-format
-msgid "This value must be at least %s."
-msgstr "Questo valore deve essere almeno pari a %s."
+#: contrib/localflavor/sk/sk_districts.py:64
+msgid "Senec"
+msgstr ""
-#: core/validators.py:371
-#, python-format
-msgid "This value must be no more than %s."
-msgstr "Questo valore non deve essere maggiore di %s."
+#: contrib/localflavor/sk/sk_districts.py:65
+msgid "Senica"
+msgstr ""
-#: core/validators.py:407
-#, python-format
-msgid "This value must be a power of %s."
-msgstr "Questo valore deve essere una potenza di %s."
+#: contrib/localflavor/sk/sk_districts.py:66
+msgid "Skalica"
+msgstr ""
-#: core/validators.py:418
-msgid "Please enter a valid decimal number."
-msgstr "Inserire un numero decimale valido."
+#: contrib/localflavor/sk/sk_districts.py:67
+msgid "Snina"
+msgstr ""
-#: core/validators.py:422
-#, python-format
-msgid "Please enter a valid decimal number with at most %s total digit."
-msgid_plural ""
-"Please enter a valid decimal number with at most %s total digits."
-msgstr[0] "Inserire un numero decimale con non più di %s cifra in totale."
-msgstr[1] "Inserire un numero decimale con non più di %s cifre in totale."
+#: contrib/localflavor/sk/sk_districts.py:68
+msgid "Sobrance"
+msgstr ""
-#: core/validators.py:425
-#, python-format
-msgid ""
-"Please enter a valid decimal number with a whole part of at most %s digit."
-msgid_plural ""
-"Please enter a valid decimal number with a whole part of at most %s digits."
-msgstr[0] ""
-"Inserire un numero decimale la cui parte intera sia composta da non più di %"
-"s cifra."
-msgstr[1] ""
-"Inserire un numero decimale la cui parte intera sia composta da non più di %"
-"s cifre."
+#: contrib/localflavor/sk/sk_districts.py:69
+msgid "Spisska Nova Ves"
+msgstr ""
-#: core/validators.py:428
-#, python-format
-msgid "Please enter a valid decimal number with at most %s decimal place."
-msgid_plural ""
-"Please enter a valid decimal number with at most %s decimal places."
-msgstr[0] "Inserire un decimale con non più di %s cifra decimale."
-msgstr[1] "Inserire un decimale con non più di %s cifre decimali."
+#: contrib/localflavor/sk/sk_districts.py:70
+msgid "Stara Lubovna"
+msgstr ""
-#: core/validators.py:438
-#, python-format
-msgid "Make sure your uploaded file is at least %s bytes big."
-msgstr "Verificare che il file caricato sia grande almeno %s byte."
+#: contrib/localflavor/sk/sk_districts.py:71
+msgid "Stropkov"
+msgstr ""
-#: core/validators.py:439
-#, python-format
-msgid "Make sure your uploaded file is at most %s bytes big."
-msgstr "Verificare che il file caricato non sia più grande di %s byte."
+#: contrib/localflavor/sk/sk_districts.py:72
+msgid "Svidnik"
+msgstr ""
-#: core/validators.py:456
-msgid "The format for this field is wrong."
-msgstr "Il formato di questo campo non è valido."
+#: contrib/localflavor/sk/sk_districts.py:73
+msgid "Sala"
+msgstr ""
-#: core/validators.py:471
-msgid "This field is invalid."
-msgstr "Questo campo non è valido."
+#: contrib/localflavor/sk/sk_districts.py:74
+msgid "Topolcany"
+msgstr ""
-#: core/validators.py:507
-#, python-format
-msgid "Could not retrieve anything from %s."
-msgstr "Impossibile recuperare alcunché da %s."
+#: contrib/localflavor/sk/sk_districts.py:75
+msgid "Trebisov"
+msgstr ""
-#: core/validators.py:510
-#, python-format
-msgid ""
-"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+#: contrib/localflavor/sk/sk_districts.py:76
+msgid "Trencin"
msgstr ""
-"La URL %(url)s ha restituito un header Content-Type non valido: '%"
-"(contenttype)s'."
-#: core/validators.py:543
-#, python-format
-msgid ""
-"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
-"\"%(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:77
+msgid "Trnava"
msgstr ""
-"Chiudere il tag %(tag)s a linea %(line)s. (La linea inizia con \"%(start)s"
-"\".)"
-#: core/validators.py:547
-#, python-format
-msgid ""
-"Some text starting on line %(line)s is not allowed in that context. (Line "
-"starts with \"%(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:78
+msgid "Turcianske Teplice"
msgstr ""
-"Il testo che comincia a linea %(line)s non e' ammesso in questo contesto. "
-"(La linea comincia con \"%(start)s\".)"
-#: core/validators.py:552
-#, python-format
-msgid ""
-"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
-"(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:79
+msgid "Tvrdosin"
msgstr ""
-"\"%(attr)s\" a linea %(line)s non è un attributo valido. (La linea comincia "
-"con \"%(start)s\".)"
-#: core/validators.py:557
-#, python-format
-msgid ""
-"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
-"(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:80
+msgid "Velky Krtis"
msgstr ""
-"\"<%(tag)s>\" a linea %(line)s non è un tag valido. (La linea comincia con "
-"\"%(start)s\".)"
-#: core/validators.py:561
-#, python-format
-msgid ""
-"A tag on line %(line)s is missing one or more required attributes. (Line "
-"starts with \"%(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:81
+msgid "Vranov nad Toplou"
msgstr ""
-"Un tag a linea %(line)s manca di uno o più attributi richiesti. (La linea "
-"comincia con \"%(start)s\".)"
-#: core/validators.py:566
-#, python-format
-msgid ""
-"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
-"starts with \"%(start)s\".)"
+#: contrib/localflavor/sk/sk_districts.py:82
+msgid "Zlate Moravce"
msgstr ""
-"L'attributo \"%(attr)s\" a linea %(line)s ha un valore non valido. (La linea "
-"comincia con \"%(start)s\".)"
-#: db/models/manipulators.py:307
-#, python-format
-msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "%(object)s·con questo·%(type)s·esiste già per questo·%(field)s."
+#: contrib/localflavor/sk/sk_districts.py:83
+msgid "Zvolen"
+msgstr ""
-#: db/models/fields/__init__.py:42
-#, python-format
-msgid "%(optname)s with this %(fieldname)s already exists."
-msgstr "%(optname)s·con questo·%(fieldname)s·esiste già."
+#: contrib/localflavor/sk/sk_districts.py:84
+msgid "Zarnovica"
+msgstr ""
-#: db/models/fields/__init__.py:117 db/models/fields/__init__.py:274
-#: db/models/fields/__init__.py:610 db/models/fields/__init__.py:621
-#: newforms/fields.py:80 newforms/fields.py:376 newforms/fields.py:452
-#: newforms/fields.py:463 newforms/models.py:178 oldforms/__init__.py:357
-msgid "This field is required."
-msgstr "Questo campo è obbligatorio."
+#: contrib/localflavor/sk/sk_districts.py:85
+msgid "Ziar nad Hronom"
+msgstr ""
-#: db/models/fields/__init__.py:367
-msgid "This value must be an integer."
-msgstr "Questo valore deve essere un intero."
+#: contrib/localflavor/sk/sk_districts.py:86
+msgid "Zilina"
+msgstr ""
-#: db/models/fields/__init__.py:402
-msgid "This value must be either True or False."
-msgstr "Questo valore deve essere True o False."
+#: contrib/localflavor/sk/sk_regions.py:8
+msgid "Banska Bystrica region"
+msgstr ""
-#: db/models/fields/__init__.py:423
-msgid "This field cannot be null."
-msgstr "Questo campo non può essere nullo."
+#: contrib/localflavor/sk/sk_regions.py:9
+msgid "Bratislava region"
+msgstr ""
-#: db/models/fields/__init__.py:630
-msgid "Enter a valid filename."
-msgstr "Inserire un nome file valido."
+#: contrib/localflavor/sk/sk_regions.py:10
+msgid "Kosice region"
+msgstr ""
-#: db/models/fields/__init__.py:751
-#, fuzzy
-msgid "This value must be either None, True or False."
-msgstr "Questo valore deve essere True o False."
+#: contrib/localflavor/sk/sk_regions.py:11
+msgid "Nitra region"
+msgstr ""
-#: db/models/fields/related.py:53
-#, python-format
-msgid "Please enter a valid %s."
-msgstr "Inserire un %s valido."
+#: contrib/localflavor/sk/sk_regions.py:12
+msgid "Presov region"
+msgstr ""
-#: db/models/fields/related.py:642
-msgid "Separate multiple IDs with commas."
-msgstr "Separare ID multipli con virgole."
+#: contrib/localflavor/sk/sk_regions.py:13
+msgid "Trencin region"
+msgstr ""
-#: db/models/fields/related.py:644
-msgid ""
-"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+#: contrib/localflavor/sk/sk_regions.py:14
+msgid "Trnava region"
msgstr ""
-"Tenere premuto \"Control\", o \"Command\" su Mac, per selezionarne più di "
-"uno."
-#: db/models/fields/related.py:691
-#, python-format
-msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural ""
-"Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] ""
-"Inserire un ID validi per %(self)s. Il valore %(value)r non è valido."
-msgstr[1] ""
-"Inserire un ID validi per %(self)s. I valori %(value)r non sono validi."
+#: contrib/localflavor/sk/sk_regions.py:15
+msgid "Zilina region"
+msgstr ""
-#: newforms/fields.py:103 newforms/fields.py:256
-#, python-format
-msgid "Ensure this value has at most %d characters."
-msgstr "Assicurarsi che questo valore non contenga più di %d caratteri."
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr ""
+"Inserire un codice postale. È obbligatorio uno spazio tra le due parti del "
+"codice postale."
-#: newforms/fields.py:105 newforms/fields.py:258
-#, python-format
-msgid "Ensure this value has at least %d characters."
-msgstr "Assicurarsi che questo valore contenga almeno %d caratteri."
+#: contrib/localflavor/us/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr "Inserire un codice postale nel formato XXXXX o XXXXX-XXXX ."
-#: newforms/fields.py:130
-#, python-format
-msgid "Ensure this value is less than or equal to %s."
-msgstr "Assicurarsi che questo valore sia minore o uguale a %s."
+#: contrib/localflavor/us/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr ""
+"Inserire un numero di assistenza sociale statunitense valido, nel formato "
+"XXX-XX-XXXX ."
-#: newforms/fields.py:132
-#, python-format
-msgid "Ensure this value is greater than or equal to %s."
-msgstr "Assicurarsi che questo valore sia maggiore o uguale a %s."
+#: contrib/localflavor/is_/forms.py:17
+msgid ""
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr ""
+"Inserire un numero di identificazione islandese valido. Il formato è XXXXXX-"
+"XXXX ."
-#: newforms/fields.py:165
-msgid "Enter a valid date."
-msgstr "Inserire una data valida."
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr "Il numero di identificazione islandese non è valido."
-#: newforms/fields.py:192
-msgid "Enter a valid time."
-msgstr "Inserire un orario valido."
+#: contrib/sessions/models.py:68
+msgid "session key"
+msgstr "chiave di sessione"
-#: newforms/fields.py:228
-msgid "Enter a valid date/time."
-msgstr "Inserire una coppia data/orario valida."
+#: contrib/sessions/models.py:69
+msgid "session data"
+msgstr "dati di sessione"
-#: newforms/fields.py:242
-msgid "Enter a valid value."
-msgstr "Inserire un valore valido."
+#: contrib/sessions/models.py:70
+msgid "expire date"
+msgstr "data di scadenza"
-#: newforms/fields.py:289 newforms/fields.py:311
-msgid "Enter a valid URL."
-msgstr "Inserire una URL valida."
+#: contrib/sessions/models.py:74
+msgid "session"
+msgstr "sessione"
-#: newforms/fields.py:313
-msgid "This URL appears to be a broken link."
-msgstr "Questa URL non sembra funzionare."
+#: contrib/sessions/models.py:75
+msgid "sessions"
+msgstr "sessioni"
-#: newforms/fields.py:362 newforms/models.py:165
-msgid "Select a valid choice. That choice is not one of the available choices."
-msgstr ""
-"Selezionare un'opzione valida. La scelta effettuata non compare tra quelle "
-"disponibili."
+#: contrib/contenttypes/models.py:37
+msgid "python model class name"
+msgstr "nome della classe del modello Python"
-#: newforms/fields.py:380 newforms/fields.py:456 newforms/models.py:182
-msgid "Enter a list of values."
-msgstr "Inserire una lista di valori."
+#: contrib/contenttypes/models.py:40
+msgid "content type"
+msgstr "content type"
-#: newforms/fields.py:389 newforms/models.py:188
-#, python-format
-msgid "Select a valid choice. %s is not one of the available choices."
-msgstr "Selezionare un'opzione valida;'%s non compare tra quelle disponibili."
+#: contrib/contenttypes/models.py:41
+msgid "content types"
+msgstr "content type"
-#: oldforms/__init__.py:392
+#: oldforms/__init__.py:408
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Assicurarsi che il testo sia più corto di %s carattere."
msgstr[1] "Assicurarsi che il testo sia più corto di %s caratteri."
-#: oldforms/__init__.py:397
+#: oldforms/__init__.py:413
msgid "Line breaks are not allowed here."
-msgstr "Non sono ammessi a capo manuali."
+msgstr "Non sono ammessi a capo manuali qui."
-#: oldforms/__init__.py:498 oldforms/__init__.py:571 oldforms/__init__.py:610
+#: oldforms/__init__.py:511 oldforms/__init__.py:585 oldforms/__init__.py:624
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "Selezionare un'opzione valida; '%(data)s' non presente in %(choices)s."
+msgstr "Scegliere un'opzione valida; '%(data)s' non presente in %(choices)s."
-#: oldforms/__init__.py:674
+#: oldforms/__init__.py:688 newforms/fields.py:380
msgid "The submitted file is empty."
msgstr "Il file inviato è vuoto."
-#: oldforms/__init__.py:730
+#: oldforms/__init__.py:744
msgid "Enter a whole number between -32,768 and 32,767."
-msgstr "Inserire un numero intero compreso tra -32.768 e 32.767."
+msgstr "Inserire un numero intero compreso tra -32.768 e 32.767 ."
-#: oldforms/__init__.py:740
+#: oldforms/__init__.py:754
msgid "Enter a positive number."
msgstr "Inserire un numero positivo."
-#: oldforms/__init__.py:750
+#: oldforms/__init__.py:764
msgid "Enter a whole number between 0 and 32,767."
-msgstr "Inserire un numero intero compreso tra 0 e 32.767."
-
-#: template/defaultfilters.py:491
-msgid "yes,no,maybe"
-msgstr "sì,no,forse"
+msgstr "Inserire un numero intero compreso tra 0 e 32.767 ."
-#: utils/dateformat.py:40
-msgid "p.m."
-msgstr ""
-
-#: utils/dateformat.py:41
-msgid "a.m."
-msgstr ""
-
-#: utils/dateformat.py:46
-msgid "PM"
-msgstr ""
-
-#: utils/dateformat.py:47
-msgid "AM"
-msgstr ""
+#: views/generic/create_update.py:43
+#, python-format
+msgid "The %(verbose_name)s was created successfully."
+msgstr "%(verbose_name)s è stato creato correttamente."
-#: utils/dateformat.py:95
-msgid "midnight"
-msgstr "mezzanotte"
+#: views/generic/create_update.py:117
+#, python-format
+msgid "The %(verbose_name)s was updated successfully."
+msgstr "%(verbose_name)s è stato aggiornato correttamente."
-#: utils/dateformat.py:97
-msgid "noon"
-msgstr "mezzogiorno"
+#: views/generic/create_update.py:184
+#, python-format
+msgid "The %(verbose_name)s was deleted."
+msgstr "%(verbose_name)s è stato cancellato."
#: utils/dates.py:6
msgid "Monday"
@@ -2617,127 +3063,155 @@ msgstr "Sabato"
msgid "Sunday"
msgstr "Domenica"
-#: utils/dates.py:14
+#: utils/dates.py:10
+msgid "Mon"
+msgstr "Lun"
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr "Mar"
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr "Mer"
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr "Gio"
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr "Ven"
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr "Sab"
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr "Dom"
+
+#: utils/dates.py:18
msgid "January"
msgstr "Gennaio"
-#: utils/dates.py:14
+#: utils/dates.py:18
msgid "February"
msgstr "Febbraio"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "Marzo"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "Aprile"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Maggio"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Giugno"
-#: utils/dates.py:15 utils/dates.py:27
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Luglio"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "August"
msgstr "Agosto"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "September"
msgstr "Settembre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "October"
msgstr "Ottobre"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "November"
msgstr "Novembre"
-#: utils/dates.py:16
+#: utils/dates.py:20
msgid "December"
msgstr "Dicembre"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jan"
msgstr "gen"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "feb"
msgstr "feb"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "mar"
msgstr "mar"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "apr"
msgstr "apr"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "may"
msgstr "mag"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jun"
msgstr "giu"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "jul"
msgstr "lug"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "aug"
msgstr "ago"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "sep"
msgstr "set"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "oct"
msgstr "ott"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "nov"
msgstr "nov"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "dec"
msgstr "dic"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Jan."
msgstr "Gen."
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Feb."
msgstr "Feb."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Aug."
msgstr "Ago."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Sept."
msgstr "Set."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Oct."
msgstr "Ott."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Nov."
msgstr "Nov."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Dec."
msgstr "Dic."
@@ -2777,40 +3251,168 @@ msgid_plural "minutes"
msgstr[0] "minuto"
msgstr[1] "minuti"
-#: utils/translation/trans_real.py:358
+#: utils/timesince.py:39
+#, python-format
+msgid "%(number)d %(type)s"
+msgstr "%(number)d %(type)s"
+
+#: utils/timesince.py:45
+#, python-format
+msgid ", %(number)d %(type)s"
+msgstr ", %(number)d %(type)s"
+
+#: utils/dateformat.py:41
+msgid "p.m."
+msgstr ""
+
+#: utils/dateformat.py:42
+msgid "a.m."
+msgstr ""
+
+#: utils/dateformat.py:47
+msgid "PM"
+msgstr ""
+
+#: utils/dateformat.py:48
+msgid "AM"
+msgstr ""
+
+#: utils/dateformat.py:97
+msgid "midnight"
+msgstr "mezzanotte"
+
+#: utils/dateformat.py:99
+msgid "noon"
+msgstr "mezzogiorno"
+
+#: utils/translation/trans_real.py:391
msgid "DATE_FORMAT"
msgstr "j F Y"
-#: utils/translation/trans_real.py:359
+#: utils/translation/trans_real.py:392
msgid "DATETIME_FORMAT"
msgstr "j F Y, H:i"
-#: utils/translation/trans_real.py:360
+#: utils/translation/trans_real.py:393
msgid "TIME_FORMAT"
msgstr "H:i"
-#: utils/translation/trans_real.py:376
+#: utils/translation/trans_real.py:409
msgid "YEAR_MONTH_FORMAT"
msgstr "Y F"
-#: utils/translation/trans_real.py:377
+#: utils/translation/trans_real.py:410
msgid "MONTH_DAY_FORMAT"
msgstr "F j"
-#: views/generic/create_update.py:43
+#: template/defaultfilters.py:485
+msgid "yes,no,maybe"
+msgstr "sì,no,forse"
+
+#: template/defaultfilters.py:514
#, python-format
-msgid "The %(verbose_name)s was created successfully."
-msgstr "%(verbose_name)s è stato creato correttamente."
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] "%(size)d byte"
+msgstr[1] "%(size)d byte"
-#: views/generic/create_update.py:117
+#: template/defaultfilters.py:516
#, python-format
-msgid "The %(verbose_name)s was updated successfully."
-msgstr "%(verbose_name)s è stato aggiornato correttamente."
+msgid "%.1f KB"
+msgstr ""
-#: views/generic/create_update.py:184
+#: template/defaultfilters.py:518
#, python-format
-msgid "The %(verbose_name)s was deleted."
-msgstr "%(verbose_name)s è stato cancellato."
+msgid "%.1f MB"
+msgstr ""
+
+#: template/defaultfilters.py:519
+#, python-format
+msgid "%.1f GB"
+msgstr ""
+
+#: newforms/fields.py:116
+#, fuzzy, python-format
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr ""
+"Assicurarsi che questo valore non contenga più di %(max)d caratteri (ne ha "
+"%(length))."
+
+#: newforms/fields.py:118
+#, fuzzy, python-format
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr ""
+"Assicurarsi che questo valore contenga almeno %(min)d caratteri (ne ha "
+"%(length))."
+
+#: newforms/fields.py:144 newforms/fields.py:167 newforms/fields.py:197
+#, python-format
+msgid "Ensure this value is less than or equal to %s."
+msgstr "Assicurarsi che questo valore sia minore o uguale a %s."
-#~ msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
-#~ msgstr "Hai <a href=\"/password_reset/\">dimenticato la password</a>?"
+#: newforms/fields.py:146 newforms/fields.py:169 newforms/fields.py:199
+#, python-format
+msgid "Ensure this value is greater than or equal to %s."
+msgstr "Assicurarsi che questo valore sia maggiore o uguale a %s."
+
+#: newforms/fields.py:165 newforms/fields.py:192
+msgid "Enter a number."
+msgstr "Inserire un numero."
+
+#: newforms/fields.py:201
+#, python-format
+msgid "Ensure that there are no more than %s digits in total."
+msgstr "Assicurarsi che non vi siano più di %s cifre in totale."
+
+#: newforms/fields.py:203
+#, python-format
+msgid "Ensure that there are no more than %s decimal places."
+msgstr "Assicurarsi che non vi siano più di %s cifre decimali."
+
+#: newforms/fields.py:205
+#, python-format
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr "Assicurarsi che non vi siano più di %s cifre prima della virgola."
+
+#: newforms/fields.py:238 newforms/fields.py:610
+msgid "Enter a valid date."
+msgstr "Inserire una data valida."
+
+#: newforms/fields.py:265 newforms/fields.py:612
+msgid "Enter a valid time."
+msgstr "Inserire un ora valida."
+
+#: newforms/fields.py:301
+msgid "Enter a valid date/time."
+msgstr "Inserire una coppia data/ora valida."
+
+#: newforms/fields.py:314
+msgid "Enter a valid value."
+msgstr "Inserire un valore valido."
+
+#: newforms/fields.py:378
+msgid "No file was submitted."
+msgstr "Nessun file è stato inviato."
+
+#: newforms/fields.py:403 newforms/fields.py:425
+msgid "Enter a valid URL."
+msgstr "Inserire una URL valida."
+
+#: newforms/fields.py:427
+msgid "This URL appears to be a broken link."
+msgstr "Questa URL non sembra funzionare."
+
+#: newforms/fields.py:478 newforms/models.py:180
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr ""
+"Scegliere un'opzione valida. La scelta effettuata non compare tra quelle "
+"disponibili."
+
+#: newforms/fields.py:494 newforms/fields.py:570 newforms/models.py:197
+msgid "Enter a list of values."
+msgstr "Inserire una lista di valori."
+
+#: newforms/fields.py:500 newforms/models.py:203
+#, python-format
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr "Scegliere un'opzione valida. '%s non compare tra quelle disponibili."
diff --git a/django/conf/locale/it/LC_MESSAGES/djangojs.mo b/django/conf/locale/it/LC_MESSAGES/djangojs.mo
index c34009f148..49620a7942 100644
--- a/django/conf/locale/it/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/it/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/it/LC_MESSAGES/djangojs.po b/django/conf/locale/it/LC_MESSAGES/djangojs.po
index 4f01cd04a0..7c8d438855 100644
--- a/django/conf/locale/it/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/it/LC_MESSAGES/djangojs.po
@@ -38,7 +38,7 @@ msgstr "Domenica Lunedì Martedì Mercoledì Giovedì Venerdì Sabato"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
-msgstr "Disponibile %s"
+msgstr "%s disponibili"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
@@ -55,11 +55,11 @@ msgstr "Rimuovi"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
-msgstr "Scelto %s"
+msgstr "%s scelti"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
-msgstr "Seleziona le tue scelte e clicca "
+msgstr "Fai le tue scelte e clicca "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
diff --git a/django/conf/locale/sk/LC_MESSAGES/django.mo b/django/conf/locale/sk/LC_MESSAGES/django.mo
index 9c8cfd3cd6..169f270969 100644
--- a/django/conf/locale/sk/LC_MESSAGES/django.mo
+++ b/django/conf/locale/sk/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/sk/LC_MESSAGES/django.po b/django/conf/locale/sk/LC_MESSAGES/django.po
index 98cc44579c..89dd4897bb 100644
--- a/django/conf/locale/sk/LC_MESSAGES/django.po
+++ b/django/conf/locale/sk/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-06-23 18:09-0400\n"
+"POT-Creation-Date: 2007-07-24 09:56-0400\n"
"PO-Revision-Date: 2007-06-22 20:54-0400\n"
"Last-Translator: Vlado <vlado@labath.org>\n"
"Language-Team: Slovak <sk@li.org>\n"
@@ -15,130 +15,130 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
-#: oldforms/__init__.py:361 db/models/fields/__init__.py:121
-#: db/models/fields/__init__.py:278 db/models/fields/__init__.py:675
-#: db/models/fields/__init__.py:686 newforms/models.py:185
-#: newforms/fields.py:87 newforms/fields.py:444 newforms/fields.py:520
-#: newforms/fields.py:531
+#: oldforms/__init__.py:369 db/models/fields/__init__.py:152
+#: db/models/fields/__init__.py:309 db/models/fields/__init__.py:706
+#: db/models/fields/__init__.py:717 newforms/models.py:187
+#: newforms/fields.py:92 newforms/fields.py:440 newforms/fields.py:516
+#: newforms/fields.py:527
msgid "This field is required."
msgstr "Toto pole je povinné."
-#: oldforms/__init__.py:396
+#: oldforms/__init__.py:404
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Uisite sa, že text je kratší ako %s znak."
msgstr[1] "Uisite sa, že text je kratší ako %s znakov."
-#: oldforms/__init__.py:401
+#: oldforms/__init__.py:409
msgid "Line breaks are not allowed here."
msgstr "Zalomenia riadkov nie sú povolené."
-#: oldforms/__init__.py:502 oldforms/__init__.py:575 oldforms/__init__.py:614
+#: oldforms/__init__.py:507 oldforms/__init__.py:581 oldforms/__init__.py:620
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Vyberte platnú možnosť; '%(data)s' nie je v %(choices)s."
-#: oldforms/__init__.py:581 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:150
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:152
msgid "Unknown"
msgstr "Neznámy"
-#: oldforms/__init__.py:581 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "Yes"
msgstr "Áno"
-#: oldforms/__init__.py:581 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "No"
msgstr "Nie"
-#: oldforms/__init__.py:676 core/validators.py:175 core/validators.py:453
+#: oldforms/__init__.py:682 core/validators.py:181 core/validators.py:461
msgid "No file was submitted. Check the encoding type on the form."
msgstr ""
"Súbor nebol odoslaný. Skontrolujte atribút 'enctype' encoding vo formulári."
-#: oldforms/__init__.py:678
+#: oldforms/__init__.py:684
msgid "The submitted file is empty."
msgstr "Odoslaný súbor je prázdný."
-#: oldforms/__init__.py:734
+#: oldforms/__init__.py:740
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Zadajte celé číslo s hodnotou medzi -32768 a 32767."
-#: oldforms/__init__.py:744
+#: oldforms/__init__.py:750
msgid "Enter a positive number."
msgstr "Zadajte celé kladné číslo."
-#: oldforms/__init__.py:754
+#: oldforms/__init__.py:760
msgid "Enter a whole number between 0 and 32,767."
msgstr "Zadajte celé číslo s hodnotou medzi 0 a 32767."
-#: db/models/manipulators.py:307
+#: db/models/manipulators.py:309
#, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "%(object)s s %(type)s už existuje pre prvok %(field)s."
-#: db/models/manipulators.py:308 contrib/admin/views/main.py:335
-#: contrib/admin/views/main.py:337 contrib/admin/views/main.py:339
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
msgid "and"
msgstr "a"
-#: db/models/fields/__init__.py:46
+#: db/models/fields/__init__.py:48
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(optname)s s %(fieldname)s už existuje."
-#: db/models/fields/__init__.py:373
+#: db/models/fields/__init__.py:404
msgid "This value must be an integer."
msgstr "Táto hodnota musí byť celé číslo."
-#: db/models/fields/__init__.py:408
+#: db/models/fields/__init__.py:439
msgid "This value must be either True or False."
msgstr "Táto hodnota musí byť True alebo False."
-#: db/models/fields/__init__.py:429
+#: db/models/fields/__init__.py:460
msgid "This field cannot be null."
msgstr "Toto pole nemôže obsahovať null."
-#: db/models/fields/__init__.py:463 core/validators.py:149
+#: db/models/fields/__init__.py:494 core/validators.py:155
msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Zadajte platný dátum vo formáte RRRR-MM-DD."
-#: db/models/fields/__init__.py:532 core/validators.py:158
+#: db/models/fields/__init__.py:563 core/validators.py:164
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Zadajte platný dátum a čas vo formáte RRRR-MM-DD HH:MM."
-#: db/models/fields/__init__.py:592
+#: db/models/fields/__init__.py:623
msgid "This value must be a decimal number."
msgstr "Táto hodnota musí byť desiatkove číslo."
-#: db/models/fields/__init__.py:695
+#: db/models/fields/__init__.py:726
msgid "Enter a valid filename."
msgstr "Zadajte platný názov súboru."
-#: db/models/fields/__init__.py:818
+#: db/models/fields/__init__.py:851
msgid "This value must be either None, True or False."
msgstr "Táto hodnota musí byť buď None, True alebo False."
-#: db/models/fields/related.py:53
+#: db/models/fields/related.py:55
#, python-format
msgid "Please enter a valid %s."
msgstr "Prosím, zadajte platné %s."
-#: db/models/fields/related.py:642
+#: db/models/fields/related.py:661
msgid "Separate multiple IDs with commas."
msgstr "Oddeľte viacnásobné ID čiarkami."
-#: db/models/fields/related.py:644
+#: db/models/fields/related.py:663
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
"Ak chcete vybrať viacero možností, podržte \"Control\" alebo \"Command\" na "
"Mac-u."
-#: db/models/fields/related.py:691
+#: db/models/fields/related.py:710
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
@@ -147,54 +147,58 @@ msgstr[0] "Prosím, vložte platné %(self)s ID. Hodnota %(value)r je neplatná.
msgstr[1] ""
"Prosím, vložte platné %(self)s ID-čka. Hodnoty %(value)r sú neplatné."
-#: conf/global_settings.py:39
+#: conf/global_settings.py:38
msgid "Arabic"
msgstr "Arabsky"
-#: conf/global_settings.py:40
+#: conf/global_settings.py:39
msgid "Bengali"
msgstr "Bengálsky"
-#: conf/global_settings.py:41
+#: conf/global_settings.py:40
msgid "Bulgarian"
msgstr "Bulharský"
-#: conf/global_settings.py:42
+#: conf/global_settings.py:41
msgid "Catalan"
msgstr "Katalánsky"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:42
msgid "Czech"
msgstr "Česky"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:43
msgid "Welsh"
msgstr "Welšsky"
-#: conf/global_settings.py:45
+#: conf/global_settings.py:44
msgid "Danish"
msgstr "Dánsky"
-#: conf/global_settings.py:46
+#: conf/global_settings.py:45
msgid "German"
msgstr "Nemecky"
-#: conf/global_settings.py:47
+#: conf/global_settings.py:46
msgid "Greek"
msgstr "Grécky"
-#: conf/global_settings.py:48
+#: conf/global_settings.py:47
msgid "English"
msgstr "Anglicky"
-#: conf/global_settings.py:49
+#: conf/global_settings.py:48
msgid "Spanish"
msgstr "Španielsky"
-#: conf/global_settings.py:50
+#: conf/global_settings.py:49
msgid "Argentinean Spanish"
msgstr "Argentínska španielčina"
+#: conf/global_settings.py:50
+msgid "Persian"
+msgstr "Perzský"
+
#: conf/global_settings.py:51
msgid "Finnish"
msgstr "Fínsky"
@@ -311,11 +315,11 @@ msgstr "Čínsky (zjednodušene)"
msgid "Traditional Chinese"
msgstr "Čínsky (tradične)"
-#: core/validators.py:65
+#: core/validators.py:71
msgid "This value must contain only letters, numbers and underscores."
msgstr "Táto hodnota môže obsahovať len písmená, číslice a podčiarkovníky."
-#: core/validators.py:69
+#: core/validators.py:75
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
@@ -323,69 +327,69 @@ msgstr ""
"Táto hodnota môže obsahovať len písmena, číslice, podčiarkovniky, pomlčky a "
"lomítka."
-#: core/validators.py:73
+#: core/validators.py:79
msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr ""
"Táto hodnota môže obsahovať len písmená, číslice, počiarkovníky a pomlčky."
-#: core/validators.py:77
+#: core/validators.py:83
msgid "Uppercase letters are not allowed here."
msgstr "Veľké písmená nie sú povolené."
-#: core/validators.py:81
+#: core/validators.py:87
msgid "Lowercase letters are not allowed here."
msgstr "Malé písmena nie sú povolené."
-#: core/validators.py:88
+#: core/validators.py:94
msgid "Enter only digits separated by commas."
msgstr "Zadávajte len číslice oddelené čiarkami."
-#: core/validators.py:100
+#: core/validators.py:106
msgid "Enter valid e-mail addresses separated by commas."
msgstr "Zadajte platné e-mailové adresy oddelené čiarkami."
-#: core/validators.py:104
+#: core/validators.py:110
msgid "Please enter a valid IP address."
msgstr "Prosím, zadajte platnú IP adresu."
-#: core/validators.py:108
+#: core/validators.py:114
msgid "Empty values are not allowed here."
msgstr "Prázdne hodnoty tu nie sú povolené."
-#: core/validators.py:112
+#: core/validators.py:118
msgid "Non-numeric characters aren't allowed here."
msgstr "Iné ako numerické znaky tu nie sú povolené."
-#: core/validators.py:116
+#: core/validators.py:122
msgid "This value can't be comprised solely of digits."
msgstr "Táto hodnota nemôže byť čisto numerická."
-#: core/validators.py:121 newforms/fields.py:135
+#: core/validators.py:127 newforms/fields.py:141
msgid "Enter a whole number."
msgstr "Zadajte celé číslo."
-#: core/validators.py:125
+#: core/validators.py:131
msgid "Only alphabetical characters are allowed here."
msgstr "Tu sú povolené len alfanumerické znaky."
-#: core/validators.py:140
+#: core/validators.py:146
msgid "Year must be 1900 or later."
msgstr "Rok musí byť 1900 alebo neskôr."
-#: core/validators.py:144
+#: core/validators.py:150
#, python-format
msgid "Invalid date: %s"
msgstr "Neplatný dátum: %s"
-#: core/validators.py:154
+#: core/validators.py:160
msgid "Enter a valid time in HH:MM format."
msgstr "Zadajte platný čas vo formáte HH:MM."
-#: core/validators.py:163 newforms/fields.py:339
+#: core/validators.py:169 newforms/fields.py:335
msgid "Enter a valid e-mail address."
msgstr "Zadajte platnú e-mailovú adresu."
-#: core/validators.py:179
+#: core/validators.py:185
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
@@ -393,27 +397,27 @@ msgstr ""
"Nahrajte platný obrázok. Súbor, ktorý ste odoslali nebol obrázkový formát "
"alebo bol poškodený."
-#: core/validators.py:186
+#: core/validators.py:192
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "URL %s neodkazuje na platný obrázok."
-#: core/validators.py:190
+#: core/validators.py:196
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr ""
"Telefónne číslo musí mať formát XXX-XXX-XXXX. Číslo \"%s\" je neplatné."
-#: core/validators.py:198
+#: core/validators.py:204
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "URL %s neodkazuje na platné QuickTime video."
-#: core/validators.py:202
+#: core/validators.py:208
msgid "A valid URL is required."
msgstr "Je požadovaná platná adresa URL."
-#: core/validators.py:216
+#: core/validators.py:222
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
@@ -422,84 +426,84 @@ msgstr ""
"HTML kód musí zodpovedať špecifikácii. Zistené chyby sú:\n"
"%s"
-#: core/validators.py:223
+#: core/validators.py:229
#, python-format
msgid "Badly formed XML: %s"
msgstr "Chybné XML nezodpovedajúce definícii: %s"
-#: core/validators.py:240
+#: core/validators.py:246
#, python-format
msgid "Invalid URL: %s"
msgstr "Neplatná adresa URL: %s"
-#: core/validators.py:245 core/validators.py:247
+#: core/validators.py:251 core/validators.py:253
#, python-format
msgid "The URL %s is a broken link."
msgstr "Odkaz na URL %s je neplatný."
-#: core/validators.py:253
+#: core/validators.py:259
msgid "Enter a valid U.S. state abbreviation."
msgstr "Zadajte platnú skratku štátu USA."
-#: core/validators.py:267
+#: core/validators.py:273
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Vyjadrujte sa slušne! Slovo %s tu nie je dovolené použivať."
msgstr[1] "Vyjadrujte sa slušne! Slová %s tu nie je dovolené použivať."
-#: core/validators.py:274
+#: core/validators.py:280
#, python-format
msgid "This field must match the '%s' field."
msgstr "Toto pole sa musí zhodovať s poľom '%s'. "
-#: core/validators.py:293
+#: core/validators.py:299
msgid "Please enter something for at least one field."
msgstr "Prosím, vyplňte aspoň jedno pole."
-#: core/validators.py:302 core/validators.py:313
+#: core/validators.py:308 core/validators.py:319
msgid "Please enter both fields or leave them both empty."
msgstr "Prosím, vyplňte buď obidve polia, alebo ich nechajte prázdne."
-#: core/validators.py:321
+#: core/validators.py:327
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "Toto pole musí byť vyplnené ak, %(field)s je %(value)s"
-#: core/validators.py:334
+#: core/validators.py:340
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Toto pole musí byť vyplnené, ak %(field)s nie je %(value)s"
-#: core/validators.py:353
+#: core/validators.py:359
msgid "Duplicate values are not allowed."
msgstr "Duplicitné hodnoty nie sú povolené."
-#: core/validators.py:368
+#: core/validators.py:374
#, python-format
msgid "This value must be between %(lower)s and %(upper)s."
msgstr "Táto hodnota musí byť medzi %(lower)s a %(upper)s."
-#: core/validators.py:370
+#: core/validators.py:376
#, python-format
msgid "This value must be at least %s."
msgstr "Táto hodnota musí byť prinajmenšom %s."
-#: core/validators.py:372
+#: core/validators.py:378
#, python-format
msgid "This value must be no more than %s."
msgstr "Táto hodnota musí byť väčšia ako %s."
-#: core/validators.py:408
+#: core/validators.py:414
#, python-format
msgid "This value must be a power of %s."
msgstr "Táto hodnota musí byť mocninou %s."
-#: core/validators.py:417
+#: core/validators.py:424
msgid "Please enter a valid decimal number."
msgstr "Prosím, vložte platné desatinné číslo. "
-#: core/validators.py:423
+#: core/validators.py:431
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
@@ -507,7 +511,7 @@ msgid_plural ""
msgstr[0] "Prosím, vložte platné desatinné číslo. "
msgstr[1] "Prosím, vložte platné desatinné čísla. "
-#: core/validators.py:426
+#: core/validators.py:434
#, python-format
msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit."
@@ -516,7 +520,7 @@ msgid_plural ""
msgstr[0] "Prosím vlož platné desatinné číslo s najviac %s číslicou. "
msgstr[1] "Prosím vlož platné desatinné číslo s najviac %s číslicami."
-#: core/validators.py:429
+#: core/validators.py:437
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
@@ -526,34 +530,34 @@ msgstr[0] ""
msgstr[1] ""
"Prosím, vložte platné desatinné číslo s najviac %s desatinnými miestamy. "
-#: core/validators.py:437
+#: core/validators.py:445
msgid "Please enter a valid floating point number."
msgstr "Prosím, vložte platné číslo s pohyblivou desatinnou čiarkou. "
-#: core/validators.py:446
+#: core/validators.py:454
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "Uistite sa, že posielaný súbor nemá menej ako %s bajtov."
-#: core/validators.py:447
+#: core/validators.py:455
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "Uistite sa, že posielaný súbor nemá viac ako %s bajtov."
-#: core/validators.py:464
+#: core/validators.py:472
msgid "The format for this field is wrong."
msgstr "Formát pre toto pole je chybný."
-#: core/validators.py:479
+#: core/validators.py:487
msgid "This field is invalid."
msgstr "Toto pole nie je platné."
-#: core/validators.py:515
+#: core/validators.py:523
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "Z %s nič neprišlo."
-#: core/validators.py:518
+#: core/validators.py:526
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
@@ -561,7 +565,7 @@ msgstr ""
"Adresa URL %(url)s vrátila v hlavičke neplatný Content-Type '%(contenttype)"
"s'."
-#: core/validators.py:551
+#: core/validators.py:559
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
@@ -570,7 +574,7 @@ msgstr ""
"Prosím, uzatvorte tag %(tag)s na riadku %(line)s. (Riadok začína s \"%(start)"
"s\".)"
-#: core/validators.py:555
+#: core/validators.py:563
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
@@ -579,7 +583,7 @@ msgstr ""
"Text začínajúci na riadku %(line)s nie je povolený v tomto kontexte. (Riadok "
"začína s \"%(start)s\".)"
-#: core/validators.py:560
+#: core/validators.py:568
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
@@ -588,7 +592,7 @@ msgstr ""
"\"%(attr)s\" na riadku %(line)s je neplatný atribút. (Riadok začína s \"%"
"(start)s\".)"
-#: core/validators.py:565
+#: core/validators.py:573
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
@@ -597,7 +601,7 @@ msgstr ""
"\"<%(tag)s>\" na riadku %(line)s je neplatný tag. (Riadok začína s \"%(start)"
"s\".)"
-#: core/validators.py:569
+#: core/validators.py:577
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
@@ -606,7 +610,7 @@ msgstr ""
"V tagu na riadku %(line)s chýba jeden alebo viac atribútov. (Riadok začína s "
"\"%(start)s\".)"
-#: core/validators.py:574
+#: core/validators.py:582
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
@@ -630,79 +634,77 @@ msgstr "Objekt %(verbose_name)s bol úspešne zmenený."
msgid "The %(verbose_name)s was deleted."
msgstr "Objekt %(verbose_name)s bol zmazaný."
-#: newforms/models.py:172 newforms/fields.py:432
+#: newforms/models.py:174 newforms/fields.py:428
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr "Vyberte platnú možnosť. Vybraná položka nepatrí medzi platné možnosti."
-#: newforms/models.py:189 newforms/fields.py:448 newforms/fields.py:524
+#: newforms/models.py:191 newforms/fields.py:444 newforms/fields.py:520
msgid "Enter a list of values."
msgstr "Vložte zoznam hodnôt."
-#: newforms/models.py:195 newforms/fields.py:457
+#: newforms/models.py:197 newforms/fields.py:450
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
msgstr "Vyberte platnú možnost. %s nepatrí medzi dostupné možnosti."
-#: newforms/fields.py:110 newforms/fields.py:324
-#, python-format
-msgid "Ensure this value has at most %d characters."
-msgstr "Uistite sa, že hodnota má najviac %d znakov."
+#: newforms/fields.py:116
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr "Uistite sa, že hodnota má najviac %d znakov( teraz má %(length)d)."
-#: newforms/fields.py:112 newforms/fields.py:326
-#, python-format
-msgid "Ensure this value has at least %d characters."
-msgstr "Uistite sa, že zadaná hodnota má menej ako %d znakov."
+#: newforms/fields.py:118
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr "Uistite sa, že zadaná hodnota nemá menej ako %d znakov ( teraz má %(length)d)."
-#: newforms/fields.py:137 newforms/fields.py:160 newforms/fields.py:192
+#: newforms/fields.py:143 newforms/fields.py:166 newforms/fields.py:196
#, python-format
msgid "Ensure this value is less than or equal to %s."
msgstr "Uistite sa, že táto hodnota je menšia alebo rovná %s."
-#: newforms/fields.py:139 newforms/fields.py:162 newforms/fields.py:194
+#: newforms/fields.py:145 newforms/fields.py:168 newforms/fields.py:198
#, python-format
msgid "Ensure this value is greater than or equal to %s."
msgstr "Uistite sa, že hodnota je väčšia alebo rovná %s."
-#: newforms/fields.py:158 newforms/fields.py:186
+#: newforms/fields.py:164 newforms/fields.py:191
msgid "Enter a number."
msgstr "Zadajte číslo."
-#: newforms/fields.py:196
+#: newforms/fields.py:200
#, python-format
msgid "Ensure that there are no more than %s digits in total."
-msgstr ""
+msgstr "Zabezpečte aby výraz nemal celkom viac ako %s číslic ."
-#: newforms/fields.py:198
+#: newforms/fields.py:202
#, python-format
msgid "Ensure that there are no more than %s decimal places."
msgstr "Zabezpečte aby nebolo viac ako %s desatinných miest."
-#: newforms/fields.py:200
+#: newforms/fields.py:204
#, python-format
msgid "Ensure that there are no more than %s digits before the decimal point."
msgstr "Zabezpečte aby nebolo viac ako %s číslic pred desatinnou bodkou."
-#: newforms/fields.py:233
+#: newforms/fields.py:237 newforms/fields.py:560
msgid "Enter a valid date."
msgstr "Zadajte platný dátum."
-#: newforms/fields.py:260
+#: newforms/fields.py:264 newforms/fields.py:562
msgid "Enter a valid time."
msgstr "Zadajte platný čas."
-#: newforms/fields.py:296
+#: newforms/fields.py:300
msgid "Enter a valid date/time."
msgstr "Zadajte platný dátum a čas."
-#: newforms/fields.py:310
+#: newforms/fields.py:313
msgid "Enter a valid value."
msgstr "Zadajte platnú hodnotu."
-#: newforms/fields.py:357 newforms/fields.py:379
+#: newforms/fields.py:353 newforms/fields.py:375
msgid "Enter a valid URL."
msgstr "Zadajte platnú adresu URL."
-#: newforms/fields.py:381
+#: newforms/fields.py:377
msgid "This URL appears to be a broken link."
msgstr "Odkaz na URL neexistuje."
@@ -868,7 +870,7 @@ msgstr "dátum a čas odoslania"
msgid "is public"
msgstr "je verejný"
-#: contrib/comments/models.py:85 contrib/admin/views/doc.py:305
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:306
msgid "IP address"
msgstr "IP adresa"
@@ -993,24 +995,24 @@ msgstr "Zmazané moderátorom"
msgid "Moderator deletion by %r"
msgstr "Zmazanané moderátorom %r"
-#: contrib/comments/views/karma.py:19
+#: contrib/comments/views/karma.py:20
msgid "Anonymous users cannot vote"
msgstr "Hlasovať môžu len prihlásení užívatelia"
-#: contrib/comments/views/karma.py:23
+#: contrib/comments/views/karma.py:24
msgid "Invalid comment ID"
msgstr "Chybné ID komentára"
-#: contrib/comments/views/karma.py:25
+#: contrib/comments/views/karma.py:26
msgid "No voting for yourself"
msgstr "Nemôžete hlasovať za samého seba"
-#: contrib/comments/views/comments.py:27
+#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr "Toto hlasovanie je nevyhnutné, lebo súvisí s predchádzjúcou voľbou."
-#: contrib/comments/views/comments.py:111
+#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
@@ -1031,7 +1033,7 @@ msgstr[1] ""
"príspevkov .\n"
"%(text)s"
-#: contrib/comments/views/comments.py:116
+#: contrib/comments/views/comments.py:117
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
@@ -1042,32 +1044,32 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
msgid "Only POSTs are allowed"
msgstr "Dovolené sú len POST"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
msgid "One or more of the required fields wasn't submitted"
msgstr "Jedno alebo viac povinných polí nebolo vložených"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
msgid "Somebody tampered with the comment form (security violation)"
msgstr ""
"Niekto sa pokúšal manipulovať s formulárom komentára (porušenie bezpečnosti)"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
msgstr ""
"Formulár komentára ma chybný 'target' parameter -- ID objektu je neplatné"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr ""
"Formulár komentára neobsahuje ani jednu z možností 'náhľad' alebo 'odoslať'."
@@ -1141,23 +1143,23 @@ msgstr "Nepovinné"
msgid "Post a photo"
msgstr "Pošli foto"
-#: contrib/sites/models.py:10
+#: contrib/sites/models.py:15
msgid "domain name"
msgstr "názov domény"
-#: contrib/sites/models.py:11
+#: contrib/sites/models.py:16
msgid "display name"
msgstr "zobrazené meno"
-#: contrib/sites/models.py:15
+#: contrib/sites/models.py:20
msgid "site"
msgstr "web"
-#: contrib/sites/models.py:16
+#: contrib/sites/models.py:21
msgid "sites"
msgstr "weby"
-#: contrib/admin/filterspecs.py:40
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
@@ -1166,60 +1168,60 @@ msgstr ""
"<h3>Od %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Všetko"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Lubovoľný dátum"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Dnes"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
msgstr "Posledných 7 dní"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Tento mesiac"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
msgstr "Tento rok"
-#: contrib/admin/models.py:16
+#: contrib/admin/models.py:17
msgid "action time"
msgstr "čas udalosti"
-#: contrib/admin/models.py:19
+#: contrib/admin/models.py:20
msgid "object id"
msgstr "id objektu"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object repr"
msgstr "objekt repr"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "action flag"
msgstr "príznak udalosti"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "change message"
msgstr "zmeniť zprávu"
-#: contrib/admin/models.py:25
+#: contrib/admin/models.py:26
msgid "log entry"
msgstr "záznam priebehu"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entries"
msgstr "záznamy priebehu"
-#: contrib/admin/templatetags/admin_list.py:249
+#: contrib/admin/templatetags/admin_list.py:254
msgid "All dates"
msgstr "Všetky dátumy"
@@ -1261,68 +1263,68 @@ msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr ""
"Vaša e-mailová adresa nie je užívateľským menom. Skúste použiť meno '%s'."
-#: contrib/admin/views/auth.py:19 contrib/admin/views/main.py:257
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "Objekt %(name)s \"%(obj)s\" bol úspešne pridaný."
-#: contrib/admin/views/auth.py:24 contrib/admin/views/main.py:261
-#: contrib/admin/views/main.py:347
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
+#: contrib/admin/views/main.py:354
msgid "You may edit it again below."
msgstr "Môžete pokračovať v zmenách."
-#: contrib/admin/views/auth.py:30
+#: contrib/admin/views/auth.py:31
msgid "Add user"
msgstr "Pridať užívateľa"
-#: contrib/admin/views/auth.py:57
+#: contrib/admin/views/auth.py:58
msgid "Password changed successfully."
msgstr "Heslo bolo úspešne zmenené."
-#: contrib/admin/views/auth.py:64
+#: contrib/admin/views/auth.py:65
#, python-format
msgid "Change password: %s"
msgstr "Zmeniť heslo: %s"
-#: contrib/admin/views/main.py:223
+#: contrib/admin/views/main.py:230
msgid "Site administration"
msgstr "Administrácia"
-#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
#, python-format
msgid "You may add another %s below."
msgstr "Môžete pokračovať v pridávaní ďaľších %s."
-#: contrib/admin/views/main.py:289
+#: contrib/admin/views/main.py:296
#, python-format
msgid "Add %s"
msgstr "Pridaj %s"
-#: contrib/admin/views/main.py:335
+#: contrib/admin/views/main.py:342
#, python-format
msgid "Added %s."
msgstr "Bol pridaný %s."
-#: contrib/admin/views/main.py:337
+#: contrib/admin/views/main.py:344
#, python-format
msgid "Changed %s."
msgstr "Bol zmenený %s"
-#: contrib/admin/views/main.py:339
+#: contrib/admin/views/main.py:346
#, python-format
msgid "Deleted %s."
msgstr "Bol vymazaný %s."
-#: contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:349
msgid "No fields changed."
msgstr "Polia neboli zmenené."
-#: contrib/admin/views/main.py:345
+#: contrib/admin/views/main.py:352
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "Objekt %(name)s \"%(obj)s\" boli úspešne zmenený."
-#: contrib/admin/views/main.py:353
+#: contrib/admin/views/main.py:360
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
@@ -1330,181 +1332,181 @@ msgstr ""
"Objekt %(name)s \"%(obj)s\" bol úspešne zmenený. Ďalšie zmeny môžeš urobiť "
"zase nižšie."
-#: contrib/admin/views/main.py:391
+#: contrib/admin/views/main.py:398
#, python-format
msgid "Change %s"
msgstr "Zmeniť %s"
-#: contrib/admin/views/main.py:476
+#: contrib/admin/views/main.py:483
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "Jeden alebo viac %(fieldname)s v %(name)s: %(obj)s"
-#: contrib/admin/views/main.py:481
+#: contrib/admin/views/main.py:488
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
msgstr "Jeden alebo viac %(fieldname)s v %(name)s:"
-#: contrib/admin/views/main.py:514
+#: contrib/admin/views/main.py:520
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "Objekt %(name)s \"%(obj)s\" bol úspešne vymazaný."
-#: contrib/admin/views/main.py:517
+#: contrib/admin/views/main.py:523
msgid "Are you sure?"
msgstr "Ste si istý?"
-#: contrib/admin/views/main.py:539
+#: contrib/admin/views/main.py:545
#, python-format
msgid "Change history: %s"
msgstr "Zmeniť históriu: %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s"
msgstr "Výber %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s to change"
msgstr "Ktorý %s sa má zmeniť?"
-#: contrib/admin/views/main.py:768
+#: contrib/admin/views/main.py:780
msgid "Database error"
msgstr "Chyba databázy"
-#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
msgid "tag:"
msgstr "označovač:"
-#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
msgid "filter:"
msgstr ""
-#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
msgid "view:"
msgstr "prehľad:"
-#: contrib/admin/views/doc.py:164
+#: contrib/admin/views/doc.py:165
#, python-format
msgid "App %r not found"
msgstr "Aplikáciu %r sa nepodarilo nájsť."
-#: contrib/admin/views/doc.py:171
+#: contrib/admin/views/doc.py:172
#, python-format
msgid "Model %(name)r not found in app %(label)r"
msgstr "Model %(name)r sa nenachádza v aplikácii %(label)r"
-#: contrib/admin/views/doc.py:183
+#: contrib/admin/views/doc.py:184
#, python-format
msgid "the related `%(label)s.%(type)s` object"
msgstr "Prepojenie na objekt `%(label)s.%(type)s`"
-#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
-#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
msgid "model:"
msgstr ""
-#: contrib/admin/views/doc.py:214
+#: contrib/admin/views/doc.py:215
#, python-format
msgid "related `%(label)s.%(name)s` objects"
msgstr "súvisiace objekty `%(label)s.%(name)s`"
-#: contrib/admin/views/doc.py:219
+#: contrib/admin/views/doc.py:220
#, python-format
msgid "all %s"
msgstr "všetky %s"
-#: contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:225
#, python-format
msgid "number of %s"
msgstr "počet %s"
-#: contrib/admin/views/doc.py:229
+#: contrib/admin/views/doc.py:230
#, python-format
msgid "Fields on %s objects"
msgstr "Polia objektu %s"
-#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:302
-#: contrib/admin/views/doc.py:304 contrib/admin/views/doc.py:310
-#: contrib/admin/views/doc.py:311 contrib/admin/views/doc.py:313
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
msgid "Integer"
msgstr "Celé číslo"
-#: contrib/admin/views/doc.py:292
+#: contrib/admin/views/doc.py:293
msgid "Boolean (Either True or False)"
msgstr "Logická hodnota (True alebo False)"
-#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:312
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "Dĺžka reťazca (maximálne do %(maxlength)s znakov)"
-#: contrib/admin/views/doc.py:294
+#: contrib/admin/views/doc.py:295
msgid "Comma-separated integers"
msgstr "Celé čísla oddelené čiarkou"
-#: contrib/admin/views/doc.py:295
+#: contrib/admin/views/doc.py:296
msgid "Date (without time)"
msgstr "Dátum (bez času)"
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:297
msgid "Date (with time)"
msgstr "Dátum (a čas)"
-#: contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:298
msgid "Decimal number"
msgstr "Desatinné číslo"
-#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:299
msgid "E-mail address"
msgstr "E-mailová adresa"
-#: contrib/admin/views/doc.py:299 contrib/admin/views/doc.py:300
-#: contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
msgid "File path"
msgstr "Cesta k súboru"
-#: contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:302
msgid "Floating point number"
msgstr "Císlo s pohyblivou čiarkou"
-#: contrib/admin/views/doc.py:307
+#: contrib/admin/views/doc.py:308
msgid "Boolean (Either True, False or None)"
msgstr "Logická hodnota (True, False alebo None)"
-#: contrib/admin/views/doc.py:308
+#: contrib/admin/views/doc.py:309
msgid "Relation to parent model"
msgstr "Má vzťah k nadradenému modelu"
-#: contrib/admin/views/doc.py:309
+#: contrib/admin/views/doc.py:310
msgid "Phone number"
msgstr "Číslo telefónu"
-#: contrib/admin/views/doc.py:314
+#: contrib/admin/views/doc.py:315
msgid "Text"
msgstr "Text"
-#: contrib/admin/views/doc.py:315
+#: contrib/admin/views/doc.py:316
msgid "Time"
msgstr "Čas"
-#: contrib/admin/views/doc.py:316 contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
-#: contrib/admin/views/doc.py:317
+#: contrib/admin/views/doc.py:318
msgid "U.S. state (two uppercase letters)"
msgstr "Štát USA (dve veľké písmena)"
-#: contrib/admin/views/doc.py:318
+#: contrib/admin/views/doc.py:319
msgid "XML text"
msgstr "XML text"
-#: contrib/admin/views/doc.py:344
+#: contrib/admin/views/doc.py:345
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s nie je urlpattern objekt"
@@ -2005,51 +2007,51 @@ msgstr "Editácia tohoto objektu (v novom okne)"
msgid "As above, but opens the admin page in a new window."
msgstr "To isté ako predtým, akurát otvorí administračnú stránku v novom okne."
-#: contrib/contenttypes/models.py:36
+#: contrib/contenttypes/models.py:37
msgid "python model class name"
msgstr "pythonové meno triedy modelu"
-#: contrib/contenttypes/models.py:39
+#: contrib/contenttypes/models.py:40
msgid "content type"
msgstr "typ obsahu"
-#: contrib/contenttypes/models.py:40
+#: contrib/contenttypes/models.py:41
msgid "content types"
msgstr "typy obsahu"
-#: contrib/auth/views.py:40
+#: contrib/auth/views.py:41
msgid "Logged out"
msgstr "Odhlásený"
-#: contrib/auth/models.py:44 contrib/auth/models.py:64
+#: contrib/auth/models.py:51 contrib/auth/models.py:71
msgid "name"
msgstr "meno"
-#: contrib/auth/models.py:46
+#: contrib/auth/models.py:53
msgid "codename"
msgstr "codename"
-#: contrib/auth/models.py:49
+#: contrib/auth/models.py:56
msgid "permission"
msgstr "povolenie"
-#: contrib/auth/models.py:50 contrib/auth/models.py:65
+#: contrib/auth/models.py:57 contrib/auth/models.py:72
msgid "permissions"
msgstr "práva"
-#: contrib/auth/models.py:68
+#: contrib/auth/models.py:75
msgid "group"
msgstr "skupina"
-#: contrib/auth/models.py:69 contrib/auth/models.py:109
+#: contrib/auth/models.py:76 contrib/auth/models.py:116
msgid "groups"
msgstr "skupiny"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid "username"
msgstr "užívateľské meno"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
@@ -2057,23 +2059,23 @@ msgstr ""
"Povinná položka s dĺžkou 30 znakov alebo menej. Povolené sú len "
"alfanumerické znaky (písmená, čísla a podtržník)."
-#: contrib/auth/models.py:100
+#: contrib/auth/models.py:107
msgid "first name"
msgstr "krstné meno"
-#: contrib/auth/models.py:101
+#: contrib/auth/models.py:108
msgid "last name"
msgstr "priezvisko"
-#: contrib/auth/models.py:102
+#: contrib/auth/models.py:109
msgid "e-mail address"
msgstr "e-mailová adresa"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid "password"
msgstr "heslo"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
@@ -2081,20 +2083,20 @@ msgstr ""
"Použite '[algo]$[salt]$[hexdigest]' alebo <a href=\"password/\">formulár na "
"zmenu hesla</a>."
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "staff status"
msgstr "zamestnanec"
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "Designates whether the user can log into this admin site."
msgstr ""
"Určuje, či má užívateľ oprávnenie prihlásiť sa do administračnej časti."
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid "active"
msgstr "aktívny"
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid ""
"Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts."
@@ -2102,11 +2104,11 @@ msgstr ""
"Určuje, či je účet aktívny. Odškrtnite, ak chcete deaktivovať užívateľský "
"účet."
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid "superuser status"
msgstr "superužívateľ"
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
@@ -2114,15 +2116,15 @@ msgstr ""
"Určuje, či užívateľ získava automaticky všetky práva aj bez priameho "
"priradenia."
-#: contrib/auth/models.py:107
+#: contrib/auth/models.py:114
msgid "last login"
msgstr "naposledy prihlásený"
-#: contrib/auth/models.py:108
+#: contrib/auth/models.py:115
msgid "date joined"
msgstr "dátum registrácie"
-#: contrib/auth/models.py:110
+#: contrib/auth/models.py:117
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@@ -2130,42 +2132,38 @@ msgstr ""
"Okrem ručne zadaných práv bude mať užívateľ aj všetky práva prislúchajúce "
"skupinám, v ktorých sa nachádza."
-#: contrib/auth/models.py:111
+#: contrib/auth/models.py:118
msgid "user permissions"
msgstr "užívateľské práva"
-#: contrib/auth/models.py:115
+#: contrib/auth/models.py:122
msgid "user"
msgstr "uživateľ"
-#: contrib/auth/models.py:116
+#: contrib/auth/models.py:123
msgid "users"
msgstr "užívatelia"
-#: contrib/auth/models.py:122
+#: contrib/auth/models.py:129
msgid "Personal info"
msgstr "Osobné údaje"
-#: contrib/auth/models.py:123
+#: contrib/auth/models.py:130
msgid "Permissions"
msgstr "Práva"
-#: contrib/auth/models.py:124
+#: contrib/auth/models.py:131
msgid "Important dates"
msgstr "Dôležité dátumy"
-#: contrib/auth/models.py:125
+#: contrib/auth/models.py:132
msgid "Groups"
msgstr "Skupiny"
-#: contrib/auth/models.py:269
+#: contrib/auth/models.py:274
msgid "message"
msgstr "správa"
-#: contrib/auth/models.py:282
-msgid "AnonymousUser"
-msgstr "Neregistrovaný užívateľ"
-
#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match."
msgstr "Pole hesla a jeho potvrdenie sa nezhodujú."
@@ -2619,7 +2617,7 @@ msgstr ""
msgid "Zurich"
msgstr ""
-#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:15
+#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:14
msgid "Enter a zip code in the format XXXX."
msgstr "Vložte poštové smerovacie číslo v tvare XXXX."
@@ -2629,12 +2627,12 @@ msgid ""
"1234567890 format."
msgstr ""
-#: contrib/localflavor/is_/forms.py:16
+#: contrib/localflavor/is_/forms.py:17
msgid ""
"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
msgstr "Zadajte platné Islanské číslo v tvare XXXXXX-XXXX."
-#: contrib/localflavor/is_/forms.py:30
+#: contrib/localflavor/is_/forms.py:31
msgid "The Icelandic identification number is not valid."
msgstr ""
@@ -2650,16 +2648,368 @@ msgstr "Vložte platné číslo sociálneho poistenia ."
msgid "Enter a valid VAT number."
msgstr "Zadajte platné VAT číslo."
-#: contrib/localflavor/no/forms.py:36
+#: contrib/localflavor/no/forms.py:35
msgid "Enter a valid Norwegian social security number."
msgstr ""
"Vložte platné nórske číslo sociálneho poistenia (social security number)."
-#: contrib/localflavor/cl/forms.py:21
+#: contrib/localflavor/sk/sk_regions.py:8
+msgid "Banska Bystrica region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:9
+msgid "Bratislava region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:10
+msgid "Kosice region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:11
+msgid "Nitra region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:12
+msgid "Presov region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:13
+msgid "Trencin region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:14
+msgid "Trnava region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_regions.py:15
+msgid "Zilina region"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:8
+msgid "Banska Bystrica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:9
+msgid "Banska Stiavnica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:10
+msgid "Bardejov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:11
+msgid "Banovce nad Bebravou"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:12
+msgid "Brezno"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:13
+msgid "Bratislava I"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:14
+msgid "Bratislava II"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:15
+msgid "Bratislava III"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:16
+msgid "Bratislava IV"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:17
+msgid "Bratislava V"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:18
+msgid "Bytca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:19
+msgid "Cadca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:20
+msgid "Detva"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:21
+msgid "Dolny Kubin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:22
+msgid "Dunajska Streda"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:23
+msgid "Galanta"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:24
+msgid "Gelnica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:25
+msgid "Hlohovec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:26
+msgid "Humenne"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:27
+msgid "Ilava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:28
+msgid "Kezmarok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:29
+msgid "Komarno"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:30
+msgid "Kosice I"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:31
+msgid "Kosice II"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:32
+msgid "Kosice III"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:33
+msgid "Kosice IV"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:34
+msgid "Kosice - okolie"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:35
+msgid "Krupina"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:36
+msgid "Kysucke Nove Mesto"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:37
+msgid "Levice"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:38
+msgid "Levoca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:39
+msgid "Liptovsky Mikulas"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:40
+msgid "Lucenec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:41
+msgid "Malacky"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:42
+msgid "Martin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:43
+msgid "Medzilaborce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:44
+msgid "Michalovce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:45
+msgid "Myjava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:46
+msgid "Namestovo"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:47
+msgid "Nitra"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:48
+msgid "Nove Mesto nad Vahom"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:49
+msgid "Nove Zamky"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:50
+msgid "Partizanske"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:51
+msgid "Pezinok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:52
+msgid "Piestany"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:53
+msgid "Poltar"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:54
+msgid "Poprad"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:55
+msgid "Povazska Bystrica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:56
+msgid "Presov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:57
+msgid "Prievidza"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:58
+msgid "Puchov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:59
+msgid "Revuca"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:60
+msgid "Rimavska Sobota"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:61
+msgid "Roznava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:62
+msgid "Ruzomberok"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:63
+msgid "Sabinov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:64
+msgid "Senec"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:65
+msgid "Senica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:66
+msgid "Skalica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:67
+msgid "Snina"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:68
+msgid "Sobrance"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:69
+msgid "Spisska Nova Ves"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:70
+msgid "Stara Lubovna"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:71
+msgid "Stropkov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:72
+msgid "Svidnik"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:73
+msgid "Sala"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:74
+msgid "Topolcany"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:75
+msgid "Trebisov"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:76
+msgid "Trencin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:77
+msgid "Trnava"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:78
+msgid "Turcianske Teplice"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:79
+msgid "Tvrdosin"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:80
+msgid "Velky Krtis"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:81
+msgid "Vranov nad Toplou"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:82
+msgid "Zlate Moravce"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:83
+msgid "Zvolen"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:84
+msgid "Zarnovica"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:85
+msgid "Ziar nad Hronom"
+msgstr ""
+
+#: contrib/localflavor/sk/sk_districts.py:86
+msgid "Zilina"
+msgstr ""
+
+#: contrib/localflavor/sk/forms.py:32
+msgid "Enter a postal code in the format XXXXX or XXX XX."
+msgstr "Zadajte poštové smerovacie číslo v tvare XXXXX alebo XXX-XX."
+
+#: contrib/localflavor/cl/forms.py:32
msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
msgstr ""
-#: contrib/localflavor/cl/forms.py:26
+#: contrib/localflavor/cl/forms.py:37
msgid "Enter valid a Chilean RUT"
msgstr ""
@@ -2763,127 +3113,155 @@ msgstr "Sobota"
msgid "Sunday"
msgstr "Nedeľa"
-#: utils/dates.py:14
+#: utils/dates.py:10
+msgid "Mon"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr ""
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr ""
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr ""
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr ""
+
+#: utils/dates.py:18
msgid "January"
msgstr "Január"
-#: utils/dates.py:14
+#: utils/dates.py:18
msgid "February"
msgstr "Február"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "Marec"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "Apríl"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Máj"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Jún"
-#: utils/dates.py:15 utils/dates.py:27
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Júl"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "August"
msgstr "August"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "September"
msgstr "September"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "October"
msgstr "Október"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "November"
msgstr "November"
-#: utils/dates.py:16
+#: utils/dates.py:20
msgid "December"
msgstr "December"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jan"
msgstr "jan"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "feb"
msgstr "feb"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "mar"
msgstr "mar"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "apr"
msgstr "apr"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "may"
msgstr "máj"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jun"
msgstr "jún"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "jul"
msgstr "júl"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "aug"
msgstr "aug"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "sep"
msgstr "sep"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "oct"
msgstr "okt"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "nov"
msgstr "nov"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "dec"
msgstr "dec"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Jan."
msgstr "Jan."
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Feb."
msgstr "Feb."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Aug."
msgstr "Aug."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Sept."
msgstr "Sept."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Oct."
msgstr "Okt."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Nov."
msgstr "Nov."
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Dec."
msgstr "Dec."
@@ -2923,87 +3301,85 @@ msgid_plural "minutes"
msgstr[0] "minúta"
msgstr[1] "minúty"
-#: utils/timesince.py:40
-#, python-format
-msgid "%d milliseconds"
-msgstr ""
-
-#: utils/timesince.py:41
+#: utils/timesince.py:39
#, python-format
msgid "%(number)d %(type)s"
msgstr ""
-#: utils/timesince.py:47
+#: utils/timesince.py:45
#, python-format
msgid ", %(number)d %(type)s"
msgstr ""
-#: utils/dateformat.py:40
+#: utils/dateformat.py:41
msgid "p.m."
msgstr "p.m."
-#: utils/dateformat.py:41
+#: utils/dateformat.py:42
msgid "a.m."
msgstr "a.m."
-#: utils/dateformat.py:46
+#: utils/dateformat.py:47
msgid "PM"
msgstr ""
-#: utils/dateformat.py:47
+#: utils/dateformat.py:48
msgid "AM"
msgstr ""
-#: utils/dateformat.py:95
+#: utils/dateformat.py:97
msgid "midnight"
msgstr "polnoc"
-#: utils/dateformat.py:97
+#: utils/dateformat.py:99
msgid "noon"
msgstr "poludnie"
-#: utils/translation/trans_real.py:358
+#: utils/translation/trans_real.py:391
msgid "DATE_FORMAT"
msgstr ""
-#: utils/translation/trans_real.py:359
+#: utils/translation/trans_real.py:392
msgid "DATETIME_FORMAT"
msgstr ""
-#: utils/translation/trans_real.py:360
+#: utils/translation/trans_real.py:393
msgid "TIME_FORMAT"
msgstr ""
-#: utils/translation/trans_real.py:376
+#: utils/translation/trans_real.py:409
msgid "YEAR_MONTH_FORMAT"
msgstr ""
-#: utils/translation/trans_real.py:377
+#: utils/translation/trans_real.py:410
msgid "MONTH_DAY_FORMAT"
msgstr ""
-#: template/defaultfilters.py:491
+#: template/defaultfilters.py:485
msgid "yes,no,maybe"
msgstr "áno,nie,možno"
-#: template/defaultfilters.py:520
+#: template/defaultfilters.py:514
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] ""
msgstr[1] ""
-#: template/defaultfilters.py:522
+#: template/defaultfilters.py:516
#, python-format
msgid "%.1f KB"
msgstr ""
-#: template/defaultfilters.py:524
+#: template/defaultfilters.py:518
#, python-format
msgid "%.1f MB"
msgstr ""
-#: template/defaultfilters.py:525
+#: template/defaultfilters.py:519
#, python-format
msgid "%.1f GB"
msgstr ""
+
+#~ msgid "AnonymousUser"
+#~ msgstr "Neregistrovaný užívateľ"
diff --git a/django/conf/locale/sl/LC_MESSAGES/django.mo b/django/conf/locale/sl/LC_MESSAGES/django.mo
index a96fd554ef..58e5bd836a 100644
--- a/django/conf/locale/sl/LC_MESSAGES/django.mo
+++ b/django/conf/locale/sl/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/sl/LC_MESSAGES/django.po b/django/conf/locale/sl/LC_MESSAGES/django.po
index b0617a5bd8..80dfeb2cfe 100644
--- a/django/conf/locale/sl/LC_MESSAGES/django.po
+++ b/django/conf/locale/sl/LC_MESSAGES/django.po
@@ -1,18 +1,13 @@
# translation of django.po to Slovenian
-# Igor Kolar <ike@email.si), 2006.
-# Nena Kojadin <nena@kiberpipa.org), 2006.
-# Jure Cuhalev <gandalf@owca.info>, 2006, 2007.
-# Gasper Koren <gasper@fdvinfo.net>, 2007.
-# Jozko Skrablin <jozko.skrablin@gmail.com>, 2007.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-05-16 10:13+0200\n"
-"PO-Revision-Date: 2007-02-15 21:47+0100\n"
-"Last-Translator: Gasper Koren <gasper@fdvinfo.net>\n"
+"POT-Creation-Date: 2007-07-02 13:55+0200\n"
+"PO-Revision-Date: 2007-07-02 14:47+0100\n"
+"Last-Translator: Gasper Koren <skrat@owca.info>\n"
"Language-Team: Slovenian <lugos-slo@lugos.si>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,336 +15,731 @@ msgstr ""
"X-Generator: KBabel 1.11.2\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
-#: contrib/comments/models.py:67
-#: contrib/comments/models.py:166
-msgid "object ID"
-msgstr "ID objekta"
+#: db/models/manipulators.py:307
+#, python-format
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "%(object)s s tem %(type)s že obstaja za dane %(field)s."
-#: contrib/comments/models.py:68
-msgid "headline"
-msgstr "naslov"
+#: db/models/manipulators.py:308
+#: contrib/admin/views/main.py:340
+#: contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344
+msgid "and"
+msgstr "in"
-#: contrib/comments/models.py:69
-#: contrib/comments/models.py:90
-#: contrib/comments/models.py:167
-msgid "comment"
-msgstr "komentar"
+#: db/models/fields/related.py:54
+#, python-format
+msgid "Please enter a valid %s."
+msgstr "Prosimo, vnesite veljaven %s."
-#: contrib/comments/models.py:70
-msgid "rating #1"
-msgstr "rating #1"
+#: db/models/fields/related.py:640
+msgid "Separate multiple IDs with commas."
+msgstr "Več ID-jev ločite z vejicami."
-#: contrib/comments/models.py:71
-msgid "rating #2"
-msgstr "rating #2"
+#: db/models/fields/related.py:642
+msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr "Držite \"Control\" (ali \"Command\" na Mac-u), za izbiro več kot enega."
-#: contrib/comments/models.py:72
-msgid "rating #3"
-msgstr "rating #3"
+#: db/models/fields/related.py:689
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] "Prosimo, vnesite veljavne %(self)s ID-e. Vrednost %(value)r ni veljavna."
+msgstr[1] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r nista veljavni."
+msgstr[2] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne."
+msgstr[3] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne."
-#: contrib/comments/models.py:73
-msgid "rating #4"
-msgstr "rating #4"
+#: db/models/fields/__init__.py:46
+#, python-format
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "%(optname)s s tem %(fieldname)s že obstaja."
-#: contrib/comments/models.py:74
-msgid "rating #5"
-msgstr "rating #5"
+#: db/models/fields/__init__.py:126
+#: db/models/fields/__init__.py:283
+#: db/models/fields/__init__.py:680
+#: db/models/fields/__init__.py:691
+#: oldforms/__init__.py:357
+#: newforms/fields.py:87
+#: newforms/fields.py:444
+#: newforms/fields.py:523
+#: newforms/fields.py:534
+#: newforms/models.py:185
+msgid "This field is required."
+msgstr "To polje je obvezno"
-#: contrib/comments/models.py:75
-msgid "rating #6"
-msgstr "rating #6"
+#: db/models/fields/__init__.py:378
+msgid "This value must be an integer."
+msgstr "Ta vrednost mora biti celo število."
-#: contrib/comments/models.py:76
-msgid "rating #7"
-msgstr "rating #7"
+#: db/models/fields/__init__.py:413
+msgid "This value must be either True or False."
+msgstr "Ta vrednost mora biti \"True\" ali \"False\"."
-#: contrib/comments/models.py:77
-msgid "rating #8"
-msgstr "rating #8"
+#: db/models/fields/__init__.py:434
+msgid "This field cannot be null."
+msgstr "To polje ne more biti prazno."
-#: contrib/comments/models.py:82
-msgid "is valid rating"
-msgstr "je veljavni rating"
+#: db/models/fields/__init__.py:468
+#: core/validators.py:149
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "Vnesite veljavni datum v zapisu YYYY-MM-DD (leto-mesec-dan)."
-#: contrib/comments/models.py:83
-#: contrib/comments/models.py:169
-msgid "date/time submitted"
-msgstr "datum/čas vnosa"
+#: db/models/fields/__init__.py:537
+#: core/validators.py:158
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "Vnesite veljavni datum/čas v zapisu YYYY-MM-DD HH:MM (leto-mesec-dan ura:minuta)"
-#: contrib/comments/models.py:84
-#: contrib/comments/models.py:170
-msgid "is public"
-msgstr "je javno"
+#: db/models/fields/__init__.py:597
+msgid "This value must be a decimal number."
+msgstr "Ta vrednost mora biti decimalno število."
-#: contrib/comments/models.py:85
-#: contrib/admin/views/doc.py:289
-msgid "IP address"
-msgstr "IP naslov"
+#: db/models/fields/__init__.py:700
+msgid "Enter a valid filename."
+msgstr "Vnesite veljavno ime datoteke."
-#: contrib/comments/models.py:86
-msgid "is removed"
-msgstr "je odstranjen/-a"
+#: db/models/fields/__init__.py:825
+msgid "This value must be either None, True or False."
+msgstr "Ta vrednost mora biti None, True ali False."
-#: contrib/comments/models.py:86
-msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead."
-msgstr "Odkljukaj, če je komentar neprimeren. Namesto komentarja bo vidno obvestilo \"Ta komentar je bil odstranjen\"."
+#: conf/global_settings.py:39
+msgid "Arabic"
+msgstr "Arabščina"
-#: contrib/comments/models.py:91
-msgid "comments"
-msgstr "komentarji"
+#: conf/global_settings.py:40
+msgid "Bengali"
+msgstr "Bengalski"
-#: contrib/comments/models.py:131
-#: contrib/comments/models.py:207
-msgid "Content object"
-msgstr "Objekt z vsebino"
+#: conf/global_settings.py:41
+msgid "Bulgarian"
+msgstr "Bolgarščina"
-#: contrib/comments/models.py:159
+#: conf/global_settings.py:42
+msgid "Catalan"
+msgstr "Katalonščina"
+
+#: conf/global_settings.py:43
+msgid "Czech"
+msgstr "Češki"
+
+#: conf/global_settings.py:44
+msgid "Welsh"
+msgstr "Valežanski"
+
+#: conf/global_settings.py:45
+msgid "Danish"
+msgstr "Danski"
+
+#: conf/global_settings.py:46
+msgid "German"
+msgstr "Nemški"
+
+#: conf/global_settings.py:47
+msgid "Greek"
+msgstr "Grški"
+
+#: conf/global_settings.py:48
+msgid "English"
+msgstr "Angleški"
+
+#: conf/global_settings.py:49
+msgid "Spanish"
+msgstr "Španski"
+
+#: conf/global_settings.py:50
+msgid "Argentinean Spanish"
+msgstr "Španščina (Argentina)"
+
+#: conf/global_settings.py:51
+msgid "Persian"
+msgstr "Perzijščina"
+
+#: conf/global_settings.py:52
+msgid "Finnish"
+msgstr "Finščina"
+
+#: conf/global_settings.py:53
+msgid "French"
+msgstr "Francoski"
+
+#: conf/global_settings.py:54
+msgid "Galician"
+msgstr "Galičanski"
+
+#: conf/global_settings.py:55
+msgid "Hungarian"
+msgstr "Madžarski"
+
+#: conf/global_settings.py:56
+msgid "Hebrew"
+msgstr "Hebrejski"
+
+#: conf/global_settings.py:57
+msgid "Icelandic"
+msgstr "Islandski"
+
+#: conf/global_settings.py:58
+msgid "Italian"
+msgstr "Italijanski"
+
+#: conf/global_settings.py:59
+msgid "Japanese"
+msgstr "Japonski"
+
+#: conf/global_settings.py:60
+msgid "Korean"
+msgstr "Korejščina"
+
+#: conf/global_settings.py:61
+msgid "Kannada"
+msgstr "Kanareščina"
+
+#: conf/global_settings.py:62
+msgid "Latvian"
+msgstr "Latvijščina"
+
+#: conf/global_settings.py:63
+msgid "Macedonian"
+msgstr "Makedonščina"
+
+#: conf/global_settings.py:64
+msgid "Dutch"
+msgstr "Nizozemski"
+
+#: conf/global_settings.py:65
+msgid "Norwegian"
+msgstr "Norveški"
+
+#: conf/global_settings.py:66
+msgid "Polish"
+msgstr "Poljščina"
+
+#: conf/global_settings.py:67
+msgid "Portugese"
+msgstr "Portugalščina"
+
+#: conf/global_settings.py:68
+msgid "Brazilian"
+msgstr "Brazilski"
+
+#: conf/global_settings.py:69
+msgid "Romanian"
+msgstr "Romunski"
+
+#: conf/global_settings.py:70
+msgid "Russian"
+msgstr "Ruski"
+
+#: conf/global_settings.py:71
+msgid "Slovak"
+msgstr "Slovaški"
+
+#: conf/global_settings.py:72
+msgid "Slovenian"
+msgstr "Slovenski"
+
+#: conf/global_settings.py:73
+msgid "Serbian"
+msgstr "Srbski"
+
+#: conf/global_settings.py:74
+msgid "Swedish"
+msgstr "Švedski"
+
+#: conf/global_settings.py:75
+msgid "Tamil"
+msgstr "Tamilščina"
+
+#: conf/global_settings.py:76
+msgid "Telugu"
+msgstr "Teluščina"
+
+#: conf/global_settings.py:77
+msgid "Turkish"
+msgstr "Turščina"
+
+#: conf/global_settings.py:78
+msgid "Ukrainian"
+msgstr "Ukrajinski"
+
+#: conf/global_settings.py:79
+msgid "Simplified Chinese"
+msgstr "Poenostavljeni kitajski"
+
+#: conf/global_settings.py:80
+msgid "Traditional Chinese"
+msgstr "Tradicionalni kitajski"
+
+#: core/validators.py:65
+msgid "This value must contain only letters, numbers and underscores."
+msgstr "Ta vrednost mora vsebovati le črke, števila in podčrtaje (_)."
+
+#: core/validators.py:69
+msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
+msgstr "Ta vrednost mora vsebovati le črke, števila, podčrtaje, poševnice ali pomišljaje."
+
+#: core/validators.py:73
+msgid "This value must contain only letters, numbers, underscores or hyphens."
+msgstr "Ta vrednost mora vsebovati le črke, števila, podčrtaje ali pomišljaje."
+
+#: core/validators.py:77
+msgid "Uppercase letters are not allowed here."
+msgstr "Velike tiskane črke niso dovoljene."
+
+#: core/validators.py:81
+msgid "Lowercase letters are not allowed here."
+msgstr "Majhne tiskane črke niso dovoljene."
+
+#: core/validators.py:88
+msgid "Enter only digits separated by commas."
+msgstr "Vnesite samo števila, ločena z vejicami."
+
+#: core/validators.py:100
+msgid "Enter valid e-mail addresses separated by commas."
+msgstr "Vnesite veljavne e-mail naslove, ločene z vejicami."
+
+#: core/validators.py:104
+msgid "Please enter a valid IP address."
+msgstr "Prosimo, vnesite veljavni IP naslov."
+
+#: core/validators.py:108
+msgid "Empty values are not allowed here."
+msgstr "Prazne vrednosti tu niso dovoljene."
+
+#: core/validators.py:112
+msgid "Non-numeric characters aren't allowed here."
+msgstr "Nenumerični znaki tukaj niso dovoljne."
+
+#: core/validators.py:116
+msgid "This value can't be comprised solely of digits."
+msgstr "Ta vrednost ne sme vsebovati le števk."
+
+#: core/validators.py:121
+#: newforms/fields.py:135
+msgid "Enter a whole number."
+msgstr "Vnesite celo število."
+
+#: core/validators.py:125
+msgid "Only alphabetical characters are allowed here."
+msgstr "Tukaj so dovoljene samo črke."
+
+#: core/validators.py:140
+msgid "Year must be 1900 or later."
+msgstr "Leto mora biti 1900 ali kasnejše."
+
+#: core/validators.py:144
+#, python-format
+msgid "Invalid date: %s"
+msgstr "Nepravilen datum: %s"
+
+#: core/validators.py:154
+msgid "Enter a valid time in HH:MM format."
+msgstr "Vnesite veljavni čas v zapisu HH:MM (ura:minuta)."
+
+#: core/validators.py:163
+#: newforms/fields.py:339
+msgid "Enter a valid e-mail address."
+msgstr "Vnesite veljaven e-mail."
+
+#: core/validators.py:175
+#: core/validators.py:453
+#: oldforms/__init__.py:672
+msgid "No file was submitted. Check the encoding type on the form."
+msgstr "Datoteka ni bila poslana. Preveite nabor znakov v formi."
+
+#: core/validators.py:179
+msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
+msgstr "Naložite veljavno sliko. Naložena datoteka ni bila slika ali pa je bila le-ta okvarjena."
+
+#: core/validators.py:186
+#, python-format
+msgid "The URL %s does not point to a valid image."
+msgstr "URL %s ne kaže na veljavno sliko."
+
+#: core/validators.py:190
+#, python-format
+msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
+msgstr "Telefonska številka mora biti v zapisu XXX-XXX-XXXX. \"%s\" ni vredu."
+
+#: core/validators.py:198
+#, python-format
+msgid "The URL %s does not point to a valid QuickTime video."
+msgstr "URL %s ne kaže na veljavni QuickTime video."
+
+#: core/validators.py:202
+msgid "A valid URL is required."
+msgstr "Potreben je veljaven URL naslov."
+
+#: core/validators.py:216
#, python-format
msgid ""
-"Posted by %(user)s at %(date)s\n"
-"\n"
-"%(comment)s\n"
-"\n"
-"http://%(domain)s%(url)s"
+"Valid HTML is required. Specific errors are:\n"
+"%s"
msgstr ""
-"Poslal uporabnik %(user)s ob %(date)s\n"
-"\n"
-"%(comment)s\n"
-"\n"
-"http://%(domain)s%(url)s"
+"Potreben je veljaven HTML. Trenutni ima sledeče napake:\n"
+"%s"
-#: contrib/comments/models.py:168
-msgid "person's name"
-msgstr "ime osebe"
+#: core/validators.py:223
+#, python-format
+msgid "Badly formed XML: %s"
+msgstr "Nepravilen XML: %s"
-#: contrib/comments/models.py:171
-msgid "ip address"
-msgstr "ip naslov"
+#: core/validators.py:240
+#, python-format
+msgid "Invalid URL: %s"
+msgstr "Neveljaven URL naslov: %s"
-#: contrib/comments/models.py:173
-msgid "approved by staff"
-msgstr "osebje je potrdilo"
+#: core/validators.py:245
+#: core/validators.py:247
+#, python-format
+msgid "The URL %s is a broken link."
+msgstr "URL povezava %s ne deluje."
-#: contrib/comments/models.py:176
-msgid "free comment"
-msgstr "anonimen komentar"
+#: core/validators.py:253
+msgid "Enter a valid U.S. state abbreviation."
+msgstr "Vnesi veljavno okrajšavo za ameriško zvezno državo."
-#: contrib/comments/models.py:177
-msgid "free comments"
-msgstr "anonimni komentarji"
+#: core/validators.py:267
+#, python-format
+msgid "Watch your mouth! The word %s is not allowed here."
+msgid_plural "Watch your mouth! The words %s are not allowed here."
+msgstr[0] "Pazite na jezik! Beseda %s tu ni dovoljena."
+msgstr[1] "Pazite na jezik! Besedi %s tu nista dovoljeni."
+msgstr[2] "Pazite na jezik! Besede %s tu niso dovoljene."
+msgstr[3] "Pazite na jezik! Besede %s tu niso dovoljene."
-#: contrib/comments/models.py:233
-msgid "score"
-msgstr "ocena"
+#: core/validators.py:274
+#, python-format
+msgid "This field must match the '%s' field."
+msgstr "To polje mora ustrezati polju '%s'."
-#: contrib/comments/models.py:234
-msgid "score date"
-msgstr "datum ocene"
+#: core/validators.py:293
+msgid "Please enter something for at least one field."
+msgstr "Prosim, vnesite nekaj v vsaj eno izmed polj."
-#: contrib/comments/models.py:237
-msgid "karma score"
-msgstr "karma točke"
+#: core/validators.py:302
+#: core/validators.py:313
+msgid "Please enter both fields or leave them both empty."
+msgstr "Prosimo, izpolnite obe polji ali pa pustite obe prazni."
-#: contrib/comments/models.py:238
-msgid "karma scores"
-msgstr "karma točke"
+#: core/validators.py:321
+#, python-format
+msgid "This field must be given if %(field)s is %(value)s"
+msgstr "To polje mora biti podano, če je %(field)s %(value)s"
-#: contrib/comments/models.py:242
+#: core/validators.py:334
#, python-format
-msgid "%(score)d rating by %(user)s"
-msgstr "oceno %(score)d podelil %(user)s"
+msgid "This field must be given if %(field)s is not %(value)s"
+msgstr "To polje mora biti podano, če ni %(field)s %(value)s"
-#: contrib/comments/models.py:258
+#: core/validators.py:353
+msgid "Duplicate values are not allowed."
+msgstr "Podvojitve niso dovoljene."
+
+#: core/validators.py:368
#, python-format
-msgid ""
-"This comment was flagged by %(user)s:\n"
-"\n"
-"%(text)s"
-msgstr ""
-"Komentar je z zastavico označil %(user)s:\n"
-"\n"
-"%(text)s"
+msgid "This value must be between %(lower)s and %(upper)s."
+msgstr "Ta vrednost mora biti med %(lower)s in %(upper)s."
-#: contrib/comments/models.py:265
-msgid "flag date"
-msgstr "datum označitve (zastavice)"
+#: core/validators.py:370
+#, python-format
+msgid "This value must be at least %s."
+msgstr "Ta vrednost mora biti vsaj %s."
-#: contrib/comments/models.py:268
-msgid "user flag"
-msgstr "uporabniška zastavica"
+#: core/validators.py:372
+#, python-format
+msgid "This value must be no more than %s."
+msgstr "Ta vrednost mora biti manjša od %s."
-#: contrib/comments/models.py:269
-msgid "user flags"
-msgstr "uporabniške zastavice"
+#: core/validators.py:408
+#, python-format
+msgid "This value must be a power of %s."
+msgstr "Ta vrednost mora biti potenca od %s."
-#: contrib/comments/models.py:273
+#: core/validators.py:417
+msgid "Please enter a valid decimal number."
+msgstr "Prosim vnesite veljavno decimalno število."
+
+#: core/validators.py:423
#, python-format
-msgid "Flag by %r"
-msgstr "Avtor zastavice je %r"
+msgid "Please enter a valid decimal number with at most %s total digit."
+msgid_plural "Please enter a valid decimal number with at most %s total digits."
+msgstr[0] "Prosimo, vnesite veljavno decimalno število z največ %s števko."
+msgstr[1] "Prosimo, vnesite veljavno decimalno število z največ %s števkama."
+msgstr[2] "Prosimo, vnesite veljavno decimalno število z največ %s števkami."
+msgstr[3] "Prosimo, vnesite veljavno decimalno število z največ %s števkami."
-#: contrib/comments/models.py:278
-msgid "deletion date"
-msgstr "datum izbrisa"
+#: core/validators.py:426
+#, python-format
+msgid "Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] "Prosimo, vnesite veljavno decimalno število s celim številom z največ %s števko."
+msgstr[1] "PProsimo, vnesite veljavno decimalno število s celim številom z največ %s števkama."
+msgstr[2] "Prosimo, vnesite veljavno decimalno število s celim številom z največ %s števkami."
+msgstr[3] "Prosimo, vnesite veljavno decimalno število s celim številom z največ %s števkami."
-#: contrib/comments/models.py:280
-msgid "moderator deletion"
-msgstr "izbris s strani moderatorja"
+#: core/validators.py:429
+#, python-format
+msgid "Please enter a valid decimal number with at most %s decimal place."
+msgid_plural "Please enter a valid decimal number with at most %s decimal places."
+msgstr[0] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnim mestom."
+msgstr[1] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnima mestoma."
+msgstr[2] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnimi mesti."
+msgstr[3] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnimi mesti."
-#: contrib/comments/models.py:281
-msgid "moderator deletions"
-msgstr "izbrisi s strani moderatorja"
+#: core/validators.py:437
+msgid "Please enter a valid floating point number."
+msgstr "Prosim vnesite veljavno decimalno število."
-#: contrib/comments/models.py:285
+#: core/validators.py:446
#, python-format
-msgid "Moderator deletion by %r"
-msgstr "Izbris opravil moderator %r"
+msgid "Make sure your uploaded file is at least %s bytes big."
+msgstr "Prosimo, poskrbite, da bo naložena datoteka velika vsaj %s bajtov."
-#: contrib/comments/views/karma.py:19
-msgid "Anonymous users cannot vote"
-msgstr "Anonimni uporabniki ne morejo glasovati"
+#: core/validators.py:447
+#, python-format
+msgid "Make sure your uploaded file is at most %s bytes big."
+msgstr "Poskrbite, da bo naložena datoteka velika največ %s bajtov."
-#: contrib/comments/views/karma.py:23
-msgid "Invalid comment ID"
-msgstr "Neveljavni ID komentarja"
+#: core/validators.py:464
+msgid "The format for this field is wrong."
+msgstr "Format za to polje je napačen."
-#: contrib/comments/views/karma.py:25
-msgid "No voting for yourself"
-msgstr "Ni mogoče glasovati zase"
+#: core/validators.py:479
+msgid "This field is invalid."
+msgstr "To polje ni veljavno."
-#: contrib/comments/views/comments.py:28
-msgid "This rating is required because you've entered at least one other rating."
-msgstr "To oceno moraš podati, ker si podal vsaj še eno drugo oceno."
+#: core/validators.py:515
+#, python-format
+msgid "Could not retrieve anything from %s."
+msgstr "Iz %s nisem mogel pridobiti ničesar."
-#: contrib/comments/views/comments.py:112
+#: core/validators.py:518
#, python-format
-msgid ""
-"This comment was posted by a user who has posted fewer than %(count)s comment:\n"
-"\n"
-"%(text)s"
-msgid_plural ""
-"This comment was posted by a user who has posted fewer than %(count)s comments:\n"
-"\n"
-"%(text)s"
-msgstr[0] ""
-"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarjev:\n"
-"\n"
-"%(text)s"
-msgstr[1] ""
-"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarja:\n"
-"\n"
-"%(text)s"
-msgstr[2] ""
-"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarje:\n"
-"\n"
-"%(text)s"
-msgstr[3] ""
-"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarjev:\n"
-"\n"
-"%(text)s"
+msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+msgstr "URL %(url)s je vrnil neveljavni Content-Type '%(contenttype)s'."
-#: contrib/comments/views/comments.py:117
+#: core/validators.py:551
#, python-format
-msgid ""
-"This comment was posted by a sketchy user:\n"
-"\n"
-"%(text)s"
-msgstr ""
-"Ta komentar je poslal sumljiv uporabnik:\n"
-"\n"
-"%(text)s"
+msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
+msgstr "Prosimo, zaprite %(tag)s oznako v vrstici %(line)s. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/views/comments.py:189
-#: contrib/comments/views/comments.py:280
-msgid "Only POSTs are allowed"
-msgstr "Dovoljena je le POST metoda"
+#: core/validators.py:555
+#, python-format
+msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
+msgstr "Tekst z začetka vrstice %(line)s ni dovoljen v tem kontekstu. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/views/comments.py:193
-#: contrib/comments/views/comments.py:284
-msgid "One or more of the required fields wasn't submitted"
-msgstr "Eno ali več obveznih polj ni vpisanih"
+#: core/validators.py:560
+#, python-format
+msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
+msgstr "\"%(attr)s\" v vrstici %(line)s je neveljaven atribut. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/views/comments.py:197
-#: contrib/comments/views/comments.py:286
-msgid "Somebody tampered with the comment form (security violation)"
-msgstr "Nekdo se je poigraval z obrazcem za komentarje (varnostna kršitev)"
+#: core/validators.py:565
+#, python-format
+msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
+msgstr "\"<%(tag)s>\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/views/comments.py:207
-#: contrib/comments/views/comments.py:292
-msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
-msgstr "Obrazec s komentarji ima neveljavni parameter 'target' -- ID objekta je neveljaven."
+#: core/validators.py:569
+#, python-format
+msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
+msgstr "Oznaki v vrstici %(line)s manjka eden ali več zahtevanih parametrov. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
-msgid "The comment form didn't provide either 'preview' or 'post'"
-msgstr "Obrazec s komentarji ni podal niti 'preview' niti 'post' akcije."
+#: core/validators.py:574
+#, python-format
+msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
+msgstr "Parameter \"%(attr)s\" v vrstici %(line)s vsebuje neveljavno vrednost. (Vrstica se začne z \"%(start)s\".)"
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/login.html:17
-msgid "Username:"
-msgstr "Uporabniško ime:"
+#: contrib/auth/forms.py:17
+#: contrib/auth/forms.py:138
+msgid "The two password fields didn't match."
+msgstr "Gesli se ne ujemata."
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/admin/templates/admin/login.html:20
-msgid "Password:"
-msgstr "Geslo:"
+#: contrib/auth/forms.py:25
+msgid "A user with that username already exists."
+msgstr "Uporabnik s tem uporabniškim imenom že obstaja."
-#: contrib/comments/templates/comments/form.html:6
-msgid "Forgotten your password?"
-msgstr "Ste pozabili geslo?"
+#: contrib/auth/forms.py:53
+msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
+msgstr "Izgleda, da vaš brskalnik nima omogočenih piškotkov. Piškotki so potrebni za prijavo."
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/model_index.html:5
-msgid "Log out"
-msgstr "Odjava"
+#: contrib/auth/forms.py:60
+#: contrib/admin/views/decorators.py:10
+msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
+msgstr "Prosimo, vnesite veljavno uporabniško ime in geslo. Opomba: obe polji upoštevata velikost črk."
-#: contrib/comments/templates/comments/form.html:12
-msgid "Ratings"
-msgstr "Ocene"
+#: contrib/auth/forms.py:62
+msgid "This account is inactive."
+msgstr "Ta uporabniški račun ni aktiven."
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Required"
-msgstr "Obvezno"
+#: contrib/auth/forms.py:84
+msgid "That e-mail address doesn't have an associated user account. Are you sure you've registered?"
+msgstr "Tega e-mail naslova ni mogoče pripisati nobenemu uporabniku. Ali ste prepričani, da ste registrirani?"
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Optional"
-msgstr "Neobvezno"
+#: contrib/auth/forms.py:117
+msgid "The two 'new password' fields didn't match."
+msgstr "Vrednosti v poljih 'novo geslo' se ne ujemata."
-#: contrib/comments/templates/comments/form.html:23
-msgid "Post a photo"
-msgstr "Objavi sliko"
+#: contrib/auth/forms.py:124
+msgid "Your old password was entered incorrectly. Please enter it again."
+msgstr "Vaše staro geslo ni pravilno. Prosim, poskusite ponovno."
-#: contrib/comments/templates/comments/form.html:27
-#: contrib/comments/templates/comments/freeform.html:5
-msgid "Comment:"
-msgstr "Komentar:"
+#: contrib/auth/models.py:49
+#: contrib/auth/models.py:69
+msgid "name"
+msgstr "ime"
-#: contrib/comments/templates/comments/form.html:32
-#: contrib/comments/templates/comments/freeform.html:9
-msgid "Preview comment"
-msgstr "Predogled komentarja"
+#: contrib/auth/models.py:51
+msgid "codename"
+msgstr "kodno ime"
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "Vaše ime:"
+#: contrib/auth/models.py:54
+msgid "permission"
+msgstr "dovoljenje"
+
+#: contrib/auth/models.py:55
+#: contrib/auth/models.py:70
+msgid "permissions"
+msgstr "dovoljenja"
+
+#: contrib/auth/models.py:73
+msgid "group"
+msgstr "skupina"
+
+#: contrib/auth/models.py:74
+#: contrib/auth/models.py:114
+msgid "groups"
+msgstr "skupine"
+
+#: contrib/auth/models.py:104
+msgid "username"
+msgstr "uporabniško ime"
+
+#: contrib/auth/models.py:104
+msgid "Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."
+msgstr "Zahtevano. 30 znakov ali manj. Samo alfanumerični znaki (črke, števke un opdčrtaji)."
+
+#: contrib/auth/models.py:105
+msgid "first name"
+msgstr "ime"
+
+#: contrib/auth/models.py:106
+msgid "last name"
+msgstr "priimek"
+
+#: contrib/auth/models.py:107
+msgid "e-mail address"
+msgstr "e-mail naslov"
+
+#: contrib/auth/models.py:108
+msgid "password"
+msgstr "geslo"
+
+#: contrib/auth/models.py:108
+msgid "Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."
+msgstr "Uporabite '[algo]$[salt]$[hexdigest]' ali <a href=\"password/\">obrazec za spremembo gesla</a>."
+
+#: contrib/auth/models.py:109
+msgid "staff status"
+msgstr "status osebja"
+
+#: contrib/auth/models.py:109
+msgid "Designates whether the user can log into this admin site."
+msgstr "Določi, če se sme uporabnik prijaviti v to administracijsko stran."
+
+#: contrib/auth/models.py:110
+msgid "active"
+msgstr "aktiven"
+
+#: contrib/auth/models.py:110
+msgid "Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."
+msgstr "Določi, če se sme uporabnik prijaviti v Django admin. Odstranite to možnost namesto da brišete račune."
+
+#: contrib/auth/models.py:111
+msgid "superuser status"
+msgstr "status superuporabnika"
+
+#: contrib/auth/models.py:111
+msgid "Designates that this user has all permissions without explicitly assigning them."
+msgstr "Uporabnik bo imel vse pravice brez posamičnega dodeljevanja pravic."
+
+#: contrib/auth/models.py:112
+msgid "last login"
+msgstr "zadnja prijava"
+
+#: contrib/auth/models.py:113
+msgid "date joined"
+msgstr "član od"
+
+#: contrib/auth/models.py:115
+msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
+msgstr "Poleg ročno določenih dovoljenj bo ta uporabnik dobil tudi vsa dovoljenja, ki pripadajo skupinam, katerih član je."
+
+#: contrib/auth/models.py:116
+msgid "user permissions"
+msgstr "uporabniška dovoljenja"
+
+#: contrib/auth/models.py:120
+msgid "user"
+msgstr "uporabnik"
+
+#: contrib/auth/models.py:121
+msgid "users"
+msgstr "uporabniki"
+
+#: contrib/auth/models.py:127
+msgid "Personal info"
+msgstr "Osebni podatki"
+
+#: contrib/auth/models.py:128
+msgid "Permissions"
+msgstr "Dovoljenja"
+
+#: contrib/auth/models.py:129
+msgid "Important dates"
+msgstr "Pomembni datumi"
+
+#: contrib/auth/models.py:130
+msgid "Groups"
+msgstr "Skupine"
+
+#: contrib/auth/models.py:272
+msgid "message"
+msgstr "sporočilo"
+
+#: contrib/auth/models.py:285
+msgid "AnonymousUser"
+msgstr "AnonimniUporabnik"
+
+#: contrib/auth/views.py:40
+msgid "Logged out"
+msgstr "Odjavljen"
+
+#: contrib/admin/models.py:16
+msgid "action time"
+msgstr "čas dejanja"
+
+#: contrib/admin/models.py:19
+msgid "object id"
+msgstr "id objekta"
+
+#: contrib/admin/models.py:20
+msgid "object repr"
+msgstr "predstavitev objekta"
+
+#: contrib/admin/models.py:21
+msgid "action flag"
+msgstr "zastavica dejanja"
+
+#: contrib/admin/models.py:22
+msgid "change message"
+msgstr "spremeni sporočilo"
+
+#: contrib/admin/models.py:25
+msgid "log entry"
+msgstr "vnos v dnevniku"
+
+#: contrib/admin/models.py:26
+msgid "log entries"
+msgstr "vnosi v dnevniku"
#: contrib/admin/filterspecs.py:40
#, python-format
@@ -363,6 +753,7 @@ msgstr ""
#: contrib/admin/filterspecs.py:70
#: contrib/admin/filterspecs.py:88
#: contrib/admin/filterspecs.py:143
+#: contrib/admin/filterspecs.py:169
msgid "All"
msgstr "Vse"
@@ -387,400 +778,391 @@ msgid "This year"
msgstr "Letos"
#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:577
+#: newforms/widgets.py:181
msgid "Yes"
msgstr "Da"
#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:577
+#: newforms/widgets.py:181
msgid "No"
msgstr "Ne"
#: contrib/admin/filterspecs.py:150
+#: oldforms/__init__.py:577
+#: newforms/widgets.py:181
msgid "Unknown"
msgstr "Neznano"
-#: contrib/admin/models.py:16
-msgid "action time"
-msgstr "čas dejanja"
-
-#: contrib/admin/models.py:19
-msgid "object id"
-msgstr "id objekta"
-
-#: contrib/admin/models.py:20
-msgid "object repr"
-msgstr "predstavitev objekta"
-
-#: contrib/admin/models.py:21
-msgid "action flag"
-msgstr "zastavica dejanja"
-
-#: contrib/admin/models.py:22
-msgid "change message"
-msgstr "spremeni sporočilo"
-
-#: contrib/admin/models.py:25
-msgid "log entry"
-msgstr "vnos v dnevniku"
-
-#: contrib/admin/models.py:26
-msgid "log entries"
-msgstr "vnosi v dnevniku"
-
-#: contrib/admin/templatetags/admin_list.py:228
-msgid "All dates"
-msgstr "Vsi datumi"
-
-#: contrib/admin/views/decorators.py:9
-#: contrib/auth/forms.py:36
-#: contrib/auth/forms.py:41
-msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
-msgstr "Prosimo, vnesite veljavno uporabniško ime in geslo. Opomba: obe polji upoštevata velikost črk."
-
-#: contrib/admin/views/decorators.py:23
+#: contrib/admin/views/decorators.py:24
#: contrib/admin/templates/admin/login.html:25
msgid "Log in"
msgstr "Prijavite se"
-#: contrib/admin/views/decorators.py:61
+#: contrib/admin/views/decorators.py:62
msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
msgstr "Vaša seja je pretekla; prosimo da se ponovno prijavite. Brez skrbi, vaše objave so varno shranjene."
-#: contrib/admin/views/decorators.py:68
+#: contrib/admin/views/decorators.py:69
msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
msgstr "Izgleda, da vaš brskalnik nima podpore za piškotke. Prosimo, vključite piškotke, osvežite stran in poskusite še enkrat."
-#: contrib/admin/views/decorators.py:82
+#: contrib/admin/views/decorators.py:83
msgid "Usernames cannot contain the '@' character."
msgstr "Uporabniška imena ne smejo vsebovati znaka '@'."
-#: contrib/admin/views/decorators.py:84
+#: contrib/admin/views/decorators.py:85
#, python-format
msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr "Vaš e-main naslov ni vaše uporabniško ime. Poskusite uporabiti '%s'."
-#: contrib/admin/views/main.py:226
+#: contrib/admin/views/main.py:228
msgid "Site administration"
msgstr "Administracija strani"
-#: contrib/admin/views/main.py:260
+#: contrib/admin/views/main.py:262
+#: contrib/admin/views/auth.py:19
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" je bil uspešno dodan."
-#: contrib/admin/views/main.py:264
-#: contrib/admin/views/main.py:348
+#: contrib/admin/views/main.py:266
+#: contrib/admin/views/main.py:352
+#: contrib/admin/views/auth.py:24
msgid "You may edit it again below."
msgstr "Vsebino lahko znova uredite spodaj."
-#: contrib/admin/views/main.py:272
-#: contrib/admin/views/main.py:357
+#: contrib/admin/views/main.py:276
+#: contrib/admin/views/main.py:361
#, python-format
msgid "You may add another %s below."
msgstr "Spodaj lahko dodate še en %s."
-#: contrib/admin/views/main.py:290
+#: contrib/admin/views/main.py:294
#, python-format
msgid "Add %s"
msgstr "Dodaj %s"
-#: contrib/admin/views/main.py:336
+#: contrib/admin/views/main.py:340
#, python-format
msgid "Added %s."
msgstr "Dodan %s."
-#: contrib/admin/views/main.py:336
-#: contrib/admin/views/main.py:338
-#: contrib/admin/views/main.py:340
-msgid "and"
-msgstr "in"
-
-#: contrib/admin/views/main.py:338
+#: contrib/admin/views/main.py:342
#, python-format
msgid "Changed %s."
msgstr "Spremenjen %s."
-#: contrib/admin/views/main.py:340
+#: contrib/admin/views/main.py:344
#, python-format
msgid "Deleted %s."
msgstr "Izbrisn %s."
-#: contrib/admin/views/main.py:343
+#: contrib/admin/views/main.py:347
msgid "No fields changed."
msgstr "Nobeno polje ni bilo spremenjeno."
-#: contrib/admin/views/main.py:346
+#: contrib/admin/views/main.py:350
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "%(name)s \"%(obj)s\" je bil uspešno spremenjeno."
-#: contrib/admin/views/main.py:354
+#: contrib/admin/views/main.py:358
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr "%(name)s \"%(obj)s\" je bil uspešno dodano. Ponovno ga lahko urejdite spodaj."
-#: contrib/admin/views/main.py:392
+#: contrib/admin/views/main.py:396
#, python-format
msgid "Change %s"
msgstr "Spremeni %s"
-#: contrib/admin/views/main.py:470
+#: contrib/admin/views/main.py:481
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "Eden ali več %(fieldname)s v %(name)s: %(obj)s"
-#: contrib/admin/views/main.py:475
+#: contrib/admin/views/main.py:486
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
msgstr "Eden ali več %(fieldname)s v %(name)s:"
-#: contrib/admin/views/main.py:508
+#: contrib/admin/views/main.py:518
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "%(name)s \"%(obj)s\" je bilo uspešno izbrisan."
-#: contrib/admin/views/main.py:511
+#: contrib/admin/views/main.py:521
msgid "Are you sure?"
msgstr "Ste prepričani?"
-#: contrib/admin/views/main.py:533
+#: contrib/admin/views/main.py:543
#, python-format
msgid "Change history: %s"
msgstr "Zgodovina sprememb: %s"
-#: contrib/admin/views/main.py:565
+#: contrib/admin/views/main.py:577
#, python-format
msgid "Select %s"
msgstr "Izberite %s"
-#: contrib/admin/views/main.py:565
+#: contrib/admin/views/main.py:577
#, python-format
msgid "Select %s to change"
msgstr "Izberite %s, ki ga želite spremeniti"
-#: contrib/admin/views/doc.py:277
-#: contrib/admin/views/doc.py:286
-#: contrib/admin/views/doc.py:288
-#: contrib/admin/views/doc.py:294
-#: contrib/admin/views/doc.py:295
-#: contrib/admin/views/doc.py:297
+#: contrib/admin/views/main.py:772
+msgid "Database error"
+msgstr "Napaka baze podatkov"
+
+#: contrib/admin/views/doc.py:46
+#: contrib/admin/views/doc.py:48
+#: contrib/admin/views/doc.py:50
+msgid "tag:"
+msgstr "značka:"
+
+#: contrib/admin/views/doc.py:77
+#: contrib/admin/views/doc.py:79
+#: contrib/admin/views/doc.py:81
+msgid "filter:"
+msgstr "filter:"
+
+#: contrib/admin/views/doc.py:135
+#: contrib/admin/views/doc.py:137
+#: contrib/admin/views/doc.py:139
+msgid "view:"
+msgstr "pogled:"
+
+#: contrib/admin/views/doc.py:164
+#, python-format
+msgid "App %r not found"
+msgstr "Aplikacije %r ni mogoče najti"
+
+#: contrib/admin/views/doc.py:171
+#, python-format
+msgid "Model %(name)r not found in app %(label)r"
+msgstr "Modela %(name)r ni v aplikaciji %(label)r"
+
+#: contrib/admin/views/doc.py:183
+#, python-format
+msgid "the related `%(label)s.%(type)s` object"
+msgstr "povezani `%(label)s.%(type)s` objekti"
+
+#: contrib/admin/views/doc.py:183
+#: contrib/admin/views/doc.py:205
+#: contrib/admin/views/doc.py:219
+#: contrib/admin/views/doc.py:224
+msgid "model:"
+msgstr "model:"
+
+#: contrib/admin/views/doc.py:214
+#, python-format
+msgid "related `%(label)s.%(name)s` objects"
+msgstr "povezani `%(label)s.%(name)s` objekti"
+
+#: contrib/admin/views/doc.py:219
+#, python-format
+msgid "all %s"
+msgstr "vse %s"
+
+#: contrib/admin/views/doc.py:224
+#, python-format
+msgid "number of %s"
+msgstr "števolo %s"
+
+#: contrib/admin/views/doc.py:229
+#, python-format
+msgid "Fields on %s objects"
+msgstr "Polja na %s objektih"
+
+#: contrib/admin/views/doc.py:291
+#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:304
+#: contrib/admin/views/doc.py:310
+#: contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:313
msgid "Integer"
msgstr "Celo število (integer)"
-#: contrib/admin/views/doc.py:278
+#: contrib/admin/views/doc.py:292
msgid "Boolean (Either True or False)"
msgstr "Boolean (True ali False)"
-#: contrib/admin/views/doc.py:279
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:293
+#: contrib/admin/views/doc.py:312
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "Niz (vse do %(maxlength)s)"
-#: contrib/admin/views/doc.py:280
+#: contrib/admin/views/doc.py:294
msgid "Comma-separated integers"
msgstr "Z vejico ločena cela števila (integer)"
-#: contrib/admin/views/doc.py:281
+#: contrib/admin/views/doc.py:295
msgid "Date (without time)"
msgstr "Datum (brez ure)"
-#: contrib/admin/views/doc.py:282
+#: contrib/admin/views/doc.py:296
msgid "Date (with time)"
msgstr "Datum (z uro)"
-#: contrib/admin/views/doc.py:283
+#: contrib/admin/views/doc.py:297
+msgid "Decimal number"
+msgstr "Decimalno število"
+
+#: contrib/admin/views/doc.py:298
msgid "E-mail address"
msgstr "E-mail naslov"
-#: contrib/admin/views/doc.py:284
-#: contrib/admin/views/doc.py:287
+#: contrib/admin/views/doc.py:299
+#: contrib/admin/views/doc.py:300
+#: contrib/admin/views/doc.py:303
msgid "File path"
msgstr "Pot do datoteke"
-#: contrib/admin/views/doc.py:285
-msgid "Decimal number"
+#: contrib/admin/views/doc.py:301
+msgid "Floating point number"
msgstr "Decimalno število"
-#: contrib/admin/views/doc.py:291
+#: contrib/admin/views/doc.py:305
+#: contrib/comments/models.py:85
+msgid "IP address"
+msgstr "IP naslov"
+
+#: contrib/admin/views/doc.py:307
msgid "Boolean (Either True, False or None)"
msgstr "Boolean (True, False ali None)"
-#: contrib/admin/views/doc.py:292
+#: contrib/admin/views/doc.py:308
msgid "Relation to parent model"
msgstr "Razmerje s starševskim modelom"
-#: contrib/admin/views/doc.py:293
+#: contrib/admin/views/doc.py:309
msgid "Phone number"
msgstr "Telefonska številka"
-#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:314
msgid "Text"
msgstr "Besedilo"
-#: contrib/admin/views/doc.py:299
+#: contrib/admin/views/doc.py:315
msgid "Time"
msgstr "Čas"
-#: contrib/admin/views/doc.py:300
+#: contrib/admin/views/doc.py:316
#: contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL (spletni naslov)"
-#: contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:317
msgid "U.S. state (two uppercase letters)"
msgstr "Koda ameriške zvezne države (dve veliki črki)"
-#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:318
msgid "XML text"
msgstr "XML besedilo"
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
+#: contrib/admin/views/doc.py:344
+#, python-format
+msgid "%s does not appear to be a urlpattern object"
+msgstr "%s ne izgleda veljaven urlpattern objekt"
+
+#: contrib/admin/views/auth.py:30
+msgid "Add user"
+msgstr "Dodaj uporabnika"
+
+#: contrib/admin/views/auth.py:57
+msgid "Password changed successfully."
+msgstr "Geslo je bilo uspešno spremenjeno"
+
+#: contrib/admin/views/auth.py:64
+#, python-format
+msgid "Change password: %s"
+msgstr "Spremeni geslo: %s"
+
+#: contrib/admin/templatetags/admin_list.py:249
+msgid "All dates"
+msgstr "Vsi datumi"
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Prikaži vse"
+
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
msgid "Documentation"
msgstr "Dokumentacija"
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/admin/auth/user/change_password.html:15
+#: contrib/admin/templates/admin/auth/user/change_password.html:46
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_detail.html:3
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
msgid "Change password"
msgstr "Spremeni geslo"
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/500.html:4
-#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/base.html:28
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
+#: contrib/comments/templates/comments/form.html:6
+msgid "Log out"
+msgstr "Odjava"
+
#: contrib/admin/templates/admin/delete_confirmation.html:6
#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/admin/change_list.html:6
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/invalid_setup.html:4
+#: contrib/admin/templates/admin/base.html:30
+#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
#: contrib/admin/templates/registration/password_reset_form.html:4
#: contrib/admin/templates/registration/logged_out.html:4
#: contrib/admin/templates/registration/password_reset_done.html:4
#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#: contrib/admin/templates/registration/password_change_done.html:4
msgid "Home"
msgstr "Domov"
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/change_form.html:20
-msgid "History"
-msgstr "Zgodovina"
-
-#: contrib/admin/templates/admin/object_history.html:18
-msgid "Date/time"
-msgstr "Datum/čas"
-
-#: contrib/admin/templates/admin/object_history.html:19
-msgid "User"
-msgstr "Uporabnik"
-
-#: contrib/admin/templates/admin/object_history.html:20
-msgid "Action"
-msgstr "Dejanje"
-
-#: contrib/admin/templates/admin/object_history.html:26
-msgid "DATE_WITH_TIME_FULL"
-msgstr "N j, Y, H:i"
-
-#: contrib/admin/templates/admin/object_history.html:36
-msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
-msgstr "Ta objekt nima zgodovine sprememb. Verjetno ni bil dodan preko te strani za administracijo."
-
-#: contrib/admin/templates/admin/base_site.html:4
-msgid "Django site admin"
-msgstr "Vmesnik za administracijo Django strani"
-
-#: contrib/admin/templates/admin/base_site.html:7
-msgid "Django administration"
-msgstr "Django administracija"
-
-#: contrib/admin/templates/admin/500.html:4
-msgid "Server error"
-msgstr "Napaka strežnika"
-
-#: contrib/admin/templates/admin/500.html:6
-msgid "Server error (500)"
-msgstr "Napaka strežnika (500)"
-
-#: contrib/admin/templates/admin/500.html:9
-msgid "Server Error <em>(500)</em>"
-msgstr "Napaka strežnika <em>(500)</em>"
-
-#: contrib/admin/templates/admin/500.html:10
-msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
-msgstr "Prišlo je do nepričakovane napake. Administrator je preko e-pošte prejel obvestilo o napaki in jo bo v kratkem odpravil. Hvala za potrpljenje."
-
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
-msgid "Page not found"
-msgstr "Strani ni mogoče najti"
-
-#: contrib/admin/templates/admin/404.html:10
-msgid "We're sorry, but the requested page could not be found."
-msgstr "Opravičujemo se, a zahtevane strani ni mogoče najti."
-
-#: contrib/admin/templates/admin/index.html:17
-#, python-format
-msgid "Models available in the %(name)s application."
-msgstr "Modeli na voljo v %(name)s aplikaciji"
-
-#: contrib/admin/templates/admin/index.html:28
-#: contrib/admin/templates/admin/change_form.html:15
-msgid "Add"
-msgstr "Dodaj"
-
-#: contrib/admin/templates/admin/index.html:34
-msgid "Change"
-msgstr "Spremeni"
-
-#: contrib/admin/templates/admin/index.html:44
-msgid "You don't have permission to edit anything."
-msgstr "Nimate dovoljenja za urejanje česar koli."
-
-#: contrib/admin/templates/admin/index.html:52
-msgid "Recent Actions"
-msgstr "Zadnja dejanja"
-
-#: contrib/admin/tempalates/admin/index.html:53
-msgid "My Actions"
-msgstr "Moja dejanja"
-
-#: contrib/admin/templates/admin/index.html:57
-msgid "None available"
-msgstr "Ni na voljo"
-
-#: contrib/admin/templates/admin/change_list.html:11
-#, python-format
-msgid "Add %(name)s"
-msgstr "Dodaj %(name)s"
-
-#: contrib/admin/templates/admin/login.html:22
-msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
-msgstr "Ste <a href=\"/password_reset/\">pozabili geslo</a>?"
-
-#: contrib/admin/templates/admin/base.html:23
-msgid "Welcome,"
-msgstr "Dobrodošli,"
-
#: contrib/admin/templates/admin/delete_confirmation.html:9
#: contrib/admin/templates/admin/submit_line.html:3
msgid "Delete"
@@ -788,32 +1170,43 @@ msgstr "Izbriši"
#: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format
-msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
-msgstr "Izbris %(object_name)s '%(object)s' bi pomenil izbris povezanih objektov, vendar nimate dovoljenja za izbris naslednjih tipov objektov:"
+msgid "Deleting the %(object_name)s '%(escaped_object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
+msgstr "Izbris %(object_name)s '%(escaped_object)s' bi pomenil izbris povezanih objektov, vendar nimate dovoljenja za izbris naslednjih tipov objektov:"
#: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format
-msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:"
-msgstr "Ste prepričani, da želite izbrisati %(object_name)s \"%(object)s\"?Vsi naslednji povezani elementi bodo izbrisani:"
+msgid "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? All of the following related items will be deleted:"
+msgstr "Ste prepričani, da želite izbrisati %(object_name)s \"%(escaped_object)s\"? Vsi naslednji povezani elementi bodo izbrisani:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
msgstr "Ja, sem prepričan"
-#: contrib/admin/templates/admin/filter.html:2
-#, python-format
-msgid " By %(title)s "
-msgstr " Po %(title)s"
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr "Strani ni mogoče najti"
-#: contrib/admin/templates/admin/search_form.html:8
-msgid "Go"
-msgstr "Pojdi"
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr "Opravičujemo se, a zahtevane strani ni mogoče najti."
+
+#: contrib/admin/templates/admin/change_form.html:15
+#: contrib/admin/templates/admin/index.html:28
+msgid "Add"
+msgstr "Dodaj"
#: contrib/admin/templates/admin/change_form.html:21
+#: contrib/admin/templates/admin/object_history.html:5
+msgid "History"
+msgstr "Zgodovina"
+
+#: contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
msgstr "Poglej na strani"
-#: contrib/admin/templates/admin/change_form.html:30
+#: contrib/admin/templates/admin/change_form.html:32
+#: contrib/admin/templates/admin/auth/user/change_password.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] "Prosimo, odpravite sledečo napako."
@@ -821,14 +1214,19 @@ msgstr[1] "Prosimo, odpravite sledeči napaki."
msgstr[2] "Prosimo, odpravite sledeče napake."
msgstr[3] "Prosimo, odpravite sledeče napake."
-#: contrib/admin/templates/admin/change_form.html:48
+#: contrib/admin/templates/admin/change_form.html:50
msgid "Ordering"
msgstr "Razvrščanje"
-#: contrib/admin/templates/admin/change_form.html:51
+#: contrib/admin/templates/admin/change_form.html:53
msgid "Order:"
msgstr "Razvrsti:"
+#: contrib/admin/templates/admin/filter.html:2
+#, python-format
+msgid " By %(filter_title)s "
+msgstr "Po %(filter_title)s "
+
#: contrib/admin/templates/admin/submit_line.html:4
msgid "Save as new"
msgstr "Shrani kot novo"
@@ -845,108 +1243,153 @@ msgstr "Shrani in nadaljuj z urejanjem"
msgid "Save"
msgstr "Shrani"
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_form.html:6
-#: contrib/admin/templates/registration/password_change_form.html:10
-msgid "Password change"
-msgstr "Sprememba gesla"
+#: contrib/admin/templates/admin/change_list.html:12
+#, python-format
+msgid "Add %(name)s"
+msgstr "Dodaj %(name)s"
-#: contrib/admin/templates/registration/password_change_done.html:6
-#: contrib/admin/templates/registration/password_change_done.html:10
-msgid "Password change successful"
-msgstr "Sprememba gesla je uspela"
+#: contrib/admin/templates/admin/index.html:17
+#, python-format
+msgid "Models available in the %(name)s application."
+msgstr "Modeli na voljo v %(name)s aplikaciji"
-#: contrib/admin/templates/registration/password_change_done.html:12
-msgid "Your password was changed."
-msgstr "Vaše geslo je bilo spremenjeno."
+#: contrib/admin/templates/admin/index.html:18
+#, python-format
+msgid "%(name)s"
+msgstr "%(name)s"
-#: contrib/admin/templates/registration/password_reset_form.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:6
-#: contrib/admin/templates/registration/password_reset_form.html:10
-#: contrib/admin/templates/registration/password_reset_done.html:4
-msgid "Password reset"
-msgstr "Ponastavitev gesla"
+#: contrib/admin/templates/admin/index.html:34
+msgid "Change"
+msgstr "Spremeni"
-#: contrib/admin/templates/registration/password_reset_form.html:12
-msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
-msgstr "Ste pozabili geslo? Vnesite vaš e-mail naslov in poslali vam bomo novo geslo."
+#: contrib/admin/templates/admin/index.html:44
+msgid "You don't have permission to edit anything."
+msgstr "Nimate dovoljenja za urejanje česar koli."
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "E-mail address:"
-msgstr "Naslov e-pošte:"
+#: contrib/admin/templates/admin/index.html:52
+msgid "Recent Actions"
+msgstr "Zadnja dejanja"
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "Reset my password"
-msgstr "Ponastavi moje geslo"
+#: contrib/admin/templates/admin/index.html:53
+msgid "My Actions"
+msgstr "Moja dejanja"
-#: contrib/admin/templates/registration/logged_out.html:8
-msgid "Thanks for spending some quality time with the Web site today."
-msgstr "Hvala, ker ste si danes vzeli nekaj časa za to spletno stran."
+#: contrib/admin/templates/admin/index.html:57
+msgid "None available"
+msgstr "Ni na voljo"
-#: contrib/admin/templates/registration/logged_out.html:10
-msgid "Log in again"
-msgstr "Ponovna prijava"
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr "Vmesnik za administracijo Django strani"
-#: contrib/admin/templates/registration/password_reset_done.html:6
-#: contrib/admin/templates/registration/password_reset_done.html:10
-msgid "Password reset successful"
-msgstr "Ponastavitev gesla je uspela"
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr "Django administracija"
-#: contrib/admin/templates/registration/password_reset_done.html:12
-msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
-msgstr "Po e-pošti smo vam poslali novo geslo. Morali bi ga prejeti v kratkem"
+#: contrib/admin/templates/admin/object_history.html:18
+msgid "Date/time"
+msgstr "Datum/čas"
-#: contrib/admin/templates/registration/password_change_form.html:12
-msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
-msgstr "Prosim, vnesite vaše staro geslo (zaradi varnosti) in nato še dvakrat novo (da preverimo, da se niste zatipkali)"
+#: contrib/admin/templates/admin/object_history.html:19
+msgid "User"
+msgstr "Uporabnik"
-#: contrib/admin/templates/registration/password_change_form.html:17
-msgid "Old password:"
-msgstr "Staro geslo:"
+#: contrib/admin/templates/admin/object_history.html:20
+msgid "Action"
+msgstr "Dejanje"
-#: contrib/admin/templates/registration/password_change_form.html:19
-msgid "New password:"
-msgstr "Novo geslo:"
+#: contrib/admin/templates/admin/object_history.html:26
+msgid "DATE_WITH_TIME_FULL"
+msgstr "N j, Y, H:i"
-#: contrib/admin/templates/registration/password_change_form.html:21
-msgid "Confirm password:"
-msgstr "Potrditev gesla:"
+#: contrib/admin/templates/admin/object_history.html:36
+msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
+msgstr "Ta objekt nima zgodovine sprememb. Verjetno ni bil dodan preko te strani za administracijo."
-#: contrib/admin/templates/registration/password_change_form.html:23
-msgid "Change my password"
-msgstr "Spremeni moje geslo"
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "Napaka strežnika"
-#: contrib/admin/templates/registration/password_reset_email.html:2
-msgid "You're receiving this e-mail because you requested a password reset"
-msgstr "Ta e-mail ste dobili, ker ste zahtevali ponastavitev gesla"
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr "Napaka strežnika (500)"
-#: contrib/admin/templates/registration/password_reset_email.html:3
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr "Napaka strežnika <em>(500)</em>"
+
+#: contrib/admin/templates/admin/500.html:10
+msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
+msgstr "Prišlo je do nepričakovane napake. Administrator je preko e-pošte prejel obvestilo o napaki in jo bo v kratkem odpravil. Hvala za potrpljenje."
+
+#: contrib/admin/templates/admin/invalid_setup.html:8
+msgid "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user."
+msgstr "Nekaj je narobe z namestitvijo vaše podatkovne baze. Preverite, da so bile ustvarjene prave tabele v podatkovni bazi in da je dostop do branja baze omogočen pravemu uporabniku."
+
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr "Pojdi"
+
+#: contrib/admin/templates/admin/search_form.html:10
#, python-format
-msgid "for your user account at %(site_name)s"
-msgstr "za vaš uporabniški račun na %(site_name)s"
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "%(counter)s rezultat"
+msgstr[1] "%(counter)s rezultata"
+msgstr[2] "%(counter)s rezultati"
+msgstr[3] "%(counter)s rezultatov"
-#: contrib/admin/templates/registration/password_reset_email.html:5
+#: contrib/admin/templates/admin/search_form.html:10
#, python-format
-msgid "Your new password is: %(new_password)s"
-msgstr "Vaše novo geslo je: %(new_password)s"
+msgid "%(full_result_count)s total"
+msgstr "%(full_result_count)s skupno"
-#: contrib/admin/templates/registration/password_reset_email.html:7
-msgid "Feel free to change this password by going to this page:"
-msgstr "Geslo lahko spremenite z obiskom strani:"
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filter"
-#: contrib/admin/templates/registration/password_reset_email.html:11
-msgid "Your username, in case you've forgotten:"
-msgstr "Vaše uporabniško ime (za vsak primer):"
+#: contrib/admin/templates/admin/login.html:17
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+msgid "Username:"
+msgstr "Uporabniško ime:"
-#: contrib/admin/templates/registration/password_reset_email.html:13
-msgid "Thanks for using our site!"
-msgstr "Hvala, ker uporabljate našo stran!"
+#: contrib/admin/templates/admin/login.html:20
+#: contrib/comments/templates/comments/form.html:8
+msgid "Password:"
+msgstr "Geslo:"
-#: contrib/admin/templates/registration/password_reset_email.html:15
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr "Dobrodošli,"
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:6
+msgid "First, enter a username and password. Then, you'll be able to edit more user options."
+msgstr "Najprej vpišite uporabniško ime in geslo, nato boste lahko urejali druge lastnosti uporabnika."
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:12
+msgid "Username"
+msgstr "Uporabniško ime"
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:18
+#: contrib/admin/templates/admin/auth/user/change_password.html:34
+msgid "Password"
+msgstr "Geslo"
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:23
+#: contrib/admin/templates/admin/auth/user/change_password.html:39
+msgid "Password (again)"
+msgstr "Geslo (ponovno)"
+
+#: contrib/admin/templates/admin/auth/user/add_form.html:24
+#: contrib/admin/templates/admin/auth/user/change_password.html:40
+msgid "Enter the same password as above, for verification."
+msgstr "Za preverjanje vpišite enako geslo kot zgoraj."
+
+#: contrib/admin/templates/admin/auth/user/change_password.html:28
#, python-format
-msgid "The %(site_name)s team"
-msgstr "Ekipa strani %(site_name)s"
+msgid "Enter a new password for the user <strong>%(username)s</strong>."
+msgstr "Vpišite novo geslo za uporabnika <strong>%(username)s</strong>."
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets"
@@ -957,7 +1400,6 @@ msgid "Documentation bookmarklets"
msgstr "Dokumentacijske zaznamkice"
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
-#, fuzzy
msgid ""
"\n"
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
@@ -969,7 +1411,7 @@ msgid ""
msgstr ""
"\n"
"<p class=\"help\">Za inštalacijo zaznamkic povlečite povezavo v orodno vrstico\n"
-"z zaznamki, ali kliknite z desno miškino tipko na povezavo in jo dodajte med zaznamke. Zdaj lahko izberete zaznamkico s katerekoli strani. Opomba: nekatere izmed teh strani lahko gledate le z računalnika, ki je označen kot \"notranji\" (v kolikor niste prepričani, če je vaš računalnik označen kot \"notranji\"se obrnite na sistemskega administratorja).</p>\n"
+"z zaznamki, ali kliknite z desno miškino tipko na povezavo in jo dodajte med zaznamke. Zdaj lahko izberete zaznamkico s katerekoli strani tega spletnega mesta. Opomba: nekatere izmed teh strani lahko gledate le z računalnika, ki je označen kot \"notranji\" (v kolikor niste prepričani, če je vaš računalnik označen kot \"notranji\" se obrnite na sistemskega administratorja).</p>\n"
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
msgid "Documentation for this page"
@@ -1019,29 +1461,207 @@ msgstr "Trenutno:"
msgid "Change:"
msgstr "Sprememba:"
-#: contrib/redirects/models.py:7
-msgid "redirect from"
-msgstr "preusmeritev iz"
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:6
+#: contrib/admin/templates/registration/password_reset_form.html:10
+#: contrib/admin/templates/registration/password_reset_done.html:4
+msgid "Password reset"
+msgstr "Ponastavitev gesla"
-#: contrib/redirects/models.py:8
-msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
-msgstr "Ta pot mora biti absolutna, brez imena domene. Primer: '/events/search'"
+#: contrib/admin/templates/registration/password_reset_form.html:12
+msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
+msgstr "Ste pozabili geslo? Vnesite vaš e-mail naslov in poslali vam bomo novo geslo."
-#: contrib/redirects/models.py:9
-msgid "redirect to"
-msgstr "preusmeri na"
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "E-mail address:"
+msgstr "Naslov e-pošte:"
-#: contrib/redirects/models.py:10
-msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
-msgstr "To je lahko absolutna pot (kot zgoraj) ali popoln URL naslov (ki se začne s 'http://')"
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "Reset my password"
+msgstr "Ponastavi moje geslo"
-#: contrib/redirects/models.py:12
-msgid "redirect"
-msgstr "preusmeritev"
+#: contrib/admin/templates/registration/password_reset_email.html:2
+msgid "You're receiving this e-mail because you requested a password reset"
+msgstr "Ta e-mail ste dobili, ker ste zahtevali ponastavitev gesla"
-#: contrib/redirects/models.py:13
-msgid "redirects"
-msgstr "preusmeritve"
+#: contrib/admin/templates/registration/password_reset_email.html:3
+#, python-format
+msgid "for your user account at %(site_name)s"
+msgstr "za vaš uporabniški račun na %(site_name)s"
+
+#: contrib/admin/templates/registration/password_reset_email.html:5
+#, python-format
+msgid "Your new password is: %(new_password)s"
+msgstr "Vaše novo geslo je: %(new_password)s"
+
+#: contrib/admin/templates/registration/password_reset_email.html:7
+msgid "Feel free to change this password by going to this page:"
+msgstr "Geslo lahko spremenite z obiskom strani:"
+
+#: contrib/admin/templates/registration/password_reset_email.html:11
+msgid "Your username, in case you've forgotten:"
+msgstr "Vaše uporabniško ime (za vsak primer):"
+
+#: contrib/admin/templates/registration/password_reset_email.html:13
+msgid "Thanks for using our site!"
+msgstr "Hvala, ker uporabljate našo stran!"
+
+#: contrib/admin/templates/registration/password_reset_email.html:15
+#, python-format
+msgid "The %(site_name)s team"
+msgstr "Ekipa strani %(site_name)s"
+
+#: contrib/admin/templates/registration/logged_out.html:8
+msgid "Thanks for spending some quality time with the Web site today."
+msgstr "Hvala, ker ste si danes vzeli nekaj časa za to spletno stran."
+
+#: contrib/admin/templates/registration/logged_out.html:10
+msgid "Log in again"
+msgstr "Ponovna prijava"
+
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr "Ponastavitev gesla je uspela"
+
+#: contrib/admin/templates/registration/password_reset_done.html:12
+msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
+msgstr "Po e-pošti smo vam poslali novo geslo. Morali bi ga prejeti v kratkem"
+
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+#: contrib/admin/templates/registration/password_change_done.html:4
+msgid "Password change"
+msgstr "Sprememba gesla"
+
+#: contrib/admin/templates/registration/password_change_form.html:12
+msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
+msgstr "Prosim, vnesite vaše staro geslo (zaradi varnosti) in nato še dvakrat novo (da preverimo, da se niste zatipkali)"
+
+#: contrib/admin/templates/registration/password_change_form.html:17
+msgid "Old password:"
+msgstr "Staro geslo:"
+
+#: contrib/admin/templates/registration/password_change_form.html:19
+msgid "New password:"
+msgstr "Novo geslo:"
+
+#: contrib/admin/templates/registration/password_change_form.html:21
+msgid "Confirm password:"
+msgstr "Potrditev gesla:"
+
+#: contrib/admin/templates/registration/password_change_form.html:23
+msgid "Change my password"
+msgstr "Spremeni moje geslo"
+
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr "Sprememba gesla je uspela"
+
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr "Vaše geslo je bilo spremenjeno."
+
+#: contrib/sites/models.py:10
+msgid "domain name"
+msgstr "domena"
+
+#: contrib/sites/models.py:11
+msgid "display name"
+msgstr "prikazno ime"
+
+#: contrib/sites/models.py:15
+msgid "site"
+msgstr "stran"
+
+#: contrib/sites/models.py:16
+msgid "sites"
+msgstr "strani"
+
+#: contrib/humanize/templatetags/humanize.py:17
+#, fuzzy
+msgid "th"
+msgstr "th"
+
+#: contrib/humanize/templatetags/humanize.py:17
+#, fuzzy
+msgid "st"
+msgstr "st"
+
+#: contrib/humanize/templatetags/humanize.py:17
+#, fuzzy
+msgid "nd"
+msgstr "nd"
+
+#: contrib/humanize/templatetags/humanize.py:17
+#, fuzzy
+msgid "rd"
+msgstr "rd"
+
+#: contrib/humanize/templatetags/humanize.py:47
+#, python-format
+msgid "%(value).1f million"
+msgid_plural "%(value).1f million"
+msgstr[0] "%(value).1f milijon"
+msgstr[1] "%(value).1f milijona"
+msgstr[2] "%(value).1f milijoni"
+msgstr[3] "%(value).1f milijonov"
+
+#: contrib/humanize/templatetags/humanize.py:50
+#, python-format
+msgid "%(value).1f billion"
+msgid_plural "%(value).1f billion"
+msgstr[0] "%(value).1f bilijon"
+msgstr[1] "%(value).1f bilijona"
+msgstr[2] "%(value).1f bilijoni"
+msgstr[3] "%(value).1f bilijonov"
+
+#: contrib/humanize/templatetags/humanize.py:53
+#, python-format
+msgid "%(value).1f trillion"
+msgid_plural "%(value).1f trillion"
+msgstr[0] "%(value).1f triljon"
+msgstr[1] "%(value).1f triljona"
+msgstr[2] "%(value).1f triljoni"
+msgstr[3] "%(value).1f triljonov"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "one"
+msgstr "ena"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "two"
+msgstr "dva"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "three"
+msgstr "tri"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "four"
+msgstr "štiri"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "five"
+msgstr "pet"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "six"
+msgstr "šest"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "seven"
+msgstr "sedem"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "eight"
+msgstr "osem"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "nine"
+msgstr "devet"
#: contrib/flatpages/models.py:8
msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
@@ -1064,8 +1684,8 @@ msgid "template name"
msgstr "ime predloge"
#: contrib/flatpages/models.py:13
-msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'."
-msgstr "Primer: 'flatpages/contact_page'. Če to polje ni izpolnjeno, bo sistem uporabil 'flatpages/default'."
+msgid "Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."
+msgstr "Primer: 'flatpages/contact_page.html'. Če to polje ni izpolnjeno, bo sistem uporabil 'flatpages/default.html'."
#: contrib/flatpages/models.py:14
msgid "registration required"
@@ -1083,180 +1703,866 @@ msgstr "enostavna stran"
msgid "flat pages"
msgstr "enostavne strani"
-#: contrib/auth/models.py:13
-#: contrib/auth/models.py:26
-msgid "name"
-msgstr "ime"
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr "preusmeritev iz"
-#: contrib/auth/models.py:15
-msgid "codename"
-msgstr "kodno ime"
+#: contrib/redirects/models.py:8
+msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
+msgstr "Ta pot mora biti absolutna, brez imena domene. Primer: '/events/search'"
-#: contrib/auth/models.py:17
-msgid "permission"
-msgstr "dovoljenje"
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr "preusmeri na"
-#: contrib/auth/models.py:18
-#: contrib/auth/models.py:27
-msgid "permissions"
-msgstr "dovoljenja"
+#: contrib/redirects/models.py:10
+msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
+msgstr "To je lahko absolutna pot (kot zgoraj) ali popoln URL naslov (ki se začne s 'http://')"
-#: contrib/auth/models.py:29
-msgid "group"
-msgstr "skupina"
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr "preusmeritev"
-#: contrib/auth/models.py:30
-#: contrib/auth/models.py:65
-msgid "groups"
-msgstr "skupine"
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr "preusmeritve"
-#: contrib/auth/models.py:55
-msgid "username"
-msgstr "uporabniško ime"
+#: contrib/comments/models.py:67
+#: contrib/comments/models.py:166
+msgid "object ID"
+msgstr "ID objekta"
-#: contrib/auth/models.py:56
-msgid "first name"
-msgstr "ime"
+#: contrib/comments/models.py:68
+msgid "headline"
+msgstr "naslov"
-#: contrib/auth/models.py:57
-msgid "last name"
-msgstr "priimek"
+#: contrib/comments/models.py:69
+#: contrib/comments/models.py:90
+#: contrib/comments/models.py:167
+msgid "comment"
+msgstr "komentar"
-#: contrib/auth/models.py:58
-msgid "e-mail address"
-msgstr "e-mail naslov"
+#: contrib/comments/models.py:70
+msgid "rating #1"
+msgstr "rating #1"
-#: contrib/auth/models.py:59
-msgid "password"
-msgstr "geslo"
+#: contrib/comments/models.py:71
+msgid "rating #2"
+msgstr "rating #2"
-#: contrib/auth/models.py:59
-msgid "Use '[algo]$[salt]$[hexdigest]'"
-msgstr "Uporabi '[algo]$[salt]$[hexdigest]'"
+#: contrib/comments/models.py:72
+msgid "rating #3"
+msgstr "rating #3"
-#: contrib/auth/models.py:60
-msgid "staff status"
-msgstr "status osebja"
+#: contrib/comments/models.py:73
+msgid "rating #4"
+msgstr "rating #4"
-#: contrib/auth/models.py:60
-msgid "Designates whether the user can log into this admin site."
-msgstr "Določi, če se sme uporabnik prijaviti v to administracijsko stran."
+#: contrib/comments/models.py:74
+msgid "rating #5"
+msgstr "rating #5"
-#: contrib/auth/models.py:61
-msgid "active"
-msgstr "aktiven"
+#: contrib/comments/models.py:75
+msgid "rating #6"
+msgstr "rating #6"
-#: contrib/auth/models.py:62
-msgid "superuser status"
-msgstr "status superuporabnika"
+#: contrib/comments/models.py:76
+msgid "rating #7"
+msgstr "rating #7"
-#: contrib/auth/models.py:63
-msgid "last login"
-msgstr "zadnja prijava"
+#: contrib/comments/models.py:77
+msgid "rating #8"
+msgstr "rating #8"
-#: contrib/auth/models.py:64
-msgid "date joined"
-msgstr "član od"
+#: contrib/comments/models.py:82
+msgid "is valid rating"
+msgstr "je veljavni rating"
-#: contrib/auth/models.py:66
-msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
-msgstr "Poleg ročno določenih dovoljenj bo ta uporabnik dobil tudi vsa dovoljenja, ki pripadajo skupinam, katerih član je."
+#: contrib/comments/models.py:83
+#: contrib/comments/models.py:169
+msgid "date/time submitted"
+msgstr "datum/čas vnosa"
-#: contrib/auth/models.py:67
-msgid "user permissions"
-msgstr "uporabniška dovoljenja"
+#: contrib/comments/models.py:84
+#: contrib/comments/models.py:170
+msgid "is public"
+msgstr "je javno"
-#: contrib/auth/models.py:70
-msgid "user"
-msgstr "uporabnik"
+#: contrib/comments/models.py:86
+msgid "is removed"
+msgstr "je odstranjen/-a"
-#: contrib/auth/models.py:71
-msgid "users"
-msgstr "uporabniki"
+#: contrib/comments/models.py:86
+msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead."
+msgstr "Odkljukaj, če je komentar neprimeren. Namesto komentarja bo vidno obvestilo \"Ta komentar je bil odstranjen\"."
-#: contrib/auth/models.py:76
-msgid "Personal info"
-msgstr "Osebni podatki"
+#: contrib/comments/models.py:91
+msgid "comments"
+msgstr "komentarji"
-#: contrib/auth/models.py:77
-msgid "Permissions"
-msgstr "Dovoljenja"
+#: contrib/comments/models.py:131
+#: contrib/comments/models.py:207
+msgid "Content object"
+msgstr "Objekt z vsebino"
-#: contrib/auth/models.py:78
-msgid "Important dates"
-msgstr "Pomembni datumi"
+#: contrib/comments/models.py:159
+#, python-format
+msgid ""
+"Posted by %(user)s at %(date)s\n"
+"\n"
+"%(comment)s\n"
+"\n"
+"http://%(domain)s%(url)s"
+msgstr ""
+"Poslal uporabnik %(user)s ob %(date)s\n"
+"\n"
+"%(comment)s\n"
+"\n"
+"http://%(domain)s%(url)s"
-#: contrib/auth/models.py:79
-msgid "Groups"
-msgstr "Skupine"
+#: contrib/comments/models.py:168
+msgid "person's name"
+msgstr "ime osebe"
-#: contrib/auth/models.py:219
-msgid "message"
-msgstr "sporočilo"
+#: contrib/comments/models.py:171
+msgid "ip address"
+msgstr "ip naslov"
-#: contrib/auth/forms.py:30
-msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
-msgstr "Izgleda, da vaš brskalnik nima omogočenih piškotkov. Piškotki so potrebni za prijavo."
+#: contrib/comments/models.py:173
+msgid "approved by staff"
+msgstr "osebje je potrdilo"
-#: contrib/contenttypes/models.py:25
-msgid "python model class name"
-msgstr "python ime razreda modela"
+#: contrib/comments/models.py:176
+msgid "free comment"
+msgstr "anonimen komentar"
-#: contrib/contenttypes/models.py:28
-msgid "content type"
-msgstr "tip vsebine"
+#: contrib/comments/models.py:177
+msgid "free comments"
+msgstr "anonimni komentarji"
-#: contrib/contenttypes/models.py:29
-msgid "content types"
-msgstr "tipi vsebine"
+#: contrib/comments/models.py:233
+msgid "score"
+msgstr "ocena"
+
+#: contrib/comments/models.py:234
+msgid "score date"
+msgstr "datum ocene"
+
+#: contrib/comments/models.py:237
+msgid "karma score"
+msgstr "karma točke"
+
+#: contrib/comments/models.py:238
+msgid "karma scores"
+msgstr "karma točke"
+
+#: contrib/comments/models.py:242
+#, python-format
+msgid "%(score)d rating by %(user)s"
+msgstr "oceno %(score)d podelil %(user)s"
+
+#: contrib/comments/models.py:258
+#, python-format
+msgid ""
+"This comment was flagged by %(user)s:\n"
+"\n"
+"%(text)s"
+msgstr ""
+"Komentar je z zastavico označil %(user)s:\n"
+"\n"
+"%(text)s"
+
+#: contrib/comments/models.py:265
+msgid "flag date"
+msgstr "datum označitve (zastavice)"
+
+#: contrib/comments/models.py:268
+msgid "user flag"
+msgstr "uporabniška zastavica"
+
+#: contrib/comments/models.py:269
+msgid "user flags"
+msgstr "uporabniške zastavice"
+
+#: contrib/comments/models.py:273
+#, python-format
+msgid "Flag by %r"
+msgstr "Avtor zastavice je %r"
+
+#: contrib/comments/models.py:278
+msgid "deletion date"
+msgstr "datum izbrisa"
+
+#: contrib/comments/models.py:280
+msgid "moderator deletion"
+msgstr "izbris s strani moderatorja"
+
+#: contrib/comments/models.py:281
+msgid "moderator deletions"
+msgstr "izbrisi s strani moderatorja"
+
+#: contrib/comments/models.py:285
+#, python-format
+msgid "Moderator deletion by %r"
+msgstr "Izbris opravil moderator %r"
+
+#: contrib/comments/views/karma.py:19
+msgid "Anonymous users cannot vote"
+msgstr "Anonimni uporabniki ne morejo glasovati"
+
+#: contrib/comments/views/karma.py:23
+msgid "Invalid comment ID"
+msgstr "Neveljavni ID komentarja"
+
+#: contrib/comments/views/karma.py:25
+msgid "No voting for yourself"
+msgstr "Ni mogoče glasovati zase"
+
+#: contrib/comments/views/comments.py:27
+msgid "This rating is required because you've entered at least one other rating."
+msgstr "To oceno moraš podati, ker si podal vsaj še eno drugo oceno."
+
+#: contrib/comments/views/comments.py:111
+#, python-format
+msgid ""
+"This comment was posted by a user who has posted fewer than %(count)s comment:\n"
+"\n"
+"%(text)s"
+msgid_plural ""
+"This comment was posted by a user who has posted fewer than %(count)s comments:\n"
+"\n"
+"%(text)s"
+msgstr[0] ""
+"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarjev:\n"
+"\n"
+"%(text)s"
+msgstr[1] ""
+"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarja:\n"
+"\n"
+"%(text)s"
+msgstr[2] ""
+"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarje:\n"
+"\n"
+"%(text)s"
+msgstr[3] ""
+"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarjev:\n"
+"\n"
+"%(text)s"
+
+#: contrib/comments/views/comments.py:116
+#, python-format
+msgid ""
+"This comment was posted by a sketchy user:\n"
+"\n"
+"%(text)s"
+msgstr ""
+"Ta komentar je poslal sumljiv uporabnik:\n"
+"\n"
+"%(text)s"
+
+#: contrib/comments/views/comments.py:188
+#: contrib/comments/views/comments.py:280
+msgid "Only POSTs are allowed"
+msgstr "Dovoljena je le POST metoda"
+
+#: contrib/comments/views/comments.py:192
+#: contrib/comments/views/comments.py:284
+msgid "One or more of the required fields wasn't submitted"
+msgstr "Eno ali več obveznih polj ni vpisanih"
+
+#: contrib/comments/views/comments.py:196
+#: contrib/comments/views/comments.py:286
+msgid "Somebody tampered with the comment form (security violation)"
+msgstr "Nekdo se je poigraval z obrazcem za komentarje (varnostna kršitev)"
+
+#: contrib/comments/views/comments.py:206
+#: contrib/comments/views/comments.py:292
+msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
+msgstr "Obrazec s komentarji ima neveljavni parameter 'target' -- ID objekta je neveljaven."
+
+#: contrib/comments/views/comments.py:257
+#: contrib/comments/views/comments.py:321
+msgid "The comment form didn't provide either 'preview' or 'post'"
+msgstr "Obrazec s komentarji ni podal niti 'preview' niti 'post' akcije."
+
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr "Ste pozabili geslo?"
+
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr "Ocene"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr "Obvezno"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr "Neobvezno"
+
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr "Objavi sliko"
+
+#: contrib/comments/templates/comments/form.html:28
+#: contrib/comments/templates/comments/freeform.html:5
+msgid "Comment:"
+msgstr "Komentar:"
+
+#: contrib/comments/templates/comments/form.html:35
+#: contrib/comments/templates/comments/freeform.html:10
+msgid "Preview comment"
+msgstr "Predogled komentarja"
+
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "Vaše ime:"
+
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr "Vnesite 4-mestno poštno številko."
+
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr "Vnesite poštno številko v zapisu XXXXX-XXX."
+
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr "Telefonska številka mora biti v zapisu XX-XXXX-XXXX."
+
+#: contrib/localflavor/br/forms.py:72
+msgid "This field requires only numbers."
+msgstr "To polje lahko vsebuje samo številke."
+
+#: contrib/localflavor/br/forms.py:74
+msgid "This field requires at most 11 digits or 14 characters."
+msgstr "To polje zahteva največ 11 števk ali 14 znakov."
+
+#: contrib/localflavor/br/forms.py:84
+msgid "Invalid CPF number."
+msgstr "Nepravilna CPF številka."
+
+#: contrib/localflavor/br/forms.py:106
+msgid "This field requires at least 14 digits"
+msgstr "To polje mora vsebovati vsaj 14 števk."
+
+#: contrib/localflavor/br/forms.py:116
+msgid "Invalid CNPJ number."
+msgstr "Nepravilna CNPJ številka."
+
+#: contrib/localflavor/ch/forms.py:18
+#: contrib/localflavor/no/forms.py:15
+msgid "Enter a zip code in the format XXXX."
+msgstr "Vnesite veljavno poštno številko v obliki XXXX."
+
+#: contrib/localflavor/ch/forms.py:90
+msgid "Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format."
+msgstr "Vpišite veljavno številko švicarske osebne izkaznice ali potenga lista v zapisu X1234567<0 ali 1234567890"
+
+#: contrib/localflavor/ch/ch_states.py:5
+msgid "Aargau"
+msgstr "Aargau"
+
+#: contrib/localflavor/ch/ch_states.py:6
+msgid "Appenzell Innerrhoden"
+msgstr "Appenzell Innerrhoden"
+
+#: contrib/localflavor/ch/ch_states.py:7
+msgid "Appenzell Ausserrhoden"
+msgstr "Appenzell Ausserrhoden"
+
+#: contrib/localflavor/ch/ch_states.py:8
+msgid "Basel-Stadt"
+msgstr "Basel (mesto)"
+
+#: contrib/localflavor/ch/ch_states.py:9
+msgid "Basel-Land"
+msgstr "Basel (dežela)"
+
+#: contrib/localflavor/ch/ch_states.py:10
+msgid "Berne"
+msgstr "Berne"
+
+#: contrib/localflavor/ch/ch_states.py:11
+msgid "Fribourg"
+msgstr "Fribourg"
+
+#: contrib/localflavor/ch/ch_states.py:12
+msgid "Geneva"
+msgstr "Ženeva"
+
+#: contrib/localflavor/ch/ch_states.py:13
+msgid "Glarus"
+msgstr "Glarus"
+
+#: contrib/localflavor/ch/ch_states.py:14
+msgid "Graubuenden"
+msgstr "Graubuenden"
+
+#: contrib/localflavor/ch/ch_states.py:15
+msgid "Jura"
+msgstr "Jura"
+
+#: contrib/localflavor/ch/ch_states.py:16
+msgid "Lucerne"
+msgstr "Lucerne"
+
+#: contrib/localflavor/ch/ch_states.py:17
+msgid "Neuchatel"
+msgstr "Neuchatel"
+
+#: contrib/localflavor/ch/ch_states.py:18
+msgid "Nidwalden"
+msgstr "Nidwalden"
+
+#: contrib/localflavor/ch/ch_states.py:19
+msgid "Obwalden"
+msgstr "Obwalden"
+
+#: contrib/localflavor/ch/ch_states.py:20
+msgid "Schaffhausen"
+msgstr "Schaffhausen"
+
+#: contrib/localflavor/ch/ch_states.py:21
+msgid "Schwyz"
+msgstr "Schwyz"
+
+#: contrib/localflavor/ch/ch_states.py:22
+msgid "Solothurn"
+msgstr "Solothurn"
+
+#: contrib/localflavor/ch/ch_states.py:23
+msgid "St. Gallen"
+msgstr "St. Gallen"
+
+#: contrib/localflavor/ch/ch_states.py:24
+msgid "Thurgau"
+msgstr "Thurgau"
+
+#: contrib/localflavor/ch/ch_states.py:25
+msgid "Ticino"
+msgstr "Ticino"
+
+#: contrib/localflavor/ch/ch_states.py:26
+msgid "Uri"
+msgstr "Uri"
+
+#: contrib/localflavor/ch/ch_states.py:27
+msgid "Valais"
+msgstr "Valais"
+
+#: contrib/localflavor/ch/ch_states.py:28
+msgid "Vaud"
+msgstr "Vaud"
+
+#: contrib/localflavor/ch/ch_states.py:29
+msgid "Zug"
+msgstr "Zug"
+
+#: contrib/localflavor/ch/ch_states.py:30
+msgid "Zurich"
+msgstr "Zurich"
+
+#: contrib/localflavor/cl/forms.py:21
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Vpišite veljaven čilenski RUT v zapisu XX.XXX.XXX-X."
+
+#: contrib/localflavor/cl/forms.py:26
+msgid "Enter valid a Chilean RUT"
+msgstr "Vnesite veljaven čilski RUT"
+
+#: contrib/localflavor/de/forms.py:16
+#: contrib/localflavor/fi/forms.py:14
+#: contrib/localflavor/fr/forms.py:17
+msgid "Enter a zip code in the format XXXXX."
+msgstr "Vnesite veljavno poštno številko v obliki XXXXX."
+
+#: contrib/localflavor/de/forms.py:60
+msgid "Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format."
+msgstr "Vpišite veljavno številko nemške osebne izkaznice v zapisu XXXXXXXXXXX-XXXXXXX-XXXXXXX-X."
+
+#: contrib/localflavor/de/de_states.py:5
+msgid "Baden-Wuerttemberg"
+msgstr "Baden-Wuerttemberg"
+
+#: contrib/localflavor/de/de_states.py:6
+msgid "Bavaria"
+msgstr "Bavarska"
+
+#: contrib/localflavor/de/de_states.py:7
+msgid "Berlin"
+msgstr "Berlin"
+
+#: contrib/localflavor/de/de_states.py:8
+msgid "Brandenburg"
+msgstr "Brandenburg"
+
+#: contrib/localflavor/de/de_states.py:9
+msgid "Bremen"
+msgstr "Bremen"
+
+#: contrib/localflavor/de/de_states.py:10
+msgid "Hamburg"
+msgstr "Hamburg"
+
+#: contrib/localflavor/de/de_states.py:11
+msgid "Hessen"
+msgstr "Hessen"
+
+#: contrib/localflavor/de/de_states.py:12
+msgid "Mecklenburg-Western Pomerania"
+msgstr "Mecklenburg-Western Pomerania"
+
+#: contrib/localflavor/de/de_states.py:13
+msgid "Lower Saxony"
+msgstr "Lower Saxony"
+
+#: contrib/localflavor/de/de_states.py:14
+msgid "North Rhine-Westphalia"
+msgstr "Severno porenje - Westfalija"
+
+#: contrib/localflavor/de/de_states.py:15
+msgid "Rhineland-Palatinate"
+msgstr "Rhineland-Palatinate"
+
+#: contrib/localflavor/de/de_states.py:16
+msgid "Saarland"
+msgstr "Posarje"
+
+#: contrib/localflavor/de/de_states.py:17
+msgid "Saxony"
+msgstr "Saxony"
+
+#: contrib/localflavor/de/de_states.py:18
+msgid "Saxony-Anhalt"
+msgstr "Saška-Anhalt"
+
+#: contrib/localflavor/de/de_states.py:19
+msgid "Schleswig-Holstein"
+msgstr "Schleswig-Holstein"
+
+#: contrib/localflavor/de/de_states.py:20
+msgid "Thuringia"
+msgstr "Thuringia"
+
+#: contrib/localflavor/fi/forms.py:40
+#: contrib/localflavor/fi/forms.py:45
+msgid "Enter a valid Finnish social security number."
+msgstr "Vnesite veljavno številko finskega socialnega zavarovanja."
+
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Vnesite veljavno poštno številko."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Vnesite veljavno številko socialnega zavarovanja."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Vnesite veljavno davčno (VAT) številko."
+
+#: contrib/localflavor/jp/forms.py:21
+msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
+msgstr "Vpišite poštno številko v zapisu XXXXXXX or XXX-XXXX."
+
+#: contrib/localflavor/jp/jp_prefectures.py:4
+msgid "Hokkaido"
+msgstr "Hokaido"
+
+#: contrib/localflavor/jp/jp_prefectures.py:5
+msgid "Aomori"
+msgstr "Aomori"
+
+#: contrib/localflavor/jp/jp_prefectures.py:6
+msgid "Iwate"
+msgstr "Iwate"
+
+#: contrib/localflavor/jp/jp_prefectures.py:7
+msgid "Miyagi"
+msgstr "Miyagi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:8
+msgid "Akita"
+msgstr "Akita"
+
+#: contrib/localflavor/jp/jp_prefectures.py:9
+msgid "Yamagata"
+msgstr "Jamagata"
+
+#: contrib/localflavor/jp/jp_prefectures.py:10
+msgid "Fukushima"
+msgstr "Fukushima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:11
+msgid "Ibaraki"
+msgstr "Ibaraki"
+
+#: contrib/localflavor/jp/jp_prefectures.py:12
+msgid "Tochigi"
+msgstr "Točigi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:13
+msgid "Gunma"
+msgstr "Gunma"
+
+#: contrib/localflavor/jp/jp_prefectures.py:14
+msgid "Saitama"
+msgstr "Saitama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:15
+msgid "Chiba"
+msgstr "Čiba"
+
+#: contrib/localflavor/jp/jp_prefectures.py:16
+msgid "Tokyo"
+msgstr "Tokio"
+
+#: contrib/localflavor/jp/jp_prefectures.py:17
+msgid "Kanagawa"
+msgstr "Kanagawa"
+
+#: contrib/localflavor/jp/jp_prefectures.py:18
+msgid "Yamanashi"
+msgstr "Jamanaši"
+
+#: contrib/localflavor/jp/jp_prefectures.py:19
+msgid "Nagano"
+msgstr "Nagano"
+
+#: contrib/localflavor/jp/jp_prefectures.py:20
+msgid "Niigata"
+msgstr "Niigata"
+
+#: contrib/localflavor/jp/jp_prefectures.py:21
+msgid "Toyama"
+msgstr "Toyama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:22
+msgid "Ishikawa"
+msgstr "Išikava"
+
+#: contrib/localflavor/jp/jp_prefectures.py:23
+msgid "Fukui"
+msgstr "Fukui"
+
+#: contrib/localflavor/jp/jp_prefectures.py:24
+msgid "Gifu"
+msgstr "Gifu"
+
+#: contrib/localflavor/jp/jp_prefectures.py:25
+msgid "Shizuoka"
+msgstr "Šizuoka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:26
+msgid "Aichi"
+msgstr "Aichi"
+
+#: contrib/localflavor/jp/jp_prefectures.py:27
+msgid "Mie"
+msgstr "Mie"
+
+#: contrib/localflavor/jp/jp_prefectures.py:28
+msgid "Shiga"
+msgstr "Šiga"
+
+#: contrib/localflavor/jp/jp_prefectures.py:29
+msgid "Kyoto"
+msgstr "Kjoto"
+
+#: contrib/localflavor/jp/jp_prefectures.py:30
+msgid "Osaka"
+msgstr "Osaka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:31
+msgid "Hyogo"
+msgstr "Hjogo"
+
+#: contrib/localflavor/jp/jp_prefectures.py:32
+msgid "Nara"
+msgstr "Nara"
+
+#: contrib/localflavor/jp/jp_prefectures.py:33
+msgid "Wakayama"
+msgstr "Vakajama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:34
+msgid "Tottori"
+msgstr "Tottori"
+
+#: contrib/localflavor/jp/jp_prefectures.py:35
+msgid "Shimane"
+msgstr "Šimane"
+
+#: contrib/localflavor/jp/jp_prefectures.py:36
+msgid "Okayama"
+msgstr "Okajama"
+
+#: contrib/localflavor/jp/jp_prefectures.py:37
+msgid "Hiroshima"
+msgstr "Hirošima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:38
+msgid "Yamaguchi"
+msgstr "Jamaguči"
+
+#: contrib/localflavor/jp/jp_prefectures.py:39
+msgid "Tokushima"
+msgstr "Tokušima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:40
+msgid "Kagawa"
+msgstr "Kagawa"
+
+#: contrib/localflavor/jp/jp_prefectures.py:41
+msgid "Ehime"
+msgstr "Ehime"
+
+#: contrib/localflavor/jp/jp_prefectures.py:42
+msgid "Kochi"
+msgstr "Koči"
+
+#: contrib/localflavor/jp/jp_prefectures.py:43
+msgid "Fukuoka"
+msgstr "Fukuoka"
+
+#: contrib/localflavor/jp/jp_prefectures.py:44
+msgid "Saga"
+msgstr "Saga"
+
+#: contrib/localflavor/jp/jp_prefectures.py:45
+msgid "Nagasaki"
+msgstr "Nagasaki"
+
+#: contrib/localflavor/jp/jp_prefectures.py:46
+msgid "Kumamoto"
+msgstr "Kumamoto"
+
+#: contrib/localflavor/jp/jp_prefectures.py:47
+msgid "Oita"
+msgstr "Oita"
+
+#: contrib/localflavor/jp/jp_prefectures.py:48
+msgid "Miyazaki"
+msgstr "Miyazaki"
-#: contrib/sessions/models.py:35
+#: contrib/localflavor/jp/jp_prefectures.py:49
+msgid "Kagoshima"
+msgstr "Kagošima"
+
+#: contrib/localflavor/jp/jp_prefectures.py:50
+msgid "Okinawa"
+msgstr "Okinava"
+
+#: contrib/localflavor/no/forms.py:36
+msgid "Enter a valid Norwegian social security number."
+msgstr "Vnesite veljavno številko norveškega socialnega zavarovanja."
+
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr "Vpišite poštno številko. Med dvema deloma poštne številke je obvezen presledek."
+
+#: contrib/localflavor/us/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr "Vnesite poštno številko v zapisu XXXXX ali XXXXX-XXXX."
+
+#: contrib/localflavor/us/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr "Vpišite veljavno številko ameriškega socialnega zavarovanja v zapisu XXX-XX-XXXX."
+
+#: contrib/localflavor/is_/forms.py:16
+msgid "Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr "Vpišite pravilno islandsko identifikacijsko številko v zapisu XXXXXX-XXXX."
+
+#: contrib/localflavor/is_/forms.py:30
+msgid "The Icelandic identification number is not valid."
+msgstr "Islandska identifikacijska številka ni pravilna."
+
+#: contrib/sessions/models.py:68
msgid "session key"
msgstr "ključ seje"
-#: contrib/sessions/models.py:36
+#: contrib/sessions/models.py:69
msgid "session data"
msgstr "podatki seje"
-#: contrib/sessions/models.py:37
+#: contrib/sessions/models.py:70
msgid "expire date"
msgstr "čaz izteka"
-#: contrib/sessions/models.py:41
+#: contrib/sessions/models.py:74
msgid "session"
msgstr "seja"
-#: contrib/sessions/models.py:42
+#: contrib/sessions/models.py:75
msgid "sessions"
msgstr "seje"
-#: contrib/sites/models.py:10
-msgid "domain name"
-msgstr "domena"
+#: contrib/contenttypes/models.py:36
+msgid "python model class name"
+msgstr "python ime razreda modela"
-#: contrib/sites/models.py:11
-msgid "display name"
-msgstr "prikazno ime"
+#: contrib/contenttypes/models.py:39
+msgid "content type"
+msgstr "tip vsebine"
-#: contrib/sites/models.py:15
-msgid "site"
-msgstr "stran"
+#: contrib/contenttypes/models.py:40
+msgid "content types"
+msgstr "tipi vsebine"
-#: contrib/sites/models.py:16
-msgid "sites"
-msgstr "strani"
+#: oldforms/__init__.py:392
+#, python-format
+msgid "Ensure your text is less than %s character."
+msgid_plural "Ensure your text is less than %s characters."
+msgstr[0] "Poskrbite, da bo tekst krajši od %s znaka."
+msgstr[1] "Poskrbite, da bo tekst krajši od %s znakov."
+msgstr[2] "Poskrbite, da bo tekst krajši od %s znakov."
+msgstr[3] "Poskrbite, da bo tekst krajši od %s znakov."
-#: utils/translation.py:360
-msgid "DATE_FORMAT"
-msgstr "N j, Y"
+#: oldforms/__init__.py:397
+msgid "Line breaks are not allowed here."
+msgstr "Prelomi vrstice tu niso dovoljeni."
-#: utils/translation.py:361
-msgid "DATETIME_FORMAT"
-msgstr "N j, Y, P"
+#: oldforms/__init__.py:498
+#: oldforms/__init__.py:571
+#: oldforms/__init__.py:610
+#, python-format
+msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
+msgstr "Izberite veljavno možnost; '%(data)s' ni v %(choices)s."
-#: utils/translation.py:362
-msgid "TIME_FORMAT"
-msgstr "P"
+#: oldforms/__init__.py:674
+msgid "The submitted file is empty."
+msgstr "Poslana datoteka je prazna."
+
+#: oldforms/__init__.py:730
+msgid "Enter a whole number between -32,768 and 32,767."
+msgstr "Vnesite celo število med -32.768 in 32.767."
+
+#: oldforms/__init__.py:740
+msgid "Enter a positive number."
+msgstr "Vnesite pozitivno število."
+
+#: oldforms/__init__.py:750
+msgid "Enter a whole number between 0 and 32,767."
+msgstr "Vnesite celo število med 0 in 32.767."
+
+#: views/generic/create_update.py:43
+#, python-format
+msgid "The %(verbose_name)s was created successfully."
+msgstr "%(verbose_name)s je bil uspešno ustvarjen."
+
+#: views/generic/create_update.py:117
+#, python-format
+msgid "The %(verbose_name)s was updated successfully."
+msgstr "%(verbose_name)s je bil uspešno posodobljen."
+
+#: views/generic/create_update.py:184
+#, python-format
+msgid "The %(verbose_name)s was deleted."
+msgstr "%(verbose_name)s je bil uspešno izbrisan."
#: utils/dates.py:6
msgid "Monday"
@@ -1463,467 +2769,199 @@ msgstr[1] "minuti"
msgstr[2] "minute"
msgstr[3] "minut"
-#: conf/global_settings.py:37
-msgid "Bengali"
-msgstr "Bengalski"
-
-#: conf/global_settings.py:38
-msgid "Czech"
-msgstr "Češki"
-
-#: conf/global_settings.py:39
-msgid "Welsh"
-msgstr "Valežanski"
-
-#: conf/global_settings.py:40
-msgid "Danish"
-msgstr "Danski"
-
-#: conf/global_settings.py:41
-msgid "German"
-msgstr "Nemški"
-
-#: conf/global_settings.py:42
-msgid "Greek"
-msgstr "Grški"
-
-#: conf/global_settings.py:43
-msgid "English"
-msgstr "Angleški"
-
-#: conf/global_settings.py:44
-msgid "Spanish"
-msgstr "Španski"
-
-#: conf/global_settings.py:45
-msgid "French"
-msgstr "Francoski"
-
-#: conf/global_settings.py:46
-msgid "Galician"
-msgstr "Galičanski"
-
-#: conf/global_settings.py:47
-msgid "Hungarian"
-msgstr "Madžarski"
-
-#: conf/global_settings.py:48
-msgid "Hebrew"
-msgstr "Hebrejski"
-
-#: conf/global_settings.py:49
-msgid "Icelandic"
-msgstr "Islandski"
-
-#: conf/global_settings.py:50
-msgid "Italian"
-msgstr "Italijanski"
-
-#: conf/global_settings.py:51
-msgid "Japanese"
-msgstr "Japonski"
-
-#: conf/global_settings.py:52
-msgid "Dutch"
-msgstr "Nizozemski"
-
-#: conf/global_settings.py:53
-msgid "Norwegian"
-msgstr "Norveški"
-
-#: conf/global_settings.py:54
-msgid "Brazilian"
-msgstr "Brazilski"
-
-#: conf/global_settings.py:55
-msgid "Romanian"
-msgstr "Romunski"
-
-#: conf/global_settings.py:56
-msgid "Russian"
-msgstr "Ruski"
-
-#: conf/global_settings.py:57
-msgid "Slovak"
-msgstr "Slovaški"
-
-#: conf/global_settings.py:58
-msgid "Slovenian"
-msgstr "Slovenski"
-
-#: conf/global_settings.py:59
-msgid "Serbian"
-msgstr "Srbski"
-
-#: conf/global_settings.py:60
-msgid "Swedish"
-msgstr "Švedski"
-
-#: conf/global_settings.py:61
-msgid "Ukrainian"
-msgstr "Ukrajinski"
-
-#: conf/global_settings.py:62
-msgid "Simplified Chinese"
-msgstr "Poenostavljeni kitajski"
-
-#: conf/global_settings.py:63
-msgid "Traditional Chinese"
-msgstr "Tradicionalni kitajski"
-
-#: core/validators.py:60
-msgid "This value must contain only letters, numbers and underscores."
-msgstr "Ta vrednost mora vsebovati le črke, števila in podčrtaje (_)."
-
-#: core/validators.py:64
-msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
-msgstr "Ta vrednost mora vsebovati le črke, števila, podčrtaje, poševnice ali pomišljaje."
-
-#: core/validators.py:72
-msgid "Uppercase letters are not allowed here."
-msgstr "Velike tiskane črke niso dovoljene."
-
-#: core/validators.py:76
-msgid "Lowercase letters are not allowed here."
-msgstr "Majhne tiskane črke niso dovoljene."
-
-#: core/validators.py:83
-msgid "Enter only digits separated by commas."
-msgstr "Vnesite samo števila, ločena z vejicami."
-
-#: core/validators.py:95
-msgid "Enter valid e-mail addresses separated by commas."
-msgstr "Vnesite veljavne e-mail naslove, ločene z vejicami."
-
-#: core/validators.py:99
-msgid "Please enter a valid IP address."
-msgstr "Prosimo, vnesite veljavni IP naslov."
-
-#: core/validators.py:103
-msgid "Empty values are not allowed here."
-msgstr "Prazne vrednosti tu niso dovoljene."
-
-#: core/validators.py:107
-msgid "Non-numeric characters aren't allowed here."
-msgstr "Nenumerični znaki tukaj niso dovoljne."
-
-#: core/validators.py:111
-msgid "This value can't be comprised solely of digits."
-msgstr "Ta vrednost ne sme vsebovati le števk."
-
-#: core/validators.py:116
-msgid "Enter a whole number."
-msgstr "Vnesite celo število."
-
-#: core/validators.py:120
-msgid "Only alphabetical characters are allowed here."
-msgstr "Tukaj so dovoljene samo črke."
-
-#: core/validators.py:124
-msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "Vnesite veljavni datum v zapisu YYYY-MM-DD (leto-mesec-dan)."
-
-#: core/validators.py:128
-msgid "Enter a valid time in HH:MM format."
-msgstr "Vnesite veljavni čas v zapisu HH:MM (ura:minuta)."
-
-#: core/validators.py:132
-#: db/models/fields/__init__.py:468
-msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Vnesite veljavni datum/čas v zapisu YYYY-MM-DD HH:MM (leto-mesec-dan ura:minuta)"
-
-#: core/validators.py:136
-msgid "Enter a valid e-mail address."
-msgstr "Vnesite veljaven e-mail."
-
-#: core/validators.py:148
-msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
-msgstr "Naložite veljavno sliko. Naložena datoteka ni bila slika ali pa je bila le-ta okvarjena."
-
-#: core/validators.py:155
-#, python-format
-msgid "The URL %s does not point to a valid image."
-msgstr "URL %s ne kaže na veljavno sliko."
-
-#: core/validators.py:159
-#, python-format
-msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
-msgstr "Telefonska številka mora biti v zapisu XXX-XXX-XXXX. \"%s\" ni vredu."
-
-#: core/validators.py:167
+#: utils/timesince.py:40
#, python-format
-msgid "The URL %s does not point to a valid QuickTime video."
-msgstr "URL %s ne kaže na veljavni QuickTime video."
+msgid "%d milliseconds"
+msgstr "%d milisekund"
-#: core/validators.py:171
-msgid "A valid URL is required."
-msgstr "Potreben je veljaven URL naslov."
-
-#: core/validators.py:185
+#: utils/timesince.py:41
#, python-format
-msgid ""
-"Valid HTML is required. Specific errors are:\n"
-"%s"
-msgstr ""
-"Potreben je veljaven HTML. Trenutni ima sledeče napake:\n"
-"%s"
+msgid "%(number)d %(type)s"
+msgstr "%(number)d %(type)s"
-#: core/validators.py:192
+#: utils/timesince.py:47
#, python-format
-msgid "Badly formed XML: %s"
-msgstr "Nepravilen XML: %s"
+msgid ", %(number)d %(type)s"
+msgstr ", %(number)d %(type)s"
-#: core/validators.py:202
-#, python-format
-msgid "Invalid URL: %s"
-msgstr "Neveljaven URL naslov: %s"
+#: utils/dateformat.py:40
+msgid "p.m."
+msgstr "p.m."
-#: core/validators.py:206
-#: core/validators.py:208
-#, python-format
-msgid "The URL %s is a broken link."
-msgstr "URL povezava %s ne deluje."
+#: utils/dateformat.py:41
+msgid "a.m."
+msgstr "a.m."
-#: core/validators.py:214
-msgid "Enter a valid U.S. state abbreviation."
-msgstr "Vnesi veljavno okrajšavo za ameriško zvezno državo."
+#: utils/dateformat.py:46
+msgid "PM"
+msgstr "PM"
-#: core/validators.py:229
-#, python-format
-msgid "Watch your mouth! The word %s is not allowed here."
-msgid_plural "Watch your mouth! The words %s are not allowed here."
-msgstr[0] "Pazite na jezik! Beseda %s tu ni dovoljena."
-msgstr[1] "Pazite na jezik! Besedi %s tu nista dovoljeni."
-msgstr[2] "Pazite na jezik! Besede %s tu niso dovoljene."
-msgstr[3] "Pazite na jezik! Besede %s tu niso dovoljene."
+#: utils/dateformat.py:47
+msgid "AM"
+msgstr "AM"
-#: core/validators.py:236
-#, python-format
-msgid "This field must match the '%s' field."
-msgstr "To polje mora ustrezati polju '%s'."
+#: utils/dateformat.py:95
+msgid "midnight"
+msgstr "polnoč"
-#: core/validators.py:255
-msgid "Please enter something for at least one field."
-msgstr "Prosim, vnesite nekaj v vsaj eno izmed polj."
+#: utils/dateformat.py:97
+msgid "noon"
+msgstr "poldne"
-#: core/validators.py:264
-#: core/validators.py:275
-msgid "Please enter both fields or leave them both empty."
-msgstr "Prosimo, izpolnite obe polji ali pa pustite obe prazni."
+#: utils/translation/trans_real.py:358
+msgid "DATE_FORMAT"
+msgstr "N j, Y"
-#: core/validators.py:282
-#, python-format
-msgid "This field must be given if %(field)s is %(value)s"
-msgstr "To polje mora biti podano, če je %(field)s %(value)s"
+#: utils/translation/trans_real.py:359
+msgid "DATETIME_FORMAT"
+msgstr "N j, Y, P"
-#: core/validators.py:294
-#, python-format
-msgid "This field must be given if %(field)s is not %(value)s"
-msgstr "To polje mora biti podano, če ni %(field)s %(value)s"
+#: utils/translation/trans_real.py:360
+msgid "TIME_FORMAT"
+msgstr "P"
-#: core/validators.py:313
-msgid "Duplicate values are not allowed."
-msgstr "Podvojitve niso dovoljene."
+#: utils/translation/trans_real.py:376
+msgid "YEAR_MONTH_FORMAT"
+msgstr "YEAR_MONTH_FORMAT"
-#: core/validators.py:336
-#, python-format
-msgid "This value must be a power of %s."
-msgstr "Ta vrednost mora biti potenca od %s."
+#: utils/translation/trans_real.py:377
+msgid "MONTH_DAY_FORMAT"
+msgstr "MONTH_DAY_FORMAT"
-#: core/validators.py:347
-msgid "Please enter a valid decimal number."
-msgstr "Prosim vnesite veljavno decimalno število."
+#: template/defaultfilters.py:491
+msgid "yes,no,maybe"
+msgstr "da,ne,morda"
-#: core/validators.py:349
+#: template/defaultfilters.py:520
#, python-format
-msgid "Please enter a valid decimal number with at most %s total digit."
-msgid_plural "Please enter a valid decimal number with at most %s total digits."
-msgstr[0] "Prosimo, vnesite veljavno decimalno število z največ %s števko."
-msgstr[1] "Prosimo, vnesite veljavno decimalno število z največ %s števkama."
-msgstr[2] "Prosimo, vnesite veljavno decimalno število z največ %s števkami."
-msgstr[3] "Prosimo, vnesite veljavno decimalno število z največ %s števkami."
+msgid "%(size)d byte"
+msgid_plural "%(size)d bytes"
+msgstr[0] "%(size)d bajt"
+msgstr[1] "%(size)d bajta"
+msgstr[2] "%(size)d bajti"
+msgstr[3] "%(size)d bajtov"
-#: core/validators.py:352
+#: template/defaultfilters.py:522
#, python-format
-msgid "Please enter a valid decimal number with at most %s decimal place."
-msgid_plural "Please enter a valid decimal number with at most %s decimal places."
-msgstr[0] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnim mestom."
-msgstr[1] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnima mestoma."
-msgstr[2] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnimi mesti."
-msgstr[3] "Prosimo, vnesite veljavno decimalno število z največ %s decimalnimi mesti."
+msgid "%.1f KB"
+msgstr "%.1f KB"
-#: core/validators.py:362
+#: template/defaultfilters.py:524
#, python-format
-msgid "Make sure your uploaded file is at least %s bytes big."
-msgstr "Prosimo, poskrbite, da bo naložena datoteka velika vsaj %s bajtov."
+msgid "%.1f MB"
+msgstr "%.1f MB"
-#: core/validators.py:363
+#: template/defaultfilters.py:525
#, python-format
-msgid "Make sure your uploaded file is at most %s bytes big."
-msgstr "Poskrbite, da bo naložena datoteka velika največ %s bajtov."
-
-#: core/validators.py:376
-msgid "The format for this field is wrong."
-msgstr "Format za to polje je napačen."
+msgid "%.1f GB"
+msgstr "%.1f GB"
-#: core/validators.py:391
-msgid "This field is invalid."
-msgstr "To polje ni veljavno."
-
-#: core/validators.py:426
+#: newforms/fields.py:110
+#: newforms/fields.py:324
#, python-format
-msgid "Could not retrieve anything from %s."
-msgstr "Iz %s nisem mogel pridobiti ničesar."
+msgid "Ensure this value has at most %d characters."
+msgstr "Poskrbite, da bo imela ta vrednost največ %d znakov."
-#: core/validators.py:429
+#: newforms/fields.py:112
+#: newforms/fields.py:326
#, python-format
-msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
-msgstr "URL %(url)s je vrnil neveljavni Content-Type '%(contenttype)s'."
+msgid "Ensure this value has at least %d characters."
+msgstr "Poskrbite, da bo imela ta vrednost vsaj %d znakov."
-#: core/validators.py:462
+#: newforms/fields.py:137
+#: newforms/fields.py:160
+#: newforms/fields.py:192
#, python-format
-msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
-msgstr "Prosimo, zaprite %(tag)s oznako v vrstici %(line)s. (Vrstica se začne z \"%(start)s\".)"
+msgid "Ensure this value is less than or equal to %s."
+msgstr "Poskrbite, da bo imela ta vrednost manj manj kot ali natanko %s znakov."
-#: core/validators.py:466
+#: newforms/fields.py:139
+#: newforms/fields.py:162
+#: newforms/fields.py:194
#, python-format
-msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
-msgstr "Tekst z začetka vrstice %(line)s ni dovoljen v tem kontekstu. (Vrstica se začne z \"%(start)s\".)"
+msgid "Ensure this value is greater than or equal to %s."
+msgstr "Poskrbite, da bo ta vrednost večja ali kvečjemu enaka %s."
-#: core/validators.py:471
-#, python-format
-msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
-msgstr "\"%(attr)s\" v vrstici %(line)s je neveljaven atribut. (Vrstica se začne z \"%(start)s\".)"
+#: newforms/fields.py:158
+#: newforms/fields.py:186
+msgid "Enter a number."
+msgstr "Vnesite število."
-#: core/validators.py:476
+#: newforms/fields.py:196
#, python-format
-msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
-msgstr "\"<%(tag)s>\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se začne z \"%(start)s\".)"
+msgid "Ensure that there are no more than %s digits in total."
+msgstr "Poskrbite, da skupno ne bo več kot %s števil."
-#: core/validators.py:480
+#: newforms/fields.py:198
#, python-format
-msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
-msgstr "Oznaki v vrstici %(line)s manjka eden ali več zahtevanih parametrov. (Vrstica se začne z \"%(start)s\".)"
+msgid "Ensure that there are no more than %s decimal places."
+msgstr "Poskrbite, da skupno ne bo več kot %s decimalnih mest."
-#: core/validators.py:485
+#: newforms/fields.py:200
#, python-format
-msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
-msgstr "Parameter \"%(attr)s\" v vrstici %(line)s vsebuje neveljavno vrednost. (Vrstica se začne z \"%(start)s\".)"
+msgid "Ensure that there are no more than %s digits before the decimal point."
+msgstr "Poskrbite, da ne bo več kot %s števil pred decimalno piko."
-#: db/models/manipulators.py:302
-#, python-format
-msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "%(object)s s tem %(type)s že obstaja za dane %(field)s."
+#: newforms/fields.py:233
+#: newforms/fields.py:567
+msgid "Enter a valid date."
+msgstr "Vnesite veljaven datum."
-#: db/models/fields/__init__.py:40
-#, python-format
-msgid "%(optname)s with this %(fieldname)s already exists."
-msgstr "%(optname)s s tem %(fieldname)s že obstaja."
+#: newforms/fields.py:260
+#: newforms/fields.py:569
+msgid "Enter a valid time."
+msgstr "Vnesite veljaven čas."
-#: db/models/fields/__init__.py:114
-#: db/models/fields/__init__.py:265
-#: db/models/fields/__init__.py:542
-#: db/models/fields/__init__.py:553
-#: forms/__init__.py:346
-msgid "This field is required."
-msgstr "To polje je obvezno"
+#: newforms/fields.py:296
+msgid "Enter a valid date/time."
+msgstr "Vnesite veljaven datum/čas."
-#: db/models/fields/__init__.py:337
-msgid "This value must be an integer."
-msgstr "Ta vrednost mora biti celo število."
+#: newforms/fields.py:310
+msgid "Enter a valid value."
+msgstr "Vnesite veljavno vrednost."
-#: db/models/fields/__init__.py:369
-msgid "This value must be either True or False."
-msgstr "Ta vrednost mora biti \"True\" ali \"False\"."
+#: newforms/fields.py:357
+#: newforms/fields.py:379
+msgid "Enter a valid URL."
+msgstr "Vnesite veljavne URL naslov."
-#: db/models/fields/__init__.py:385
-msgid "This field cannot be null."
-msgstr "To polje ne more biti prazno."
+#: newforms/fields.py:381
+msgid "This URL appears to be a broken link."
+msgstr "Izgleda, da povezava na ta URL ne deluje."
-#: db/models/fields/__init__.py:562
-msgid "Enter a valid filename."
-msgstr "Vnesite veljavno ime datoteke."
+#: newforms/fields.py:432
+#: newforms/models.py:172
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr "Izberite veljavno možnost. Te možnosti ni med možnimi izbirami."
-#: db/models/fields/related.py:43
-#, python-format
-msgid "Please enter a valid %s."
-msgstr "Prosimo, vnesite veljaven %s."
+#: newforms/fields.py:448
+#: newforms/fields.py:527
+#: newforms/models.py:189
+msgid "Enter a list of values."
+msgstr "Vnesite seznam vrednosti."
-#: db/models/fields/related.py:579
-msgid "Separate multiple IDs with commas."
-msgstr "Več ID-jev ločite z vejicami."
-
-#: db/models/fields/related.py:581
-msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
-msgstr "Držite \"Control\" (ali \"Command\" na Mac-u), za izbiro več kot enega."
-
-#: db/models/fields/related.py:625
-#, python-format
-msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] "Prosimo, vnesite veljavne %(self)s ID-e. Vrednost %(value)r ni veljavna."
-msgstr[1] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r nista veljavni."
-msgstr[2] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne."
-msgstr[3] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne."
-
-#: forms/__init__.py:380
+#: newforms/fields.py:457
+#: newforms/models.py:195
#, python-format
-msgid "Ensure your text is less than %s character."
-msgid_plural "Ensure your text is less than %s characters."
-msgstr[0] "Poskrbite, da bo tekst krajši od %s znaka."
-msgstr[1] "Poskrbite, da bo tekst krajši od %s znakov."
-msgstr[2] "Poskrbite, da bo tekst krajši od %s znakov."
-msgstr[3] "Poskrbite, da bo tekst krajši od %s znakov."
-
-#: forms/__init__.py:385
-msgid "Line breaks are not allowed here."
-msgstr "Prelomi vrstice tu niso dovoljeni."
-
-#: forms/__init__.py:480
-#: forms/__init__.py:551
-#: forms/__init__.py:589
-#, python-format
-msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "Izberite veljavno možnost; '%(data)s' ni v %(choices)s."
-
-#: forms/__init__.py:645
-msgid "The submitted file is empty."
-msgstr "Poslana datoteka je prazna."
-
-#: forms/__init__.py:699
-msgid "Enter a whole number between -32,768 and 32,767."
-msgstr "Vnesite celo število med -32.768 in 32.767."
-
-#: forms/__init__.py:708
-msgid "Enter a positive number."
-msgstr "Vnesite pozitivno število."
-
-#: forms/__init__.py:717
-msgid "Enter a whole number between 0 and 32,767."
-msgstr "Vnesite celo število med 0 in 32.767."
-
-#: template/defaultfilters.py:379
-msgid "yes,no,maybe"
-msgstr "da,ne,morda"
-
-msgid "Comment"
-msgstr "Komentar"
-
-msgid "Comments"
-msgstr "Komentarji"
-
-msgid "String (up to 50)"
-msgstr "Niz (do 50 znakov)"
-
-msgid "label"
-msgstr "oznaka"
-
-msgid "package"
-msgstr "paket"
-
-msgid "packages"
-msgstr "paketi"
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr "Izberite veljavno možnost. %s ni med možnimi izbirami."
-msgid "Slovene"
-msgstr "Slovensko"
+#~ msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
+#~ msgstr "Ste <a href=\"/password_reset/\">pozabili geslo</a>?"
+#~ msgid "Use '[algo]$[salt]$[hexdigest]'"
+#~ msgstr "Uporabi '[algo]$[salt]$[hexdigest]'"
+#~ msgid "Comment"
+#~ msgstr "Komentar"
+#~ msgid "Comments"
+#~ msgstr "Komentarji"
+#~ msgid "String (up to 50)"
+#~ msgstr "Niz (do 50 znakov)"
+#~ msgid "label"
+#~ msgstr "oznaka"
+#~ msgid "package"
+#~ msgstr "paket"
+#~ msgid "packages"
+#~ msgstr "paketi"
+#~ msgid "Slovene"
+#~ msgstr "Slovensko"
diff --git a/django/conf/locale/sl/LC_MESSAGES/djangojs.mo b/django/conf/locale/sl/LC_MESSAGES/djangojs.mo
index 9288529a3f..51fadfa406 100644
--- a/django/conf/locale/sl/LC_MESSAGES/djangojs.mo
+++ b/django/conf/locale/sl/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/django/conf/locale/sl/LC_MESSAGES/djangojs.po b/django/conf/locale/sl/LC_MESSAGES/djangojs.po
index ef5edccda4..b6a7b05605 100644
--- a/django/conf/locale/sl/LC_MESSAGES/djangojs.po
+++ b/django/conf/locale/sl/LC_MESSAGES/djangojs.po
@@ -5,8 +5,8 @@ msgid ""
msgstr ""
"Project-Id-Version: DJANGO-JS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2005-12-09 11:51+0100\n"
-"PO-Revision-Date: 2007-03-31 21:29+0100\n"
+"POT-Creation-Date: 2007-07-02 13:55+0200\n"
+"PO-Revision-Date: 2007-07-02 13:56+0100\n"
"Last-Translator: Gasper Koren <skrat@owca.info>\n"
"Language-Team: SLOVENIAN <lugos-slo@lugos.si>\n"
"MIME-Version: 1.0\n"
@@ -15,6 +15,19 @@ msgstr ""
"X-Poedit-Language: Slovenian\n"
"X-Poedit-Country: SLOVENIA\n"
+#: contrib/admin/media/js/calendar.js:24
+#: contrib/admin/media/js/dateparse.js:32
+msgid "January February March April May June July August September October November December"
+msgstr "Januar Februar Marec April Maj Junij Julij Avgust September Oktober November December"
+
+#: contrib/admin/media/js/calendar.js:25
+msgid "S M T W T F S"
+msgstr "N P T S Č P S"
+
+#: contrib/admin/media/js/dateparse.js:33
+msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+msgstr "Nedelja Ponedeljek Torek Sreda Četrtek Petek Sobota"
+
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
@@ -45,63 +58,59 @@ msgstr "Izberite in kliknite"
msgid "Clear all"
msgstr "Izbriši vse"
-#: contrib/admin/media/js/dateparse.js:26
-#: contrib/admin/media/js/calendar.js:24
-msgid "January February March April May June July August September October November December"
-msgstr "Januar Februar Marec April Maj Junij Julij Avgust September Oktober November December"
-
-#: contrib/admin/media/js/dateparse.js:27
-msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
-msgstr "Nedelja Ponedeljek Torek Sreda Četrtek Petek Sobota"
-
-#: contrib/admin/media/js/calendar.js:25
-msgid "S M T W T F S"
-msgstr "N P T S Č P S"
-
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Sedaj"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "URA"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Izberite čas"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Polnoč"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "Ob 6h"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "Opoldne"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Prekliči"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Danes"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Koledar"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Včeraj"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Jutri"
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
+msgid "Show"
+msgstr "Prikaži"
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
+msgid "Hide"
+msgstr "Skrij"
+
diff --git a/django/conf/locale/sv/LC_MESSAGES/django.mo b/django/conf/locale/sv/LC_MESSAGES/django.mo
index 5654541a4e..9d35676a65 100644
--- a/django/conf/locale/sv/LC_MESSAGES/django.mo
+++ b/django/conf/locale/sv/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/sv/LC_MESSAGES/django.po b/django/conf/locale/sv/LC_MESSAGES/django.po
index db542460e6..d77cf04cc4 100644
--- a/django/conf/locale/sv/LC_MESSAGES/django.po
+++ b/django/conf/locale/sv/LC_MESSAGES/django.po
@@ -1,14 +1,14 @@
# Swedish translation of Django
-# Copyright (C) 2005
+# Copyright (C) 2005-2007
# This file is distributed under the same license as the Django package.
#
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-06-15 17:35+0200\n"
+"POT-Creation-Date: 2007-07-18 16:49+0200\n"
"PO-Revision-Date: 2007-03-06 10:30+0100\n"
-"Last-Translator: Ludvig Ericson <ludvig.ericson@gmail.com>\n"
+"Last-Translator: Philip Lindborg <philip.lindborg@gmail.com>\n"
"Language-Team: Django I18N <Django-I18N@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -17,130 +17,128 @@ msgstr ""
"X-Poedit-Language: Swedish\n"
"X-Poedit-Country: SWEDEN\n"
-#: oldforms/__init__.py:357 db/models/fields/__init__.py:121
-#: db/models/fields/__init__.py:278 db/models/fields/__init__.py:675
-#: db/models/fields/__init__.py:686 newforms/models.py:185
-#: newforms/fields.py:87 newforms/fields.py:444 newforms/fields.py:520
-#: newforms/fields.py:531
+#: oldforms/__init__.py:369 db/models/fields/__init__.py:127
+#: db/models/fields/__init__.py:284 db/models/fields/__init__.py:681
+#: db/models/fields/__init__.py:692 newforms/models.py:187
+#: newforms/fields.py:92 newforms/fields.py:440 newforms/fields.py:516
+#: newforms/fields.py:527
msgid "This field is required."
msgstr "Det här fältet är obligatoriskt."
-#: oldforms/__init__.py:392
+#: oldforms/__init__.py:404
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Se till att din text är kortare än %s tecken."
msgstr[1] "Se till att din text är kortare än %s tecken."
-#: oldforms/__init__.py:397
+#: oldforms/__init__.py:409
msgid "Line breaks are not allowed here."
msgstr "Radbrytningar är inte tillåtna här."
-#: oldforms/__init__.py:498 oldforms/__init__.py:571 oldforms/__init__.py:610
+#: oldforms/__init__.py:507 oldforms/__init__.py:581 oldforms/__init__.py:620
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "Välj ett giltigt alternativ. '%(data)s' finns inte bland %(choices)s."
+msgstr "Välj ett giltigt alternativ; '%(data)s' finns inte bland %(choices)s."
-#: oldforms/__init__.py:577 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:150
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:152
msgid "Unknown"
msgstr "Okänt"
-#: oldforms/__init__.py:577 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "Yes"
msgstr "Ja"
-#: oldforms/__init__.py:577 newforms/widgets.py:182
-#: contrib/admin/filterspecs.py:143
+#: oldforms/__init__.py:587 newforms/widgets.py:181
+#: contrib/admin/filterspecs.py:145
msgid "No"
msgstr "Nej"
-#: oldforms/__init__.py:672 core/validators.py:175 core/validators.py:453
+#: oldforms/__init__.py:682 core/validators.py:181 core/validators.py:461
msgid "No file was submitted. Check the encoding type on the form."
-msgstr "Ingen fil skickades. Kontrollera kodningnstypen i formen."
+msgstr "Ingen fil skickades. Kontrollera kodningnstypen i formuläret."
-#: oldforms/__init__.py:674
+#: oldforms/__init__.py:684
msgid "The submitted file is empty."
msgstr "Den insända filen är tom."
-#: oldforms/__init__.py:730
+#: oldforms/__init__.py:740
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Fyll i ett heltal mellan -32768 och 32767."
-#: oldforms/__init__.py:740
+#: oldforms/__init__.py:750
msgid "Enter a positive number."
msgstr "Fyll i ett positivt heltal."
-#: oldforms/__init__.py:750
+#: oldforms/__init__.py:760
msgid "Enter a whole number between 0 and 32,767."
msgstr "Fyll i ett heltal mellan 0 och 32767."
-#: db/models/manipulators.py:307
+#: db/models/manipulators.py:309
#, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "%(object)s med typen %(type)s finns redan för %(field)s."
-#: db/models/manipulators.py:308 contrib/admin/views/main.py:335
-#: contrib/admin/views/main.py:337 contrib/admin/views/main.py:339
+#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
msgid "and"
msgstr "och"
-#: db/models/fields/__init__.py:46
+#: db/models/fields/__init__.py:47
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(optname)s med det här %(fieldname)s finns redan."
-#: db/models/fields/__init__.py:373
+#: db/models/fields/__init__.py:379
msgid "This value must be an integer."
msgstr "Det här värdet måste vara ett heltal."
-#: db/models/fields/__init__.py:408
+#: db/models/fields/__init__.py:414
msgid "This value must be either True or False."
-msgstr "Det här värdet måste vara True eller False"
+msgstr "Det här värdet måste vara True eller False."
-#: db/models/fields/__init__.py:429
+#: db/models/fields/__init__.py:435
msgid "This field cannot be null."
-msgstr "Det här fältet kan inte vara null."
+msgstr "Det här fältet kan inte vara tomt."
-#: db/models/fields/__init__.py:463 core/validators.py:149
+#: db/models/fields/__init__.py:469 core/validators.py:155
msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "Fyll i ett giltigt datum i ÅÅÅÅ-MM-DD format."
+msgstr "Fyll i ett giltigt datum på formatet ÅÅÅÅ-MM-DD."
-#: db/models/fields/__init__.py:532 core/validators.py:158
+#: db/models/fields/__init__.py:538 core/validators.py:164
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Fyll i en giltig tidpunkt i ÅÅÅÅ-MM-DD HH:MM format"
+msgstr "Fyll i en giltig tidpunkt på formatet ÅÅÅÅ-MM-DD TT:MM."
-#: db/models/fields/__init__.py:592
-#, fuzzy
+#: db/models/fields/__init__.py:598
msgid "This value must be a decimal number."
-msgstr "Det här värdet måste vara ett heltal."
+msgstr "Det här värdet måste vara ett hel- eller decimaltal."
-#: db/models/fields/__init__.py:695
+#: db/models/fields/__init__.py:701
msgid "Enter a valid filename."
msgstr "Fyll i ett giltigt filnamn."
-#: db/models/fields/__init__.py:818
-#, fuzzy
+#: db/models/fields/__init__.py:826
msgid "This value must be either None, True or False."
-msgstr "Det här värdet måste vara antingen True eller False."
+msgstr "Det här värdet måste vara antingen None, True eller False."
-#: db/models/fields/related.py:53
+#: db/models/fields/related.py:55
#, python-format
msgid "Please enter a valid %s."
msgstr "Var god fyll i giltigt %s."
-#: db/models/fields/related.py:642
+#: db/models/fields/related.py:641
msgid "Separate multiple IDs with commas."
-msgstr "Separera flera ID:n med kommatecken."
+msgstr "Separera flera ID-nummer med kommatecken."
-#: db/models/fields/related.py:644
+#: db/models/fields/related.py:643
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
-"Håll ner \"Control\", eller \"Command\" på en Mac, för att välja mer än en."
+"Håll ner \"Control\" (eller \"Command\" på en Mac) för att välja fler än en."
-#: db/models/fields/related.py:691
+#: db/models/fields/related.py:690
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
@@ -150,55 +148,58 @@ msgstr[0] ""
msgstr[1] ""
"Var god och fyll giltiga %(self)s ID-nummer. Värdena %(value)r är ogiltiga."
-#: conf/global_settings.py:39
+#: conf/global_settings.py:38
msgid "Arabic"
msgstr "Arabiska"
-#: conf/global_settings.py:40
+#: conf/global_settings.py:39
msgid "Bengali"
msgstr "Bengaliska"
-#: conf/global_settings.py:41
-#, fuzzy
+#: conf/global_settings.py:40
msgid "Bulgarian"
-msgstr "Ungerska"
+msgstr "Bulgariska"
-#: conf/global_settings.py:42
+#: conf/global_settings.py:41
msgid "Catalan"
msgstr "Katalanska"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:42
msgid "Czech"
msgstr "Tjeckiska"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:43
msgid "Welsh"
msgstr "Walesiska"
-#: conf/global_settings.py:45
+#: conf/global_settings.py:44
msgid "Danish"
msgstr "Danska"
-#: conf/global_settings.py:46
+#: conf/global_settings.py:45
msgid "German"
msgstr "Tyska"
-#: conf/global_settings.py:47
+#: conf/global_settings.py:46
msgid "Greek"
msgstr "Grekiska"
-#: conf/global_settings.py:48
+#: conf/global_settings.py:47
msgid "English"
msgstr "Engelska"
-#: conf/global_settings.py:49
+#: conf/global_settings.py:48
msgid "Spanish"
msgstr "Spanska"
-#: conf/global_settings.py:50
+#: conf/global_settings.py:49
msgid "Argentinean Spanish"
msgstr "Argentisk Spanska"
+#: conf/global_settings.py:50
+msgid "Persian"
+msgstr "Persiska"
+
#: conf/global_settings.py:51
msgid "Finnish"
msgstr "Finska"
@@ -315,82 +316,82 @@ msgstr "Förenklad Kinesiska"
msgid "Traditional Chinese"
msgstr "Traditionell Kinesiska"
-#: core/validators.py:65
+#: core/validators.py:71
msgid "This value must contain only letters, numbers and underscores."
-msgstr "Det här värdet får bara innehålla bokstäver, tal och understräck."
+msgstr "Det här värdet får bara innehålla bokstäver, siffror och understreck."
-#: core/validators.py:69
+#: core/validators.py:75
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
msgstr ""
-"Det här värdet får bara innehålla bokstäver, siffror, understräck, sträck "
-"och snedsträck"
+"Det här värdet får bara innehålla bokstäver, siffror, understreck, "
+"bindestreck eller snedstreck."
-#: core/validators.py:73
+#: core/validators.py:79
msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr ""
-"Det här värdet får bara innehålla bokstäver, siffror, understräck eller "
-"bindessträck."
+"Det här värdet får bara innehålla bokstäver, siffror, understreck eller "
+"avstavningstecken."
-#: core/validators.py:77
+#: core/validators.py:83
msgid "Uppercase letters are not allowed here."
-msgstr "Stora bokstäver är inte tillåtna här."
+msgstr "Versaler är inte tillåtna här."
-#: core/validators.py:81
+#: core/validators.py:87
msgid "Lowercase letters are not allowed here."
-msgstr "Små bokstäver är inte tillåtna här."
+msgstr "Gemener är inte tillåtna här."
-#: core/validators.py:88
+#: core/validators.py:94
msgid "Enter only digits separated by commas."
msgstr "Fyll enbart i siffror avskilda med kommatecken."
-#: core/validators.py:100
+#: core/validators.py:106
msgid "Enter valid e-mail addresses separated by commas."
-msgstr "Fyll i giltiga e-mailadresser avskilda med kommatecken."
+msgstr "Fyll i giltiga e-postadresser avskilda med kommatecken."
-#: core/validators.py:104
+#: core/validators.py:110
msgid "Please enter a valid IP address."
msgstr "Var god fyll i en giltigt IP-adress."
-#: core/validators.py:108
+#: core/validators.py:114
msgid "Empty values are not allowed here."
msgstr "Tomma värden är inte tillåtna här."
-#: core/validators.py:112
+#: core/validators.py:118
msgid "Non-numeric characters aren't allowed here."
msgstr "Icke-numeriska tecken är inte tillåtna här."
-#: core/validators.py:116
+#: core/validators.py:122
msgid "This value can't be comprised solely of digits."
msgstr "Det här värdet kan inte enbart bestå av siffror."
-#: core/validators.py:121 newforms/fields.py:135
+#: core/validators.py:127 newforms/fields.py:141
msgid "Enter a whole number."
msgstr "Fyll i ett heltal."
-#: core/validators.py:125
+#: core/validators.py:131
msgid "Only alphabetical characters are allowed here."
msgstr "Endast bokstäver är tillåtna här."
-#: core/validators.py:140
+#: core/validators.py:146
msgid "Year must be 1900 or later."
msgstr "Årtal måste vara 1900 eller senare."
-#: core/validators.py:144
-#, fuzzy, python-format
+#: core/validators.py:150
+#, python-format
msgid "Invalid date: %s"
-msgstr "Felaktigt datum: %s"
+msgstr "Ogiltigt datum: %s"
-#: core/validators.py:154
+#: core/validators.py:160
msgid "Enter a valid time in HH:MM format."
-msgstr "Fyll i en giltig tid i HH:MM format."
+msgstr "Fyll i en giltig tid i TT:MM format."
-#: core/validators.py:163 newforms/fields.py:339
+#: core/validators.py:169 newforms/fields.py:335
msgid "Enter a valid e-mail address."
-msgstr "Fyll i en giltig e-mailadress."
+msgstr "Fyll i en giltig e-postadress."
-#: core/validators.py:179
+#: core/validators.py:185
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
@@ -398,28 +399,28 @@ msgstr ""
"Ladda upp en giltig bild. Filen du laddade upp var antingen ingen bild eller "
"en korrupt bild."
-#: core/validators.py:186
+#: core/validators.py:192
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "URL:en %s pekar inte mot en giltig bild."
-#: core/validators.py:190
+#: core/validators.py:196
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr ""
-"Telefonnummer måste vara i det amerikanska XXX-XXX-XXXX formated. \"%s\" är "
+"Telefonnummer måste vara på det amerikanska formatet XXX-XXX-XXXX. \"%s\" är "
"ogiltigt."
-#: core/validators.py:198
+#: core/validators.py:204
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "URL:en %s pekar inte på en giltig QuickTime-video."
-#: core/validators.py:202
+#: core/validators.py:208
msgid "A valid URL is required."
msgstr "En giltig URL krävs."
-#: core/validators.py:216
+#: core/validators.py:222
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
@@ -428,146 +429,150 @@ msgstr ""
"Giltig HTML krävs. Specifika fel är:\n"
"%s"
-#: core/validators.py:223
+#: core/validators.py:229
#, python-format
msgid "Badly formed XML: %s"
msgstr "Missformad XML: %s"
-#: core/validators.py:240
+#: core/validators.py:246
#, python-format
msgid "Invalid URL: %s"
msgstr "Felaktig URL: %s"
-#: core/validators.py:245 core/validators.py:247
+#: core/validators.py:251 core/validators.py:253
#, python-format
msgid "The URL %s is a broken link."
msgstr "URL:en %s är en trasig länk."
-#: core/validators.py:253
+#: core/validators.py:259
msgid "Enter a valid U.S. state abbreviation."
msgstr "Fyll i en giltig förkortning för en amerikansk delstat."
-#: core/validators.py:267
+#: core/validators.py:273
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Akta din tunga! Ordet %s är inte tillåtet här."
msgstr[1] "Akta din tunga! Orden %s är inte tillåtna här."
-#: core/validators.py:274
+#: core/validators.py:280
#, python-format
msgid "This field must match the '%s' field."
msgstr "Det här fältet måste matcha fältet '%s'."
-#: core/validators.py:293
+#: core/validators.py:299
msgid "Please enter something for at least one field."
msgstr "Var god fyll i minst ett fält."
-#: core/validators.py:302 core/validators.py:313
+#: core/validators.py:308 core/validators.py:319
msgid "Please enter both fields or leave them both empty."
msgstr "Fyll antingen i båda fälten, eller lämna båda tomma."
-#: core/validators.py:321
+#: core/validators.py:327
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "Det är fältet måste anges om %(field)s är %(value)s"
-#: core/validators.py:334
+#: core/validators.py:340
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "Det här fältet måste anges om %(field)s inte är %(value)s"
-#: core/validators.py:353
+#: core/validators.py:359
msgid "Duplicate values are not allowed."
-msgstr "Upprepade värden är inte tillåtna."
+msgstr "Dubbelvärden är inte tillåtna."
-#: core/validators.py:368
+#: core/validators.py:374
#, python-format
msgid "This value must be between %(lower)s and %(upper)s."
msgstr "Det här värdet måste vara mellan %(lower)s och %(upper)s."
-#: core/validators.py:370
+#: core/validators.py:376
#, python-format
msgid "This value must be at least %s."
msgstr "Det här värdet måste vara minst %s."
-#: core/validators.py:372
+#: core/validators.py:378
#, python-format
msgid "This value must be no more than %s."
msgstr "Det här värdet får inte vara mer än %s."
-#: core/validators.py:408
+#: core/validators.py:414
#, python-format
msgid "This value must be a power of %s."
msgstr "Det här värdet måste vara en potens av %s."
-#: core/validators.py:417
+#: core/validators.py:424
msgid "Please enter a valid decimal number."
-msgstr "Fyll i ett giltigt decimaltal."
+msgstr "Fyll i ett giltigt hel- eller decimaltal."
-#: core/validators.py:423
+#: core/validators.py:431
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
-msgstr[0] "Fyll i ett giltigt decimaltal med högst %s siffra totalt."
-msgstr[1] "Fyll i ett giltigt decimaltal med högst %s siffror totalt."
+msgstr[0] ""
+"Fyll i ett giltigt hel- eller decimaltal med högst %s siffra totalt."
+msgstr[1] ""
+"Fyll i ett giltigt hel- eller decimaltal med högst %s siffror totalt."
-#: core/validators.py:426
+#: core/validators.py:434
#, python-format
msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit."
msgid_plural ""
"Please enter a valid decimal number with a whole part of at most %s digits."
msgstr[0] ""
-"Fyll i ett giltigt decimaltal med en heltalsdel som högst är %s siffra."
+"Fyll i ett giltigt hel- eller decimaltal med en heltalsdel som högst är %s "
+"siffra."
msgstr[1] ""
-"Fyll i ett giltigt decimaltal med en heltalsdel som högst är %s siffror."
+"Fyll i ett giltigt hel- eller decimaltal med en heltalsdel som högst är %s "
+"siffror."
-#: core/validators.py:429
+#: core/validators.py:437
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places."
-msgstr[0] "Fyll i ett giltigt decimaltal med högst %s decimal."
-msgstr[1] "Fyll i ett giltigt decimaltal med högst %s decimaler."
+msgstr[0] "Fyll i ett giltigt hel- eller decimaltal med högst %s decimal."
+msgstr[1] "Fyll i ett giltigt hel- eller decimaltal med högst %s decimaler."
-#: core/validators.py:437
+#: core/validators.py:445
msgid "Please enter a valid floating point number."
-msgstr "Fyll i ett giltigt flyttal."
+msgstr "Fyll i ett giltigt decimaltal."
-#: core/validators.py:446
+#: core/validators.py:454
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "Se till att filen du laddade upp är minst %s bytes stor."
-#: core/validators.py:447
+#: core/validators.py:455
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "Se till att filen du laddade upp är som mest %s bytes stor."
-#: core/validators.py:464
+#: core/validators.py:472
msgid "The format for this field is wrong."
msgstr "Formatet på det här fältet är fel."
-#: core/validators.py:479
+#: core/validators.py:487
msgid "This field is invalid."
msgstr "Det här fältet är ogiltigt."
-#: core/validators.py:515
+#: core/validators.py:523
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "Kunde inte hämta något från %s."
-#: core/validators.py:518
+#: core/validators.py:526
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr ""
"URL:en %(url)s returnerade den ogiltiga Content-Type headern '%(contenttype)"
-"s'"
+"s'."
-#: core/validators.py:551
+#: core/validators.py:559
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
@@ -576,16 +581,16 @@ msgstr ""
"Var god avsluta den oavslutade taggen %(tag)s på rad %(line)s. (Raden börjar "
"med \"%(start)s\".)"
-#: core/validators.py:555
+#: core/validators.py:563
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
"starts with \"%(start)s\".)"
msgstr ""
-"En del text från rad %(line)s är inte tillåtet i det sammanhanget. (Raden "
-"börjar med \"%(start)s\".)"
+"En del text som börjar på rad %(line)s är inte tillåtet i det sammanhanget. "
+"(Raden börjar med \"%(start)s\".)"
-#: core/validators.py:560
+#: core/validators.py:568
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
@@ -594,7 +599,7 @@ msgstr ""
"\"%(attr)s\" på rad %(line)s är inte ett giltigt attribut. (Raden startar "
"med \"%(start)s\".)"
-#: core/validators.py:565
+#: core/validators.py:573
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
@@ -603,16 +608,16 @@ msgstr ""
"\"<%(tag)s>\" på rad %(line)s är en ogiltig tagg. (Raden börjar med \"%"
"(start)s\".)"
-#: core/validators.py:569
+#: core/validators.py:577
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
"starts with \"%(start)s\".)"
msgstr ""
-"En tagg på rad %(line)s saknar en eller flera nödvändiga attribut. (Raden "
+"En tagg på rad %(line)s saknar en eller flera obligatoriska attribut. (Raden "
"börjar med \"%(start)s\".)"
-#: core/validators.py:574
+#: core/validators.py:582
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
@@ -622,98 +627,96 @@ msgstr ""
"börjar med \"%(start)s\".)"
#: views/generic/create_update.py:43
-#, python-format
-#, fuzzy
+#, fuzzy, python-format
msgid "The %(verbose_name)s was created successfully."
-msgstr "%(verbose_name)s skapades framgångsrikt."
+msgstr "%(verbose_name)s skapades."
#: views/generic/create_update.py:117
-#, python-format
-#, fuzzy
+#, fuzzy, python-format
msgid "The %(verbose_name)s was updated successfully."
-msgstr " %(verbose_name)s uppdaterades framgångsrikt."
+msgstr "%(verbose_name)s uppdaterades."
#: views/generic/create_update.py:184
#, python-format
msgid "The %(verbose_name)s was deleted."
msgstr "%(verbose_name)s togs bort."
-#: newforms/models.py:172 newforms/fields.py:432
+#: newforms/models.py:174 newforms/fields.py:428
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr ""
"Välj ett giltigt alternativ. Det valet finns inte bland tillgängliga "
"alternativ."
-#: newforms/models.py:189 newforms/fields.py:448 newforms/fields.py:524
+#: newforms/models.py:191 newforms/fields.py:444 newforms/fields.py:520
msgid "Enter a list of values."
msgstr "Fyll i en lista med värden."
-#: newforms/models.py:195 newforms/fields.py:457
+#: newforms/models.py:197 newforms/fields.py:450
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
msgstr ""
-"Välj ett giltigt alternativ. '%s' finns inte bland tillgängliga alternativ."
+"Välj ett giltigt alternativ. %s finns inte bland tillgängliga alternativ."
-#: newforms/fields.py:110 newforms/fields.py:324
-#, python-format
-msgid "Ensure this value has at most %d characters."
-msgstr "Säkerställ att detta värdet har högst %d tecken."
+#: newforms/fields.py:116
+#, fuzzy, python-format
+msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
+msgstr "Kontrollera att detta värde har högst %d tecken."
-#: newforms/fields.py:112 newforms/fields.py:326
-#, python-format
-msgid "Ensure this value has at least %d characters."
-msgstr "Säkerställ att detta värdet har minst %d tecken."
+#: newforms/fields.py:118
+#, fuzzy, python-format
+msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
+msgstr "Kontrollera att detta värde har minst %d tecken."
-#: newforms/fields.py:137 newforms/fields.py:160 newforms/fields.py:192
+#: newforms/fields.py:143 newforms/fields.py:166 newforms/fields.py:196
#, python-format
msgid "Ensure this value is less than or equal to %s."
-msgstr "Säkerställ att detta värdet är mindre eller lika med %s."
+msgstr "Kontrollera att detta värde är mindre eller lika med %s."
-#: newforms/fields.py:139 newforms/fields.py:162 newforms/fields.py:194
+#: newforms/fields.py:145 newforms/fields.py:168 newforms/fields.py:198
#, python-format
msgid "Ensure this value is greater than or equal to %s."
-msgstr "Säkerställ att detta värdet är mer eller lika med %s."
+msgstr "Kontrollera att detta värde är mer eller lika med %s."
-#: newforms/fields.py:158 newforms/fields.py:186
+#: newforms/fields.py:164 newforms/fields.py:191
msgid "Enter a number."
msgstr "Fyll i ett tal."
-#: newforms/fields.py:196
+#: newforms/fields.py:200
#, python-format
msgid "Ensure that there are no more than %s digits in total."
-msgstr "Säkerställ att det inte finns mer än %s siffror totalt."
+msgstr "Kontrollera att det inte finns mer än totalt %s siffror."
-#: newforms/fields.py:198
+#: newforms/fields.py:202
#, python-format
msgid "Ensure that there are no more than %s decimal places."
-msgstr "Säkerställ att det inte finns mer än %s decimaler."
+msgstr "Kontrollera att det inte finns mer än %s decimaler."
-#: newforms/fields.py:200
+#: newforms/fields.py:204
#, python-format
msgid "Ensure that there are no more than %s digits before the decimal point."
-msgstr "Säkerställ att det inte finns mer än %s siffror före kommatecknet."
+msgstr "Kontrollera att det inte finns mer än %s siffror före decimaltecknet."
-#: newforms/fields.py:233
+#: newforms/fields.py:237 newforms/fields.py:560
msgid "Enter a valid date."
msgstr "Fyll i ett giltigt datum."
-#: newforms/fields.py:260
+#: newforms/fields.py:264 newforms/fields.py:562
msgid "Enter a valid time."
msgstr "Fyll i en giltig tid."
-#: newforms/fields.py:296
+#: newforms/fields.py:300
msgid "Enter a valid date/time."
msgstr "Fyll i ett giltigt datum/tid."
-#: newforms/fields.py:310
+#: newforms/fields.py:313
msgid "Enter a valid value."
msgstr "Fyll i ett giltigt värde."
-#: newforms/fields.py:357 newforms/fields.py:379
+#: newforms/fields.py:353 newforms/fields.py:375
msgid "Enter a valid URL."
-msgstr "Fyll i ett giltigt URL."
+msgstr "Fyll i en giltig URL."
-#: newforms/fields.py:381
+#: newforms/fields.py:377
msgid "This URL appears to be a broken link."
msgstr "Denna URL verkar vara en trasig länk."
@@ -742,7 +745,6 @@ msgstr[1] "%(value).1f miljoner"
#: contrib/humanize/templatetags/humanize.py:50
#, python-format
-#, fuzzy
msgid "%(value).1f billion"
msgid_plural "%(value).1f billion"
msgstr[0] "%(value)1.f miljard"
@@ -750,14 +752,12 @@ msgstr[1] "%(value)1.f miljarder"
#: contrib/humanize/templatetags/humanize.py:53
#, python-format
-#, fuzzy
msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion"
msgstr[0] "%(value)1.f biljon"
msgstr[1] "%(value)1.f biljoner"
#: contrib/humanize/templatetags/humanize.py:68
-#, fuzzy
msgid "one"
msgstr "ett"
@@ -802,8 +802,8 @@ msgid ""
"This should be an absolute path, excluding the domain name. Example: '/"
"events/search/'."
msgstr ""
-"Det här bör vara en absolut sökväg, förutom domännamnet. Exempel: '/"
-"handelser/sok/'."
+"Det här bör vara en absolut sökväg, utan domännamnet. Exempel: '/handelser/"
+"sok/'."
#: contrib/redirects/models.py:9
msgid "redirect to"
@@ -814,8 +814,8 @@ msgid ""
"This can be either an absolute path (as above) or a full URL starting with "
"'http://'."
msgstr ""
-"Detta kan vara antingen en absolut sökväg (som ovan), eller en komplett URL "
-"som börjar med 'http://'."
+"Detta kan vara antingen en absolut sökväg (som ovan), eller en fullständig "
+"URL som börjar med 'http://'."
#: contrib/redirects/models.py:13
msgid "redirect"
@@ -876,13 +876,13 @@ msgstr "är ett giltigt betyg"
#: contrib/comments/models.py:83 contrib/comments/models.py:169
msgid "date/time submitted"
-msgstr "datum/tid postat"
+msgstr "datum/tid skickat"
#: contrib/comments/models.py:84 contrib/comments/models.py:170
msgid "is public"
msgstr "är offentligt"
-#: contrib/comments/models.py:85 contrib/admin/views/doc.py:305
+#: contrib/comments/models.py:85 contrib/admin/views/doc.py:306
msgid "IP address"
msgstr "IP-adress"
@@ -896,7 +896,7 @@ msgid ""
"removed\" message will be displayed instead."
msgstr ""
"Bocka för den här rutan om kommentaren är olämplig. Ett \"Den här "
-"kommentaren har tagits bort\"-meddelande kommer visas istället"
+"kommentaren har tagits bort\"-meddelande kommer visas istället."
#: contrib/comments/models.py:91
msgid "comments"
@@ -979,11 +979,11 @@ msgstr "flaggdatum"
#: contrib/comments/models.py:268
msgid "user flag"
-msgstr "användares flagga"
+msgstr "användarflagga"
#: contrib/comments/models.py:269
msgid "user flags"
-msgstr "användares flaggor"
+msgstr "användarflaggor"
#: contrib/comments/models.py:273
#, python-format
@@ -1007,24 +1007,24 @@ msgstr "moderatorborttagningar"
msgid "Moderator deletion by %r"
msgstr "Moderatorborttagning av %r"
-#: contrib/comments/views/karma.py:19
+#: contrib/comments/views/karma.py:20
msgid "Anonymous users cannot vote"
msgstr "Anonyma användare kan inte rösta"
-#: contrib/comments/views/karma.py:23
+#: contrib/comments/views/karma.py:24
msgid "Invalid comment ID"
-msgstr "Ogiltig kommentarsidentifikation"
+msgstr "Ogiltigt kommentar-ID"
-#: contrib/comments/views/karma.py:25
+#: contrib/comments/views/karma.py:26
msgid "No voting for yourself"
msgstr "Du får inte rösta på dig själv"
-#: contrib/comments/views/comments.py:27
+#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr "Det här betyget krävs eftersom du har fyllt i minst ett annat betyg."
-#: contrib/comments/views/comments.py:111
+#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
@@ -1037,17 +1037,17 @@ msgid_plural ""
"\n"
"%(text)s"
msgstr[0] ""
-"Den här kommentaren postades av en användare som har postat mindre än %"
-"(count)s kommentar:\n"
+"Den här kommentaren postades av en användare som har postat färre än %(count)"
+"s kommentar:\n"
"\n"
"%(text)s"
msgstr[1] ""
-"Den här kommentaren postades av en användare som har postat mindre än %"
-"(count)s kommentarer:\n"
+"Den här kommentaren postades av en användare som har postat färre än %(count)"
+"s kommentarer:\n"
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:116
+#: contrib/comments/views/comments.py:117
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
@@ -1058,35 +1058,49 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:188
-#: contrib/comments/views/comments.py:280
+#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:281
msgid "Only POSTs are allowed"
-msgstr "Endast POST tillåtet"
+msgstr "Endast POST är tillåtet"
-#: contrib/comments/views/comments.py:192
-#: contrib/comments/views/comments.py:284
+#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:285
msgid "One or more of the required fields wasn't submitted"
msgstr "Ett eller flera av de obligatoriska fälten var inte ifyllda"
-#: contrib/comments/views/comments.py:196
-#: contrib/comments/views/comments.py:286
+#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:287
msgid "Somebody tampered with the comment form (security violation)"
msgstr "Någon fifflade med kommentarformuläret (säkerhetsbrott)"
-#: contrib/comments/views/comments.py:206
-#: contrib/comments/views/comments.py:292
+#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:293
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
msgstr ""
-"Kommentars-formuläret hade en ogiltig 'mål'-parameter -- objektets ID var "
+"Kommentarformuläret hade en ogiltig 'target'-parameter -- objektets ID var "
"ogiltigt"
-#: contrib/comments/views/comments.py:257
-#: contrib/comments/views/comments.py:321
+#: contrib/comments/views/comments.py:258
+#: contrib/comments/views/comments.py:322
msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr "Kommentars-formuläret skickade varken 'förhandsgranska' eller 'post'"
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "Ditt namn:"
+
+#: contrib/comments/templates/comments/freeform.html:5
+#: contrib/comments/templates/comments/form.html:28
+msgid "Comment:"
+msgstr "Kommentar:"
+
+#: contrib/comments/templates/comments/freeform.html:10
+#: contrib/comments/templates/comments/form.html:35
+msgid "Preview comment"
+msgstr "Förhandsgranska kommentar"
+
#: contrib/comments/templates/comments/form.html:6
#: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/login.html:17
@@ -1094,24 +1108,24 @@ msgid "Username:"
msgstr "Användarnamn:"
#: contrib/comments/templates/comments/form.html:6
-#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/view_index.html:5
#: contrib/admin/templates/admin_doc/model_detail.html:3
#: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
msgid "Log out"
msgstr "Logga ut"
@@ -1142,37 +1156,23 @@ msgstr "Valfri"
msgid "Post a photo"
msgstr "Lägg till foto"
-#: contrib/comments/templates/comments/form.html:28
-#: contrib/comments/templates/comments/freeform.html:5
-msgid "Comment:"
-msgstr "Kommentar:"
-
-#: contrib/comments/templates/comments/form.html:35
-#: contrib/comments/templates/comments/freeform.html:10
-msgid "Preview comment"
-msgstr "Förhandsgranska kommentar"
-
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "Ditt namn:"
-
-#: contrib/sites/models.py:10
+#: contrib/sites/models.py:15
msgid "domain name"
msgstr "domännamn"
-#: contrib/sites/models.py:11
+#: contrib/sites/models.py:16
msgid "display name"
msgstr "visat namn"
-#: contrib/sites/models.py:15
+#: contrib/sites/models.py:20
msgid "site"
-msgstr "site"
+msgstr "webbplats"
-#: contrib/sites/models.py:16
+#: contrib/sites/models.py:21
msgid "sites"
-msgstr "siter"
+msgstr "webbplatser"
-#: contrib/admin/filterspecs.py:40
+#: contrib/admin/filterspecs.py:42
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
@@ -1181,350 +1181,350 @@ msgstr ""
"<h3>Av %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
-#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169
+#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
+#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
msgid "All"
msgstr "Alla"
-#: contrib/admin/filterspecs.py:109
+#: contrib/admin/filterspecs.py:111
msgid "Any date"
msgstr "Alla datum"
-#: contrib/admin/filterspecs.py:110
+#: contrib/admin/filterspecs.py:112
msgid "Today"
msgstr "Idag"
-#: contrib/admin/filterspecs.py:113
+#: contrib/admin/filterspecs.py:115
msgid "Past 7 days"
msgstr "Senaste 7 dagarna"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "This month"
msgstr "Den här månaden"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This year"
msgstr "Det här året"
-#: contrib/admin/models.py:16
+#: contrib/admin/models.py:17
msgid "action time"
msgstr "händelsetid"
-#: contrib/admin/models.py:19
+#: contrib/admin/models.py:20
msgid "object id"
msgstr "objektets id"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object repr"
msgstr "objektets beskrivning"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "action flag"
msgstr "händelseflagga"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "change message"
msgstr "ändra meddelande"
-#: contrib/admin/models.py:25
+#: contrib/admin/models.py:26
msgid "log entry"
msgstr "loggpost"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entries"
msgstr "loggposter"
-#: contrib/admin/templatetags/admin_list.py:249
+#: contrib/admin/templatetags/admin_list.py:254
msgid "All dates"
msgstr "Alla datum"
-#: contrib/admin/views/auth.py:19 contrib/admin/views/main.py:257
+#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
+msgid ""
+"Please enter a correct username and password. Note that both fields are case-"
+"sensitive."
+msgstr ""
+"Var god ange ett korrekt användarnamn och lösenord. Observera att båda "
+"fälten är skiftlägeskänsliga."
+
+#: contrib/admin/views/decorators.py:24
+#: contrib/admin/templates/admin/login.html:25
+msgid "Log in"
+msgstr "Logga in"
+
+#: contrib/admin/views/decorators.py:62
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+"Var god logga in igen, eftersom din session har tagit slut. Oroa dig inte: "
+"Ditt bidrag har sparats."
+
+#: contrib/admin/views/decorators.py:69
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr ""
+"Det verkar som att din webläsare inte är konfigurerad att acceptera cookies. "
+"Aktivera cookies, ladda om den här sidan, och försök igen."
+
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr "Användarnamn får inte innehålla '@'-tecknet."
+
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr "Din e-postadress är inte ditt användarnamn. Försök med '%s' istället."
+
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" lades till."
-#: contrib/admin/views/auth.py:24 contrib/admin/views/main.py:261
-#: contrib/admin/views/main.py:347
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
+#: contrib/admin/views/main.py:354
msgid "You may edit it again below."
msgstr "Du kan ändra det igen nedanför."
-#: contrib/admin/views/auth.py:30
+#: contrib/admin/views/auth.py:31
msgid "Add user"
msgstr "Lägg till användare"
-#: contrib/admin/views/auth.py:57
+#: contrib/admin/views/auth.py:58
msgid "Password changed successfully."
-msgstr "Lösenordet ändrades framgångsrikt."
+msgstr "Lösenordet ändrades."
-#: contrib/admin/views/auth.py:64
+#: contrib/admin/views/auth.py:65
#, python-format
msgid "Change password: %s"
msgstr "Ändra lösenord: %s"
-#: contrib/admin/views/main.py:223
+#: contrib/admin/views/main.py:230
msgid "Site administration"
-msgstr "Site-administration"
+msgstr "Webbplatsadministration"
-#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
+#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
#, python-format
msgid "You may add another %s below."
msgstr "Du kan lägga till en till %s nedanför."
-#: contrib/admin/views/main.py:289
+#: contrib/admin/views/main.py:296
#, python-format
msgid "Add %s"
msgstr "Lägg till %s"
-#: contrib/admin/views/main.py:335
+#: contrib/admin/views/main.py:342
#, python-format
msgid "Added %s."
msgstr "Lade till %s."
-#: contrib/admin/views/main.py:337
+#: contrib/admin/views/main.py:344
#, python-format
msgid "Changed %s."
msgstr "Ändrade %s."
-#: contrib/admin/views/main.py:339
+#: contrib/admin/views/main.py:346
#, python-format
msgid "Deleted %s."
msgstr "Tog bort %s."
-#: contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:349
msgid "No fields changed."
msgstr "Inga fält ändrade."
-#: contrib/admin/views/main.py:345
+#: contrib/admin/views/main.py:352
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "%(name)s \"%(obj)s\" ändrades."
-#: contrib/admin/views/main.py:353
+#: contrib/admin/views/main.py:360
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr "%(name)s \"%(obj)s\" lades till. Du kan ändra det igen nedanför."
-#: contrib/admin/views/main.py:391
+#: contrib/admin/views/main.py:398
#, python-format
msgid "Change %s"
msgstr "Ändra %s"
-#: contrib/admin/views/main.py:476
+#: contrib/admin/views/main.py:483
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "Ett eller flera %(fieldname)s i %(name)s: %(obj)s"
-#: contrib/admin/views/main.py:481
+#: contrib/admin/views/main.py:488
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
msgstr "Ett eller flera %(fieldname)s i %(name)s:"
-#: contrib/admin/views/main.py:514
+#: contrib/admin/views/main.py:520
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "%(name)set \"%(obj)s\" togs bort."
-#: contrib/admin/views/main.py:517
+#: contrib/admin/views/main.py:523
msgid "Are you sure?"
msgstr "Är du säker?"
-#: contrib/admin/views/main.py:539
+#: contrib/admin/views/main.py:545
#, python-format
msgid "Change history: %s"
-msgstr "Ändra historik: %s"
+msgstr "Ändringshistorik: %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s"
msgstr "Välj %s"
-#: contrib/admin/views/main.py:573
+#: contrib/admin/views/main.py:579
#, python-format
msgid "Select %s to change"
msgstr "Välj %s att ändra"
-#: contrib/admin/views/main.py:768
+#: contrib/admin/views/main.py:780
msgid "Database error"
msgstr "Databasfel"
-#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
-msgid ""
-"Please enter a correct username and password. Note that both fields are case-"
-"sensitive."
-msgstr ""
-"Var god ange ett korrekt användarnamn och lösenord. Observera att båda "
-"fälten är skiftlägeskänsliga."
-
-#: contrib/admin/views/decorators.py:24
-#: contrib/admin/templates/admin/login.html:25
-msgid "Log in"
-msgstr "Logga in"
-
-#: contrib/admin/views/decorators.py:62
-msgid ""
-"Please log in again, because your session has expired. Don't worry: Your "
-"submission has been saved."
-msgstr ""
-"Var god logga in igen, eftersom din session har tagit slut. "
-"Oroa dig inte: Ditt bidrag har sparats."
-
-#: contrib/admin/views/decorators.py:69
-msgid ""
-"Looks like your browser isn't configured to accept cookies. Please enable "
-"cookies, reload this page, and try again."
-msgstr ""
-"Det ser ut som om din webläsare inte är konfigurerad att acceptera cookies. "
-"Aktivera cookies, ladda om den här sidan, och försök igen."
-
-#: contrib/admin/views/decorators.py:83
-msgid "Usernames cannot contain the '@' character."
-msgstr "Användarnamn kan inte innehålla '@' tecknet."
-
-#: contrib/admin/views/decorators.py:85
-#, python-format
-msgid "Your e-mail address is not your username. Try '%s' instead."
-msgstr "Din e-mailadress är inte ditt användarnamn. Försök med '%s' istället."
-
-#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
+#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
+#: contrib/admin/views/doc.py:51
msgid "tag:"
msgstr "tagg:"
-#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
+#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
+#: contrib/admin/views/doc.py:82
msgid "filter:"
msgstr "filter:"
-#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
+#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
+#: contrib/admin/views/doc.py:140
msgid "view:"
msgstr "vy:"
-#: contrib/admin/views/doc.py:164
+#: contrib/admin/views/doc.py:165
#, python-format
msgid "App %r not found"
msgstr "Applikation %r hittades inte"
-#: contrib/admin/views/doc.py:171
-#, fuzzy, python-format
+#: contrib/admin/views/doc.py:172
+#, python-format
msgid "Model %(name)r not found in app %(label)r"
-msgstr "Modellen %(model_name)r hittades inte i applikation %(app_label)r"
+msgstr "Modellen %(name)r hittades inte i applikation %(label)r"
-#: contrib/admin/views/doc.py:183
-#, fuzzy, python-format
+#: contrib/admin/views/doc.py:184
+#, python-format
msgid "the related `%(label)s.%(type)s` object"
-msgstr "det relaterade `%(app_label)s.%(data_type)s` objektet"
+msgstr "det relaterade `%(label)s.%(type)s`-objektet"
-#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
-#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
+#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
msgid "model:"
msgstr "modell:"
-#: contrib/admin/views/doc.py:214
-#, fuzzy, python-format
+#: contrib/admin/views/doc.py:215
+#, python-format
msgid "related `%(label)s.%(name)s` objects"
-msgstr "relaterade `%(app_label)s.%(object_name)s` objekt"
+msgstr "relaterade `%(label)s.%(name)s`-objekt"
-#: contrib/admin/views/doc.py:219
+#: contrib/admin/views/doc.py:220
#, python-format
msgid "all %s"
msgstr "alla %s"
-#: contrib/admin/views/doc.py:224
+#: contrib/admin/views/doc.py:225
#, python-format
msgid "number of %s"
msgstr "antal %s"
-#: contrib/admin/views/doc.py:229
+#: contrib/admin/views/doc.py:230
#, python-format
msgid "Fields on %s objects"
msgstr "Fält på %s objekt"
-#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:302
-#: contrib/admin/views/doc.py:304 contrib/admin/views/doc.py:310
-#: contrib/admin/views/doc.py:311 contrib/admin/views/doc.py:313
+#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
+#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
msgid "Integer"
msgstr "Heltal"
-#: contrib/admin/views/doc.py:292
+#: contrib/admin/views/doc.py:293
msgid "Boolean (Either True or False)"
msgstr "Boolesk (antingen True eller False)"
-#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:312
+#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "Sträng (upp till %(maxlength)s)"
-#: contrib/admin/views/doc.py:294
+#: contrib/admin/views/doc.py:295
msgid "Comma-separated integers"
msgstr "Komma-separerade heltal"
-#: contrib/admin/views/doc.py:295
+#: contrib/admin/views/doc.py:296
msgid "Date (without time)"
msgstr "Datum (utan tid)"
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:297
msgid "Date (with time)"
msgstr "Datum (med tid)"
-#: contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:298
msgid "Decimal number"
msgstr "Decimaltal"
-#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:299
msgid "E-mail address"
msgstr "E-postadress:"
-#: contrib/admin/views/doc.py:299 contrib/admin/views/doc.py:300
-#: contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:304
msgid "File path"
msgstr "Filsökväg"
-#: contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:302
msgid "Floating point number"
msgstr "Flyttal"
-#: contrib/admin/views/doc.py:307
+#: contrib/admin/views/doc.py:308
msgid "Boolean (Either True, False or None)"
msgstr "Boolesk (antingen True, False eller None)"
-#: contrib/admin/views/doc.py:308
+#: contrib/admin/views/doc.py:309
msgid "Relation to parent model"
msgstr "Relation till förälder-modell"
-#: contrib/admin/views/doc.py:309
+#: contrib/admin/views/doc.py:310
msgid "Phone number"
msgstr "Telefonnummer"
-#: contrib/admin/views/doc.py:314
+#: contrib/admin/views/doc.py:315
msgid "Text"
msgstr "Text"
-#: contrib/admin/views/doc.py:315
+#: contrib/admin/views/doc.py:316
msgid "Time"
msgstr "Tid"
-#: contrib/admin/views/doc.py:316 contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
-#: contrib/admin/views/doc.py:317
+#: contrib/admin/views/doc.py:318
msgid "U.S. state (two uppercase letters)"
-msgstr "Stat i USA (två versaler)"
+msgstr "Delstat i USA (två versaler)"
-#: contrib/admin/views/doc.py:318
+#: contrib/admin/views/doc.py:319
msgid "XML text"
msgstr "XML-text"
-#: contrib/admin/views/doc.py:344
+#: contrib/admin/views/doc.py:345
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s verkar inte vara ett urlpattern-objekt"
#: contrib/admin/templates/widget/file.html:2
msgid "Currently:"
-msgstr "Nuvarande:"
+msgstr "Aktuell:"
#: contrib/admin/templates/widget/file.html:3
msgid "Change:"
@@ -1538,11 +1538,11 @@ msgstr "Datum:"
msgid "Time:"
msgstr "Tid:"
-#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
@@ -1550,36 +1550,36 @@ msgstr "Tid:"
msgid "Documentation"
msgstr "Dokumentation"
-#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin/auth/user/change_password.html:15
#: contrib/admin/templates/admin/auth/user/change_password.html:46
#: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/view_detail.html:4
#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
#: contrib/admin/templates/admin_doc/missing_docutils.html:4
#: contrib/admin/templates/admin_doc/view_index.html:5
#: contrib/admin/templates/admin_doc/model_detail.html:3
#: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/model_index.html:5
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
msgid "Change password"
msgstr "Ändra lösenord"
-#: contrib/admin/templates/admin/change_list.html:6
#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/change_list.html:6
#: contrib/admin/templates/admin/500.html:4
#: contrib/admin/templates/admin/invalid_setup.html:4
#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/admin/delete_confirmation.html:6
#: contrib/admin/templates/admin/base.html:30
+#: contrib/admin/templates/admin/delete_confirmation.html:6
#: contrib/admin/templates/admin/auth/user/change_password.html:12
#: contrib/admin/templates/registration/password_change_done.html:4
#: contrib/admin/templates/registration/password_reset_form.html:4
@@ -1590,16 +1590,6 @@ msgstr "Ändra lösenord"
msgid "Home"
msgstr "Hem"
-#: contrib/admin/templates/admin/change_list.html:12
-#, python-format
-msgid "Add %(name)s"
-msgstr "Lägg till %(name)s"
-
-#: contrib/admin/templates/admin/filter.html:2
-#, python-format
-msgid " By %(filter_title)s "
-msgstr " Av %(filter_title)s "
-
#: contrib/admin/templates/admin/object_history.html:5
#: contrib/admin/templates/admin/change_form.html:21
msgid "History"
@@ -1627,35 +1617,17 @@ msgid ""
"admin site."
msgstr ""
"Det här objektet har ingen ändringshistorik. Det lades antagligen inte till "
-"via denna administrationssite."
-
-#: contrib/admin/templates/admin/search_form.html:8
-msgid "Go"
-msgstr "Kör"
+"via denna administrationssida."
-#: contrib/admin/templates/admin/search_form.html:10
+#: contrib/admin/templates/admin/change_list.html:12
#, python-format
-msgid "1 result"
-msgid_plural "%(counter)s results"
-msgstr[0] "1 resultat"
-msgstr[1] "%(counter)s resultat"
+msgid "Add %(name)s"
+msgstr "Lägg till %(name)s"
-#: contrib/admin/templates/admin/search_form.html:10
+#: contrib/admin/templates/admin/filter.html:2
#, python-format
-msgid "%(full_result_count)s total"
-msgstr "%(full_result_count)s totalt"
-
-#: contrib/admin/templates/admin/pagination.html:10
-msgid "Show all"
-msgstr "Visa alla"
-
-#: contrib/admin/templates/admin/base_site.html:4
-msgid "Django site admin"
-msgstr "Django site-administration"
-
-#: contrib/admin/templates/admin/base_site.html:7
-msgid "Django administration"
-msgstr "Django administration"
+msgid " By %(filter_title)s "
+msgstr " Av %(filter_title)s "
#: contrib/admin/templates/admin/500.html:4
msgid "Server error"
@@ -1674,7 +1646,7 @@ msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
-"Ett fel har uppstått. Administratören har meddelats via e-mail och felet bör "
+"Ett fel har uppstått. Administratören har meddelats via e-post och felet bör "
"åtgärdas snart. Tack för ditt tålamod."
#: contrib/admin/templates/admin/invalid_setup.html:8
@@ -1684,12 +1656,53 @@ msgid ""
"the appropriate user."
msgstr ""
"Någonting är fel med din databasinstallation. Se till att de rätta "
-"tabellerna har skapats och att databasen är läsbar av rätt användare."
+"databastabellerna har skapats och att databasen är läsbar av rätt användare."
+
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr "Kör"
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "1 resultat"
+msgstr[1] "%(counter)s resultat"
+
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr "%(full_result_count)s totalt"
+
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "Visa alla"
+
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr "Django webbplatsadministration"
+
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr "Django-administration"
+
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "Filter"
+
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
+msgid "Page not found"
+msgstr "Sidan kunde inte hittas"
+
+#: contrib/admin/templates/admin/404.html:10
+msgid "We're sorry, but the requested page could not be found."
+msgstr "Vi är ledsna, men den efterfrågade sidan kunde inte hittas."
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
-msgstr "Modeller tillgängliga i %(name)s applikationen."
+msgstr "Modeller tillgängliga i applikationen %(name)s."
#: contrib/admin/templates/admin/index.html:18
#, python-format
@@ -1698,9 +1711,8 @@ msgstr "%(name)s"
#: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15
-#, fuzzy
msgid "Add"
-msgstr "Lägg&nbsp;till"
+msgstr "Lägg till"
#: contrib/admin/templates/admin/index.html:34
msgid "Change"
@@ -1712,32 +1724,19 @@ msgstr "Du har inte rättigheter att ändra något."
#: contrib/admin/templates/admin/index.html:52
msgid "Recent Actions"
-msgstr "Senaste Händelserna"
+msgstr "Senaste händelser"
#: contrib/admin/templates/admin/index.html:53
msgid "My Actions"
-msgstr "Mina Händelser"
+msgstr "Mina händelser"
#: contrib/admin/templates/admin/index.html:57
msgid "None available"
msgstr "Inga tillgängliga"
-#: contrib/admin/templates/admin/404.html:4
-#: contrib/admin/templates/admin/404.html:8
-msgid "Page not found"
-msgstr "Sidan kunde inte hittas"
-
-#: contrib/admin/templates/admin/404.html:10
-msgid "We're sorry, but the requested page could not be found."
-msgstr "Vi är ledsna, men den efterfrågade sidan kunde inte hittas."
-
-#: contrib/admin/templates/admin/filters.html:4
-msgid "Filter"
-msgstr "Filter"
-
#: contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
-msgstr "Visa på site"
+msgstr "Visa på webbplats"
#: contrib/admin/templates/admin/change_form.html:32
#: contrib/admin/templates/admin/auth/user/change_password.html:24
@@ -1754,6 +1753,10 @@ msgstr "Sortering"
msgid "Order:"
msgstr "Sortera:"
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr "Välkommen,"
+
#: contrib/admin/templates/admin/delete_confirmation.html:9
#: contrib/admin/templates/admin/submit_line.html:3
msgid "Delete"
@@ -1767,7 +1770,7 @@ msgid ""
"following types of objects:"
msgstr ""
"Att ta bort %(object_name)s '%(escaped_object)s' skulle innebära att "
-"besläktade objekt togs bort, men ditt konto har inte rättigheter att ta bort "
+"relaterade objekt togs bort, men ditt konto har inte rättigheter att ta bort "
"följande objekttyper:"
#: contrib/admin/templates/admin/delete_confirmation.html:21
@@ -1777,16 +1780,12 @@ msgid ""
"All of the following related items will be deleted:"
msgstr ""
"Är du säker på att du vill ta bort %(object_name)s \"%(escaped_object)s\"? "
-"Alla dessa sammanlänkade objekt kommer att tas bort:"
+"Alla dessa relaterade objekt kommer att tas bort:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
msgstr "Ja, jag är säker"
-#: contrib/admin/templates/admin/base.html:25
-msgid "Welcome,"
-msgstr "Välkommen,"
-
#: contrib/admin/templates/admin/submit_line.html:4
msgid "Save as new"
msgstr "Spara som ny"
@@ -1821,14 +1820,14 @@ msgstr "Lösenord (igen)"
#: contrib/admin/templates/admin/auth/user/change_password.html:40
#: contrib/admin/templates/admin/auth/user/add_form.html:24
msgid "Enter the same password as above, for verification."
-msgstr "Fyll i samma lösenord som ovan för verifiering."
+msgstr "Fyll i samma lösenord som ovan, för verifiering."
#: contrib/admin/templates/admin/auth/user/add_form.html:6
msgid ""
"First, enter a username and password. Then, you'll be able to edit more user "
"options."
msgstr ""
-"Ange först ett användarnamn och ett lösenord. Sedan kommer du att kunna "
+"Ange först ett användarnamn och ett lösenord. Du kommer sedan att kunna "
"ändra fler användaralternativ."
#: contrib/admin/templates/admin/auth/user/add_form.html:12
@@ -1863,8 +1862,8 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you."
msgstr ""
-"Har du glömt ditt lösenord? Fyll i din e-mailadress nedan, så nollställer vi "
-"ditt lösenord och mailar det nya till dig."
+"Har du glömt ditt lösenord? Fyll i din e-postadress nedan, så nollställer vi "
+"ditt lösenord och skickar det nya till dig via e-post."
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
@@ -1876,7 +1875,7 @@ msgstr "Nollställ mitt lösenord"
#: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
-msgstr "Tack för att du spenderade kvalitetstid med web-siten idag."
+msgstr "Tack för att du spenderade lite kvalitetstid med webbplatsen idag."
#: contrib/admin/templates/registration/logged_out.html:10
msgid "Log in again"
@@ -1885,15 +1884,15 @@ msgstr "Logga in igen"
#: contrib/admin/templates/registration/password_reset_done.html:6
#: contrib/admin/templates/registration/password_reset_done.html:10
msgid "Password reset successful"
-msgstr "Lösenordsnollställning lyckades."
+msgstr "Lösenordsnollställning lyckades"
#: contrib/admin/templates/registration/password_reset_done.html:12
msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly."
msgstr ""
-"Vi har skickat ett nytt lösenord till e-mailadressen du fyllde i. Det bör "
-"anlända snarast."
+"Vi har skickat ett nytt lösenord till e-postadressen du fyllde i. Det bör "
+"anlända inom kort."
#: contrib/admin/templates/registration/password_change_form.html:12
msgid ""
@@ -1905,7 +1904,7 @@ msgstr ""
#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
-msgstr "Gamla lösenordet:"
+msgstr "Gammalt lösenord:"
#: contrib/admin/templates/registration/password_change_form.html:19
msgid "New password:"
@@ -1921,7 +1920,8 @@ msgstr "Ändra mitt lösenord"
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
-msgstr "Du får det här mailet eftersom du bad om att få lösenordet nollställt"
+msgstr ""
+"Du får det här e-postbrevet eftersom du bad om att få lösenordet nollställt"
#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
@@ -1936,8 +1936,7 @@ msgstr "Ditt nya lösenord är: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
msgstr ""
-"Känn dig välkommen att ändra det här lösenordet genom att gå till den här "
-"sidan:"
+"Du är välkommen att ändra det här lösenordet genom att gå till den här sidan:"
#: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:"
@@ -1945,7 +1944,7 @@ msgstr "Ditt användarnamn, om du har glömt:"
#: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!"
-msgstr "Tack för att du använder vår site!"
+msgstr "Tack för att du använder vår webbplats!"
#: contrib/admin/templates/registration/password_reset_email.html:15
#, python-format
@@ -1974,7 +1973,7 @@ msgstr ""
"<p class=\"help\">För att installera smarta bokmärken, dra länken till din\n"
"verktygsrad med bokmärken, eller högerklicka på länken och lägg till den\n"
"till dina bokmärken. Nu kan du välja det smarta bokmärket från alla sidor\n"
-"på siten. Observera att några av dessa smarta bokmärken kräver att du "
+"på webbplatsen. Observera att några av dessa smarta bokmärken kräver att du "
"besöker\n"
"sidan från en dator som är \"intern\" (tala med din systemadministratör\n"
"om du inte är säker på om din dator är \"intern\").</p>\n"
@@ -2000,12 +1999,12 @@ msgid ""
"Shows the content-type and unique ID for pages that represent a single "
"object."
msgstr ""
-"Visa innehållstypen och det unika ID:t för sidor som representerar ett "
+"Visa innehållstypen och det unika ID-numret för sidor som representerar ett "
"enskilt objekt."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)"
-msgstr "Redigera det här objektet (nuvarande fönster)"
+msgstr "Redigera det här objektet (aktuellt fönster)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object."
@@ -2021,123 +2020,123 @@ msgstr "Redigera det här objektet (nytt fönster)"
msgid "As above, but opens the admin page in a new window."
msgstr "Som ovan, men öppnar administrationssidan i ett nytt fönster."
-#: contrib/contenttypes/models.py:36
+#: contrib/contenttypes/models.py:37
msgid "python model class name"
-msgstr "python modell klassnamn"
+msgstr "Python-modellklassnamn"
-#: contrib/contenttypes/models.py:39
+#: contrib/contenttypes/models.py:40
msgid "content type"
msgstr "innehållstyp"
-#: contrib/contenttypes/models.py:40
+#: contrib/contenttypes/models.py:41
msgid "content types"
msgstr "innehållstyper"
-#: contrib/auth/views.py:40
+#: contrib/auth/views.py:41
msgid "Logged out"
msgstr "Utloggad"
-#: contrib/auth/models.py:44 contrib/auth/models.py:64
+#: contrib/auth/models.py:51 contrib/auth/models.py:71
msgid "name"
msgstr "namn"
-#: contrib/auth/models.py:46
+#: contrib/auth/models.py:53
msgid "codename"
msgstr "kodnamn"
-#: contrib/auth/models.py:49
+#: contrib/auth/models.py:56
msgid "permission"
msgstr "rättighet"
-#: contrib/auth/models.py:50 contrib/auth/models.py:65
+#: contrib/auth/models.py:57 contrib/auth/models.py:72
msgid "permissions"
msgstr "rättigheter"
-#: contrib/auth/models.py:68
+#: contrib/auth/models.py:75
msgid "group"
msgstr "grupp"
-#: contrib/auth/models.py:69 contrib/auth/models.py:109
+#: contrib/auth/models.py:76 contrib/auth/models.py:116
msgid "groups"
msgstr "grupper"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid "username"
msgstr "användarnamn"
-#: contrib/auth/models.py:99
+#: contrib/auth/models.py:106
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
msgstr ""
-"Obligatorisk. 30 tecken eller mindre. Endast bokstäver, siffror eller "
-"understräck."
+"Obligatorisk. 30 tecken eller färre. Endast bokstäver, siffror eller "
+"understreck."
-#: contrib/auth/models.py:100
+#: contrib/auth/models.py:107
msgid "first name"
msgstr "förnamn"
-#: contrib/auth/models.py:101
+#: contrib/auth/models.py:108
msgid "last name"
msgstr "efternamn"
-#: contrib/auth/models.py:102
+#: contrib/auth/models.py:109
msgid "e-mail address"
-msgstr "e-mailadress"
+msgstr "e-postadress"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid "password"
msgstr "lösenord"
-#: contrib/auth/models.py:103
+#: contrib/auth/models.py:110
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
msgstr ""
"Använd '[algo]$[salt]$[hexdigest]' eller använd <a href=\"password/\">Ändra "
-"lösenord</a>."
+"lösenord-formuläret</a>."
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "staff status"
msgstr "personalstatus"
-#: contrib/auth/models.py:104
+#: contrib/auth/models.py:111
msgid "Designates whether the user can log into this admin site."
-msgstr "Avgör om användaren kan logga in på den här admin-siten."
+msgstr "Avgör om användaren kan logga in på den här adminsidan."
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid "active"
msgstr "aktiv"
-#: contrib/auth/models.py:105
+#: contrib/auth/models.py:112
msgid ""
"Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts."
msgstr ""
-"Avgör om användaren kan logga in till Django admin. Avmarkera denna "
+"Avgör om användaren kan logga in till Django-adminsidan. Avmarkera denna "
"istället för att ta bort konton."
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid "superuser status"
msgstr "superanvändare"
-#: contrib/auth/models.py:106
+#: contrib/auth/models.py:113
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
msgstr ""
-"Avgör om användaren har alla rättigheter utan att uttryckligen tilldela "
-"dem"
+"Anger att den här användaren har alla rättigheter utan att uttryckligen "
+"tilldela dem."
-#: contrib/auth/models.py:107
+#: contrib/auth/models.py:114
msgid "last login"
msgstr "senaste inloggning"
-#: contrib/auth/models.py:108
+#: contrib/auth/models.py:115
msgid "date joined"
msgstr "registreringsdatum"
-#: contrib/auth/models.py:110
+#: contrib/auth/models.py:117
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@@ -2145,43 +2144,38 @@ msgstr ""
"Förutom de rättigheterna som utdelas manuellt så kommer användaren dessutom "
"få samma rättigheter som de grupper där han/hon är medlem."
-#: contrib/auth/models.py:111
+#: contrib/auth/models.py:118
msgid "user permissions"
msgstr "användarättigheter"
-#: contrib/auth/models.py:115
+#: contrib/auth/models.py:122
msgid "user"
msgstr "användare"
-#: contrib/auth/models.py:116
+#: contrib/auth/models.py:123
msgid "users"
msgstr "användare"
-#: contrib/auth/models.py:122
+#: contrib/auth/models.py:129
msgid "Personal info"
msgstr "Personlig information"
-#: contrib/auth/models.py:123
+#: contrib/auth/models.py:130
msgid "Permissions"
msgstr "Rättigheter"
-#: contrib/auth/models.py:124
+#: contrib/auth/models.py:131
msgid "Important dates"
msgstr "Viktiga datum"
-#: contrib/auth/models.py:125
+#: contrib/auth/models.py:132
msgid "Groups"
msgstr "Grupper"
-#: contrib/auth/models.py:269
+#: contrib/auth/models.py:274
msgid "message"
msgstr "meddelande"
-#: contrib/auth/models.py:282
-#, fuzzy
-msgid "AnonymousUser"
-msgstr "Anonym användare"
-
#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match."
msgstr "De båda lösenorden stämde inte överens."
@@ -2195,40 +2189,36 @@ msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgstr ""
-"Din webläsare verkar inte stödja cookies. Cookie behövs för att kunna logga "
-"in."
+"Din webbläsare verkar inte tillåta cookies. Cookies behövs för att kunna "
+"logga in."
#: contrib/auth/forms.py:62
msgid "This account is inactive."
msgstr "Detta konto är inaktivt."
-#: contrib/auth/forms.py:85
+#: contrib/auth/forms.py:84
msgid ""
"That e-mail address doesn't have an associated user account. Are you sure "
"you've registered?"
msgstr ""
-"Den e-mailadressen har inte något konto associerat med sig. Är du säker på "
-"att du har registrerat dig?"
+"Den e-postadressen är inte associerad med något användarkonto. Är du säker "
+"på att du har registrerat dig?"
#: contrib/auth/forms.py:117
msgid "The two 'new password' fields didn't match."
-msgstr "De två lösenordsfälten stämde inte överens."
+msgstr "De två 'nytt lösenord'-fälten stämde inte överens."
#: contrib/auth/forms.py:124
msgid "Your old password was entered incorrectly. Please enter it again."
-msgstr "Ditt gamla lösenord var felaktigt ifyllt. Var vänlig fyll i det igen"
+msgstr "Ditt gamla lösenord var felaktigt ifyllt. Var vänlig fyll i det igen."
#: contrib/localflavor/uk/forms.py:18
msgid "Enter a postcode. A space is required between the two postcode parts."
msgstr "Fyll i ett postnummer. Du måste ha mellanslag mellan nummerdelarna."
-#: contrib/localflavor/au/forms.py:18
-msgid "Enter a 4 digit post code."
-msgstr "Fyll i en fyra-sifrigt postkod."
-
#: contrib/localflavor/br/forms.py:18
msgid "Enter a zip code in the format XXXXX-XXX."
-msgstr "Fyll i zipkod i XXXXX-XXX format."
+msgstr "Fyll i zipkod på formatet XXXXX-XXX."
#: contrib/localflavor/br/forms.py:30
msgid "Phone numbers must be in XX-XXXX-XXXX format."
@@ -2254,14 +2244,26 @@ msgstr "Detta fält kräver minst 14 sifrror"
msgid "Invalid CNPJ number."
msgstr "Ogiltigt CNPJ-nummer."
+#: contrib/localflavor/au/forms.py:18
+msgid "Enter a 4 digit post code."
+msgstr "Fyll i en fyrsiffrig postkod."
+
#: contrib/localflavor/fr/forms.py:17 contrib/localflavor/de/forms.py:16
#: contrib/localflavor/fi/forms.py:14
msgid "Enter a zip code in the format XXXXX."
-msgstr "Fyll i en zipkod i XXXXX format."
+msgstr "Fyll i en zipkod på formatet XXXXX."
+
+#: contrib/localflavor/us/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr "Fyll i zipkod på formatet XXXXX eller XXXXX-XXXX."
+
+#: contrib/localflavor/us/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr "Fyll i ett giltigt amerikanskt personnummer i formatet XXX-XX-XXXX."
#: contrib/localflavor/de/de_states.py:5
msgid "Baden-Wuerttemberg"
-msgstr ""
+msgstr "Baden-Württemberg"
#: contrib/localflavor/de/de_states.py:6
msgid "Bavaria"
@@ -2296,9 +2298,8 @@ msgid "Lower Saxony"
msgstr "Nedre Sachsen"
#: contrib/localflavor/de/de_states.py:14
-#, fuzzy
msgid "North Rhine-Westphalia"
-msgstr "Norra Rhen-Westphalia"
+msgstr "Nordrhein-Westfalen"
#: contrib/localflavor/de/de_states.py:15
msgid "Rhineland-Palatinate"
@@ -2318,19 +2319,23 @@ msgstr "Sachsen-Anhalt"
#: contrib/localflavor/de/de_states.py:19
msgid "Schleswig-Holstein"
-msgstr ""
+msgstr "Schleswig-Holstein"
#: contrib/localflavor/de/de_states.py:20
msgid "Thuringia"
-msgstr ""
+msgstr "Thüringen"
#: contrib/localflavor/de/forms.py:60
msgid ""
"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
"format."
msgstr ""
-"Fyll i ett giltigt tyskt ID-kortnummer i XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
-"format."
+"Fyll i ett giltigt tyskt ID-kortnummer på formatet XXXXXXXXXXX-XXXXXXX-"
+"XXXXXXX-X."
+
+#: contrib/localflavor/jp/forms.py:21
+msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
+msgstr "Fyll i postkod på formatet XXXXXXX eller XXX-XXXX."
#: contrib/localflavor/jp/jp_prefectures.py:4
msgid "Hokkaido"
@@ -2520,170 +2525,158 @@ msgstr "kagoshima"
msgid "Okinawa"
msgstr "Okinawa"
-#: contrib/localflavor/jp/forms.py:21
-msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
-msgstr "Fyll i zipkod i formatet XXXXXXX eller XXX-XXXX."
-
-#: contrib/localflavor/it/forms.py:16
-msgid "Enter a valid zip code."
-msgstr "Fyll i en giltigt zipkod."
-
-#: contrib/localflavor/it/forms.py:41
-msgid "Enter a valid Social Security number."
-msgstr "Fyll i ett giltigt personnummer."
-
-#: contrib/localflavor/it/forms.py:68
-msgid "Enter a valid VAT number."
-msgstr "Fyll i ett giltigt VAT-nummer."
-
-#: contrib/localflavor/no/forms.py:15 contrib/localflavor/ch/forms.py:18
-msgid "Enter a zip code in the format XXXX."
-msgstr "Fyll i zipkod i formatet XXXX."
-
-#: contrib/localflavor/no/forms.py:36
-msgid "Enter a valid Norwegian social security number."
-msgstr "Fyll i ett giltigt norskt personnummer."
-
-#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
-msgid "Enter a valid Finnish social security number."
-msgstr "Fyll i ett giltigt finskt personnummer."
-
-#: contrib/localflavor/us/forms.py:18
-msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
-msgstr "Fyll i zipkod i formatet XXXXX eller XXXXX-XXXX."
-
-#: contrib/localflavor/us/forms.py:51
-msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
-msgstr "Fyll i ett giltigt amerikanskt personnummer i XXX-XX-XXXX format."
-
-#: contrib/localflavor/is_/forms.py:16
-msgid ""
-"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
-msgstr "Fyll i ett giltigt isländskt personnummer. Formatet är XXXXXX-XXXX."
-
-#: contrib/localflavor/is_/forms.py:30
-msgid "The Icelandic identification number is not valid."
-msgstr "Det isländska personnumret är inte giltigt."
-
-#: contrib/localflavor/cl/forms.py:21
-msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
-msgstr "Fyll i ett giltigt chileanskt RUT. Formatet är XX.XXX.XXX-X."
-
-#: contrib/localflavor/cl/forms.py:26
-msgid "Enter valid a Chilean RUT"
-msgstr "Fyll i ett giltigt chileanskt RUT"
-
#: contrib/localflavor/ch/ch_states.py:5
msgid "Aargau"
msgstr "Aargau"
#: contrib/localflavor/ch/ch_states.py:6
msgid "Appenzell Innerrhoden"
-msgstr ""
+msgstr "Appenzell Innerrhoden"
#: contrib/localflavor/ch/ch_states.py:7
msgid "Appenzell Ausserrhoden"
-msgstr ""
+msgstr "Appenzell Ausserrhoden"
#: contrib/localflavor/ch/ch_states.py:8
msgid "Basel-Stadt"
-msgstr ""
+msgstr "Basel-Stadt"
#: contrib/localflavor/ch/ch_states.py:9
msgid "Basel-Land"
-msgstr ""
+msgstr "Basel-Landschaft"
#: contrib/localflavor/ch/ch_states.py:10
msgid "Berne"
-msgstr ""
+msgstr "Bern"
#: contrib/localflavor/ch/ch_states.py:11
msgid "Fribourg"
-msgstr ""
+msgstr "Fribourg"
#: contrib/localflavor/ch/ch_states.py:12
msgid "Geneva"
-msgstr ""
+msgstr "Genève"
#: contrib/localflavor/ch/ch_states.py:13
msgid "Glarus"
-msgstr ""
+msgstr "Glarus"
#: contrib/localflavor/ch/ch_states.py:14
msgid "Graubuenden"
-msgstr ""
+msgstr "Graubünden"
#: contrib/localflavor/ch/ch_states.py:15
msgid "Jura"
-msgstr ""
+msgstr "Jura"
#: contrib/localflavor/ch/ch_states.py:16
msgid "Lucerne"
-msgstr ""
+msgstr "Luzern"
#: contrib/localflavor/ch/ch_states.py:17
msgid "Neuchatel"
-msgstr ""
+msgstr "Neuchâtel"
#: contrib/localflavor/ch/ch_states.py:18
msgid "Nidwalden"
-msgstr ""
+msgstr "Nidwalden"
#: contrib/localflavor/ch/ch_states.py:19
msgid "Obwalden"
-msgstr ""
+msgstr "Obwalden"
#: contrib/localflavor/ch/ch_states.py:20
msgid "Schaffhausen"
-msgstr ""
+msgstr "Schaffhausen"
#: contrib/localflavor/ch/ch_states.py:21
msgid "Schwyz"
-msgstr ""
+msgstr "Schwyz"
#: contrib/localflavor/ch/ch_states.py:22
msgid "Solothurn"
-msgstr ""
+msgstr "Solothurn"
#: contrib/localflavor/ch/ch_states.py:23
msgid "St. Gallen"
-msgstr ""
+msgstr "Sankt Gallen"
#: contrib/localflavor/ch/ch_states.py:24
msgid "Thurgau"
-msgstr ""
+msgstr "Thurgau"
#: contrib/localflavor/ch/ch_states.py:25
msgid "Ticino"
-msgstr ""
+msgstr "Ticino"
#: contrib/localflavor/ch/ch_states.py:26
msgid "Uri"
-msgstr ""
+msgstr "Uri"
#: contrib/localflavor/ch/ch_states.py:27
msgid "Valais"
-msgstr ""
+msgstr "Valais"
#: contrib/localflavor/ch/ch_states.py:28
msgid "Vaud"
-msgstr ""
+msgstr "Vaud"
#: contrib/localflavor/ch/ch_states.py:29
msgid "Zug"
-msgstr ""
+msgstr "Zug"
#: contrib/localflavor/ch/ch_states.py:30
msgid "Zurich"
-msgstr ""
+msgstr "Zürich"
+
+#: contrib/localflavor/ch/forms.py:18 contrib/localflavor/no/forms.py:14
+msgid "Enter a zip code in the format XXXX."
+msgstr "Fyll i zipkod på formatet XXXX."
#: contrib/localflavor/ch/forms.py:90
msgid ""
"Enter a valid Swiss identity or passport card number in X1234567<0 or "
"1234567890 format."
msgstr ""
-"Fyll i ett giltigt Schweiziskt ID- eller passkortnummer i X1234567<0 eller "
-"1234567890 format."
+"Fyll i ett giltigt Schweiziskt ID- eller passkortnummer på formatet "
+"X1234567<0 eller 1234567890."
+
+#: contrib/localflavor/is_/forms.py:17
+msgid ""
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr "Fyll i ett giltigt isländskt personnummer. Formatet är XXXXXX-XXXX."
+
+#: contrib/localflavor/is_/forms.py:31
+msgid "The Icelandic identification number is not valid."
+msgstr "Det isländska personnumret är inte giltigt."
+
+#: contrib/localflavor/it/forms.py:16
+msgid "Enter a valid zip code."
+msgstr "Fyll i en giltigt zipkod."
+
+#: contrib/localflavor/it/forms.py:41
+msgid "Enter a valid Social Security number."
+msgstr "Fyll i ett giltigt personnummer."
+
+#: contrib/localflavor/it/forms.py:68
+msgid "Enter a valid VAT number."
+msgstr "Fyll i ett giltigt VAT-nummer."
+
+#: contrib/localflavor/no/forms.py:35
+msgid "Enter a valid Norwegian social security number."
+msgstr "Fyll i ett giltigt norskt personnummer."
+
+#: contrib/localflavor/cl/forms.py:32
+msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
+msgstr "Fyll i ett giltigt chilenskt RUT. Formatet är XX.XXX.XXX-X."
+
+#: contrib/localflavor/cl/forms.py:37
+msgid "Enter valid a Chilean RUT"
+msgstr "Fyll i ett giltigt chilenskt RUT"
+
+#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
+msgid "Enter a valid Finnish social security number."
+msgstr "Fyll i ett giltigt finskt personnummer."
#: contrib/sessions/models.py:68
msgid "session key"
@@ -2709,7 +2702,7 @@ msgstr "sessioner"
msgid ""
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr ""
-"Exempel: '/om/kontakt/'. Se till att ha inledande och avslutande snedsträck."
+"Exempel: '/om/kontakt/'. Se till att ha inledande och avslutande snedstreck."
#: contrib/flatpages/models.py:9
msgid "title"
@@ -2733,7 +2726,7 @@ msgid ""
"will use 'flatpages/default.html'."
msgstr ""
"Exempel: 'sidor/kontaktsida.html'. Om det här inte fylls i kommer systemet "
-"att använda 'sidor/default.html'."
+"att använda 'flatpages/default.html'."
#: contrib/flatpages/models.py:14
msgid "registration required"
@@ -2742,15 +2735,15 @@ msgstr "registrering krävs"
#: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page."
msgstr ""
-"Om det här bockas i kommer endast inloggade användare att kunna visa sidan"
+"Om det här bockas i kommer endast inloggade användare att kunna se sidan."
#: contrib/flatpages/models.py:18
msgid "flat page"
-msgstr "flatsida"
+msgstr "flat sida"
#: contrib/flatpages/models.py:19
msgid "flat pages"
-msgstr "flatsidor"
+msgstr "flata sidor"
#: utils/dates.py:6
msgid "Monday"
@@ -2780,129 +2773,157 @@ msgstr "Lördag"
msgid "Sunday"
msgstr "Söndag"
-#: utils/dates.py:14
+#: utils/dates.py:10
+msgid "Mon"
+msgstr "Mån"
+
+#: utils/dates.py:10
+msgid "Tue"
+msgstr "Tis"
+
+#: utils/dates.py:10
+msgid "Wed"
+msgstr "Ons"
+
+#: utils/dates.py:10
+msgid "Thu"
+msgstr "Tors"
+
+#: utils/dates.py:10
+msgid "Fri"
+msgstr "Fre"
+
+#: utils/dates.py:11
+msgid "Sat"
+msgstr "Lör"
+
+#: utils/dates.py:11
+msgid "Sun"
+msgstr "Sön"
+
+#: utils/dates.py:18
msgid "January"
msgstr "Januari"
-#: utils/dates.py:14
+#: utils/dates.py:18
msgid "February"
msgstr "Februari"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "Mars"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "April"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Maj"
-#: utils/dates.py:14 utils/dates.py:27
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Juni"
-#: utils/dates.py:15 utils/dates.py:27
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Juli"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "August"
msgstr "Augusti"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "September"
msgstr "September"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "October"
msgstr "Oktober"
-#: utils/dates.py:15
+#: utils/dates.py:19
msgid "November"
msgstr "November"
-#: utils/dates.py:16
+#: utils/dates.py:20
msgid "December"
msgstr "December"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jan"
msgstr "jan"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "feb"
msgstr "feb"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "mar"
-msgstr "mars"
+msgstr "mar"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "apr"
msgstr "apr"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "may"
msgstr "maj"
-#: utils/dates.py:19
+#: utils/dates.py:23
msgid "jun"
-msgstr "juni"
+msgstr "jun"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "jul"
-msgstr "juli"
+msgstr "jul"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "aug"
msgstr "aug"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "sep"
-msgstr "sept"
+msgstr "sep"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "oct"
msgstr "okt"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "nov"
msgstr "nov"
-#: utils/dates.py:20
+#: utils/dates.py:24
msgid "dec"
msgstr "dec"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Jan."
-msgstr "jan"
+msgstr "Januari"
-#: utils/dates.py:27
+#: utils/dates.py:31
msgid "Feb."
-msgstr "feb"
+msgstr "Februari"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Aug."
-msgstr "aug"
+msgstr "Augusti"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Sept."
-msgstr "sept"
+msgstr "September"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Oct."
-msgstr "okt"
+msgstr "Oktober"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Nov."
-msgstr "nov"
+msgstr "November"
-#: utils/dates.py:28
+#: utils/dates.py:32
msgid "Dec."
-msgstr "dec"
+msgstr "December"
#: utils/timesince.py:12
msgid "year"
@@ -2940,87 +2961,89 @@ msgid_plural "minutes"
msgstr[0] "minut"
msgstr[1] "minuter"
-#: utils/timesince.py:40
-#, python-format
-msgid "%d milliseconds"
-msgstr "%d millisekunder"
-
-#: utils/timesince.py:41
+#: utils/timesince.py:39
#, python-format
msgid "%(number)d %(type)s"
msgstr "%(number)d %(type)s"
-#: utils/timesince.py:47
+#: utils/timesince.py:45
#, python-format
msgid ", %(number)d %(type)s"
msgstr ", %(number)d %(type)s"
-#: utils/dateformat.py:40
+#: utils/dateformat.py:41
msgid "p.m."
-msgstr "p.m."
+msgstr "e.m."
-#: utils/dateformat.py:41
+#: utils/dateformat.py:42
msgid "a.m."
-msgstr "a.m."
+msgstr "f.m."
-#: utils/dateformat.py:46
+#: utils/dateformat.py:47
msgid "PM"
-msgstr "PM"
+msgstr "FM"
-#: utils/dateformat.py:47
+#: utils/dateformat.py:48
msgid "AM"
-msgstr "AM"
+msgstr "EM"
-#: utils/dateformat.py:95
+#: utils/dateformat.py:97
msgid "midnight"
msgstr "midnatt"
-#: utils/dateformat.py:97
+#: utils/dateformat.py:99
msgid "noon"
msgstr "middag"
-#: utils/translation/trans_real.py:358
+#: utils/translation/trans_real.py:391
msgid "DATE_FORMAT"
-msgstr "N j, Y"
+msgstr "j M, Y"
-#: utils/translation/trans_real.py:359
+#: utils/translation/trans_real.py:392
msgid "DATETIME_FORMAT"
-msgstr "N j, Y, P"
+msgstr "j M, Y, H:i"
-#: utils/translation/trans_real.py:360
+#: utils/translation/trans_real.py:393
msgid "TIME_FORMAT"
-msgstr "P"
+msgstr "H:i"
-#: utils/translation/trans_real.py:376
+#: utils/translation/trans_real.py:409
msgid "YEAR_MONTH_FORMAT"
msgstr "F Y"
-#: utils/translation/trans_real.py:377
+#: utils/translation/trans_real.py:410
msgid "MONTH_DAY_FORMAT"
-msgstr "F j"
+msgstr "j F"
-#: template/defaultfilters.py:491
+#: template/defaultfilters.py:485
msgid "yes,no,maybe"
msgstr "ja,nej,kanske"
-#: template/defaultfilters.py:520
+#: template/defaultfilters.py:514
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] "%(size)d byte"
msgstr[1] "%(size)d bytes"
-#: template/defaultfilters.py:522
+#: template/defaultfilters.py:516
#, python-format
msgid "%.1f KB"
msgstr "%.1f KB"
-#: template/defaultfilters.py:524
+#: template/defaultfilters.py:518
#, python-format
msgid "%.1f MB"
msgstr "%.1f MB"
-#: template/defaultfilters.py:525
+#: template/defaultfilters.py:519
#, python-format
msgid "%.1f GB"
msgstr "%.1f GB"
+
+#~ msgid "%d milliseconds"
+#~ msgstr "%d millisekunder"
+
+#, fuzzy
+#~ msgid "AnonymousUser"
+#~ msgstr "Anonym användare"
diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/django.mo b/django/conf/locale/zh_CN/LC_MESSAGES/django.mo
index 3b04920654..df3bf3f6a0 100644
--- a/django/conf/locale/zh_CN/LC_MESSAGES/django.mo
+++ b/django/conf/locale/zh_CN/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/django.po b/django/conf/locale/zh_CN/LC_MESSAGES/django.po
index 1f30a08b15..e9f296a1bf 100644
--- a/django/conf/locale/zh_CN/LC_MESSAGES/django.po
+++ b/django/conf/locale/zh_CN/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: django v1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 10:10+0200\n"
-"PO-Revision-Date: 2006-09-01 22:05+0800\n"
+"PO-Revision-Date: 2007-07-05 12:44+0800\n"
"Last-Translator: limodou <limodou@gmail.com>\n"
"Language-Team: Simplified Chinese <limodou@gmail.com>\n"
"MIME-Version: 1.0\n"
@@ -19,6 +19,1161 @@ msgstr ""
"X-Poedit-SourceCharset: utf-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
+#: db/models/manipulators.py:307
+#, python-format
+msgid "%(object)s with this %(type)s already exists for the given %(field)s."
+msgstr "带有这个 %(type)s 的 %(object)s 对于给定的 %(field)s 已经存在了。"
+
+#: db/models/manipulators.py:308
+#: contrib/admin/views/main.py:335
+#: contrib/admin/views/main.py:337
+#: contrib/admin/views/main.py:339
+msgid "and"
+msgstr "和"
+
+#: db/models/fields/related.py:53
+#, python-format
+msgid "Please enter a valid %s."
+msgstr "请输入一个有效的 %s 。"
+
+#: db/models/fields/related.py:642
+msgid "Separate multiple IDs with commas."
+msgstr "用逗号分隔多个ID。"
+
+#: db/models/fields/related.py:644
+msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr "按下 \"Control\",或者在Mac上按 \"Command\" 来选择多个值。"
+
+#: db/models/fields/related.py:691
+#, python-format
+msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
+msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] "请输入有效的 %(self)s ID。值 %(value)r 无效。"
+
+#: db/models/fields/__init__.py:42
+#, python-format
+msgid "%(optname)s with this %(fieldname)s already exists."
+msgstr "%(optname)s 带有 %(fieldname)s 已经存在。"
+
+#: db/models/fields/__init__.py:117
+#: db/models/fields/__init__.py:274
+#: db/models/fields/__init__.py:610
+#: db/models/fields/__init__.py:621
+#: oldforms/__init__.py:357
+#: newforms/fields.py:80
+#: newforms/fields.py:376
+#: newforms/fields.py:452
+#: newforms/fields.py:463
+#: newforms/models.py:178
+msgid "This field is required."
+msgstr "这个字段是必输项。"
+
+#: db/models/fields/__init__.py:367
+msgid "This value must be an integer."
+msgstr "这个值必须是一个整数。"
+
+#: db/models/fields/__init__.py:402
+msgid "This value must be either True or False."
+msgstr "这个值必须是 True 或 False。"
+
+#: db/models/fields/__init__.py:423
+msgid "This field cannot be null."
+msgstr "这个值不能为 null。"
+
+#: db/models/fields/__init__.py:457
+#: core/validators.py:148
+msgid "Enter a valid date in YYYY-MM-DD format."
+msgstr "输入一个 YYYY-MM-DD 格式的有效日期。"
+
+#: db/models/fields/__init__.py:526
+#: core/validators.py:157
+msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
+msgstr "输入一个 YYYY-MM-DD HH:MM 格式的有效日期/时间。"
+
+#: db/models/fields/__init__.py:630
+msgid "Enter a valid filename."
+msgstr "输入一个有效的文件名。"
+
+#: db/models/fields/__init__.py:751
+msgid "This value must be either None, True or False."
+msgstr "这个值必须是 None, True 或 False。"
+
+#: conf/global_settings.py:39
+msgid "Arabic"
+msgstr "阿拉伯语"
+
+#: conf/global_settings.py:40
+msgid "Bengali"
+msgstr "孟加拉语"
+
+#: conf/global_settings.py:41
+msgid "Catalan"
+msgstr "加泰罗尼亚语"
+
+#: conf/global_settings.py:42
+msgid "Czech"
+msgstr "捷克语"
+
+#: conf/global_settings.py:43
+msgid "Welsh"
+msgstr "威尔士语"
+
+#: conf/global_settings.py:44
+msgid "Danish"
+msgstr "丹麦语"
+
+#: conf/global_settings.py:45
+msgid "German"
+msgstr "德语"
+
+#: conf/global_settings.py:46
+msgid "Greek"
+msgstr "希腊语"
+
+#: conf/global_settings.py:47
+msgid "English"
+msgstr "英语"
+
+#: conf/global_settings.py:48
+msgid "Spanish"
+msgstr "西班牙语"
+
+#: conf/global_settings.py:49
+msgid "Argentinean Spanish"
+msgstr "阿根廷的西班牙语"
+
+#: conf/global_settings.py:50
+msgid "Finnish"
+msgstr "芬兰语"
+
+#: conf/global_settings.py:51
+msgid "French"
+msgstr "法语"
+
+#: conf/global_settings.py:52
+msgid "Galician"
+msgstr "加利西亚语"
+
+#: conf/global_settings.py:53
+msgid "Hungarian"
+msgstr "匈牙利语"
+
+#: conf/global_settings.py:54
+msgid "Hebrew"
+msgstr "希伯来语"
+
+#: conf/global_settings.py:55
+msgid "Icelandic"
+msgstr "冰岛语"
+
+#: conf/global_settings.py:56
+msgid "Italian"
+msgstr "意大利语"
+
+#: conf/global_settings.py:57
+msgid "Japanese"
+msgstr "日语"
+
+#: conf/global_settings.py:58
+msgid "Kannada"
+msgstr "埃纳德语"
+
+#: conf/global_settings.py:59
+msgid "Latvian"
+msgstr "拉脱维亚语"
+
+#: conf/global_settings.py:60
+msgid "Macedonian"
+msgstr "马其顿语"
+
+#: conf/global_settings.py:61
+msgid "Dutch"
+msgstr "荷兰语"
+
+#: conf/global_settings.py:62
+msgid "Norwegian"
+msgstr "挪威语"
+
+#: conf/global_settings.py:63
+msgid "Polish"
+msgstr "波兰语"
+
+#: conf/global_settings.py:64
+msgid "Portugese"
+msgstr "葡萄牙语"
+
+#: conf/global_settings.py:65
+msgid "Brazilian"
+msgstr "巴西语"
+
+#: conf/global_settings.py:66
+msgid "Romanian"
+msgstr "罗马尼亚语"
+
+#: conf/global_settings.py:67
+msgid "Russian"
+msgstr "俄语"
+
+#: conf/global_settings.py:68
+msgid "Slovak"
+msgstr "斯洛伐克语"
+
+#: conf/global_settings.py:69
+msgid "Slovenian"
+msgstr "斯洛文尼亚语"
+
+#: conf/global_settings.py:70
+msgid "Serbian"
+msgstr "塞尔维亚语"
+
+#: conf/global_settings.py:71
+msgid "Swedish"
+msgstr "瑞典语"
+
+#: conf/global_settings.py:72
+msgid "Tamil"
+msgstr "泰米尔语"
+
+#: conf/global_settings.py:73
+msgid "Telugu"
+msgstr "泰卢固语"
+
+#: conf/global_settings.py:74
+msgid "Turkish"
+msgstr "土耳其语"
+
+#: conf/global_settings.py:75
+msgid "Ukrainian"
+msgstr "乌克兰语"
+
+#: conf/global_settings.py:76
+msgid "Simplified Chinese"
+msgstr "简体中文"
+
+#: conf/global_settings.py:77
+msgid "Traditional Chinese"
+msgstr "繁体中文"
+
+#: utils/timesince.py:12
+msgid "year"
+msgid_plural "years"
+msgstr[0] "年"
+
+#: utils/timesince.py:13
+msgid "month"
+msgid_plural "months"
+msgstr[0] "月"
+
+#: utils/timesince.py:14
+msgid "week"
+msgid_plural "weeks"
+msgstr[0] "周"
+
+#: utils/timesince.py:15
+msgid "day"
+msgid_plural "days"
+msgstr[0] "天"
+
+#: utils/timesince.py:16
+msgid "hour"
+msgid_plural "hours"
+msgstr[0] "小时"
+
+#: utils/timesince.py:17
+msgid "minute"
+msgid_plural "minutes"
+msgstr[0] "分钟"
+
+#: utils/dates.py:6
+msgid "Monday"
+msgstr "星期一"
+
+#: utils/dates.py:6
+msgid "Tuesday"
+msgstr "星期二"
+
+#: utils/dates.py:6
+msgid "Wednesday"
+msgstr "星期三"
+
+#: utils/dates.py:6
+msgid "Thursday"
+msgstr "星期四"
+
+#: utils/dates.py:6
+msgid "Friday"
+msgstr "星期五"
+
+#: utils/dates.py:7
+msgid "Saturday"
+msgstr "星期六"
+
+#: utils/dates.py:7
+msgid "Sunday"
+msgstr "星期日"
+
+#: utils/dates.py:14
+msgid "January"
+msgstr "一月"
+
+#: utils/dates.py:14
+msgid "February"
+msgstr "二月"
+
+#: utils/dates.py:14
+#: utils/dates.py:27
+msgid "March"
+msgstr "三月"
+
+#: utils/dates.py:14
+#: utils/dates.py:27
+msgid "April"
+msgstr "四月"
+
+#: utils/dates.py:14
+#: utils/dates.py:27
+msgid "May"
+msgstr "五月"
+
+#: utils/dates.py:14
+#: utils/dates.py:27
+msgid "June"
+msgstr "六月"
+
+#: utils/dates.py:15
+#: utils/dates.py:27
+msgid "July"
+msgstr "七月"
+
+#: utils/dates.py:15
+msgid "August"
+msgstr "八月"
+
+#: utils/dates.py:15
+msgid "September"
+msgstr "九月"
+
+#: utils/dates.py:15
+msgid "October"
+msgstr "十月"
+
+#: utils/dates.py:15
+msgid "November"
+msgstr "十一月"
+
+#: utils/dates.py:16
+msgid "December"
+msgstr "十二月"
+
+#: utils/dates.py:19
+msgid "jan"
+msgstr "一月"
+
+#: utils/dates.py:19
+msgid "feb"
+msgstr "二月"
+
+#: utils/dates.py:19
+msgid "mar"
+msgstr "三月"
+
+#: utils/dates.py:19
+msgid "apr"
+msgstr "四月"
+
+#: utils/dates.py:19
+msgid "may"
+msgstr "五月"
+
+#: utils/dates.py:19
+msgid "jun"
+msgstr "六月"
+
+#: utils/dates.py:20
+msgid "jul"
+msgstr "七月"
+
+#: utils/dates.py:20
+msgid "aug"
+msgstr "八月"
+
+#: utils/dates.py:20
+msgid "sep"
+msgstr "九月"
+
+#: utils/dates.py:20
+msgid "oct"
+msgstr "十月"
+
+#: utils/dates.py:20
+msgid "nov"
+msgstr "十一月"
+
+#: utils/dates.py:20
+msgid "dec"
+msgstr "十二月"
+
+#: utils/dates.py:27
+msgid "Jan."
+msgstr "一月"
+
+#: utils/dates.py:27
+msgid "Feb."
+msgstr "二月"
+
+#: utils/dates.py:28
+msgid "Aug."
+msgstr "八月"
+
+#: utils/dates.py:28
+msgid "Sept."
+msgstr "九月"
+
+#: utils/dates.py:28
+msgid "Oct."
+msgstr "十月"
+
+#: utils/dates.py:28
+msgid "Nov."
+msgstr "十一月"
+
+#: utils/dates.py:28
+msgid "Dec."
+msgstr "十二月"
+
+#: utils/dateformat.py:40
+msgid "p.m."
+msgstr ""
+
+#: utils/dateformat.py:41
+msgid "a.m."
+msgstr ""
+
+#: utils/dateformat.py:46
+msgid "PM"
+msgstr ""
+
+#: utils/dateformat.py:47
+msgid "AM"
+msgstr ""
+
+#: utils/dateformat.py:95
+msgid "midnight"
+msgstr "午夜"
+
+#: utils/dateformat.py:97
+msgid "noon"
+msgstr "中午"
+
+#: utils/translation/trans_real.py:358
+msgid "DATE_FORMAT"
+msgstr "DATE_FORMAT"
+
+#: utils/translation/trans_real.py:359
+msgid "DATETIME_FORMAT"
+msgstr "DATETIME_FORMAT"
+
+#: utils/translation/trans_real.py:360
+msgid "TIME_FORMAT"
+msgstr "TIME_FORMAT"
+
+#: utils/translation/trans_real.py:376
+msgid "YEAR_MONTH_FORMAT"
+msgstr "YEAR_MONTH_FORMAT"
+
+#: utils/translation/trans_real.py:377
+msgid "MONTH_DAY_FORMAT"
+msgstr "MONTH_DAY_FORMAT"
+
+#: oldforms/__init__.py:392
+#, python-format
+msgid "Ensure your text is less than %s character."
+msgid_plural "Ensure your text is less than %s characters."
+msgstr[0] "确定你输入的文本少于 %s 个字符。"
+
+#: oldforms/__init__.py:397
+msgid "Line breaks are not allowed here."
+msgstr "这里不允许换行符。"
+
+#: oldforms/__init__.py:498
+#: oldforms/__init__.py:571
+#: oldforms/__init__.py:610
+#, python-format
+msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
+msgstr "选择一个有效的选项: '%(data)s' 不在 %(choices)s 中。"
+
+#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:150
+#: newforms/widgets.py:174
+msgid "Unknown"
+msgstr "未知"
+
+#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:143
+#: newforms/widgets.py:174
+msgid "Yes"
+msgstr "是"
+
+#: oldforms/__init__.py:577
+#: contrib/admin/filterspecs.py:143
+#: newforms/widgets.py:174
+msgid "No"
+msgstr "否"
+
+#: oldforms/__init__.py:672
+#: core/validators.py:174
+#: core/validators.py:445
+msgid "No file was submitted. Check the encoding type on the form."
+msgstr "没有文件被提交。请检查表单的编码类型。"
+
+#: oldforms/__init__.py:674
+msgid "The submitted file is empty."
+msgstr "所提交的文件为空。"
+
+#: oldforms/__init__.py:730
+msgid "Enter a whole number between -32,768 and 32,767."
+msgstr "输入在 -32,768 到 32,767 之间的一个整数。"
+
+#: oldforms/__init__.py:740
+msgid "Enter a positive number."
+msgstr "输入正整数。"
+
+#: oldforms/__init__.py:750
+msgid "Enter a whole number between 0 and 32,767."
+msgstr "输入在 0 到 32,767 之间的一个整数。"
+
+#: contrib/localflavor/no/forms.py:15
+msgid "Enter a zip code in the format XXXX."
+msgstr "用 XXXX 的格式输入一个邮编。"
+
+#: contrib/localflavor/no/forms.py:36
+msgid "Enter a valid Norwegian social security number."
+msgstr "请输入一个有效的挪威社会保障号码。"
+
+#: contrib/localflavor/it/forms.py:14
+#: contrib/localflavor/fr/forms.py:17
+#: contrib/localflavor/fi/forms.py:14
+#: contrib/localflavor/de/forms.py:16
+msgid "Enter a zip code in the format XXXXX."
+msgstr "以 XXXXX 的格式输入一个邮编。"
+
+#: contrib/localflavor/jp/forms.py:21
+msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
+msgstr "以 XXXXXXX 或 XXX-XXXX 的格式输入一个邮编。"
+
+#: contrib/localflavor/jp/jp_prefectures.py:4
+msgid "Hokkaido"
+msgstr "北海道"
+
+#: contrib/localflavor/jp/jp_prefectures.py:5
+msgid "Aomori"
+msgstr "青森"
+
+#: contrib/localflavor/jp/jp_prefectures.py:6
+msgid "Iwate"
+msgstr "岩手"
+
+#: contrib/localflavor/jp/jp_prefectures.py:7
+msgid "Miyagi"
+msgstr "宫城"
+
+#: contrib/localflavor/jp/jp_prefectures.py:8
+msgid "Akita"
+msgstr "秋田"
+
+#: contrib/localflavor/jp/jp_prefectures.py:9
+msgid "Yamagata"
+msgstr "山形"
+
+#: contrib/localflavor/jp/jp_prefectures.py:10
+msgid "Fukushima"
+msgstr "福岛"
+
+#: contrib/localflavor/jp/jp_prefectures.py:11
+msgid "Ibaraki"
+msgstr "茨城"
+
+#: contrib/localflavor/jp/jp_prefectures.py:12
+msgid "Tochigi"
+msgstr "枥木"
+
+#: contrib/localflavor/jp/jp_prefectures.py:13
+msgid "Gunma"
+msgstr "群马"
+
+#: contrib/localflavor/jp/jp_prefectures.py:14
+msgid "Saitama"
+msgstr "埼玉"
+
+#: contrib/localflavor/jp/jp_prefectures.py:15
+msgid "Chiba"
+msgstr "千叶"
+
+#: contrib/localflavor/jp/jp_prefectures.py:16
+msgid "Tokyo"
+msgstr "东京"
+
+#: contrib/localflavor/jp/jp_prefectures.py:17
+msgid "Kanagawa"
+msgstr "神奈川"
+
+#: contrib/localflavor/jp/jp_prefectures.py:18
+msgid "Yamanashi"
+msgstr "山梨"
+
+#: contrib/localflavor/jp/jp_prefectures.py:19
+msgid "Nagano"
+msgstr "长野"
+
+#: contrib/localflavor/jp/jp_prefectures.py:20
+msgid "Niigata"
+msgstr "新舄"
+
+#: contrib/localflavor/jp/jp_prefectures.py:21
+msgid "Toyama"
+msgstr "富山"
+
+#: contrib/localflavor/jp/jp_prefectures.py:22
+msgid "Ishikawa"
+msgstr "石川"
+
+#: contrib/localflavor/jp/jp_prefectures.py:23
+msgid "Fukui"
+msgstr "福井"
+
+#: contrib/localflavor/jp/jp_prefectures.py:24
+msgid "Gifu"
+msgstr "岐阜"
+
+#: contrib/localflavor/jp/jp_prefectures.py:25
+msgid "Shizuoka"
+msgstr "静冈"
+
+#: contrib/localflavor/jp/jp_prefectures.py:26
+msgid "Aichi"
+msgstr "爱知"
+
+#: contrib/localflavor/jp/jp_prefectures.py:27
+msgid "Mie"
+msgstr "三重"
+
+#: contrib/localflavor/jp/jp_prefectures.py:28
+msgid "Shiga"
+msgstr "滋贺"
+
+#: contrib/localflavor/jp/jp_prefectures.py:29
+msgid "Kyoto"
+msgstr "京都"
+
+#: contrib/localflavor/jp/jp_prefectures.py:30
+msgid "Osaka"
+msgstr " 大坂"
+
+#: contrib/localflavor/jp/jp_prefectures.py:31
+msgid "Hyogo"
+msgstr "兵库"
+
+#: contrib/localflavor/jp/jp_prefectures.py:32
+msgid "Nara"
+msgstr "奈良"
+
+#: contrib/localflavor/jp/jp_prefectures.py:33
+msgid "Wakayama"
+msgstr "和歌山"
+
+#: contrib/localflavor/jp/jp_prefectures.py:34
+msgid "Tottori"
+msgstr "鸟取"
+
+#: contrib/localflavor/jp/jp_prefectures.py:35
+msgid "Shimane"
+msgstr "岛根"
+
+#: contrib/localflavor/jp/jp_prefectures.py:36
+msgid "Okayama"
+msgstr "冈山"
+
+#: contrib/localflavor/jp/jp_prefectures.py:37
+msgid "Hiroshima"
+msgstr "广岛"
+
+#: contrib/localflavor/jp/jp_prefectures.py:38
+msgid "Yamaguchi"
+msgstr "山口"
+
+#: contrib/localflavor/jp/jp_prefectures.py:39
+msgid "Tokushima"
+msgstr "德岛"
+
+#: contrib/localflavor/jp/jp_prefectures.py:40
+msgid "Kagawa"
+msgstr "香川"
+
+#: contrib/localflavor/jp/jp_prefectures.py:41
+msgid "Ehime"
+msgstr "爱媛"
+
+#: contrib/localflavor/jp/jp_prefectures.py:42
+msgid "Kochi"
+msgstr "高知"
+
+#: contrib/localflavor/jp/jp_prefectures.py:43
+msgid "Fukuoka"
+msgstr "福冈"
+
+#: contrib/localflavor/jp/jp_prefectures.py:44
+msgid "Saga"
+msgstr "佐贺"
+
+#: contrib/localflavor/jp/jp_prefectures.py:45
+msgid "Nagasaki"
+msgstr "长崎"
+
+#: contrib/localflavor/jp/jp_prefectures.py:46
+msgid "Kumamoto"
+msgstr "熊本"
+
+#: contrib/localflavor/jp/jp_prefectures.py:47
+msgid "Oita"
+msgstr "大分"
+
+#: contrib/localflavor/jp/jp_prefectures.py:48
+msgid "Miyazaki"
+msgstr "宫崎"
+
+#: contrib/localflavor/jp/jp_prefectures.py:49
+msgid "Kagoshima"
+msgstr "鹿儿岛"
+
+#: contrib/localflavor/jp/jp_prefectures.py:50
+msgid "Okinawa"
+msgstr "冲绳岛"
+
+#: contrib/localflavor/br/forms.py:18
+msgid "Enter a zip code in the format XXXXX-XXX."
+msgstr "以 XXXXX-XXX 的格式输入一个邮编。"
+
+#: contrib/localflavor/br/forms.py:30
+msgid "Phone numbers must be in XX-XXXX-XXXX format."
+msgstr "电话号码必须为 XXX-XXX-XXXX 格式。"
+
+#: contrib/localflavor/fi/forms.py:40
+#: contrib/localflavor/fi/forms.py:46
+msgid "Enter a valid Finnish social security number."
+msgstr "输入一个有效的芬兰社会保障号码。"
+
+#: contrib/localflavor/uk/forms.py:18
+msgid "Enter a postcode. A space is required between the two postcode parts."
+msgstr "输入一个邮政编码。两个邮编部分之间的空格是必须的。"
+
+#: contrib/localflavor/de/forms.py:63
+msgid "Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format"
+msgstr "以 XXXXXXXXXXX-XXXXXXX-XXXXXXX-X 的格式输入一个有效的德国身份证号码。"
+
+#: contrib/localflavor/de/de_states.py:5
+msgid "Baden-Wuerttemberg"
+msgstr "巴登符腾堡州"
+
+#: contrib/localflavor/de/de_states.py:6
+msgid "Bavaria"
+msgstr "巴伐利亚"
+
+#: contrib/localflavor/de/de_states.py:7
+msgid "Berlin"
+msgstr "柏林"
+
+#: contrib/localflavor/de/de_states.py:8
+msgid "Brandenburg"
+msgstr "勃兰登堡"
+
+#: contrib/localflavor/de/de_states.py:9
+msgid "Bremen"
+msgstr "不来梅"
+
+#: contrib/localflavor/de/de_states.py:10
+msgid "Hamburg"
+msgstr "汉堡"
+
+#: contrib/localflavor/de/de_states.py:11
+msgid "Hessen"
+msgstr "黑森州"
+
+#: contrib/localflavor/de/de_states.py:12
+msgid "Mecklenburg-Western Pomerania"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:13
+msgid "Lower Saxony"
+msgstr "下萨克森"
+
+#: contrib/localflavor/de/de_states.py:14
+msgid "North Rhine-Westphalia"
+msgstr "北莱茵-威斯特法伦州"
+
+#: contrib/localflavor/de/de_states.py:15
+msgid "Rhineland-Palatinate"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:16
+msgid "Saarland"
+msgstr "萨尔州"
+
+#: contrib/localflavor/de/de_states.py:17
+msgid "Saxony"
+msgstr "萨克森"
+
+#: contrib/localflavor/de/de_states.py:18
+msgid "Saxony-Anhalt"
+msgstr ""
+
+#: contrib/localflavor/de/de_states.py:19
+msgid "Schleswig-Holstein"
+msgstr "石勒苏益格-荷尔斯泰因"
+
+#: contrib/localflavor/de/de_states.py:20
+msgid "Thuringia"
+msgstr "图林根州"
+
+#: contrib/localflavor/usa/forms.py:18
+msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
+msgstr "以 XXXXX 或 XXXXX-XXX 的格式输入一个邮编。"
+
+#: contrib/localflavor/usa/forms.py:51
+msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
+msgstr "以 XXX-XX-XXXX 的格式输入一个有效的美国社会保障号码。"
+
+#: contrib/sessions/models.py:68
+msgid "session key"
+msgstr "session键字"
+
+#: contrib/sessions/models.py:69
+msgid "session data"
+msgstr "session数据"
+
+#: contrib/sessions/models.py:70
+msgid "expire date"
+msgstr "过期日期"
+
+#: contrib/sessions/models.py:74
+msgid "session"
+msgstr "会话(session)"
+
+#: contrib/sessions/models.py:75
+msgid "sessions"
+msgstr "会话(session)"
+
+#: contrib/auth/forms.py:17
+#: contrib/auth/forms.py:138
+msgid "The two password fields didn't match."
+msgstr "两个口令字段不一致。"
+
+#: contrib/auth/forms.py:25
+msgid "A user with that username already exists."
+msgstr "一个使用此用户名的用户已经存在。"
+
+#: contrib/auth/forms.py:53
+msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
+msgstr "你的Web浏览器好象不允许使用cookie。登录需要使用cookie。"
+
+#: contrib/auth/forms.py:60
+#: contrib/admin/views/decorators.py:10
+msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
+msgstr "请输入正确的用户名和口令。请注意两个域都是大小写敏感的。"
+
+#: contrib/auth/forms.py:62
+msgid "This account is inactive."
+msgstr "该帐号未激活。"
+
+#: contrib/auth/forms.py:85
+msgid "That e-mail address doesn't have an associated user account. Are you sure you've registered?"
+msgstr "该电子邮件地址没有关联任何用户帐号。你确定你已经注册过了?"
+
+#: contrib/auth/forms.py:117
+msgid "The two 'new password' fields didn't match."
+msgstr "两个'新口令'字段不一致。"
+
+#: contrib/auth/forms.py:124
+msgid "Your old password was entered incorrectly. Please enter it again."
+msgstr "你的旧口令不正确。请重新输入。"
+
+#: contrib/auth/views.py:39
+msgid "Logged out"
+msgstr "退出登录"
+
+#: contrib/auth/models.py:38
+#: contrib/auth/models.py:57
+msgid "name"
+msgstr "名称"
+
+#: contrib/auth/models.py:40
+msgid "codename"
+msgstr "代码名称"
+
+#: contrib/auth/models.py:42
+msgid "permission"
+msgstr "权限"
+
+#: contrib/auth/models.py:43
+#: contrib/auth/models.py:58
+msgid "permissions"
+msgstr "权限"
+
+#: contrib/auth/models.py:60
+msgid "group"
+msgstr "组"
+
+#: contrib/auth/models.py:61
+#: contrib/auth/models.py:100
+msgid "groups"
+msgstr "组"
+
+#: contrib/auth/models.py:90
+msgid "username"
+msgstr "用户名"
+
+#: contrib/auth/models.py:90
+msgid "Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."
+msgstr "必须。不多于30个字符。只能用字母数字(字母、数字和下横线)"
+
+#: contrib/auth/models.py:91
+msgid "first name"
+msgstr "名字"
+
+#: contrib/auth/models.py:92
+msgid "last name"
+msgstr "姓"
+
+#: contrib/auth/models.py:93
+msgid "e-mail address"
+msgstr "邮件地址"
+
+#: contrib/auth/models.py:94
+msgid "password"
+msgstr "口令"
+
+#: contrib/auth/models.py:94
+msgid "Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."
+msgstr "使用 '[algo]$[salt]$[hexdigest]' 或使用 <a href=\"password/\">修改密码表单</a>"
+
+#: contrib/auth/models.py:95
+msgid "staff status"
+msgstr "人员状态"
+
+#: contrib/auth/models.py:95
+msgid "Designates whether the user can log into this admin site."
+msgstr "指定是否用户可以登录到这个管理站点。"
+
+#: contrib/auth/models.py:96
+msgid "active"
+msgstr "活动"
+
+#: contrib/auth/models.py:96
+msgid "Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."
+msgstr "指定是否用户可以登录到这个管理站点。用取消选择来取代删除帐号。"
+
+#: contrib/auth/models.py:97
+msgid "superuser status"
+msgstr "超级用户状态"
+
+#: contrib/auth/models.py:97
+msgid "Designates that this user has all permissions without explicitly assigning them."
+msgstr "指定是否用户可以登录到这个管理站点。"
+
+#: contrib/auth/models.py:98
+msgid "last login"
+msgstr "上次登录"
+
+#: contrib/auth/models.py:99
+msgid "date joined"
+msgstr "加入日期"
+
+#: contrib/auth/models.py:101
+msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
+msgstr "除了手动设置权限以外,用户也会从他(她)所在的小组获得所赋组小组的所有权限。"
+
+#: contrib/auth/models.py:102
+msgid "user permissions"
+msgstr "用户权限"
+
+#: contrib/auth/models.py:105
+msgid "user"
+msgstr "用户"
+
+#: contrib/auth/models.py:106
+msgid "users"
+msgstr "用户"
+
+#: contrib/auth/models.py:111
+msgid "Personal info"
+msgstr "个人信息"
+
+#: contrib/auth/models.py:112
+msgid "Permissions"
+msgstr "权限"
+
+#: contrib/auth/models.py:113
+msgid "Important dates"
+msgstr "重要日期"
+
+#: contrib/auth/models.py:114
+msgid "Groups"
+msgstr "组"
+
+#: contrib/auth/models.py:258
+msgid "message"
+msgstr "消息"
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "th"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "st"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "nd"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:17
+msgid "rd"
+msgstr ""
+
+#: contrib/humanize/templatetags/humanize.py:47
+#, python-format
+msgid "%(value).1f million"
+msgid_plural "%(value).1f million"
+msgstr[0] "%(value).1f 百万"
+
+#: contrib/humanize/templatetags/humanize.py:50
+#, python-format
+msgid "%(value).1f billion"
+msgid_plural "%(value).1f billion"
+msgstr[0] "%(value).1f 十亿"
+
+#: contrib/humanize/templatetags/humanize.py:53
+#, python-format
+msgid "%(value).1f trillion"
+msgid_plural "%(value).1f trillion"
+msgstr[0] "%(value).1f 万亿"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "one"
+msgstr "一"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "two"
+msgstr "二"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "three"
+msgstr "三"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "four"
+msgstr "四"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "five"
+msgstr "五"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "six"
+msgstr "六"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "seven"
+msgstr "七"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "eight"
+msgstr "八"
+
+#: contrib/humanize/templatetags/humanize.py:68
+msgid "nine"
+msgstr "九"
+
+#: contrib/contenttypes/models.py:36
+msgid "python model class name"
+msgstr "python模块类名"
+
+#: contrib/contenttypes/models.py:39
+msgid "content type"
+msgstr "内容类型"
+
+#: contrib/contenttypes/models.py:40
+msgid "content types"
+msgstr "内容类型"
+
+#: contrib/redirects/models.py:7
+msgid "redirect from"
+msgstr "重定向自"
+
+#: contrib/redirects/models.py:8
+msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
+msgstr "应该是一个绝对路径,不包括域名。例如:'/events/search/'。"
+
+#: contrib/redirects/models.py:9
+msgid "redirect to"
+msgstr "重定向到"
+
+#: contrib/redirects/models.py:10
+msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
+msgstr "可以是绝对路径(同上)或以'http://'开始的全URL。"
+
+#: contrib/redirects/models.py:13
+msgid "redirect"
+msgstr "重定向"
+
+#: contrib/redirects/models.py:14
+msgid "redirects"
+msgstr "重定向"
+
+#: contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:315
+msgid "URL"
+msgstr "URL"
+
+#: contrib/flatpages/models.py:8
+msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
+msgstr "例如:'/about/contact/'。请确保前导和结尾的除号。"
+
+#: contrib/flatpages/models.py:9
+msgid "title"
+msgstr "标题"
+
+#: contrib/flatpages/models.py:10
+msgid "content"
+msgstr "内容"
+
+#: contrib/flatpages/models.py:11
+msgid "enable comments"
+msgstr "允许评论"
+
+#: contrib/flatpages/models.py:12
+msgid "template name"
+msgstr "模板名称"
+
+#: contrib/flatpages/models.py:13
+msgid "Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."
+msgstr "例如:'flatpages/contact_page.html'。如果未提供,系统将使用'flatpages/default.html'。"
+
+#: contrib/flatpages/models.py:14
+msgid "registration required"
+msgstr "请先注册"
+
+#: contrib/flatpages/models.py:14
+msgid "If this is checked, only logged-in users will be able to view the page."
+msgstr "如果被选中,仅登录用户才可以查看此页。"
+
+#: contrib/flatpages/models.py:18
+msgid "flat page"
+msgstr "简单页面"
+
+#: contrib/flatpages/models.py:19
+msgid "flat pages"
+msgstr "简单页面"
+
#: contrib/comments/models.py:67
#: contrib/comments/models.py:166
msgid "object ID"
@@ -81,7 +1236,7 @@ msgid "is public"
msgstr "公开"
#: contrib/comments/models.py:85
-#: contrib/admin/views/doc.py:289
+#: contrib/admin/views/doc.py:304
msgid "IP address"
msgstr "IP地址"
@@ -203,6 +1358,75 @@ msgstr "删除仲裁"
msgid "Moderator deletion by %r"
msgstr "被 %r 仲裁删除"
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:17
+msgid "Username:"
+msgstr "用户名:"
+
+#: contrib/comments/templates/comments/form.html:6
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
+msgid "Log out"
+msgstr "注销"
+
+#: contrib/comments/templates/comments/form.html:8
+#: contrib/admin/templates/admin/login.html:20
+msgid "Password:"
+msgstr "口令:"
+
+#: contrib/comments/templates/comments/form.html:8
+msgid "Forgotten your password?"
+msgstr "忘记你的口令?"
+
+#: contrib/comments/templates/comments/form.html:12
+msgid "Ratings"
+msgstr "等级"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Required"
+msgstr "必须的"
+
+#: contrib/comments/templates/comments/form.html:12
+#: contrib/comments/templates/comments/form.html:23
+msgid "Optional"
+msgstr "可选的"
+
+#: contrib/comments/templates/comments/form.html:23
+msgid "Post a photo"
+msgstr "上传一张照片"
+
+#: contrib/comments/templates/comments/form.html:28
+#: contrib/comments/templates/comments/freeform.html:5
+msgid "Comment:"
+msgstr "评论:"
+
+#: contrib/comments/templates/comments/form.html:35
+#: contrib/comments/templates/comments/freeform.html:10
+msgid "Preview comment"
+msgstr "预览评论"
+
+#: contrib/comments/templates/comments/freeform.html:4
+msgid "Your name:"
+msgstr "你的名字:"
+
#: contrib/comments/views/karma.py:19
msgid "Anonymous users cannot vote"
msgstr "匿名用户不能投票"
@@ -215,11 +1439,11 @@ msgstr "无效评论ID"
msgid "No voting for yourself"
msgstr "不能给自已投票"
-#: contrib/comments/views/comments.py:28
+#: contrib/comments/views/comments.py:27
msgid "This rating is required because you've entered at least one other rating."
msgstr "要求此等级,因为你已经输入了至少一个等级。"
-#: contrib/comments/views/comments.py:112
+#: contrib/comments/views/comments.py:111
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s comment:\n"
@@ -234,7 +1458,7 @@ msgstr[0] ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:117
+#: contrib/comments/views/comments.py:116
#, python-format
msgid ""
"This comment was posted by a sketchy user:\n"
@@ -245,22 +1469,22 @@ msgstr ""
"\n"
"%(text)s"
-#: contrib/comments/views/comments.py:189
+#: contrib/comments/views/comments.py:188
#: contrib/comments/views/comments.py:280
msgid "Only POSTs are allowed"
msgstr "只允许张贴"
-#: contrib/comments/views/comments.py:193
+#: contrib/comments/views/comments.py:192
#: contrib/comments/views/comments.py:284
msgid "One or more of the required fields wasn't submitted"
msgstr "一个或多个必输字段没有被提交"
-#: contrib/comments/views/comments.py:197
+#: contrib/comments/views/comments.py:196
#: contrib/comments/views/comments.py:286
msgid "Somebody tampered with the comment form (security violation)"
msgstr "有人篡改了评论表格(安全侵害)"
-#: contrib/comments/views/comments.py:207
+#: contrib/comments/views/comments.py:206
#: contrib/comments/views/comments.py:292
msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
msgstr "评论表格有一个无效的 'target' 参数 -- 对象 ID 无效"
@@ -270,73 +1494,21 @@ msgstr "评论表格有一个无效的 'target' 参数 -- 对象 ID 无效"
msgid "The comment form didn't provide either 'preview' or 'post'"
msgstr "评论表格无法提供 '预览' 或 '张贴' 功能"
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/login.html:17
-msgid "Username:"
-msgstr "用户名:"
-
-#: contrib/comments/templates/comments/form.html:6
-#: contrib/admin/templates/admin/login.html:20
-msgid "Password:"
-msgstr "口令:"
-
-#: contrib/comments/templates/comments/form.html:6
-msgid "Forgotten your password?"
-msgstr "忘记你的口令?"
-
-#: contrib/comments/templates/comments/form.html:8
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/model_index.html:5
-msgid "Log out"
-msgstr "注销"
-
-#: contrib/comments/templates/comments/form.html:12
-msgid "Ratings"
-msgstr "等级"
-
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Required"
-msgstr "必须的"
-
-#: contrib/comments/templates/comments/form.html:12
-#: contrib/comments/templates/comments/form.html:23
-msgid "Optional"
-msgstr "可选的"
-
-#: contrib/comments/templates/comments/form.html:23
-msgid "Post a photo"
-msgstr "上传一张照片"
+#: contrib/sites/models.py:10
+msgid "domain name"
+msgstr "域名"
-#: contrib/comments/templates/comments/form.html:27
-#: contrib/comments/templates/comments/freeform.html:5
-msgid "Comment:"
-msgstr "评论:"
+#: contrib/sites/models.py:11
+msgid "display name"
+msgstr "显示名"
-#: contrib/comments/templates/comments/form.html:32
-#: contrib/comments/templates/comments/freeform.html:9
-msgid "Preview comment"
-msgstr "预览评论"
+#: contrib/sites/models.py:15
+msgid "site"
+msgstr "站点"
-#: contrib/comments/templates/comments/freeform.html:4
-msgid "Your name:"
-msgstr "你的名字:"
+#: contrib/sites/models.py:16
+msgid "sites"
+msgstr "站点"
#: contrib/admin/filterspecs.py:40
#, python-format
@@ -350,6 +1522,7 @@ msgstr ""
#: contrib/admin/filterspecs.py:70
#: contrib/admin/filterspecs.py:88
#: contrib/admin/filterspecs.py:143
+#: contrib/admin/filterspecs.py:169
msgid "All"
msgstr "全部"
@@ -373,18 +1546,6 @@ msgstr "本月"
msgid "This year"
msgstr "今年"
-#: contrib/admin/filterspecs.py:143
-msgid "Yes"
-msgstr "是"
-
-#: contrib/admin/filterspecs.py:143
-msgid "No"
-msgstr "否"
-
-#: contrib/admin/filterspecs.py:150
-msgid "Unknown"
-msgstr "未知"
-
#: contrib/admin/models.py:16
msgid "action time"
msgstr "动作时间"
@@ -413,262 +1574,188 @@ msgstr "日志记录"
msgid "log entries"
msgstr "日志记录"
-#: contrib/admin/templatetags/admin_list.py:228
+#: contrib/admin/templatetags/admin_list.py:247
msgid "All dates"
msgstr "全有日期"
-#: contrib/admin/views/decorators.py:9
-#: contrib/auth/forms.py:36
-#: contrib/auth/forms.py:41
-msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
-msgstr "请输入正确的用户名和口令。请注意两个域都是大小写敏感的。"
-
-#: contrib/admin/views/decorators.py:23
-#: contrib/admin/templates/admin/login.html:25
-msgid "Log in"
-msgstr "登录"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/invalid_setup.html:4
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/change_list.html:6
+#: contrib/admin/templates/admin/change_form.html:13
+#: contrib/admin/templates/admin/base.html:30
+#: contrib/admin/templates/admin/auth/user/change_password.html:12
+#: contrib/admin/templates/registration/logged_out.html:4
+#: contrib/admin/templates/registration/password_reset_done.html:4
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_done.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:4
+msgid "Home"
+msgstr "首页"
-#: contrib/admin/views/decorators.py:61
-msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
-msgstr "请重新登录,因为你的会话已经过期。不用担心:你的提交已经被保存。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
+msgid "Documentation"
+msgstr "文档"
-#: contrib/admin/views/decorators.py:68
-msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
-msgstr "看上去你的浏览器没有配置成接受 cookie 。请允许 cookie,重新装入本页面,再试一次。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:3
+msgid "Bookmarklets"
+msgstr "书签"
-#: contrib/admin/views/decorators.py:82
-msgid "Usernames cannot contain the '@' character."
-msgstr "用户名不能包含 '@' 字符。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:4
+#: contrib/admin/templates/admin_doc/missing_docutils.html:4
+#: contrib/admin/templates/admin_doc/view_detail.html:4
+#: contrib/admin/templates/admin_doc/template_filter_index.html:5
+#: contrib/admin/templates/admin_doc/view_index.html:5
+#: contrib/admin/templates/admin_doc/template_tag_index.html:5
+#: contrib/admin/templates/admin_doc/model_detail.html:3
+#: contrib/admin/templates/admin_doc/model_index.html:5
+#: contrib/admin/templates/admin_doc/index.html:4
+#: contrib/admin/templates/admin_doc/template_detail.html:4
+#: contrib/admin/templates/admin/object_history.html:3
+#: contrib/admin/templates/admin/delete_confirmation.html:3
+#: contrib/admin/templates/admin/change_list.html:5
+#: contrib/admin/templates/admin/change_form.html:10
+#: contrib/admin/templates/admin/base.html:25
+#: contrib/admin/templates/admin/auth/user/change_password.html:9
+#: contrib/admin/templates/admin/auth/user/change_password.html:15
+#: contrib/admin/templates/admin/auth/user/change_password.html:46
+#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/registration/password_change_done.html:3
+msgid "Change password"
+msgstr "修改口令"
-#: contrib/admin/views/decorators.py:84
-#, python-format
-msgid "Your e-mail address is not your username. Try '%s' instead."
-msgstr "你的邮箱地址不是你的用户名。换 '%s' 试试。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:5
+msgid "Documentation bookmarklets"
+msgstr "文档书签"
-#: contrib/admin/views/main.py:226
-msgid "Site administration"
-msgstr "站点管理员"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:9
+msgid ""
+"\n"
+"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
+"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
+"select the bookmarklet from any page in the site. Note that some of these\n"
+"bookmarklets require you to be viewing the site from a computer designated\n"
+"as \"internal\" (talk to your system administrator if you aren't sure if\n"
+"your computer is \"internal\").</p>\n"
+msgstr ""
+"\n"
+"<p class=\"help\">为安装书签,拖动链接到你的工具条,\n"
+"或右击鼠标,然后增加到你的书签上。现在你可以从这个站\n"
+"点的任何页面选择书签。注意一些这样的书签要求你从一个\n"
+"被指定为\"内部\"的计算机上来进行查看(如果你不确定是\n"
+"否你的计算机是否是\"内部\"的,同你的系统管理员沟通一\n"
+"下。</p>\n"
-#: contrib/admin/views/main.py:260
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully."
-msgstr "%(name)s \"%(obj)s\" 添加成功。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:19
+msgid "Documentation for this page"
+msgstr "本页面的文档"
-#: contrib/admin/views/main.py:264
-#: contrib/admin/views/main.py:348
-msgid "You may edit it again below."
-msgstr "你可以在下面再次编辑它。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:20
+msgid "Jumps you from any page to the documentation for the view that generates that page."
+msgstr "对于任何页面跳转到生成这个页面的view所在的文件。"
-#: contrib/admin/views/main.py:272
-#: contrib/admin/views/main.py:357
-#, python-format
-msgid "You may add another %s below."
-msgstr "你可以在下面增加另一个 %s 。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:22
+msgid "Show object ID"
+msgstr "显示对象ID"
-#: contrib/admin/views/main.py:290
-#, python-format
-msgid "Add %s"
-msgstr "增加 %s"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:23
+msgid "Shows the content-type and unique ID for pages that represent a single object."
+msgstr "用于那些表现单个对象的页面显示 content-type 和唯一ID。"
-#: contrib/admin/views/main.py:336
-#, python-format
-msgid "Added %s."
-msgstr "%s 已增加。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:25
+msgid "Edit this object (current window)"
+msgstr "编辑本对象(当前窗口)"
-#: contrib/admin/views/main.py:336
-#: contrib/admin/views/main.py:338
-#: contrib/admin/views/main.py:340
-msgid "and"
-msgstr "和"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:26
+msgid "Jumps to the admin page for pages that represent a single object."
+msgstr "用于那些表现单个对象的页面跳转到管理页面。"
-#: contrib/admin/views/main.py:338
-#, python-format
-msgid "Changed %s."
-msgstr "已修改 %s 。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:28
+msgid "Edit this object (new window)"
+msgstr "编辑本对象(新窗口)"
-#: contrib/admin/views/main.py:340
-#, python-format
-msgid "Deleted %s."
-msgstr "%s 已删除。"
+#: contrib/admin/templates/admin_doc/bookmarklets.html:29
+msgid "As above, but opens the admin page in a new window."
+msgstr "同上,但在新窗口中打开管理页面。"
-#: contrib/admin/views/main.py:343
-msgid "No fields changed."
-msgstr "没有字段被修改。"
+#: contrib/admin/templates/admin/submit_line.html:3
+#: contrib/admin/templates/admin/delete_confirmation.html:9
+msgid "Delete"
+msgstr "删除"
-#: contrib/admin/views/main.py:346
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was changed successfully."
-msgstr "%(name)s \"%(obj)s\" 修改成功。"
+#: contrib/admin/templates/admin/submit_line.html:4
+msgid "Save as new"
+msgstr "保存为新的"
-#: contrib/admin/views/main.py:354
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
-msgstr "%(name)s \"%(obj)s\" 添加成功。你可以在下面再次编辑它。"
+#: contrib/admin/templates/admin/submit_line.html:5
+msgid "Save and add another"
+msgstr "保存并增加另一个"
-#: contrib/admin/views/main.py:392
-#, python-format
-msgid "Change %s"
-msgstr "修改 %s"
+#: contrib/admin/templates/admin/submit_line.html:6
+msgid "Save and continue editing"
+msgstr "保存并继续编辑"
-#: contrib/admin/views/main.py:470
-#, python-format
-msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
-msgstr "一个或多个 %(fieldname)s 在 %(name)s 中: %(obj)s"
+#: contrib/admin/templates/admin/submit_line.html:7
+msgid "Save"
+msgstr "保存"
-#: contrib/admin/views/main.py:475
-#, python-format
-msgid "One or more %(fieldname)s in %(name)s:"
-msgstr "一个或多个 %(fieldname)s 在 %(name)s 中:"
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "服务器错误"
-#: contrib/admin/views/main.py:508
-#, python-format
-msgid "The %(name)s \"%(obj)s\" was deleted successfully."
-msgstr "%(name)s \"%(obj)s\" 删除成功。"
+#: contrib/admin/templates/admin/500.html:6
+msgid "Server error (500)"
+msgstr "服务器错误(500)"
-#: contrib/admin/views/main.py:511
-msgid "Are you sure?"
-msgstr "你确信吗?"
+#: contrib/admin/templates/admin/500.html:9
+msgid "Server Error <em>(500)</em>"
+msgstr "服务器错误 <em>(500)</em>"
-#: contrib/admin/views/main.py:533
-#, python-format
-msgid "Change history: %s"
-msgstr "修改历史: %s"
+#: contrib/admin/templates/admin/500.html:10
+msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
+msgstr "存在一个错误。它已经通过电子邮件被报告给站点管理员了,并且应该很快被改正。谢谢你的关心。"
-#: contrib/admin/views/main.py:565
+#: contrib/admin/templates/admin/filter.html:2
#, python-format
-msgid "Select %s"
-msgstr "选择 %s"
+msgid " By %(filter_title)s "
+msgstr " 由 %(filter_title)s"
-#: contrib/admin/views/main.py:565
-#, python-format
-msgid "Select %s to change"
-msgstr "选择 %s 来修改"
+#: contrib/admin/templates/admin/filters.html:4
+msgid "Filter"
+msgstr "过滤器"
-#: contrib/admin/views/doc.py:277
-#: contrib/admin/views/doc.py:286
-#: contrib/admin/views/doc.py:288
-#: contrib/admin/views/doc.py:294
-#: contrib/admin/views/doc.py:295
-#: contrib/admin/views/doc.py:297
-msgid "Integer"
-msgstr "整数"
+#: contrib/admin/templates/admin/invalid_setup.html:8
+msgid "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user."
+msgstr "你的数据库安装有错误。确保合适的数据库表已经创建好,并确保数据库可被适合的用户读取。"
-#: contrib/admin/views/doc.py:278
-msgid "Boolean (Either True or False)"
-msgstr "布尔(True或False)"
+#: contrib/admin/templates/admin/search_form.html:8
+msgid "Go"
+msgstr "去"
-#: contrib/admin/views/doc.py:279
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/templates/admin/search_form.html:10
#, python-format
-msgid "String (up to %(maxlength)s)"
-msgstr "字符串(最长 %(maxlength)s)"
-
-#: contrib/admin/views/doc.py:280
-msgid "Comma-separated integers"
-msgstr "逗号分隔的整数"
+msgid "1 result"
+msgid_plural "%(counter)s results"
+msgstr[0] "1 条结果"
+msgstr[1] "%(counter)s 条结果"
-#: contrib/admin/views/doc.py:281
-msgid "Date (without time)"
-msgstr "日期(无时间)"
-
-#: contrib/admin/views/doc.py:282
-msgid "Date (with time)"
-msgstr "日期(带时间)"
-
-#: contrib/admin/views/doc.py:283
-msgid "E-mail address"
-msgstr "邮箱地址"
-
-#: contrib/admin/views/doc.py:284
-#: contrib/admin/views/doc.py:287
-msgid "File path"
-msgstr "文件路径"
-
-#: contrib/admin/views/doc.py:285
-msgid "Decimal number"
-msgstr "小数"
-
-#: contrib/admin/views/doc.py:291
-msgid "Boolean (Either True, False or None)"
-msgstr "布尔(True, False或None)"
-
-#: contrib/admin/views/doc.py:292
-msgid "Relation to parent model"
-msgstr "与父模型的关系"
-
-#: contrib/admin/views/doc.py:293
-msgid "Phone number"
-msgstr "电话号码"
-
-#: contrib/admin/views/doc.py:298
-msgid "Text"
-msgstr "文本"
-
-#: contrib/admin/views/doc.py:299
-msgid "Time"
-msgstr "时间"
-
-#: contrib/admin/views/doc.py:300
-#: contrib/flatpages/models.py:7
-msgid "URL"
-msgstr "URL"
-
-#: contrib/admin/views/doc.py:301
-msgid "U.S. state (two uppercase letters)"
-msgstr "美国州名(两个大写字母)"
-
-#: contrib/admin/views/doc.py:302
-msgid "XML text"
-msgstr "XML文本"
-
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-msgid "Documentation"
-msgstr "文档"
-
-#: contrib/admin/templates/admin/object_history.html:3
-#: contrib/admin/templates/admin/change_list.html:5
-#: contrib/admin/templates/admin/base.html:23
-#: contrib/admin/templates/admin/delete_confirmation.html:3
-#: contrib/admin/templates/admin/change_form.html:10
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/admin_doc/bookmarklets.html:4
-#: contrib/admin/templates/admin_doc/view_detail.html:4
-#: contrib/admin/templates/admin_doc/template_tag_index.html:5
-#: contrib/admin/templates/admin_doc/template_detail.html:4
-#: contrib/admin/templates/admin_doc/template_filter_index.html:5
-#: contrib/admin/templates/admin_doc/missing_docutils.html:4
-#: contrib/admin/templates/admin_doc/view_index.html:5
-#: contrib/admin/templates/admin_doc/model_detail.html:3
-#: contrib/admin/templates/admin_doc/index.html:4
-#: contrib/admin/templates/admin_doc/model_index.html:5
-msgid "Change password"
-msgstr "修改口令"
-
-#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/500.html:4
-#: contrib/admin/templates/admin/change_list.html:6
-#: contrib/admin/templates/admin/base.html:28
-#: contrib/admin/templates/admin/delete_confirmation.html:6
-#: contrib/admin/templates/admin/change_form.html:13
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:4
-#: contrib/admin/templates/registration/logged_out.html:4
-#: contrib/admin/templates/registration/password_reset_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-msgid "Home"
-msgstr "首页"
+#: contrib/admin/templates/admin/search_form.html:10
+#, python-format
+msgid "%(full_result_count)s total"
+msgstr "总共 %(full_result_count)s"
#: contrib/admin/templates/admin/object_history.html:5
-#: contrib/admin/templates/admin/change_form.html:20
+#: contrib/admin/templates/admin/change_form.html:21
msgid "History"
msgstr "历史"
@@ -692,29 +1779,55 @@ msgstr "N j, Y, P"
msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
msgstr "此对象没有修改历史。可能不能通过这个管理站点来增加。"
-#: contrib/admin/templates/admin/base_site.html:4
-msgid "Django site admin"
-msgstr "Django管理站点"
+#: contrib/admin/templates/admin/delete_confirmation.html:14
+#, python-format
+msgid "Deleting the %(object_name)s '%(escaped_object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
+msgstr "删除 %(object_name)s '%(escaped_object)s' 会导致删除相关的对象,但你的帐号无权删除下列类型的对象:"
-#: contrib/admin/templates/admin/base_site.html:7
-msgid "Django administration"
-msgstr "Django管理员"
+#: contrib/admin/templates/admin/delete_confirmation.html:21
+#, python-format
+msgid "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? All of the following related items will be deleted:"
+msgstr "你确信相要删除 %(object_name)s \"%(escaped_object)s\"?下列所有相关的项目都将被删除:"
-#: contrib/admin/templates/admin/500.html:4
-msgid "Server error"
-msgstr "服务器错误"
+#: contrib/admin/templates/admin/delete_confirmation.html:26
+msgid "Yes, I'm sure"
+msgstr "是的,我确定"
-#: contrib/admin/templates/admin/500.html:6
-msgid "Server error (500)"
-msgstr "服务器错误(500)"
+#: contrib/admin/templates/admin/pagination.html:10
+msgid "Show all"
+msgstr "显示全部"
-#: contrib/admin/templates/admin/500.html:9
-msgid "Server Error <em>(500)</em>"
-msgstr "服务器错误 <em>(500)</em>"
+#: contrib/admin/templates/admin/change_list.html:12
+#, python-format
+msgid "Add %(name)s"
+msgstr "增加 %(name)s"
-#: contrib/admin/templates/admin/500.html:10
-msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
-msgstr "存在一个错误。它已经通过电子邮件被报告给站点管理员了,并且应该很快被改正。谢谢你的关心。"
+#: contrib/admin/templates/admin/change_form.html:15
+#: contrib/admin/templates/admin/index.html:28
+msgid "Add"
+msgstr "增加"
+
+#: contrib/admin/templates/admin/change_form.html:22
+msgid "View on site"
+msgstr "在站点上查看"
+
+#: contrib/admin/templates/admin/change_form.html:32
+#: contrib/admin/templates/admin/auth/user/change_password.html:24
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "请改正下面的错误。"
+
+#: contrib/admin/templates/admin/change_form.html:50
+msgid "Ordering"
+msgstr "排序中"
+
+#: contrib/admin/templates/admin/change_form.html:53
+msgid "Order:"
+msgstr "排序:"
+
+#: contrib/admin/templates/admin/base.html:25
+msgid "Welcome,"
+msgstr "欢迎,"
#: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8
@@ -725,15 +1838,20 @@ msgstr "页面没有找到"
msgid "We're sorry, but the requested page could not be found."
msgstr "很报歉,请求页面无法找到。"
+#: contrib/admin/templates/admin/login.html:25
+#: contrib/admin/views/decorators.py:24
+msgid "Log in"
+msgstr "登录"
+
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
msgstr "在 %(name)s 应用中模块有效。"
-#: contrib/admin/templates/admin/index.html:28
-#: contrib/admin/templates/admin/change_form.html:15
-msgid "Add"
-msgstr "增加"
+#: contrib/admin/templates/admin/index.html:18
+#, python-format
+msgid "%(name)s"
+msgstr "%(name)s"
#: contrib/admin/templates/admin/index.html:34
msgid "Change"
@@ -755,114 +1873,57 @@ msgstr "我的动作"
msgid "None available"
msgstr "无可用的"
-#: contrib/admin/templates/admin/change_list.html:11
-#, python-format
-msgid "Add %(name)s"
-msgstr "增加 %(name)s"
+#: contrib/admin/templates/admin/base_site.html:4
+msgid "Django site admin"
+msgstr "Django管理站点"
-#: contrib/admin/templates/admin/login.html:22
-msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
-msgstr "<a href=\"/password_reset/\">忘记你的密码</a>?"
+#: contrib/admin/templates/admin/base_site.html:7
+msgid "Django administration"
+msgstr "Django管理员"
-#: contrib/admin/templates/admin/base.html:23
-msgid "Welcome,"
-msgstr "欢迎,"
+#: contrib/admin/templates/admin/auth/user/add_form.html:6
+msgid "First, enter a username and password. Then, you'll be able to edit more user options."
+msgstr "首先,输入一个用户名和口令。然后,你可以编辑更多的用户选项。"
-#: contrib/admin/templates/admin/delete_confirmation.html:9
-#: contrib/admin/templates/admin/submit_line.html:3
-msgid "Delete"
-msgstr "删除"
+#: contrib/admin/templates/admin/auth/user/add_form.html:12
+msgid "Username"
+msgstr "用户名"
-#: contrib/admin/templates/admin/delete_confirmation.html:14
-#, python-format
-msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
-msgstr "删除 %(object_name)s '%(object)s' 会导致删除相关的对象,但你的帐号无权删除下列类型的对象:"
+#: contrib/admin/templates/admin/auth/user/add_form.html:18
+#: contrib/admin/templates/admin/auth/user/change_password.html:34
+msgid "Password"
+msgstr "口令"
-#: contrib/admin/templates/admin/delete_confirmation.html:21
-#, python-format
-msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:"
-msgstr "你确信相要删除 %(object_name)s \"%(object)s\"?所有相关的项目都将被删除:"
+#: contrib/admin/templates/admin/auth/user/add_form.html:23
+#: contrib/admin/templates/admin/auth/user/change_password.html:39
+msgid "Password (again)"
+msgstr "口令(重复)"
-#: contrib/admin/templates/admin/delete_confirmation.html:26
-msgid "Yes, I'm sure"
-msgstr "是的,我确定"
+#: contrib/admin/templates/admin/auth/user/add_form.html:24
+#: contrib/admin/templates/admin/auth/user/change_password.html:40
+msgid "Enter the same password as above, for verification."
+msgstr "为了校验,输入与上面相同的口令。"
-#: contrib/admin/templates/admin/filter.html:2
+#: contrib/admin/templates/admin/auth/user/change_password.html:28
#, python-format
-msgid " By %(title)s "
-msgstr " 由 %(title)s"
-
-#: contrib/admin/templates/admin/search_form.html:8
-msgid "Go"
-msgstr "去"
-
-#: contrib/admin/templates/admin/change_form.html:21
-msgid "View on site"
-msgstr "在站点上查看"
+msgid "Enter a new password for the user <strong>%(username)s</strong>."
+msgstr "为用户<strong>%(username)s</strong>输入一个新的口令。"
-#: contrib/admin/templates/admin/change_form.html:30
-msgid "Please correct the error below."
-msgid_plural "Please correct the errors below."
-msgstr[0] "请改正下面的错误。"
-
-#: contrib/admin/templates/admin/change_form.html:48
-msgid "Ordering"
-msgstr "排序中"
-
-#: contrib/admin/templates/admin/change_form.html:51
-msgid "Order:"
-msgstr "排序:"
-
-#: contrib/admin/templates/admin/submit_line.html:4
-msgid "Save as new"
-msgstr "保存为新的"
-
-#: contrib/admin/templates/admin/submit_line.html:5
-msgid "Save and add another"
-msgstr "保存并增加另一个"
-
-#: contrib/admin/templates/admin/submit_line.html:6
-msgid "Save and continue editing"
-msgstr "保存并继续编辑"
-
-#: contrib/admin/templates/admin/submit_line.html:7
-msgid "Save"
-msgstr "保存"
-
-#: contrib/admin/templates/registration/password_change_done.html:4
-#: contrib/admin/templates/registration/password_change_form.html:4
-#: contrib/admin/templates/registration/password_change_form.html:6
-#: contrib/admin/templates/registration/password_change_form.html:10
-msgid "Password change"
-msgstr "口令修改"
-
-#: contrib/admin/templates/registration/password_change_done.html:6
-#: contrib/admin/templates/registration/password_change_done.html:10
-msgid "Password change successful"
-msgstr "口令修改成功"
-
-#: contrib/admin/templates/registration/password_change_done.html:12
-msgid "Your password was changed."
-msgstr "你的口令已经被修改。"
-
-#: contrib/admin/templates/registration/password_reset_form.html:4
-#: contrib/admin/templates/registration/password_reset_form.html:6
-#: contrib/admin/templates/registration/password_reset_form.html:10
-#: contrib/admin/templates/registration/password_reset_done.html:4
-msgid "Password reset"
-msgstr "口令重设"
+#: contrib/admin/templates/widget/file.html:2
+msgid "Currently:"
+msgstr "当前:"
-#: contrib/admin/templates/registration/password_reset_form.html:12
-msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
-msgstr "忘记你的口令?在下面输入你的邮箱地址,我们将重设你的口令并且将新的口令通过邮件发送给你。"
+#: contrib/admin/templates/widget/file.html:3
+msgid "Change:"
+msgstr "改动:"
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "E-mail address:"
-msgstr "邮箱地址:"
+#: contrib/admin/templates/widget/date_time.html:3
+msgid "Date:"
+msgstr "日期:"
-#: contrib/admin/templates/registration/password_reset_form.html:16
-msgid "Reset my password"
-msgstr "重设我的口令"
+#: contrib/admin/templates/widget/date_time.html:4
+msgid "Time:"
+msgstr "时间:"
#: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
@@ -872,35 +1933,6 @@ msgstr "感谢今天在本网站花费了您的一些宝贵时间。"
msgid "Log in again"
msgstr "重新登录"
-#: contrib/admin/templates/registration/password_reset_done.html:6
-#: contrib/admin/templates/registration/password_reset_done.html:10
-msgid "Password reset successful"
-msgstr "口令重设成功"
-
-#: contrib/admin/templates/registration/password_reset_done.html:12
-msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
-msgstr "我们已经按你所提交的邮箱地址发送了一个新的口令给你。你应该很会收到这封邮件。"
-
-#: contrib/admin/templates/registration/password_change_form.html:12
-msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
-msgstr "请输入你的旧口令,为了安全起见,接着要输入你的新口令两遍,这样我们可以校验你输入的是否正确。"
-
-#: contrib/admin/templates/registration/password_change_form.html:17
-msgid "Old password:"
-msgstr "旧口令:"
-
-#: contrib/admin/templates/registration/password_change_form.html:19
-msgid "New password:"
-msgstr "新口令:"
-
-#: contrib/admin/templates/registration/password_change_form.html:21
-msgid "Confirm password:"
-msgstr "确认口令:"
-
-#: contrib/admin/templates/registration/password_change_form.html:23
-msgid "Change my password"
-msgstr "修改我的口令"
-
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
msgstr "你所收到的这封邮件是由于你请求了口令重设"
@@ -932,703 +1964,515 @@ msgstr "感谢使用我们的站点!"
msgid "The %(site_name)s team"
msgstr "%(site_name)s 小组"
-#: contrib/admin/templates/admin_doc/bookmarklets.html:3
-msgid "Bookmarklets"
-msgstr "书签"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:5
-msgid "Documentation bookmarklets"
-msgstr "文档书签"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:9
-msgid ""
-"\n"
-"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
-"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
-"select the bookmarklet from any page in the site. Note that some of these\n"
-"bookmarklets require you to be viewing the site from a computer designated\n"
-"as \"internal\" (talk to your system administrator if you aren't sure if\n"
-"your computer is \"internal\").</p>\n"
-msgstr ""
-"\n"
-"<p class=\"help\">为安装书签,拖动链接到你的工具条,\n"
-"或右击鼠标,然后增加到你的书签上。现在你可以从这个站\n"
-"点的任何页面选择书签。注意一些这样的书签要求你从一个\n"
-"被指定为\"内部\"的计算机上来进行查看(如果你不确定是\n"
-"否你的计算机是否是\"内部\"的,同你的系统管理员沟通一\n"
-"下。</p>\n"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:19
-msgid "Documentation for this page"
-msgstr "本页面的文档"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:20
-msgid "Jumps you from any page to the documentation for the view that generates that page."
-msgstr "对于任何页面跳转到生成这个页面的view所在的文件。"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:22
-msgid "Show object ID"
-msgstr "显示对象ID"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:23
-msgid "Shows the content-type and unique ID for pages that represent a single object."
-msgstr "用于那些表现单个对象的页面显示 content-type 和唯一ID。"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:25
-msgid "Edit this object (current window)"
-msgstr "编辑本对象(当前窗口)"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:26
-msgid "Jumps to the admin page for pages that represent a single object."
-msgstr "用于那些表现单个对象的页面跳转到管理页面。"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:28
-msgid "Edit this object (new window)"
-msgstr "编辑本对象(新窗口)"
-
-#: contrib/admin/templates/admin_doc/bookmarklets.html:29
-msgid "As above, but opens the admin page in a new window."
-msgstr "同上,但在新窗口中打开管理页面。"
-
-#: contrib/admin/templates/widget/date_time.html:3
-msgid "Date:"
-msgstr "日期:"
-
-#: contrib/admin/templates/widget/date_time.html:4
-msgid "Time:"
-msgstr "时间:"
-
-#: contrib/admin/templates/widget/file.html:2
-msgid "Currently:"
-msgstr "当前:"
-
-#: contrib/admin/templates/widget/file.html:3
-msgid "Change:"
-msgstr "改动:"
-
-#: contrib/redirects/models.py:7
-msgid "redirect from"
-msgstr "重定向自"
-
-#: contrib/redirects/models.py:8
-msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
-msgstr "应该是一个绝对路径,不包括域名。例如:'/events/search/'。"
-
-#: contrib/redirects/models.py:9
-msgid "redirect to"
-msgstr "重定向到"
-
-#: contrib/redirects/models.py:10
-msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
-msgstr "可以是绝对路径(同上)或以'http://'开始的全URL。"
-
-#: contrib/redirects/models.py:12
-msgid "redirect"
-msgstr "重定向"
-
-#: contrib/redirects/models.py:13
-msgid "redirects"
-msgstr "重定向"
-
-#: contrib/flatpages/models.py:8
-msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
-msgstr "例如:'/about/contact/'。请确保前导和结尾的除号。"
-
-#: contrib/flatpages/models.py:9
-msgid "title"
-msgstr "标题"
-
-#: contrib/flatpages/models.py:10
-msgid "content"
-msgstr "内容"
-
-#: contrib/flatpages/models.py:11
-msgid "enable comments"
-msgstr "允许评论"
-
-#: contrib/flatpages/models.py:12
-msgid "template name"
-msgstr "模板名称"
-
-#: contrib/flatpages/models.py:13
-msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'."
-msgstr "例如:'flatfiles/contact_page'。如果未提供,系统将使用'flatfiles/default'。"
-
-#: contrib/flatpages/models.py:14
-msgid "registration required"
-msgstr "请先注册"
-
-#: contrib/flatpages/models.py:14
-msgid "If this is checked, only logged-in users will be able to view the page."
-msgstr "如果被选中,仅登录用户才可以查看此页。"
-
-#: contrib/flatpages/models.py:18
-msgid "flat page"
-msgstr "简单页面"
-
-#: contrib/flatpages/models.py:19
-msgid "flat pages"
-msgstr "简单页面"
-
-#: contrib/auth/models.py:13
-#: contrib/auth/models.py:26
-msgid "name"
-msgstr "名称"
-
-#: contrib/auth/models.py:15
-msgid "codename"
-msgstr "代码名称"
-
-#: contrib/auth/models.py:17
-msgid "permission"
-msgstr "权限"
-
-#: contrib/auth/models.py:18
-#: contrib/auth/models.py:27
-msgid "permissions"
-msgstr "权限"
-
-#: contrib/auth/models.py:29
-msgid "group"
-msgstr "组"
-
-#: contrib/auth/models.py:30
-#: contrib/auth/models.py:65
-msgid "groups"
-msgstr "组"
-
-#: contrib/auth/models.py:55
-msgid "username"
-msgstr "用户名"
-
-#: contrib/auth/models.py:56
-msgid "first name"
-msgstr "名字"
-
-#: contrib/auth/models.py:57
-msgid "last name"
-msgstr "姓"
-
-#: contrib/auth/models.py:58
-msgid "e-mail address"
-msgstr "邮件地址"
-
-#: contrib/auth/models.py:59
-msgid "password"
-msgstr "口令"
-
-#: contrib/auth/models.py:59
-msgid "Use '[algo]$[salt]$[hexdigest]'"
-msgstr "使用 '[algo]$[salt]$[hexdigest]'"
-
-#: contrib/auth/models.py:60
-msgid "staff status"
-msgstr "人员状态"
-
-#: contrib/auth/models.py:60
-msgid "Designates whether the user can log into this admin site."
-msgstr "指定是否用户可以登录到这个管理站点。"
-
-#: contrib/auth/models.py:61
-msgid "active"
-msgstr "活动"
-
-#: contrib/auth/models.py:62
-msgid "superuser status"
-msgstr "超级用户状态"
-
-#: contrib/auth/models.py:63
-msgid "last login"
-msgstr "上次登录"
-
-#: contrib/auth/models.py:64
-msgid "date joined"
-msgstr "加入日期"
-
-#: contrib/auth/models.py:66
-msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
-msgstr "除了手动设置权限以外,用户也会从他(她)所在的小组获得所赋组小组的所有权限。"
-
-#: contrib/auth/models.py:67
-msgid "user permissions"
-msgstr "用户权限"
-
-#: contrib/auth/models.py:70
-msgid "user"
-msgstr "用户"
-
-#: contrib/auth/models.py:71
-msgid "users"
-msgstr "用户"
-
-#: contrib/auth/models.py:76
-msgid "Personal info"
-msgstr "个人信息"
-
-#: contrib/auth/models.py:77
-msgid "Permissions"
-msgstr "权限"
-
-#: contrib/auth/models.py:78
-msgid "Important dates"
-msgstr "重要日期"
-
-#: contrib/auth/models.py:79
-msgid "Groups"
-msgstr "组"
-
-#: contrib/auth/models.py:219
-msgid "message"
-msgstr "消息"
+#: contrib/admin/templates/registration/password_reset_done.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:6
+#: contrib/admin/templates/registration/password_reset_form.html:10
+msgid "Password reset"
+msgstr "口令重设"
-#: contrib/auth/forms.py:30
-msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
-msgstr "你的Web浏览器好象不允许使用cookie。登录需要使用cookie。"
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
+msgid "Password reset successful"
+msgstr "口令重设成功"
-#: contrib/contenttypes/models.py:25
-msgid "python model class name"
-msgstr "python模块类名"
+#: contrib/admin/templates/registration/password_reset_done.html:12
+msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
+msgstr "我们已经按你所提交的邮箱地址发送了一个新的口令给你。你应该很会收到这封邮件。"
-#: contrib/contenttypes/models.py:28
-msgid "content type"
-msgstr "内容类型"
+#: contrib/admin/templates/registration/password_change_form.html:4
+#: contrib/admin/templates/registration/password_change_form.html:6
+#: contrib/admin/templates/registration/password_change_form.html:10
+#: contrib/admin/templates/registration/password_change_done.html:4
+msgid "Password change"
+msgstr "口令修改"
-#: contrib/contenttypes/models.py:29
-msgid "content types"
-msgstr "内容类型"
+#: contrib/admin/templates/registration/password_change_form.html:12
+msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
+msgstr "请输入你的旧口令,为了安全起见,接着要输入你的新口令两遍,这样我们可以校验你输入的是否正确。"
-#: contrib/sessions/models.py:35
-msgid "session key"
-msgstr "session键字"
+#: contrib/admin/templates/registration/password_change_form.html:17
+msgid "Old password:"
+msgstr "旧口令:"
-#: contrib/sessions/models.py:36
-msgid "session data"
-msgstr "session数据"
+#: contrib/admin/templates/registration/password_change_form.html:19
+msgid "New password:"
+msgstr "新口令:"
-#: contrib/sessions/models.py:37
-msgid "expire date"
-msgstr "过期日期"
+#: contrib/admin/templates/registration/password_change_form.html:21
+msgid "Confirm password:"
+msgstr "确认口令:"
-#: contrib/sessions/models.py:41
-msgid "session"
-msgstr "会话(session)"
+#: contrib/admin/templates/registration/password_change_form.html:23
+msgid "Change my password"
+msgstr "修改我的口令"
-#: contrib/sessions/models.py:42
-msgid "sessions"
-msgstr "会话(session)"
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
+msgid "Password change successful"
+msgstr "口令修改成功"
-#: contrib/sites/models.py:10
-msgid "domain name"
-msgstr "域名"
+#: contrib/admin/templates/registration/password_change_done.html:12
+msgid "Your password was changed."
+msgstr "你的口令已经被修改。"
-#: contrib/sites/models.py:11
-msgid "display name"
-msgstr "显示名"
+#: contrib/admin/templates/registration/password_reset_form.html:12
+msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
+msgstr "忘记你的口令?在下面输入你的邮箱地址,我们将重设你的口令并且将新的口令通过邮件发送给你。"
-#: contrib/sites/models.py:15
-msgid "site"
-msgstr "站点"
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "E-mail address:"
+msgstr "邮箱地址:"
-#: contrib/sites/models.py:16
-msgid "sites"
-msgstr "站点"
+#: contrib/admin/templates/registration/password_reset_form.html:16
+msgid "Reset my password"
+msgstr "重设我的口令"
-#: utils/translation.py:360
-msgid "DATE_FORMAT"
-msgstr "DATE_FORMAT"
+#: contrib/admin/views/main.py:223
+msgid "Site administration"
+msgstr "站点管理员"
-#: utils/translation.py:361
-msgid "DATETIME_FORMAT"
-msgstr "DATETIME_FORMAT"
+#: contrib/admin/views/main.py:257
+#: contrib/admin/views/auth.py:19
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully."
+msgstr "%(name)s \"%(obj)s\" 添加成功。"
-#: utils/translation.py:362
-msgid "TIME_FORMAT"
-msgstr "TIME_FORMAT"
+#: contrib/admin/views/main.py:261
+#: contrib/admin/views/main.py:347
+#: contrib/admin/views/auth.py:24
+msgid "You may edit it again below."
+msgstr "你可以在下面再次编辑它。"
-#: utils/dates.py:6
-msgid "Monday"
-msgstr "星期一"
+#: contrib/admin/views/main.py:271
+#: contrib/admin/views/main.py:356
+#, python-format
+msgid "You may add another %s below."
+msgstr "你可以在下面增加另一个 %s 。"
-#: utils/dates.py:6
-msgid "Tuesday"
-msgstr "星期二"
+#: contrib/admin/views/main.py:289
+#, python-format
+msgid "Add %s"
+msgstr "增加 %s"
-#: utils/dates.py:6
-msgid "Wednesday"
-msgstr "星期三"
+#: contrib/admin/views/main.py:335
+#, python-format
+msgid "Added %s."
+msgstr "%s 已增加。"
-#: utils/dates.py:6
-msgid "Thursday"
-msgstr "星期四"
+#: contrib/admin/views/main.py:337
+#, python-format
+msgid "Changed %s."
+msgstr "已修改 %s 。"
-#: utils/dates.py:6
-msgid "Friday"
-msgstr "星期五"
+#: contrib/admin/views/main.py:339
+#, python-format
+msgid "Deleted %s."
+msgstr "%s 已删除。"
-#: utils/dates.py:7
-msgid "Saturday"
-msgstr "星期六"
+#: contrib/admin/views/main.py:342
+msgid "No fields changed."
+msgstr "没有字段被修改。"
-#: utils/dates.py:7
-msgid "Sunday"
-msgstr "星期日"
+#: contrib/admin/views/main.py:345
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was changed successfully."
+msgstr "%(name)s \"%(obj)s\" 修改成功。"
-#: utils/dates.py:14
-msgid "January"
-msgstr "一月"
+#: contrib/admin/views/main.py:353
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
+msgstr "%(name)s \"%(obj)s\" 添加成功。你可以在下面再次编辑它。"
-#: utils/dates.py:14
-msgid "February"
-msgstr "二月"
+#: contrib/admin/views/main.py:391
+#, python-format
+msgid "Change %s"
+msgstr "修改 %s"
-#: utils/dates.py:14
-#: utils/dates.py:27
-msgid "March"
-msgstr "三月"
+#: contrib/admin/views/main.py:476
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
+msgstr "一个或多个 %(fieldname)s 在 %(name)s 中: %(obj)s"
-#: utils/dates.py:14
-#: utils/dates.py:27
-msgid "April"
-msgstr "四月"
+#: contrib/admin/views/main.py:481
+#, python-format
+msgid "One or more %(fieldname)s in %(name)s:"
+msgstr "一个或多个 %(fieldname)s 在 %(name)s 中:"
-#: utils/dates.py:14
-#: utils/dates.py:27
-msgid "May"
-msgstr "五月"
+#: contrib/admin/views/main.py:514
+#, python-format
+msgid "The %(name)s \"%(obj)s\" was deleted successfully."
+msgstr "%(name)s \"%(obj)s\" 删除成功。"
-#: utils/dates.py:14
-#: utils/dates.py:27
-msgid "June"
-msgstr "六月"
+#: contrib/admin/views/main.py:517
+msgid "Are you sure?"
+msgstr "你确信吗?"
-#: utils/dates.py:15
-#: utils/dates.py:27
-msgid "July"
-msgstr "七月"
+#: contrib/admin/views/main.py:539
+#, python-format
+msgid "Change history: %s"
+msgstr "修改历史: %s"
-#: utils/dates.py:15
-msgid "August"
-msgstr "八月"
+#: contrib/admin/views/main.py:573
+#, python-format
+msgid "Select %s"
+msgstr "选择 %s"
-#: utils/dates.py:15
-msgid "September"
-msgstr "九月"
+#: contrib/admin/views/main.py:573
+#, python-format
+msgid "Select %s to change"
+msgstr "选择 %s 来修改"
-#: utils/dates.py:15
-msgid "October"
-msgstr "十月"
+#: contrib/admin/views/main.py:768
+msgid "Database error"
+msgstr "数据库错误"
-#: utils/dates.py:15
-msgid "November"
-msgstr "十一月"
+#: contrib/admin/views/decorators.py:62
+msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
+msgstr "请重新登录,因为你的会话已经过期。不用担心:你的提交已经被保存。"
-#: utils/dates.py:16
-msgid "December"
-msgstr "十二月"
+#: contrib/admin/views/decorators.py:69
+msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
+msgstr "看上去你的浏览器没有配置成接受 cookie 。请允许 cookie,重新装入本页面,再试一次。"
-#: utils/dates.py:19
-msgid "jan"
-msgstr "一月"
+#: contrib/admin/views/decorators.py:83
+msgid "Usernames cannot contain the '@' character."
+msgstr "用户名不能包含 '@' 字符。"
-#: utils/dates.py:19
-msgid "feb"
-msgstr "二月"
+#: contrib/admin/views/decorators.py:85
+#, python-format
+msgid "Your e-mail address is not your username. Try '%s' instead."
+msgstr "你的邮箱地址不是你的用户名。换 '%s' 试试。"
-#: utils/dates.py:19
-msgid "mar"
-msgstr "三月"
+#: contrib/admin/views/doc.py:46
+#: contrib/admin/views/doc.py:48
+#: contrib/admin/views/doc.py:50
+msgid "tag:"
+msgstr "标签:"
-#: utils/dates.py:19
-msgid "apr"
-msgstr "四月"
+#: contrib/admin/views/doc.py:77
+#: contrib/admin/views/doc.py:79
+#: contrib/admin/views/doc.py:81
+msgid "filter:"
+msgstr "过滤器:"
-#: utils/dates.py:19
-msgid "may"
-msgstr "五月"
+#: contrib/admin/views/doc.py:135
+#: contrib/admin/views/doc.py:137
+#: contrib/admin/views/doc.py:139
+msgid "view:"
+msgstr "视图:"
-#: utils/dates.py:19
-msgid "jun"
-msgstr "六月"
+#: contrib/admin/views/doc.py:164
+#, python-format
+msgid "App %r not found"
+msgstr "应用 %r 没有找到"
-#: utils/dates.py:20
-msgid "jul"
-msgstr "七月"
+#: contrib/admin/views/doc.py:171
+#, python-format
+msgid "Model %(name)r not found in app %(label)r"
+msgstr "在应用 %(label)r 里找不到模型 %(name)r"
-#: utils/dates.py:20
-msgid "aug"
-msgstr "八月"
+#: contrib/admin/views/doc.py:183
+#, python-format
+msgid "the related `%(label)s.%(type)s` object"
+msgstr "相关的 `%(label)s.%(type)s` 对象"
-#: utils/dates.py:20
-msgid "sep"
-msgstr "九月"
+#: contrib/admin/views/doc.py:183
+#: contrib/admin/views/doc.py:205
+#: contrib/admin/views/doc.py:219
+#: contrib/admin/views/doc.py:224
+msgid "model:"
+msgstr "模型:"
-#: utils/dates.py:20
-msgid "oct"
-msgstr "十月"
+#: contrib/admin/views/doc.py:214
+#, python-format
+msgid "related `%(label)s.%(name)s` objects"
+msgstr "相关的 `%(label)s.%(name)s` 对象"
-#: utils/dates.py:20
-msgid "nov"
-msgstr "十一月"
+#: contrib/admin/views/doc.py:219
+#, python-format
+msgid "all %s"
+msgstr "所有 %s"
-#: utils/dates.py:20
-msgid "dec"
-msgstr "十二月"
+#: contrib/admin/views/doc.py:224
+#, python-format
+msgid "number of %s"
+msgstr "%s 的数量"
-#: utils/dates.py:27
-msgid "Jan."
-msgstr "一月"
+#: contrib/admin/views/doc.py:229
+#, python-format
+msgid "Fields on %s objects"
+msgstr "%s 对象的字段"
-#: utils/dates.py:27
-msgid "Feb."
-msgstr "二月"
+#: contrib/admin/views/doc.py:291
+#: contrib/admin/views/doc.py:301
+#: contrib/admin/views/doc.py:303
+#: contrib/admin/views/doc.py:309
+#: contrib/admin/views/doc.py:310
+#: contrib/admin/views/doc.py:312
+msgid "Integer"
+msgstr "整数"
-#: utils/dates.py:28
-msgid "Aug."
-msgstr "八月"
+#: contrib/admin/views/doc.py:292
+msgid "Boolean (Either True or False)"
+msgstr "布尔(True或False)"
-#: utils/dates.py:28
-msgid "Sept."
-msgstr "九月"
+#: contrib/admin/views/doc.py:293
+#: contrib/admin/views/doc.py:311
+#, python-format
+msgid "String (up to %(maxlength)s)"
+msgstr "字符串(最长 %(maxlength)s)"
-#: utils/dates.py:28
-msgid "Oct."
-msgstr "十月"
+#: contrib/admin/views/doc.py:294
+msgid "Comma-separated integers"
+msgstr "逗号分隔的整数"
-#: utils/dates.py:28
-msgid "Nov."
-msgstr "十一月"
+#: contrib/admin/views/doc.py:295
+msgid "Date (without time)"
+msgstr "日期(无时间)"
-#: utils/dates.py:28
-msgid "Dec."
-msgstr "十二月"
+#: contrib/admin/views/doc.py:296
+msgid "Date (with time)"
+msgstr "日期(带时间)"
-#: utils/timesince.py:12
-msgid "year"
-msgid_plural "years"
-msgstr[0] "年"
+#: contrib/admin/views/doc.py:297
+msgid "E-mail address"
+msgstr "邮箱地址"
-#: utils/timesince.py:13
-msgid "month"
-msgid_plural "months"
-msgstr[0] "月"
+#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:299
+#: contrib/admin/views/doc.py:302
+msgid "File path"
+msgstr "文件路径"
-#: utils/timesince.py:14
-msgid "week"
-msgid_plural "weeks"
-msgstr[0] "周"
+#: contrib/admin/views/doc.py:300
+msgid "Decimal number"
+msgstr "小数"
-#: utils/timesince.py:15
-msgid "day"
-msgid_plural "days"
-msgstr[0] "天"
+#: contrib/admin/views/doc.py:306
+msgid "Boolean (Either True, False or None)"
+msgstr "布尔(True, False或None)"
-#: utils/timesince.py:16
-msgid "hour"
-msgid_plural "hours"
-msgstr[0] "小时"
+#: contrib/admin/views/doc.py:307
+msgid "Relation to parent model"
+msgstr "与父模型的关系"
-#: utils/timesince.py:17
-msgid "minute"
-msgid_plural "minutes"
-msgstr[0] "分钟"
+#: contrib/admin/views/doc.py:308
+msgid "Phone number"
+msgstr "电话号码"
-#: conf/global_settings.py:37
-msgid "Bengali"
-msgstr "孟加拉语"
+#: contrib/admin/views/doc.py:313
+msgid "Text"
+msgstr "文本"
-#: conf/global_settings.py:38
-msgid "Czech"
-msgstr "捷克语"
+#: contrib/admin/views/doc.py:314
+msgid "Time"
+msgstr "时间"
-#: conf/global_settings.py:39
-msgid "Welsh"
-msgstr "威尔士语"
+#: contrib/admin/views/doc.py:316
+msgid "U.S. state (two uppercase letters)"
+msgstr "美国州名(两个大写字母)"
-#: conf/global_settings.py:40
-msgid "Danish"
-msgstr "丹麦语"
+#: contrib/admin/views/doc.py:317
+msgid "XML text"
+msgstr "XML文本"
-#: conf/global_settings.py:41
-msgid "German"
-msgstr "德语"
+#: contrib/admin/views/doc.py:343
+#, python-format
+msgid "%s does not appear to be a urlpattern object"
+msgstr "%s 似乎不是一个 urlpattern 对象"
-#: conf/global_settings.py:42
-msgid "Greek"
-msgstr "希腊语"
+#: contrib/admin/views/auth.py:30
+msgid "Add user"
+msgstr "增加用户"
-#: conf/global_settings.py:43
-msgid "English"
-msgstr "英语"
+#: contrib/admin/views/auth.py:57
+msgid "Password changed successfully."
+msgstr "口令修改成功。"
-#: conf/global_settings.py:44
-msgid "Spanish"
-msgstr "西班牙语"
+#: contrib/admin/views/auth.py:64
+#, python-format
+msgid "Change password: %s"
+msgstr "修改口令:%s"
-#: conf/global_settings.py:45
-msgid "French"
-msgstr "法语"
+#: newforms/fields.py:103
+#: newforms/fields.py:256
+#, python-format
+msgid "Ensure this value has at most %d characters."
+msgstr "确保你输入的文本至多 %d 个字符。"
-#: conf/global_settings.py:46
-msgid "Galician"
-msgstr "加利西亚语"
+#: newforms/fields.py:105
+#: newforms/fields.py:258
+#, python-format
+msgid "Ensure this value has at least %d characters."
+msgstr "确保你输入的文本至少 %d 个字符。"
-#: conf/global_settings.py:47
-msgid "Hungarian"
-msgstr "匈牙利语"
+#: newforms/fields.py:128
+#: core/validators.py:120
+msgid "Enter a whole number."
+msgstr "输入整数。"
-#: conf/global_settings.py:48
-msgid "Hebrew"
-msgstr "希伯来语"
+#: newforms/fields.py:130
+#, python-format
+msgid "Ensure this value is less than or equal to %s."
+msgstr "这个值必须小于或等于 %s。"
-#: conf/global_settings.py:49
-msgid "Icelandic"
-msgstr "冰岛语"
+#: newforms/fields.py:132
+#, python-format
+msgid "Ensure this value is greater than or equal to %s."
+msgstr "这个值必须小于或等于 %s。"
-#: conf/global_settings.py:50
-msgid "Italian"
-msgstr "意大利语"
+#: newforms/fields.py:165
+msgid "Enter a valid date."
+msgstr "输入一个有效的日期。"
-#: conf/global_settings.py:51
-msgid "Japanese"
-msgstr "日语"
+#: newforms/fields.py:192
+msgid "Enter a valid time."
+msgstr "输入一个有效的时间。"
-#: conf/global_settings.py:52
-msgid "Dutch"
-msgstr "荷兰语"
+#: newforms/fields.py:228
+msgid "Enter a valid date/time."
+msgstr "输入一个有效的日期/时间。"
-#: conf/global_settings.py:53
-msgid "Norwegian"
-msgstr "挪威语"
+#: newforms/fields.py:242
+msgid "Enter a valid value."
+msgstr "输入一个有效的值。"
-#: conf/global_settings.py:54
-msgid "Brazilian"
-msgstr "巴西语"
+#: newforms/fields.py:271
+#: core/validators.py:162
+msgid "Enter a valid e-mail address."
+msgstr "输入一个有效的邮件地址。"
-#: conf/global_settings.py:55
-msgid "Romanian"
-msgstr "罗马尼亚语"
+#: newforms/fields.py:289
+#: newforms/fields.py:311
+msgid "Enter a valid URL."
+msgstr "输入一个有效的URL。"
-#: conf/global_settings.py:56
-msgid "Russian"
-msgstr "俄语"
+#: newforms/fields.py:313
+msgid "This URL appears to be a broken link."
+msgstr "URL %s 似乎是一个坏的链接。"
-#: conf/global_settings.py:57
-msgid "Slovak"
-msgstr "斯洛伐克语"
+#: newforms/fields.py:362
+#: newforms/models.py:165
+msgid "Select a valid choice. That choice is not one of the available choices."
+msgstr "选择一个有效的选项: 此选择不在可用的选项中。"
-#: conf/global_settings.py:58
-msgid "Slovenian"
-msgstr "斯洛文尼亚语"
+#: newforms/fields.py:380
+#: newforms/fields.py:456
+#: newforms/models.py:182
+msgid "Enter a list of values."
+msgstr "输入一个值的列表。"
-#: conf/global_settings.py:59
-msgid "Serbian"
-msgstr "塞尔维亚语"
+#: newforms/fields.py:389
+#: newforms/models.py:188
+#, python-format
+msgid "Select a valid choice. %s is not one of the available choices."
+msgstr "选择一个有效的选项: '%s' 不在可用的选项中。"
-#: conf/global_settings.py:60
-msgid "Swedish"
-msgstr "瑞典语"
+#: template/defaultfilters.py:491
+msgid "yes,no,maybe"
+msgstr "是、否、也许"
-#: conf/global_settings.py:61
-msgid "Ukrainian"
-msgstr "乌克兰语"
+#: views/generic/create_update.py:43
+#, python-format
+msgid "The %(verbose_name)s was created successfully."
+msgstr "%(verbose_name)s 创建成功。"
-#: conf/global_settings.py:62
-msgid "Simplified Chinese"
-msgstr "简体中文"
+#: views/generic/create_update.py:117
+#, python-format
+msgid "The %(verbose_name)s was updated successfully."
+msgstr "%(verbose_name)s 更新成功。"
-#: conf/global_settings.py:63
-msgid "Traditional Chinese"
-msgstr "繁体中文"
+#: views/generic/create_update.py:184
+#, python-format
+msgid "The %(verbose_name)s was deleted."
+msgstr "%(verbose_name)s 已被删除。"
-#: core/validators.py:60
+#: core/validators.py:64
msgid "This value must contain only letters, numbers and underscores."
msgstr "此值只能包含字母、数字和下划线。"
-#: core/validators.py:64
+#: core/validators.py:68
msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
msgstr "此值只能包含字母、数字、下划线、反斜线和斜线。"
#: core/validators.py:72
+msgid "This value must contain only letters, numbers, underscores or hyphens."
+msgstr "此值只能包含字母、数字和下划线。"
+
+#: core/validators.py:76
msgid "Uppercase letters are not allowed here."
msgstr "这里不允许大写字母。"
-#: core/validators.py:76
+#: core/validators.py:80
msgid "Lowercase letters are not allowed here."
msgstr "这里不允许小写字母。"
-#: core/validators.py:83
+#: core/validators.py:87
msgid "Enter only digits separated by commas."
msgstr "只能输入用逗号分隔的数字。"
-#: core/validators.py:95
+#: core/validators.py:99
msgid "Enter valid e-mail addresses separated by commas."
msgstr "输入用逗号分隔的有效邮件地址。"
-#: core/validators.py:99
+#: core/validators.py:103
msgid "Please enter a valid IP address."
msgstr "请输入一个有效的IP地址。"
-#: core/validators.py:103
+#: core/validators.py:107
msgid "Empty values are not allowed here."
msgstr "这里不允许输入空值。"
-#: core/validators.py:107
+#: core/validators.py:111
msgid "Non-numeric characters aren't allowed here."
msgstr "这里不允许非数字字符。"
-#: core/validators.py:111
+#: core/validators.py:115
msgid "This value can't be comprised solely of digits."
msgstr "此值不能全部由数字组成。"
-#: core/validators.py:116
-msgid "Enter a whole number."
-msgstr "输入整数。"
-
-#: core/validators.py:120
+#: core/validators.py:124
msgid "Only alphabetical characters are allowed here."
msgstr "这里只允许字母。"
-#: core/validators.py:124
-msgid "Enter a valid date in YYYY-MM-DD format."
-msgstr "输入一个 YYYY-MM-DD 格式的有效日期。"
+#: core/validators.py:139
+msgid "Year must be 1900 or later."
+msgstr "年份必须是1900或之后"
-#: core/validators.py:128
+#: core/validators.py:143
+#, python-format
+msgid "Invalid date: %s"
+msgstr "无效日期: %s"
+
+#: core/validators.py:153
msgid "Enter a valid time in HH:MM format."
msgstr "输入一个 HH:MM 格式的有效时间。"
-#: core/validators.py:132
-#: db/models/fields/__init__.py:468
-msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "输入一个 YYYY-MM-DD HH:MM 格式的有效日期/时间。"
-
-#: core/validators.py:136
-msgid "Enter a valid e-mail address."
-msgstr "输入一个有效的邮件地址。"
-
-#: core/validators.py:148
+#: core/validators.py:178
msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
msgstr "上传一个有效的图片。您所上传的文件或者不是图片或是一个破坏的图片。"
-#: core/validators.py:155
+#: core/validators.py:185
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "URL %s 指向的不是一个有效的图片。"
-#: core/validators.py:159
+#: core/validators.py:189
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr "电话号码必须为 XXX-XXX-XXXX 格式。\"%s\"是无效的。"
-#: core/validators.py:167
+#: core/validators.py:197
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "URL %s 指向的不是一个有效的 QuickTime 视频。"
-#: core/validators.py:171
+#: core/validators.py:201
msgid "A valid URL is required."
msgstr "需要是一个有效的URL。"
-#: core/validators.py:185
+#: core/validators.py:215
#, python-format
msgid ""
"Valid HTML is required. Specific errors are:\n"
@@ -1637,243 +2481,157 @@ msgstr ""
"需要有效的HTML。详细的错误是:\n"
"%s"
-#: core/validators.py:192
+#: core/validators.py:222
#, python-format
msgid "Badly formed XML: %s"
msgstr "格式错误的 XML: %s"
-#: core/validators.py:202
+#: core/validators.py:239
#, python-format
msgid "Invalid URL: %s"
msgstr "无效 URL: %s"
-#: core/validators.py:206
-#: core/validators.py:208
+#: core/validators.py:244
+#: core/validators.py:246
#, python-format
msgid "The URL %s is a broken link."
msgstr "URL %s 是一个断开的链接。"
-#: core/validators.py:214
+#: core/validators.py:252
msgid "Enter a valid U.S. state abbreviation."
msgstr "输入一个有效的 U.S. 州缩写。"
-#: core/validators.py:229
+#: core/validators.py:266
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "看住你的嘴!%s 不允许在这里出现。"
-#: core/validators.py:236
+#: core/validators.py:273
#, python-format
msgid "This field must match the '%s' field."
msgstr "这个字段必须与 '%s' 字段相匹配。"
-#: core/validators.py:255
+#: core/validators.py:292
msgid "Please enter something for at least one field."
msgstr "请至少在一个字段上输入些什么。"
-#: core/validators.py:264
-#: core/validators.py:275
+#: core/validators.py:301
+#: core/validators.py:312
msgid "Please enter both fields or leave them both empty."
msgstr "请要么两个字段都输入或者两个字段都空着。"
-#: core/validators.py:282
+#: core/validators.py:320
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
msgstr "如果 %(field)s 是 %(value)s 时这个字段必须给出"
-#: core/validators.py:294
+#: core/validators.py:333
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
msgstr "如果 %(field)s 不是 %(value)s 时这个字段必须给出"
-#: core/validators.py:313
+#: core/validators.py:352
msgid "Duplicate values are not allowed."
msgstr "重复值不允许。"
-#: core/validators.py:336
+#: core/validators.py:367
+#, python-format
+msgid "This value must be between %(lower)s and %(upper)s."
+msgstr "这个值必须介于 %(lower)s 和 %(upper)s 之间。"
+
+#: core/validators.py:369
+#, python-format
+msgid "This value must be at least %s."
+msgstr "这个值需要至少为 %s"
+
+#: core/validators.py:371
+#, python-format
+msgid "This value must be no more than %s."
+msgstr "这个值不能大于 %s 。"
+
+#: core/validators.py:407
#, python-format
msgid "This value must be a power of %s."
msgstr "这个值必须是 %s 的乘方。"
-#: core/validators.py:347
+#: core/validators.py:418
msgid "Please enter a valid decimal number."
msgstr "请输入一个有效的小数。"
-#: core/validators.py:349
+#: core/validators.py:422
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "Please enter a valid decimal number with at most %s total digits."
msgstr[0] "请输入一个有效的小数,最多 %s 个数字。 "
-#: core/validators.py:352
+#: core/validators.py:425
+#, python-format
+msgid "Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] "请输入一个有效的小数,最多 %s 个数字。"
+
+#: core/validators.py:428
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural "Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "请输入一个有效的小数,最多 %s 个小数位。 "
-#: core/validators.py:362
+#: core/validators.py:438
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "请确保你上传的文件至少 %s 字节大。"
-#: core/validators.py:363
+#: core/validators.py:439
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "请确保你上传的文件至多 %s 字节大。"
-#: core/validators.py:376
+#: core/validators.py:456
msgid "The format for this field is wrong."
msgstr "这个字段的格式不正确。"
-#: core/validators.py:391
+#: core/validators.py:471
msgid "This field is invalid."
msgstr "这个字段无效。"
-#: core/validators.py:426
+#: core/validators.py:507
#, python-format
msgid "Could not retrieve anything from %s."
msgstr "不能从 %s 得到任何东西。"
-#: core/validators.py:429
+#: core/validators.py:510
#, python-format
msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "URL %(url)s 返回了无效的 Content-Type 头 '%(contenttype)s'。"
-#: core/validators.py:462
+#: core/validators.py:543
#, python-format
msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
msgstr "请关闭未关闭的 %(tag)s 标签从第 %(line)s 行。(行开始于 \"%(start)s\"。)"
-#: core/validators.py:466
+#: core/validators.py:547
#, python-format
msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行开始的一些文本不允许在那个上下文中。(行开始于 \"%(start)s\"。)"
-#: core/validators.py:471
+#: core/validators.py:552
#, python-format
msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行的\"%(attr)s\"不是一个有效的属性。(行开始于 \"%(start)s\"。)"
-#: core/validators.py:476
+#: core/validators.py:557
#, python-format
msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行的\"<%(tag)s>\"不是一个有效的标签。(行开始于 \"%(start)s\"。)"
-#: core/validators.py:480
+#: core/validators.py:561
#, python-format
msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
msgstr "在行 %(line)s 的标签少了一个或多个必须的属性。(行开始于 \"%(start)s\"。)"
-#: core/validators.py:485
+#: core/validators.py:566
#, python-format
msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
msgstr "在行 %(line)s 的\"%(attr)s\"属性有一个无效的值。(行开始于 \"%(start)s\"。)"
-#: db/models/manipulators.py:302
-#, python-format
-msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "带有这个 %(type)s 的 %(object)s 对于给定的 %(field)s 已经存在了。"
-
-#: db/models/fields/__init__.py:40
-#, python-format
-msgid "%(optname)s with this %(fieldname)s already exists."
-msgstr "%(optname)s 带有 %(fieldname)s 已经存在。"
-
-#: db/models/fields/__init__.py:114
-#: db/models/fields/__init__.py:265
-#: db/models/fields/__init__.py:542
-#: db/models/fields/__init__.py:553
-#: forms/__init__.py:346
-msgid "This field is required."
-msgstr "这个字段是必输项。"
-
-#: db/models/fields/__init__.py:337
-msgid "This value must be an integer."
-msgstr "这个值必须是一个整数。"
-
-#: db/models/fields/__init__.py:369
-msgid "This value must be either True or False."
-msgstr "这个值必须是 True 或 False。"
-
-#: db/models/fields/__init__.py:385
-msgid "This field cannot be null."
-msgstr "这个值不能为 null。"
-
-#: db/models/fields/__init__.py:562
-msgid "Enter a valid filename."
-msgstr "输入一个有效的文件名。"
-
-#: db/models/fields/related.py:43
-#, python-format
-msgid "Please enter a valid %s."
-msgstr "请输入一个有效的 %s 。"
-
-#: db/models/fields/related.py:579
-msgid "Separate multiple IDs with commas."
-msgstr "用逗号分隔多个ID。"
-
-#: db/models/fields/related.py:581
-msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
-msgstr "按下 \"Control\",或者在Mac上按 \"Command\" 来选择多个值。"
-
-#: db/models/fields/related.py:625
-#, python-format
-msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] "请输入有效的 %(self)s ID。值 %(value)r 无效。"
-
-#: forms/__init__.py:380
-#, python-format
-msgid "Ensure your text is less than %s character."
-msgid_plural "Ensure your text is less than %s characters."
-msgstr[0] "确定你输入的文本少于 %s 个字符。"
-
-#: forms/__init__.py:385
-msgid "Line breaks are not allowed here."
-msgstr "这里不允许换行符。"
-
-#: forms/__init__.py:480
-#: forms/__init__.py:551
-#: forms/__init__.py:589
-#, python-format
-msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
-msgstr "选择一个有效的选项: '%(data)s' 不在 %(choices)s 中。"
-
-#: forms/__init__.py:645
-msgid "The submitted file is empty."
-msgstr "所提交的文件为空。"
-
-#: forms/__init__.py:699
-msgid "Enter a whole number between -32,768 and 32,767."
-msgstr "输入在 -32,768 到 32,767 之间的一个整数。"
-
-#: forms/__init__.py:708
-msgid "Enter a positive number."
-msgstr "输入正整数。"
-
-#: forms/__init__.py:717
-msgid "Enter a whole number between 0 and 32,767."
-msgstr "输入在 0 到 32,767 之间的一个整数。"
-
-#: template/defaultfilters.py:379
-msgid "yes,no,maybe"
-msgstr "是、否、也许"
-
-#~ msgid "Comment"
-#~ msgstr "评论"
-#~ msgid "Comments"
-#~ msgstr "评论"
-#~ msgid "String (up to 50)"
-#~ msgstr "整数(最长50)"
-#~ msgid "label"
-#~ msgstr "标签"
-#~ msgid "package"
-#~ msgstr "包"
-#~ msgid "packages"
-#~ msgstr "包"
-
-#, fuzzy
-#~ msgid "count"
-#~ msgstr "内容"
-
diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py
index 8b3617d4b6..ecd716b50d 100644
--- a/django/conf/project_template/settings.py
+++ b/django/conf/project_template/settings.py
@@ -17,15 +17,14 @@ DATABASE_HOST = '' # Set to empty string for localhost. Not used wit
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
-# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
-# although not all variations may be possible on all operating systems.
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be avilable on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
-# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py
index 8c2b82147e..5aa950cbf4 100644
--- a/django/contrib/admin/filterspecs.py
+++ b/django/contrib/admin/filterspecs.py
@@ -7,6 +7,8 @@ certain test -- e.g. being a DateField or ForeignKey.
"""
from django.db import models
+from django.utils.encoding import smart_unicode, iri_to_uri
+from django.utils.translation import ugettext as _
import datetime
class FilterSpec(object):
@@ -37,12 +39,12 @@ class FilterSpec(object):
def output(self, cl):
t = []
if self.has_output():
- t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
+ t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % self.title())
for choice in self.choices(cl):
- t.append('<li%s><a href="%s">%s</a></li>\n' % \
+ t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
((choice['selected'] and ' class="selected"' or ''),
- choice['query_string'] ,
+ iri_to_uri(choice['query_string']),
choice['display']))
t.append('</ul>\n\n')
return "".join(t)
@@ -70,7 +72,7 @@ class RelatedFilterSpec(FilterSpec):
'display': _('All')}
for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
- yield {'selected': self.lookup_val == str(pk_val),
+ yield {'selected': self.lookup_val == smart_unicode(pk_val),
'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
'display': val}
@@ -87,7 +89,7 @@ class ChoicesFilterSpec(FilterSpec):
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')}
for k, v in self.field.choices:
- yield {'selected': str(k) == self.lookup_val,
+ yield {'selected': smart_unicode(k) == self.lookup_val,
'query_string': cl.get_query_string({self.lookup_kwarg: k}),
'display': v}
@@ -168,7 +170,7 @@ class AllValuesFilterSpec(FilterSpec):
'query_string': cl.get_query_string({}, [self.field.name]),
'display': _('All')}
for val in self.lookup_choices:
- val = str(val[self.field.name])
+ val = smart_unicode(val[self.field.name])
yield {'selected': self.lookup_val == val,
'query_string': cl.get_query_string({self.field.name: val}),
'display': val}
diff --git a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
index e5e05a7e32..36ae21411d 100644
--- a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
+++ b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
@@ -31,10 +31,11 @@ function showAddAnotherPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^add_/, '');
name = name.replace(/\./g, '___');
href = triggeringLink.href
- if (href.indexOf('?') == -1)
- href += '?_popup=1';
- else
- href += '&_popup=1';
+ if (href.indexOf('?') == -1) {
+ href += '?_popup=1';
+ } else {
+ href += '&_popup=1';
+ }
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus();
return false;
diff --git a/django/contrib/admin/media/js/urlify.js b/django/contrib/admin/media/js/urlify.js
index 9b87113628..1545d80ec9 100644
--- a/django/contrib/admin/media/js/urlify.js
+++ b/django/contrib/admin/media/js/urlify.js
@@ -1,15 +1,121 @@
+var LATIN_MAP = {
+ 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
+ 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
+ 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
+ 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U',
+ 'Ý': 'Y', 'Þ': 'TH', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä':
+ 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
+ 'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó':
+ 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u',
+ 'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
+}
+var LATIN_SYMBOLS_MAP = {
+ '©':'(c)'
+}
+var GREEK_MAP = {
+ 'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
+ 'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
+ 'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
+ 'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
+ 'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
+ 'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
+ 'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
+ 'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
+ 'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
+ 'Ϋ':'Y'
+}
+var TURKISH_MAP = {
+ 'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
+ 'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G'
+}
+var RUSSIAN_MAP = {
+ 'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'yo', 'ж':'zh',
+ 'з':'z', 'и':'i', 'й':'j', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o',
+ 'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c',
+ 'ч':'ch', 'ш':'sh', 'щ':'sh', 'ъ':'', 'ы':'y', 'ь':'', 'э':'e', 'ю':'yu',
+ 'я':'ya',
+ 'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'Yo', 'Ж':'Zh',
+ 'З':'Z', 'И':'I', 'Й':'J', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O',
+ 'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C',
+ 'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
+ 'Я':'Ya'
+}
+var CZECH_MAP = {
+ 'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
+ 'ž':'z'
+}
+
+var ALL_DOWNCODE_MAPS=new Array()
+ALL_DOWNCODE_MAPS[0]=LATIN_MAP
+ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
+ALL_DOWNCODE_MAPS[2]=GREEK_MAP
+ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
+ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
+ALL_DOWNCODE_MAPS[5]=CZECH_MAP
+
+var Downcoder = new Object();
+Downcoder.Initialize = function()
+{
+ if (Downcoder.map) // already made
+ return ;
+ Downcoder.map ={}
+ Downcoder.chars = '' ;
+ for(var i in ALL_DOWNCODE_MAPS)
+ {
+ var lookup = ALL_DOWNCODE_MAPS[i]
+ for (var c in lookup)
+ {
+ Downcoder.map[c] = lookup[c] ;
+ Downcoder.chars += c ;
+ }
+ }
+ Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
+}
+
+downcode= function( slug )
+{
+ Downcoder.Initialize() ;
+ var downcoded =""
+ var pieces = slug.match(Downcoder.regex);
+ if(pieces)
+ {
+ for (var i = 0 ; i < pieces.length ; i++)
+ {
+ if (pieces[i].length == 1)
+ {
+ var mapped = Downcoder.map[pieces[i]] ;
+ if (mapped != null)
+ {
+ downcoded+=mapped;
+ continue ;
+ }
+ }
+ downcoded+=pieces[i];
+ }
+ }
+ else
+ {
+ downcoded = slug;
+ }
+ return downcoded;
+}
+
+
function URLify(s, num_chars) {
// changes, e.g., "Petty theft" to "petty_theft"
// remove all these words from the string before urlifying
+ s = downcode(s);
removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
"is", "in", "into", "like", "of", "off", "on", "onto", "per",
"since", "than", "the", "this", "that", "to", "up", "via",
"with"];
r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
s = s.replace(r, '');
+ // if downcode doesn't hit, the char will be stripped here
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
s = s.toLowerCase(); // convert to lowercase
return s.substring(0, num_chars);// trim to first num_chars chars
}
+
diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py
index 7144c0b20b..ffa2740d5e 100644
--- a/django/contrib/admin/models.py
+++ b/django/contrib/admin/models.py
@@ -1,7 +1,8 @@
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import smart_unicode
ADDITION = 1
CHANGE = 2
@@ -9,7 +10,7 @@ DELETION = 3
class LogEntryManager(models.Manager):
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
- e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message)
+ e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message)
e.save()
class LogEntry(models.Model):
@@ -17,7 +18,7 @@ class LogEntry(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.TextField(_('object id'), blank=True, null=True)
- object_repr = models.CharField(_('object repr'), maxlength=200)
+ object_repr = models.CharField(_('object repr'), max_length=200)
action_flag = models.PositiveSmallIntegerField(_('action flag'))
change_message = models.TextField(_('change message'), blank=True)
objects = LogEntryManager()
@@ -28,7 +29,7 @@ class LogEntry(models.Model):
ordering = ('-action_time',)
def __repr__(self):
- return str(self.action_time)
+ return smart_unicode(self.action_time)
def is_addition(self):
return self.action_flag == ADDITION
@@ -48,4 +49,4 @@ class LogEntry(models.Model):
Returns the admin URL to edit the object represented by this log entry.
This is relative to the Django admin index page.
"""
- return "%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
+ return u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
diff --git a/django/contrib/admin/templates/admin/auth/user/change_password.html b/django/contrib/admin/templates/admin/auth/user/change_password.html
index 3d359ecf8f..d9c1eae637 100644
--- a/django/contrib/admin/templates/admin/auth/user/change_password.html
+++ b/django/contrib/admin/templates/admin/auth/user/change_password.html
@@ -6,7 +6,7 @@
{% endblock %}
{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
-{% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
+{% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
{% block breadcrumbs %}{% if not is_popup %}
<div class="breadcrumbs">
<a href="../../../../">{% trans "Home" %}</a> &rsaquo;
diff --git a/django/contrib/admin/templates/admin/filter.html b/django/contrib/admin/templates/admin/filter.html
index 8b5b521437..bcc64ac7e4 100644
--- a/django/contrib/admin/templates/admin/filter.html
+++ b/django/contrib/admin/templates/admin/filter.html
@@ -3,6 +3,6 @@
<ul>
{% for choice in choices %}
<li{% if choice.selected %} class="selected"{% endif %}>
- <a href="{{ choice.query_string }}">{{ choice.display|escape }}</a></li>
+ <a href="{{ choice.query_string|iriencode }}">{{ choice.display|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html
index aa63c14fce..3626c89cb2 100644
--- a/django/contrib/admin/templates/admin/index.html
+++ b/django/contrib/admin/templates/admin/index.html
@@ -58,7 +58,7 @@
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
- <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst|escape }}</span></li>
+ <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst|escape %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
{% endfor %}
</ul>
{% endif %}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 7ad66c250d..0e96f28191 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -6,7 +6,8 @@ from django.db import models
from django.utils import dateformat
from django.utils.html import escape
from django.utils.text import capfirst
-from django.utils.translation import get_date_formats, get_partial_date_formats
+from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
+from django.utils.encoding import smart_unicode, smart_str, force_unicode
from django.template import Library
import datetime
@@ -16,11 +17,11 @@ DOT = '.'
def paginator_number(cl,i):
if i == DOT:
- return '... '
+ return u'... '
elif i == cl.page_num:
- return '<span class="this-page">%d</span> ' % (i+1)
+ return u'<span class="this-page">%d</span> ' % (i+1)
else:
- return '<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
+ return u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
paginator_number = register.simple_tag(paginator_number)
def pagination(cl):
@@ -75,10 +76,12 @@ def result_headers(cl):
admin_order_field = None
except models.FieldDoesNotExist:
# For non-field list_display values, check for the function
- # attribute "short_description". If that doesn't exist, fall
- # back to the method name. And __str__ is a special-case.
- if field_name == '__str__':
- header = lookup_opts.verbose_name
+ # attribute "short_description". If that doesn't exist, fall back
+ # to the method name. And __str__ and __unicode__ are special-cases.
+ if field_name == '__unicode__':
+ header = force_unicode(lookup_opts.verbose_name)
+ elif field_name == '__str__':
+ header = smart_str(lookup_opts.verbose_name)
else:
attr = getattr(cl.model, field_name) # Let AttributeErrors propagate.
try:
@@ -114,7 +117,7 @@ def result_headers(cl):
def _boolean_icon(field_val):
BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
- return '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
+ return u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
def items_for_result(cl, result):
first = True
@@ -136,7 +139,7 @@ def items_for_result(cl, result):
allow_tags = True
result_repr = _boolean_icon(attr)
else:
- result_repr = str(attr)
+ result_repr = smart_unicode(attr)
except (AttributeError, ObjectDoesNotExist):
result_repr = EMPTY_CHANGELIST_VALUE
else:
@@ -179,19 +182,21 @@ def items_for_result(cl, result):
elif f.choices:
result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
else:
- result_repr = escape(str(field_val))
- if result_repr == '':
+ result_repr = escape(field_val)
+ if force_unicode(result_repr) == '':
result_repr = '&nbsp;'
# If list_display_links not defined, add the link tag to the first field
- if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
+ if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
table_tag = {True:'th', False:'td'}[first]
first = False
url = cl.url_for_result(result)
- result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints)
- yield ('<%s%s><a href="%s"%s>%s</a></%s>' % \
- (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
+ # Convert the pk to something that can be used in Javascript.
+ # Problem cases are long ints (23L) and non-ASCII strings.
+ result_id = repr(force_unicode(getattr(result, pk)))[1:]
+ yield (u'<%s%s><a href="%s"%s>%s</a></%s>' % \
+ (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), result_repr, table_tag))
else:
- yield ('<td%s>%s</td>' % (row_class, result_repr))
+ yield (u'<td%s>%s</td>' % (row_class, result_repr))
def results(cl):
for res in cl.result_list:
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index f9cad005d5..5f29782903 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -2,6 +2,7 @@ from django import template
from django.contrib.admin.views.main import AdminBoundField
from django.template import loader
from django.utils.text import capfirst
+from django.utils.encoding import force_unicode
from django.db import models
from django.db.models.fields import Field
from django.db.models.related import BoundRelatedObject
@@ -14,7 +15,7 @@ word_re = re.compile('[A-Z][a-z]+')
absolute_url_re = re.compile(r'^(?:http(?:s)?:/)?/', re.IGNORECASE)
def class_name_to_underscored(name):
- return '_'.join([s.lower() for s in word_re.findall(name)[:-1]])
+ return u'_'.join([s.lower() for s in word_re.findall(name)[:-1]])
def include_admin_script(script_path):
"""
@@ -31,7 +32,7 @@ def include_admin_script(script_path):
"""
if not absolute_url_re.match(script_path):
script_path = '%s%s' % (settings.ADMIN_MEDIA_PREFIX, script_path)
- return '<script type="text/javascript" src="%s"></script>' % script_path
+ return u'<script type="text/javascript" src="%s"></script>' % script_path
include_admin_script = register.simple_tag(include_admin_script)
def submit_row(context):
@@ -61,9 +62,9 @@ def field_label(bound_field):
if not bound_field.first:
class_names.append('inline')
colon = ":"
- class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
- return '<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \
- capfirst(bound_field.field.verbose_name), colon)
+ class_str = class_names and u' class="%s"' % u' '.join(class_names) or u''
+ return u'<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \
+ force_unicode(capfirst(bound_field.field.verbose_name)), colon)
field_label = register.simple_tag(field_label)
class FieldWidgetNode(template.Node):
@@ -77,7 +78,7 @@ class FieldWidgetNode(template.Node):
if klass not in cls.nodelists:
try:
field_class_name = klass.__name__
- template_name = "widget/%s.html" % class_name_to_underscored(field_class_name)
+ template_name = u"widget/%s.html" % class_name_to_underscored(field_class_name)
nodelist = loader.get_template(template_name).nodelist
except template.TemplateDoesNotExist:
super_klass = bool(klass.__bases__) and klass.__bases__[0] or None
@@ -175,30 +176,30 @@ class EditInlineNode(template.Node):
return output
def output_all(form_fields):
- return ''.join([str(f) for f in form_fields])
+ return u''.join([force_unicode(f) for f in form_fields])
output_all = register.simple_tag(output_all)
def auto_populated_field_script(auto_pop_fields, change = False):
t = []
for field in auto_pop_fields:
if change:
- t.append('document.getElementById("id_%s")._changed = true;' % field.name)
+ t.append(u'document.getElementById("id_%s")._changed = true;' % field.name)
else:
- t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
+ t.append(u'document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
- add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
+ add_values = u' + " " + '.join([u'document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
for f in field.prepopulate_from:
- t.append('document.getElementById("id_%s").onkeyup = function() {' \
+ t.append(u'document.getElementById("id_%s").onkeyup = function() {' \
' var e = document.getElementById("id_%s");' \
' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % (
- f, field.name, add_values, field.maxlength))
- return ''.join(t)
+ f, field.name, add_values, field.max_length))
+ return u''.join(t)
auto_populated_field_script = register.simple_tag(auto_populated_field_script)
def filter_interface_script_maybe(bound_field):
f = bound_field.field
if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface:
- return '<script type="text/javascript">addEvent(window, "load", function(e) {' \
+ return u'<script type="text/javascript">addEvent(window, "load", function(e) {' \
' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX)
else:
diff --git a/django/contrib/admin/templatetags/adminapplist.py b/django/contrib/admin/templatetags/adminapplist.py
index 10e09ca0b6..673b77a1e0 100644
--- a/django/contrib/admin/templatetags/adminapplist.py
+++ b/django/contrib/admin/templatetags/adminapplist.py
@@ -1,5 +1,6 @@
from django import template
from django.db.models import get_models
+from django.utils.encoding import force_unicode
register = template.Library()
@@ -36,8 +37,8 @@ class AdminApplistNode(template.Node):
# If so, add the module to the model_list.
if True in perms.values():
model_list.append({
- 'name': capfirst(m._meta.verbose_name_plural),
- 'admin_url': '%s/%s/' % (app_label, m.__name__.lower()),
+ 'name': force_unicode(capfirst(m._meta.verbose_name_plural)),
+ 'admin_url': u'%s/%s/' % (force_unicode(app_label), m.__name__.lower()),
'perms': perms,
})
diff --git a/django/contrib/admin/views/auth.py b/django/contrib/admin/views/auth.py
index c6ad0c3a95..0c8104831b 100644
--- a/django/contrib/admin/views/auth.py
+++ b/django/contrib/admin/views/auth.py
@@ -6,6 +6,7 @@ from django import oldforms, template
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect
from django.utils.html import escape
+from django.utils.translation import ugettext as _
def user_add_stage(request):
if not request.user.has_perm('auth.change_user'):
diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py
index 5389ca4dff..9ae0170b54 100644
--- a/django/contrib/admin/views/decorators.py
+++ b/django/contrib/admin/views/decorators.py
@@ -3,11 +3,11 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django.shortcuts import render_to_response
-from django.utils.translation import gettext_lazy
+from django.utils.translation import ugettext_lazy, ugettext as _
import base64, datetime, md5
import cPickle as pickle
-ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
+ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form'
def _display_login_form(request, error_message=''):
diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py
index 6430252690..37caa0f43b 100644
--- a/django/contrib/admin/views/doc.py
+++ b/django/contrib/admin/views/doc.py
@@ -9,6 +9,7 @@ from django.http import Http404, get_host
from django.core import urlresolvers
from django.contrib.admin import utils
from django.contrib.sites.models import Site
+from django.utils.translation import ugettext as _
import inspect, os, re
# Exclude methods starting with these strings from documentation
@@ -290,7 +291,7 @@ def get_return_data_type(func_name):
DATA_TYPE_MAPPING = {
'AutoField' : _('Integer'),
'BooleanField' : _('Boolean (Either True or False)'),
- 'CharField' : _('String (up to %(maxlength)s)'),
+ 'CharField' : _('String (up to %(max_length)s)'),
'CommaSeparatedIntegerField': _('Comma-separated integers'),
'DateField' : _('Date (without time)'),
'DateTimeField' : _('Date (with time)'),
@@ -309,7 +310,7 @@ DATA_TYPE_MAPPING = {
'PhoneNumberField' : _('Phone number'),
'PositiveIntegerField' : _('Integer'),
'PositiveSmallIntegerField' : _('Integer'),
- 'SlugField' : _('String (up to %(maxlength)s)'),
+ 'SlugField' : _('String (up to %(max_length)s)'),
'SmallIntegerField' : _('Integer'),
'TextField' : _('Text'),
'TimeField' : _('Time'),
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index e372b45439..cfbe9a1f95 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -12,6 +12,8 @@ from django.db.models.query import handle_legacy_orderlist, QuerySet
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.utils.html import escape
from django.utils.text import capfirst, get_text_list
+from django.utils.encoding import force_unicode, smart_str
+from django.utils.translation import ugettext as _
import operator
try:
@@ -130,11 +132,11 @@ class AdminBoundField(object):
if max([bool(f.errors()) for f in self.form_fields]):
classes.append('error')
if classes:
- self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
+ self.cell_class_attribute = u' class="%s" ' % ' '.join(classes)
self._repr_filled = False
if field.rel:
- self.related_url = '../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
+ self.related_url = u'../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
def original_value(self):
if self.original:
@@ -145,9 +147,9 @@ class AdminBoundField(object):
return self._display
except AttributeError:
if isinstance(self.field.rel, models.ManyToOneRel):
- self._display = getattr(self.original, self.field.name)
+ self._display = force_unicode(getattr(self.original, self.field.name), strings_only=True)
elif isinstance(self.field.rel, models.ManyToManyRel):
- self._display = ", ".join([str(obj) for obj in getattr(self.original, self.field.name).all()])
+ self._display = u", ".join([force_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
return self._display
def __repr__(self):
@@ -258,8 +260,8 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if not errors:
new_object = manipulator.save(new_data)
pk_value = new_object._get_pk_val()
- LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION)
- msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
+ LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), ADDITION)
+ msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)}
# Here, we distinguish between different save types by checking for
# the presence of keys in request.POST.
if "_continue" in request.POST:
@@ -271,9 +273,9 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
pk_value = '"%s"' % pk_value.replace('"', '\\"')
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
- (pk_value, str(new_object).replace('"', '\\"')))
+ (pk_value, force_unicode(new_object).replace('"', '\\"')))
elif "_addanother" in request.POST:
- request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
+ request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect(request.path)
else:
request.user.message_set.create(message=msg)
@@ -291,7 +293,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
form = oldforms.FormWrapper(manipulator, new_data, errors)
c = template.RequestContext(request, {
- 'title': _('Add %s') % opts.verbose_name,
+ 'title': _('Add %s') % force_unicode(opts.verbose_name),
'form': form,
'is_popup': '_popup' in request.REQUEST,
'show_delete': show_delete,
@@ -345,9 +347,9 @@ def change_stage(request, app_label, model_name, object_id):
change_message = ' '.join(change_message)
if not change_message:
change_message = _('No fields changed.')
- LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message)
+ LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
- msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
+ msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)}
if "_continue" in request.POST:
request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
if '_popup' in request.REQUEST:
@@ -355,10 +357,10 @@ def change_stage(request, app_label, model_name, object_id):
else:
return HttpResponseRedirect(request.path)
elif "_saveasnew" in request.POST:
- request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
+ request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(new_object)})
return HttpResponseRedirect("../%s/" % pk_value)
elif "_addanother" in request.POST:
- request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
+ request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect("../add/")
else:
request.user.message_set.create(message=msg)
@@ -393,7 +395,7 @@ def change_stage(request, app_label, model_name, object_id):
form.order_objects.extend(orig_list)
c = template.RequestContext(request, {
- 'title': _('Change %s') % opts.verbose_name,
+ 'title': _('Change %s') % force_unicode(opts.verbose_name),
'form': form,
'object_id': object_id,
'original': manipulator.original_object,
@@ -434,11 +436,11 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
- nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
+ nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj), []])
else:
# Display a link to the admin page.
- nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
- (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
+ nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
+ (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(),
sub_obj._get_pk_val(), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
else:
@@ -448,11 +450,11 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
- nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(str(sub_obj))), []])
+ nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), escape(sub_obj)), []])
else:
# Display a link to the admin page.
- nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
- (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(str(sub_obj))), []])
+ nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
+ (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
# If there were related objects, and the user doesn't have
# permission to delete them, add the missing perm to perms_needed.
@@ -466,7 +468,7 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
opts_seen.append(related.opts)
rel_opts_name = related.get_accessor_name()
has_related_objs = False
-
+
# related.get_accessor_name() could return None for symmetrical relationships
if rel_opts_name:
rel_objs = getattr(obj, rel_opts_name, None)
@@ -479,17 +481,17 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \
- {'fieldname': related.field.verbose_name, 'name': related.opts.verbose_name, 'obj': escape(str(sub_obj))}, []])
+ {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name), 'obj': escape(sub_obj)}, []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, [
- (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.verbose_name, 'name':related.opts.verbose_name}) + \
- (' <a href="../../../../%s/%s/%s/">%s</a>' % \
- (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(str(sub_obj)))), []])
+ (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name)}) + \
+ (u' <a href="../../../../%s/%s/%s/">%s</a>' % \
+ (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []])
# If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
- p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
+ p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
@@ -505,21 +507,21 @@ def delete_stage(request, app_label, model_name, object_id):
# Populate deleted_objects, a data structure of all related objects that
# will also be deleted.
- deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(str(obj))), []]
+ deleted_objects = [u'%s: <a href="../../%s/">%s</a>' % (force_unicode(capfirst(opts.verbose_name)), force_unicode(object_id), escape(obj)), []]
perms_needed = set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
if request.POST: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied
- obj_display = str(obj)
+ obj_display = force_unicode(obj)
obj.delete()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION)
- request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
+ request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': obj_display})
return HttpResponseRedirect("../../")
extra_context = {
"title": _("Are you sure?"),
- "object_name": opts.verbose_name,
+ "object_name": force_unicode(opts.verbose_name),
"object": obj,
"deleted_objects": deleted_objects,
"perms_lacking": perms_needed,
@@ -542,7 +544,7 @@ def history(request, app_label, model_name, object_id):
extra_context = {
'title': _('Change history: %s') % obj,
'action_list': action_list,
- 'module_name': capfirst(model._meta.verbose_name_plural),
+ 'module_name': force_unicode(capfirst(model._meta.verbose_name_plural)),
'object': obj,
}
return render_to_response(["admin/%s/%s/object_history.html" % (app_label, model._meta.object_name.lower()),
@@ -574,7 +576,7 @@ class ChangeList(object):
self.query = request.GET.get(SEARCH_VAR, '')
self.query_set = self.get_query_set()
self.get_results(request)
- self.title = (self.is_popup and _('Select %s') % self.opts.verbose_name or _('Select %s to change') % self.opts.verbose_name)
+ self.title = (self.is_popup and _('Select %s') % force_unicode(self.opts.verbose_name) or _('Select %s to change') % force_unicode(self.opts.verbose_name))
self.filter_specs, self.has_filters = self.get_filters(request)
self.pk_attname = self.lookup_opts.pk.attname
@@ -602,7 +604,7 @@ class ChangeList(object):
del p[k]
elif v is not None:
p[k] = v
- return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
+ return '?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
def get_results(self, request):
paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page)
@@ -671,7 +673,7 @@ class ChangeList(object):
try:
attr = getattr(lookup_opts.admin.manager.model, field_name)
order_field = attr.admin_order_field
- except IndexError:
+ except AttributeError:
pass
else:
if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
@@ -688,6 +690,12 @@ class ChangeList(object):
for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR):
if i in lookup_params:
del lookup_params[i]
+ for key, value in lookup_params.items():
+ if not isinstance(key, str):
+ # 'key' will be used as a keyword argument later, so Python
+ # requires it to be a string.
+ del lookup_params[key]
+ lookup_params[smart_str(key)] = value
# Apply lookup parameters from the query string.
qs = qs.filter(**lookup_params)
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index 14ae020674..9813d9a2a2 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -12,6 +12,8 @@ def load_backend(path):
mod = __import__(module, {}, {}, [attr])
except ImportError, e:
raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e)
+ except ValueError, e:
+ raise ImproperlyConfigured, 'Error importing authentication backends. Is AUTHENTICATION_BACKENDS a correctly defined list or tuple?'
try:
cls = getattr(mod, attr)
except AttributeError:
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index 9d5a48c2f1..16ee0289a2 100644
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -4,16 +4,16 @@ from django.contrib.sites.models import Site
from django.template import Context, loader
from django.core import validators
from django import oldforms
-from django.utils.translation import gettext as _
+from django.utils.translation import ugettext as _
class UserCreationForm(oldforms.Manipulator):
"A form that creates a user, with no privileges, from the given username and password."
def __init__(self):
self.fields = (
- oldforms.TextField(field_name='username', length=30, maxlength=30, is_required=True,
+ oldforms.TextField(field_name='username', length=30, max_length=30, is_required=True,
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
- oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
- oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
+ oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True),
+ oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True,
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
)
@@ -42,9 +42,9 @@ class AuthenticationForm(oldforms.Manipulator):
"""
self.request = request
self.fields = [
- oldforms.TextField(field_name="username", length=15, maxlength=30, is_required=True,
+ oldforms.TextField(field_name="username", length=15, max_length=30, is_required=True,
validator_list=[self.isValidUser, self.hasCookiesEnabled]),
- oldforms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True),
+ oldforms.PasswordField(field_name="password", length=15, max_length=30, is_required=True),
]
self.user_cache = None
@@ -111,11 +111,11 @@ class PasswordChangeForm(oldforms.Manipulator):
def __init__(self, user):
self.user = user
self.fields = (
- oldforms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True,
+ oldforms.PasswordField(field_name="old_password", length=30, max_length=30, is_required=True,
validator_list=[self.isValidOldPassword]),
- oldforms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True,
+ oldforms.PasswordField(field_name="new_password1", length=30, max_length=30, is_required=True,
validator_list=[validators.AlwaysMatchesOtherField('new_password2', _("The two 'new password' fields didn't match."))]),
- oldforms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True),
+ oldforms.PasswordField(field_name="new_password2", length=30, max_length=30, is_required=True),
)
def isValidOldPassword(self, new_data, all_data):
@@ -133,8 +133,8 @@ class AdminPasswordChangeForm(oldforms.Manipulator):
def __init__(self, user):
self.user = user
self.fields = (
- oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
- oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
+ oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True),
+ oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True,
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
)
diff --git a/django/contrib/auth/management.py b/django/contrib/auth/management.py
index 3f52681747..2b4cb8bd19 100644
--- a/django/contrib/auth/management.py
+++ b/django/contrib/auth/management.py
@@ -7,13 +7,13 @@ from django.db.models import get_models, signals
from django.contrib.auth import models as auth_app
def _get_permission_codename(action, opts):
- return '%s_%s' % (action, opts.object_name.lower())
+ return u'%s_%s' % (action, opts.object_name.lower())
def _get_all_permissions(opts):
"Returns (codename, name) for all permissions in the given opts."
perms = []
for action in ('add', 'change', 'delete'):
- perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name)))
+ perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
return perms + list(opts.permissions)
def create_permissions(app, created_models, verbosity):
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index e8384ba353..3584cea533 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -1,9 +1,13 @@
from django.core import validators
from django.core.exceptions import ImproperlyConfigured
-from django.db import backend, connection, models
+from django.db import connection, models
from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import gettext_lazy as _
+from django.utils.encoding import smart_str
+from django.utils.translation import ugettext_lazy as _
import datetime
+import urllib
+
+UNUSABLE_PASSWORD = '!' # This will never be a valid hash
try:
set
@@ -18,16 +22,16 @@ def check_password(raw_password, enc_password):
algo, salt, hsh = enc_password.split('$')
if algo == 'md5':
import md5
- return hsh == md5.new(salt+raw_password).hexdigest()
+ return hsh == md5.new(smart_str(salt + raw_password)).hexdigest()
elif algo == 'sha1':
import sha
- return hsh == sha.new(salt+raw_password).hexdigest()
+ return hsh == sha.new(smart_str(salt + raw_password)).hexdigest()
elif algo == 'crypt':
try:
import crypt
except ImportError:
raise ValueError, "Crypt password algorithm not supported in this environment."
- return hsh == crypt.crypt(raw_password, salt)
+ return hsh == crypt.crypt(smart_str(raw_password), smart_str(salt))
raise ValueError, "Got unknown password algorithm type in password."
class SiteProfileNotAvailable(Exception):
@@ -46,9 +50,9 @@ class Permission(models.Model):
Three basic permissions -- add, change and delete -- are automatically created for each Django model.
"""
- name = models.CharField(_('name'), maxlength=50)
+ name = models.CharField(_('name'), max_length=50)
content_type = models.ForeignKey(ContentType)
- codename = models.CharField(_('codename'), maxlength=100)
+ codename = models.CharField(_('codename'), max_length=100)
class Meta:
verbose_name = _('permission')
@@ -56,8 +60,8 @@ class Permission(models.Model):
unique_together = (('content_type', 'codename'),)
ordering = ('content_type', 'codename')
- def __str__(self):
- return "%s | %s | %s" % (self.content_type.app_label, self.content_type, self.name)
+ def __unicode__(self):
+ return u"%s | %s | %s" % (self.content_type.app_label, self.content_type, self.name)
class Group(models.Model):
"""Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
@@ -66,7 +70,7 @@ class Group(models.Model):
Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only e-mail messages.
"""
- name = models.CharField(_('name'), maxlength=80, unique=True)
+ name = models.CharField(_('name'), max_length=80, unique=True)
permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True, filter_interface=models.HORIZONTAL)
class Meta:
@@ -77,15 +81,18 @@ class Group(models.Model):
class Admin:
search_fields = ('name',)
- def __str__(self):
+ def __unicode__(self):
return self.name
class UserManager(models.Manager):
- def create_user(self, username, email, password):
+ def create_user(self, username, email, password=None):
"Creates and saves a User with the given username, e-mail and password."
now = datetime.datetime.now()
user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
- user.set_password(password)
+ if password:
+ user.set_password(password)
+ else:
+ user.set_unusable_password()
user.save()
return user
@@ -101,11 +108,11 @@ class User(models.Model):
Username and password are required. Other fields are optional.
"""
- username = models.CharField(_('username'), maxlength=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
- first_name = models.CharField(_('first name'), maxlength=30, blank=True)
- last_name = models.CharField(_('last name'), maxlength=30, blank=True)
+ username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
+ first_name = models.CharField(_('first name'), max_length=30, blank=True)
+ last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('e-mail address'), blank=True)
- password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
+ password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."))
is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
@@ -133,11 +140,11 @@ class User(models.Model):
list_filter = ('is_staff', 'is_superuser')
search_fields = ('username', 'first_name', 'last_name', 'email')
- def __str__(self):
+ def __unicode__(self):
return self.username
def get_absolute_url(self):
- return "/users/%s/" % self.username
+ return "/users/%s/" % urllib.quote(smart_str(self.username))
def is_anonymous(self):
"Always returns False. This is a way of comparing User objects to anonymous users."
@@ -150,14 +157,14 @@ class User(models.Model):
def get_full_name(self):
"Returns the first_name plus the last_name, with a space in between."
- full_name = '%s %s' % (self.first_name, self.last_name)
+ full_name = u'%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def set_password(self, raw_password):
import sha, random
algo = 'sha1'
salt = sha.new(str(random.random())).hexdigest()[:5]
- hsh = sha.new(salt+raw_password).hexdigest()
+ hsh = sha.new(salt + smart_str(raw_password)).hexdigest()
self.password = '%s$%s$%s' % (algo, salt, hsh)
def check_password(self, raw_password):
@@ -169,7 +176,7 @@ class User(models.Model):
# algorithm or salt.
if '$' not in self.password:
import md5
- is_correct = (self.password == md5.new(raw_password).hexdigest())
+ is_correct = (self.password == md5.new(smart_str(raw_password)).hexdigest())
if is_correct:
# Convert the password to the new, more secure format.
self.set_password(raw_password)
@@ -177,6 +184,13 @@ class User(models.Model):
return is_correct
return check_password(raw_password, self.password)
+ def set_unusable_password(self):
+ # Sets a value that will never be a valid hash
+ self.password = UNUSABLE_PASSWORD
+
+ def has_usable_password(self):
+ return self.password != UNUSABLE_PASSWORD
+
def get_group_permissions(self):
"Returns a list of permission strings that this user has through his/her groups."
if not hasattr(self, '_group_perm_cache'):
@@ -189,6 +203,7 @@ class User(models.Model):
# AND gp."group_id" = ug."group_id"
# AND ct."id" = p."content_type_id"
# AND ug."user_id" = %s, [self.id])
+ qn = connection.ops.quote_name
sql = """
SELECT ct.%s, p.%s
FROM %s p, %s gp, %s ug, %s ct
@@ -196,20 +211,20 @@ class User(models.Model):
AND gp.%s = ug.%s
AND ct.%s = p.%s
AND ug.%s = %%s""" % (
- backend.quote_name('app_label'), backend.quote_name('codename'),
- backend.quote_name('auth_permission'), backend.quote_name('auth_group_permissions'),
- backend.quote_name('auth_user_groups'), backend.quote_name('django_content_type'),
- backend.quote_name('id'), backend.quote_name('permission_id'),
- backend.quote_name('group_id'), backend.quote_name('group_id'),
- backend.quote_name('id'), backend.quote_name('content_type_id'),
- backend.quote_name('user_id'),)
+ qn('app_label'), qn('codename'),
+ qn('auth_permission'), qn('auth_group_permissions'),
+ qn('auth_user_groups'), qn('django_content_type'),
+ qn('id'), qn('permission_id'),
+ qn('group_id'), qn('group_id'),
+ qn('id'), qn('content_type_id'),
+ qn('user_id'),)
cursor.execute(sql, [self.id])
self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
return self._group_perm_cache
def get_all_permissions(self):
if not hasattr(self, '_perm_cache'):
- self._perm_cache = set(["%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
+ self._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
self._perm_cache.update(self.get_group_permissions())
return self._perm_cache
@@ -266,12 +281,13 @@ class User(models.Model):
return self._profile_cache
class Message(models.Model):
- """The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
+ """
+ The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
"""
user = models.ForeignKey(User)
message = models.TextField(_('message'))
- def __str__(self):
+ def __unicode__(self):
return self.message
class AnonymousUser(object):
@@ -281,8 +297,11 @@ class AnonymousUser(object):
def __init__(self):
pass
+ def __unicode__(self):
+ return 'AnonymousUser'
+
def __str__(self):
- return _('AnonymousUser')
+ return unicode(self).encode('utf-8')
def __eq__(self, other):
return isinstance(other, self.__class__)
diff --git a/django/contrib/auth/tests.py b/django/contrib/auth/tests.py
new file mode 100644
index 0000000000..ed768aa429
--- /dev/null
+++ b/django/contrib/auth/tests.py
@@ -0,0 +1,19 @@
+"""
+>>> from models import User
+>>> u = User.objects.create_user('testuser', 'test@example.com', 'testpw')
+>>> u.has_usable_password()
+True
+>>> u.check_password('bad')
+False
+>>> u.check_password('testpw')
+True
+>>> u.set_unusable_password()
+>>> u.save()
+>>> u.check_password('testpw')
+False
+>>> u.has_usable_password()
+False
+>>> u2 = User.objects.create_user('testuser2', 'test2@example.com')
+>>> u2.has_usable_password()
+False
+""" \ No newline at end of file
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index 77350b9a8f..6c40228fab 100644
--- a/django/contrib/auth/views.py
+++ b/django/contrib/auth/views.py
@@ -3,10 +3,11 @@ from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm
from django import oldforms
from django.shortcuts import render_to_response
from django.template import RequestContext
-from django.contrib.sites.models import Site
+from django.contrib.sites.models import Site, RequestSite
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.utils.translation import ugettext as _
def login(request, template_name='registration/login.html'):
"Displays the login form and handles the login action."
@@ -26,10 +27,16 @@ def login(request, template_name='registration/login.html'):
else:
errors = {}
request.session.set_test_cookie()
+
+ if Site._meta.installed:
+ current_site = Site.objects.get_current()
+ else:
+ current_site = RequestSite(request)
+
return render_to_response(template_name, {
'form': oldforms.FormWrapper(manipulator, request.POST, errors),
REDIRECT_FIELD_NAME: redirect_to,
- 'site_name': Site.objects.get_current().name,
+ 'site_name': current_site.name,
}, context_instance=RequestContext(request))
def logout(request, next_page=None, template_name='registration/logged_out.html'):
diff --git a/django/contrib/comments/feeds.py b/django/contrib/comments/feeds.py
index 1ad638469b..417e1d928a 100644
--- a/django/contrib/comments/feeds.py
+++ b/django/contrib/comments/feeds.py
@@ -11,7 +11,7 @@ class LatestFreeCommentsFeed(Feed):
def title(self):
if not hasattr(self, '_site'):
self._site = Site.objects.get_current()
- return "%s comments" % self._site.name
+ return u"%s comments" % self._site.name
def link(self):
if not hasattr(self, '_site'):
@@ -21,7 +21,7 @@ class LatestFreeCommentsFeed(Feed):
def description(self):
if not hasattr(self, '_site'):
self._site = Site.objects.get_current()
- return "Latest comments on %s" % self._site.name
+ return u"Latest comments on %s" % self._site.name
def get_query_set(self):
return self.comments_class.objects.filter(site__pk=settings.SITE_ID, is_public=True)
diff --git a/django/contrib/comments/models.py b/django/contrib/comments/models.py
index fa6c6aa363..a88d2b3a8e 100644
--- a/django/contrib/comments/models.py
+++ b/django/contrib/comments/models.py
@@ -2,7 +2,7 @@ from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
from django.conf import settings
import datetime
@@ -65,8 +65,8 @@ class Comment(models.Model):
user = models.ForeignKey(User, raw_id_admin=True)
content_type = models.ForeignKey(ContentType)
object_id = models.IntegerField(_('object ID'))
- headline = models.CharField(_('headline'), maxlength=255, blank=True)
- comment = models.TextField(_('comment'), maxlength=3000)
+ headline = models.CharField(_('headline'), max_length=255, blank=True)
+ comment = models.TextField(_('comment'), max_length=3000)
rating1 = models.PositiveSmallIntegerField(_('rating #1'), blank=True, null=True)
rating2 = models.PositiveSmallIntegerField(_('rating #2'), blank=True, null=True)
rating3 = models.PositiveSmallIntegerField(_('rating #3'), blank=True, null=True)
@@ -106,7 +106,10 @@ class Comment(models.Model):
return "%s: %s..." % (self.user.username, self.comment[:100])
def get_absolute_url(self):
- return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
+ try:
+ return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
+ except AttributeError:
+ return ""
def get_crossdomain_url(self):
return "/r/%d/%d/" % (self.content_type_id, self.object_id)
@@ -164,8 +167,8 @@ class FreeComment(models.Model):
# A FreeComment is a comment by a non-registered user.
content_type = models.ForeignKey(ContentType)
object_id = models.IntegerField(_('object ID'))
- comment = models.TextField(_('comment'), maxlength=3000)
- person_name = models.CharField(_("person's name"), maxlength=50)
+ comment = models.TextField(_('comment'), max_length=3000)
+ person_name = models.CharField(_("person's name"), max_length=50)
submit_date = models.DateTimeField(_('date/time submitted'), auto_now_add=True)
is_public = models.BooleanField(_('is public'))
ip_address = models.IPAddressField(_('ip address'))
@@ -191,7 +194,10 @@ class FreeComment(models.Model):
return "%s: %s..." % (self.person_name, self.comment[:100])
def get_absolute_url(self):
- return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
+ try:
+ return self.get_content_object().get_absolute_url() + "#c" + str(self.id)
+ except AttributeError:
+ return ""
def get_content_object(self):
"""
diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py
index 5c02c16f95..1d4628978d 100644
--- a/django/contrib/comments/templatetags/comments.py
+++ b/django/contrib/comments/templatetags/comments.py
@@ -5,6 +5,7 @@ from django import template
from django.template import loader
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType
+from django.utils.encoding import smart_str
import re
register = template.Library()
@@ -111,9 +112,9 @@ class CommentListNode(template.Node):
'site__id__exact': settings.SITE_ID,
}
kwargs.update(self.extra_kwargs)
- if not self.free and settings.COMMENTS_BANNED_USERS_GROUP:
- kwargs['select'] = {'is_hidden': 'user_id IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)' % settings.COMMENTS_BANNED_USERS_GROUP}
comment_list = get_list_function(**kwargs).order_by(self.ordering + 'submit_date').select_related()
+ if not self.free and settings.COMMENTS_BANNED_USERS_GROUP:
+ comment_list = comment_list.extra(select={'is_hidden': 'user_id IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)' % settings.COMMENTS_BANNED_USERS_GROUP})
if not self.free:
if 'user' in context and context['user'].is_authenticated():
@@ -174,6 +175,7 @@ class DoCommentForm:
if tokens[4] != 'with':
raise template.TemplateSyntaxError, "Fourth argument in %r tag must be 'with'" % tokens[0]
for option, args in zip(tokens[5::2], tokens[6::2]):
+ option = smart_str(option)
if option in ('photos_optional', 'photos_required') and not self.free:
# VALIDATION ##############################################
option_list = args.split(',')
diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py
index 73a9b2c480..fbec04c8eb 100644
--- a/django/contrib/comments/views/comments.py
+++ b/django/contrib/comments/views/comments.py
@@ -11,7 +11,8 @@ from django.contrib.auth.forms import AuthenticationForm
from django.http import HttpResponseRedirect
from django.utils.text import normalize_newlines
from django.conf import settings
-from django.utils.translation import ngettext
+from django.utils.translation import ungettext, ugettext as _
+from django.utils.encoding import smart_unicode
import base64, datetime
COMMENTS_PER_PAGE = 20
@@ -28,7 +29,7 @@ class PublicCommentManipulator(AuthenticationForm):
else:
return []
self.fields.extend([
- oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True,
+ oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True,
validator_list=[self.hasNoProfanities]),
oldforms.RadioSelectField(field_name="rating1", choices=choices,
is_required=ratings_required and num_rating_choices > 0,
@@ -108,11 +109,11 @@ class PublicCommentManipulator(AuthenticationForm):
# If the commentor has posted fewer than COMMENTS_FIRST_FEW comments,
# send the comment to the managers.
if self.user_cache.comment_set.count() <= settings.COMMENTS_FIRST_FEW:
- message = ngettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s',
+ message = ungettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s',
'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s', settings.COMMENTS_FIRST_FEW) % \
{'count': settings.COMMENTS_FIRST_FEW, 'text': c.get_as_text()}
mail_managers("Comment posted by rookie user", message)
- if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]:
+ if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.groups.all()]:
message = _('This comment was posted by a sketchy user:\n\n%(text)s') % {'text': c.get_as_text()}
mail_managers("Comment posted by sketchy user (%s)" % self.user_cache.username, c.get_as_text())
return c
@@ -121,9 +122,9 @@ class PublicFreeCommentManipulator(oldforms.Manipulator):
"Manipulator that handles public free (unregistered) comments"
def __init__(self):
self.fields = (
- oldforms.TextField(field_name="person_name", maxlength=50, is_required=True,
+ oldforms.TextField(field_name="person_name", max_length=50, is_required=True,
validator_list=[self.hasNoProfanities]),
- oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True,
+ oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True,
validator_list=[self.hasNoProfanities]),
)
@@ -248,7 +249,7 @@ def post_comment(request):
# If the IP is banned, mail the admins, do NOT save the comment, and
# serve up the "Thanks for posting" page as if the comment WAS posted.
if request.META['REMOTE_ADDR'] in settings.BANNED_IPS:
- mail_admins("Banned IP attempted to post comment", str(request.POST) + "\n\n" + str(request.META))
+ mail_admins("Banned IP attempted to post comment", smart_unicode(request.POST) + "\n\n" + str(request.META))
else:
manipulator.do_html2python(new_data)
comment = manipulator.save(new_data)
@@ -312,7 +313,7 @@ def post_free_comment(request):
# serve up the "Thanks for posting" page as if the comment WAS posted.
if request.META['REMOTE_ADDR'] in settings.BANNED_IPS:
from django.core.mail import mail_admins
- mail_admins("Practical joker", str(request.POST) + "\n\n" + str(request.META))
+ mail_admins("Practical joker", smart_unicode(request.POST) + "\n\n" + str(request.META))
else:
manipulator.do_html2python(new_data)
comment = manipulator.save(new_data)
diff --git a/django/contrib/comments/views/karma.py b/django/contrib/comments/views/karma.py
index 8c18523feb..c6ad301dee 100644
--- a/django/contrib/comments/views/karma.py
+++ b/django/contrib/comments/views/karma.py
@@ -2,6 +2,7 @@ from django.http import Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.comments.models import Comment, KarmaScore
+from django.utils.translation import ugettext as _
def vote(request, comment_id, vote):
"""
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index f995ab2044..b738a269ec 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -4,7 +4,7 @@ Classes allowing "generic" relations through ContentType and object-id fields.
from django import oldforms
from django.core.exceptions import ObjectDoesNotExist
-from django.db import backend
+from django.db import connection
from django.db.models import signals
from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
from django.db.models.loading import get_model
@@ -49,7 +49,7 @@ class GenericForeignKey(object):
def __get__(self, instance, instance_type=None):
if instance is None:
- raise AttributeError, "%s must be accessed via instance" % self.name
+ raise AttributeError, u"%s must be accessed via instance" % self.name
try:
return getattr(instance, self.cache_attr)
@@ -66,7 +66,7 @@ class GenericForeignKey(object):
def __set__(self, instance, value):
if instance is None:
- raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
+ raise AttributeError, u"%s must be accessed via instance" % self.related.opts.object_name
ct = None
fk = None
@@ -163,13 +163,15 @@ class ReverseGenericRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__
RelatedManager = create_generic_related_manager(superclass)
+ qn = connection.ops.quote_name
+
manager = RelatedManager(
model = rel_model,
instance = instance,
symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model),
- join_table = backend.quote_name(self.field.m2m_db_table()),
- source_col_name = backend.quote_name(self.field.m2m_column_name()),
- target_col_name = backend.quote_name(self.field.m2m_reverse_name()),
+ join_table = qn(self.field.m2m_db_table()),
+ source_col_name = qn(self.field.m2m_column_name()),
+ target_col_name = qn(self.field.m2m_reverse_name()),
content_type = ContentType.objects.get_for_model(self.field.model),
content_type_field_name = self.field.content_type_field_name,
object_id_field_name = self.field.object_id_field_name
diff --git a/django/contrib/contenttypes/management.py b/django/contrib/contenttypes/management.py
index 3572d93049..cb52e0805e 100644
--- a/django/contrib/contenttypes/management.py
+++ b/django/contrib/contenttypes/management.py
@@ -4,6 +4,7 @@ Creates content types for all installed models.
from django.dispatch import dispatcher
from django.db.models import get_apps, get_models, signals
+from django.utils.encoding import smart_unicode
def create_contenttypes(app, created_models, verbosity=2):
from django.contrib.contenttypes.models import ContentType
@@ -17,7 +18,7 @@ def create_contenttypes(app, created_models, verbosity=2):
ContentType.objects.get(app_label=opts.app_label,
model=opts.object_name.lower())
except ContentType.DoesNotExist:
- ct = ContentType(name=str(opts.verbose_name),
+ ct = ContentType(name=smart_unicode(opts.verbose_name_raw),
app_label=opts.app_label, model=opts.object_name.lower())
ct.save()
if verbosity >= 2:
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 0a5e68f37e..cda47a18aa 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -1,5 +1,6 @@
from django.db import models
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import smart_unicode
CONTENT_TYPE_CACHE = {}
class ContentTypeManager(models.Manager):
@@ -13,13 +14,13 @@ class ContentTypeManager(models.Manager):
try:
ct = CONTENT_TYPE_CACHE[key]
except KeyError:
- # The str() is needed around opts.verbose_name because it's a
- # django.utils.functional.__proxy__ object.
+ # The smart_unicode() is needed around opts.verbose_name_raw because it might
+ # be a django.utils.functional.__proxy__ object.
ct, created = self.model._default_manager.get_or_create(app_label=key[0],
- model=key[1], defaults={'name': str(opts.verbose_name)})
+ model=key[1], defaults={'name': smart_unicode(opts.verbose_name_raw)})
CONTENT_TYPE_CACHE[key] = ct
return ct
-
+
def clear_cache(self):
"""
Clear out the content-type cache. This needs to happen during database
@@ -31,9 +32,9 @@ class ContentTypeManager(models.Manager):
CONTENT_TYPE_CACHE = {}
class ContentType(models.Model):
- name = models.CharField(maxlength=100)
- app_label = models.CharField(maxlength=100)
- model = models.CharField(_('python model class name'), maxlength=100)
+ name = models.CharField(max_length=100)
+ app_label = models.CharField(max_length=100)
+ model = models.CharField(_('python model class name'), max_length=100)
objects = ContentTypeManager()
class Meta:
verbose_name = _('content type')
@@ -42,7 +43,7 @@ class ContentType(models.Model):
ordering = ('name',)
unique_together = (('app_label', 'model'),)
- def __str__(self):
+ def __unicode__(self):
return self.name
def model_class(self):
diff --git a/django/contrib/databrowse/datastructures.py b/django/contrib/databrowse/datastructures.py
index 24f2e68f46..0a26db18b1 100644
--- a/django/contrib/databrowse/datastructures.py
+++ b/django/contrib/databrowse/datastructures.py
@@ -7,6 +7,8 @@ from django.db import models
from django.utils import dateformat
from django.utils.text import capfirst
from django.utils.translation import get_date_formats
+from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
+from django.db.models.query import QuerySet
EMPTY_VALUE = '(None)'
@@ -19,7 +21,7 @@ class EasyModel(object):
self.verbose_name_plural = model._meta.verbose_name_plural
def __repr__(self):
- return '<EasyModel for %s>' % self.model._meta.object_name
+ return '<EasyModel for %s>' % smart_str(self.model._meta.object_name)
def model_databrowse(self):
"Returns the ModelDatabrowse class for this model."
@@ -29,8 +31,12 @@ class EasyModel(object):
return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
def objects(self, **kwargs):
- for obj in self.model._default_manager.filter(**kwargs):
- yield EasyInstance(self, obj)
+ return self.get_query_set().filter(**kwargs)
+
+ def get_query_set(self):
+ easy_qs = self.model._default_manager.get_query_set()._clone(klass=EasyQuerySet)
+ easy_qs._easymodel = self
+ return easy_qs
def object_by_pk(self, pk):
return EasyInstance(self, self.model._default_manager.get(pk=pk))
@@ -54,7 +60,7 @@ class EasyField(object):
self.model, self.field = easy_model, field
def __repr__(self):
- return '<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name)
+ return smart_str(u'<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def choices(self):
for value, label in self.field.choices:
@@ -72,29 +78,32 @@ class EasyChoice(object):
self.value, self.label = value, label
def __repr__(self):
- return '<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name)
+ return smart_str(u'<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def url(self):
- return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, self.value)
+ return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
class EasyInstance(object):
def __init__(self, easy_model, instance):
self.model, self.instance = easy_model, instance
def __repr__(self):
- return '<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val())
+ return smart_str(u'<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
- def __str__(self):
- val = str(self.instance)
+ def __unicode__(self):
+ val = smart_unicode(self.instance)
if len(val) > 30:
- return val[:30] + '...'
+ return val[:30] + u'...'
return val
+ def __str__(self):
+ return self.__unicode__().encode('utf-8')
+
def pk(self):
return self.instance._get_pk_val()
def url(self):
- return '%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.pk())
+ return '%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk()))
def fields(self):
"""
@@ -126,7 +135,7 @@ class EasyInstanceField(object):
self.raw_value = getattr(instance.instance, field.name)
def __repr__(self):
- return '<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name)
+ return smart_str(u'<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def values(self):
"""
@@ -175,18 +184,32 @@ class EasyInstanceField(object):
if self.field.rel.to in self.model.model_list:
lst = []
for value in self.values():
- url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, value._get_pk_val())
- lst.append((str(value), url))
+ url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
+ lst.append((smart_unicode(value), url))
else:
lst = [(value, None) for value in self.values()]
elif self.field.choices:
lst = []
for value in self.values():
- url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, self.raw_value)
+ url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
lst.append((value, url))
elif isinstance(self.field, models.URLField):
val = self.values()[0]
- lst = [(val, val)]
+ lst = [(val, iri_to_uri(val))]
else:
lst = [(self.values()[0], None)]
return lst
+
+class EasyQuerySet(QuerySet):
+ """
+ When creating (or cloning to) an `EasyQuerySet`, make sure to set the
+ `_easymodel` variable to the related `EasyModel`.
+ """
+ def iterator(self, *args, **kwargs):
+ for obj in super(EasyQuerySet, self).iterator(*args, **kwargs):
+ yield EasyInstance(self._easymodel, obj)
+
+ def _clone(self, *args, **kwargs):
+ c = super(EasyQuerySet, self)._clone(*args, **kwargs)
+ c._easymodel = self._easymodel
+ return c
diff --git a/django/contrib/databrowse/plugins/calendars.py b/django/contrib/databrowse/plugins/calendars.py
index 7977524cdb..1b1a197290 100644
--- a/django/contrib/databrowse/plugins/calendars.py
+++ b/django/contrib/databrowse/plugins/calendars.py
@@ -6,6 +6,7 @@ from django.shortcuts import render_to_response
from django.utils.text import capfirst
from django.utils.translation import get_date_formats
from django.views.generic import date_based
+from django.utils.encoding import force_unicode
import datetime
import time
@@ -27,13 +28,13 @@ class CalendarPlugin(DatabrowsePlugin):
def model_index_html(self, request, model, site):
fields = self.field_dict(model)
if not fields:
- return ''
- return '<p class="filter"><strong>View calendar by:</strong> %s</p>' % \
- ', '.join(['<a href="calendars/%s/">%s</a>' % (f.name, capfirst(f.verbose_name)) for f in fields.values()])
+ return u''
+ return u'<p class="filter"><strong>View calendar by:</strong> %s</p>' % \
+ u', '.join(['<a href="calendars/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()])
def urls(self, plugin_name, easy_instance_field):
if isinstance(easy_instance_field.field, models.DateField):
- return ['%s%s/%s/%s/%s/%s/' % (easy_instance_field.model.url(),
+ return [u'%s%s/%s/%s/%s/%s/' % (easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
easy_instance_field.raw_value.year,
easy_instance_field.raw_value.strftime('%b').lower(),
@@ -63,22 +64,22 @@ class CalendarPlugin(DatabrowsePlugin):
def calendar_view(self, request, field, year=None, month=None, day=None):
easy_model = EasyModel(self.site, self.model)
+ queryset = easy_model.get_query_set()
extra_context = {'root_url': self.site.root_url, 'model': easy_model, 'field': field}
if day is not None:
- # TODO: The objects in this template should be EasyInstances
- return date_based.archive_day(request, year, month, day, self.model.objects.all(), field.name,
+ return date_based.archive_day(request, year, month, day, queryset, field.name,
template_name='databrowse/calendar_day.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
elif month is not None:
- return date_based.archive_month(request, year, month, self.model.objects.all(), field.name,
+ return date_based.archive_month(request, year, month, queryset, field.name,
template_name='databrowse/calendar_month.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
elif year is not None:
- return date_based.archive_year(request, year, self.model.objects.all(), field.name,
+ return date_based.archive_year(request, year, queryset, field.name,
template_name='databrowse/calendar_year.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
else:
- return date_based.archive_index(request, self.model.objects.all(), field.name,
+ return date_based.archive_index(request, queryset, field.name,
template_name='databrowse/calendar_main.html', allow_empty=True, allow_future=True,
extra_context=extra_context)
assert False, ('%s, %s, %s, %s' % (field, year, month, day))
diff --git a/django/contrib/databrowse/plugins/fieldchoices.py b/django/contrib/databrowse/plugins/fieldchoices.py
index 49d17ff148..a5dd07c639 100644
--- a/django/contrib/databrowse/plugins/fieldchoices.py
+++ b/django/contrib/databrowse/plugins/fieldchoices.py
@@ -4,9 +4,11 @@ from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
from django.utils.text import capfirst
+from django.utils.encoding import smart_str, force_unicode
from django.views.generic import date_based
import datetime
import time
+import urllib
class FieldChoicePlugin(DatabrowsePlugin):
def __init__(self, field_filter=None):
@@ -29,15 +31,16 @@ class FieldChoicePlugin(DatabrowsePlugin):
def model_index_html(self, request, model, site):
fields = self.field_dict(model)
if not fields:
- return ''
- return '<p class="filter"><strong>View by:</strong> %s</p>' % \
- ', '.join(['<a href="fields/%s/">%s</a>' % (f.name, capfirst(f.verbose_name)) for f in fields.values()])
+ return u''
+ return u'<p class="filter"><strong>View by:</strong> %s</p>' % \
+ u', '.join(['<a href="fields/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()])
def urls(self, plugin_name, easy_instance_field):
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
- return ['%s%s/%s/%s/' % (easy_instance_field.model.url(),
+ field_value = smart_str(easy_instance_field.raw_value)
+ return [u'%s%s/%s/%s/' % (easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
- easy_instance_field.raw_value)]
+ urllib.quote(field_value, safe=''))]
def model_view(self, request, model_databrowse, url):
self.model, self.site = model_databrowse.model, model_databrowse.site
diff --git a/django/contrib/databrowse/sites.py b/django/contrib/databrowse/sites.py
index 8521343e50..c07ec2129b 100644
--- a/django/contrib/databrowse/sites.py
+++ b/django/contrib/databrowse/sites.py
@@ -60,7 +60,7 @@ class ModelDatabrowse(object):
def main_view(self, request):
easy_model = EasyModel(self.site, self.model)
- html_snippets = '\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()])
+ html_snippets = u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()])
return render_to_response('databrowse/model_detail.html', {
'model': easy_model,
'root_url': self.site.root_url,
diff --git a/django/contrib/databrowse/templates/databrowse/base.html b/django/contrib/databrowse/templates/databrowse/base.html
index 30ba5bb2fc..a3419851c4 100644
--- a/django/contrib/databrowse/templates/databrowse/base.html
+++ b/django/contrib/databrowse/templates/databrowse/base.html
@@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
+{% block style %}
<style type="text/css">
* { margin:0; padding:0; }
body { background:#eee; color:#333; font:76%/1.6 "Lucida Grande","Bitstream Vera Sans",Verdana,sans-serif; }
@@ -48,9 +49,11 @@ p { margin:0.5em 0 1em 0; }
/* CONTENT */
#content { background:#fff; border-bottom:1px solid #ddd; padding:0 20px; }
</style>
+{% endblock %}
+{% block extrahead %}{% endblock %}
</head>
<body id="{% block bodyid %}page{% endblock %}">
-<div id="header"><a href="{{ root_url }}">Databrowse</a></div>
+<div id="header"><a href="{{ root_url }}">{% block databrowse_title %}Databrowse{% endblock %}</a></div>
<div id="content">
{% block content %}{% endblock %}
</div>
diff --git a/django/contrib/databrowse/templates/databrowse/base_site.html b/django/contrib/databrowse/templates/databrowse/base_site.html
new file mode 100644
index 0000000000..b577ab8427
--- /dev/null
+++ b/django/contrib/databrowse/templates/databrowse/base_site.html
@@ -0,0 +1 @@
+{% extends "databrowse/base.html" %}
diff --git a/django/contrib/databrowse/templates/databrowse/calendar_day.html b/django/contrib/databrowse/templates/databrowse/calendar_day.html
index d45fb3e768..b0f57e1eae 100644
--- a/django/contrib/databrowse/templates/databrowse/calendar_day.html
+++ b/django/contrib/databrowse/templates/databrowse/calendar_day.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} {{ day|date:"F j, Y" }}{% endblock %}
@@ -6,11 +6,11 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../../">Calendars</a> / <a href="../../../">By {{ field.verbose_name }}</a> / <a href="../../">{{ day.year }}</a> / <a href="../">{{ day|date:"F" }}</a> / {{ day.day }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
-<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
+<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/calendar_homepage.html b/django/contrib/databrowse/templates/databrowse/calendar_homepage.html
index 5bbc42e353..daf45dfdeb 100644
--- a/django/contrib/databrowse/templates/databrowse/calendar_homepage.html
+++ b/django/contrib/databrowse/templates/databrowse/calendar_homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Calendars{% endblock %}
diff --git a/django/contrib/databrowse/templates/databrowse/calendar_main.html b/django/contrib/databrowse/templates/databrowse/calendar_main.html
index 7f9ba03bbe..18ee5bdc8b 100644
--- a/django/contrib/databrowse/templates/databrowse/calendar_main.html
+++ b/django/contrib/databrowse/templates/databrowse/calendar_main.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ field.verbose_name|capfirst }} calendar{% endblock %}
diff --git a/django/contrib/databrowse/templates/databrowse/calendar_month.html b/django/contrib/databrowse/templates/databrowse/calendar_month.html
index 51a25967f8..67506f452f 100644
--- a/django/contrib/databrowse/templates/databrowse/calendar_month.html
+++ b/django/contrib/databrowse/templates/databrowse/calendar_month.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ month|date:"F Y" }}{% endblock %}
@@ -6,11 +6,11 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../">Calendars</a> / <a href="../../">By {{ field.verbose_name }}</a> / <a href="../">{{ month.year }}</a> / {{ month|date:"F" }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ month|date:"F Y" }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
-<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
+<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/calendar_year.html b/django/contrib/databrowse/templates/databrowse/calendar_year.html
index 676ae88e27..729c2ddf3b 100644
--- a/django/contrib/databrowse/templates/databrowse/calendar_year.html
+++ b/django/contrib/databrowse/templates/databrowse/calendar_year.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ year }}{% endblock %}
diff --git a/django/contrib/databrowse/templates/databrowse/choice_detail.html b/django/contrib/databrowse/templates/databrowse/choice_detail.html
index 977a4a482f..e6add55021 100644
--- a/django/contrib/databrowse/templates/databrowse/choice_detail.html
+++ b/django/contrib/databrowse/templates/databrowse/choice_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}: {{ value|escape }}{% endblock %}
@@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
-<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
+<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/choice_list.html b/django/contrib/databrowse/templates/databrowse/choice_list.html
index b15531a0fd..07a1319459 100644
--- a/django/contrib/databrowse/templates/databrowse/choice_list.html
+++ b/django/contrib/databrowse/templates/databrowse/choice_list.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}{% endblock %}
@@ -10,7 +10,7 @@
<ul class="objectlist">
{% for choice in field.choices %}
-<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label }}</a></li>
+<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html b/django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
index a620ec931c..d1c8b877cb 100644
--- a/django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
+++ b/django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst|escape }} with {{ field.field.verbose_name|escape }} {{ value|escape }}{% endblock %}
@@ -6,7 +6,7 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../">Fields</a> / <a href="../">By {{ field.field.verbose_name|escape }}</a> / {{ value|escape }}</div>
-<h1>{{ model.verbose_name_plural|capfirst|escape }} with {{ field.field.verbose_name|escape }} {{ value|escape }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.field.verbose_name|escape }} {{ value|escape }}</h1>
<ul class="objectlist">
{% for object in object_list %}
diff --git a/django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html b/django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
index ad842c1e6d..8760bd4ad1 100644
--- a/django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
+++ b/django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Browsable fields in {{ model.verbose_name_plural|escape }}{% endblock %}
diff --git a/django/contrib/databrowse/templates/databrowse/fieldchoice_list.html b/django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
index 686e6bc533..9f41213a6f 100644
--- a/django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
+++ b/django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst|escape }} by {{ field.field.verbose_name|escape }}{% endblock %}
@@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
-<li class="{% cycle odd,even %}"><a href="{{ object }}/">{{ object|escape }}</a></li>
+<li class="{% cycle odd,even %}"><a href="{{ object|iriencode }}/">{{ object|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/homepage.html b/django/contrib/databrowse/templates/databrowse/homepage.html
index ebf3ceca80..104a804253 100644
--- a/django/contrib/databrowse/templates/databrowse/homepage.html
+++ b/django/contrib/databrowse/templates/databrowse/homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Databrowse{% endblock %}
@@ -11,7 +11,7 @@
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
<p>
{% for object in model.sample_objects %}
- <a href="{{ object.url }}">{{ object }}</a>,
+ <a href="{{ object.url }}">{{ object|escape }}</a>,
{% endfor %}
<a class="more" href="{{ model.url }}">More &rarr;</a>
</p>
diff --git a/django/contrib/databrowse/templates/databrowse/model_detail.html b/django/contrib/databrowse/templates/databrowse/model_detail.html
index 24cd766a3d..2084b18ca7 100644
--- a/django/contrib/databrowse/templates/databrowse/model_detail.html
+++ b/django/contrib/databrowse/templates/databrowse/model_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }}{% endblock %}
@@ -6,13 +6,13 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / {{ model.verbose_name_plural|capfirst }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }}</h1>
+<h1>{{ model.objects.count }} {% if model.objects.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %}</h1>
{{ plugin_html }}
<ul class="objectlist">
{% for object in model.objects %}
- <li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
+ <li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
diff --git a/django/contrib/databrowse/templates/databrowse/object_detail.html b/django/contrib/databrowse/templates/databrowse/object_detail.html
index 2195ad3080..e9977743fd 100644
--- a/django/contrib/databrowse/templates/databrowse/object_detail.html
+++ b/django/contrib/databrowse/templates/databrowse/object_detail.html
@@ -1,12 +1,12 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ object.model.verbose_name|capfirst }}: {{ object }}{% endblock %}
{% block content %}
-<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ object.model.url }}">{{ object.model.verbose_name_plural|capfirst }}</a> / {{ object }}</div>
+<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ object.model.url }}">{{ object.model.verbose_name_plural|capfirst }}</a> / {{ object|escape }}</div>
-<h1>{{ object.model.verbose_name|capfirst }}: {{ object }}</h1>
+<h1>{{ object.model.verbose_name|capfirst }}: {{ object|escape }}</h1>
<table class="objectinfo">
{% for field in object.fields %}
@@ -14,8 +14,8 @@
<th>{{ field.field.verbose_name|capfirst }}</th>
<td>
{% if field.urls %}
-{% for urlvalue in field.urls %}
-{% if urlvalue.1 %}<a href="{{ urlvalue.1 }}">{% endif %}{{ urlvalue.0 }}{% if urlvalue.1 %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
+{% for value, url in field.urls %}
+{% if url %}<a href="{{ url }}">{% endif %}{{ value|escape }}{% if url %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
{% endfor %}
{% else %}None{% endif %}
</td>
@@ -29,7 +29,7 @@
{% if related_object.object_list %}
<ul class="objectlist">
{% for object in related_object.object_list %}
- <li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
+ <li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
{% else %}
diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py
index 8d0b2c0d90..36327c80c3 100644
--- a/django/contrib/flatpages/models.py
+++ b/django/contrib/flatpages/models.py
@@ -1,15 +1,15 @@
from django.core import validators
from django.db import models
from django.contrib.sites.models import Site
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
class FlatPage(models.Model):
- url = models.CharField(_('URL'), maxlength=100, validator_list=[validators.isAlphaNumericURL], db_index=True,
+ url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True,
help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes."))
- title = models.CharField(_('title'), maxlength=200)
+ title = models.CharField(_('title'), max_length=200)
content = models.TextField(_('content'))
enable_comments = models.BooleanField(_('enable comments'))
- template_name = models.CharField(_('template name'), maxlength=70, blank=True,
+ template_name = models.CharField(_('template name'), max_length=70, blank=True,
help_text=_("Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."))
registration_required = models.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page."))
sites = models.ManyToManyField(Site)
@@ -26,8 +26,8 @@ class FlatPage(models.Model):
list_filter = ('sites',)
search_fields = ('url', 'title')
- def __str__(self):
- return "%s -- %s" % (self.url, self.title)
+ def __unicode__(self):
+ return u"%s -- %s" % (self.url, self.title)
def get_absolute_url(self):
return self.url
diff --git a/django/contrib/gis/db/backend/__init__.py b/django/contrib/gis/db/backend/__init__.py
index 514a9e02d6..06a5d3e736 100644
--- a/django/contrib/gis/db/backend/__init__.py
+++ b/django/contrib/gis/db/backend/__init__.py
@@ -12,9 +12,10 @@
additional spatial databases.
"""
from django.conf import settings
-from django.db import backend
+from django.db import connection
from django.db.models.query import LOOKUP_SEPARATOR, field_choices, find_field, FieldFound, QUERY_TERMS, get_where_clause
from django.utils.datastructures import SortedDict
+qn = connection.ops.quote_name
if settings.DATABASE_ENGINE == 'postgresql_psycopg2':
# PostGIS is the spatial database, getting the rquired modules, renaming as necessary.
@@ -89,7 +90,6 @@ def parse_lookup(kwarg_items, opts):
return joins, where, params
def lookup_inner(path, lookup_type, value, opts, table, column):
- qn = backend.quote_name
joins, where, params = SortedDict(), [], []
current_opts = opts
current_table = table
@@ -216,6 +216,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
else:
# No elements left in path. Current element is the element on which
# the search is being performed.
+ db_type = None
if join_required:
# Last query term is a RelatedObject
@@ -282,7 +283,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
where.append(gwc)
params.extend(geo_params)
else:
- where.append(get_where_clause(lookup_type, current_table + '.', column, value))
+ where.append(get_where_clause(lookup_type, current_table + '.', column, value, db_type))
params.extend(field.get_db_prep_lookup(lookup_type, value))
return joins, where, params
diff --git a/django/contrib/gis/db/backend/postgis/creation.py b/django/contrib/gis/db/backend/postgis/creation.py
index 0fa618b4df..dfd62a841e 100644
--- a/django/contrib/gis/db/backend/postgis/creation.py
+++ b/django/contrib/gis/db/backend/postgis/creation.py
@@ -1,6 +1,6 @@
from django.conf import settings
-from django.core.management import syncdb
-from django.db import connection, backend
+from django.core.management import call_command
+from django.db import connection
from django.test.utils import _set_autocommit, TEST_DATABASE_PREFIX
from commands import getstatusoutput
import os, re, sys
@@ -22,14 +22,13 @@ def create_lang(db_name, verbosity=1):
# Checking the status of the command, 0 => execution successful
if status != 0:
raise Exception, "Error executing 'plpgsql' command: %s\n" % output
-
def _create_with_cursor(db_name, verbosity=1, autoclobber=False):
"Creates database with psycopg2 cursor."
# Constructing the necessary SQL to create the database (the DATABASE_USER
# must possess the privileges to create a database)
- create_sql = 'CREATE DATABASE %s OWNER %s' % (backend.quote_name(db_name),
+ create_sql = 'CREATE DATABASE %s OWNER %s' % (connection.ops.quote_name(db_name),
settings.DATABASE_USER)
cursor = connection.cursor()
_set_autocommit(connection)
@@ -113,7 +112,7 @@ def create_spatial_db(test=False, verbosity=1, autoclobber=False, interactive=Fa
settings.DATABASE_NAME = db_name
# Syncing the database
- syncdb(verbosity, interactive=interactive)
+ call_command('syncdb', verbosity=verbosity, interactive=interactive)
# Get a cursor (even though we don't need one yet). This has
# the side effect of initializing the test database.
@@ -123,7 +122,7 @@ def drop_db(db_name=False, test=False):
"Using the cursor, drops the given database. All exceptions will be propagated up."
if not db_name: db_name = get_spatial_db(test=test)
cursor = connection.cursor()
- cursor.execute("DROP DATABASE %s" % backend.quote_name(db_name))
+ cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(db_name))
def get_cmd_options(db_name):
"Obtains the command-line PostgreSQL connection options for shell commands."
diff --git a/django/contrib/gis/db/backend/postgis/query.py b/django/contrib/gis/db/backend/postgis/query.py
index 3dbba3ceb2..4979e5b1c9 100644
--- a/django/contrib/gis/db/backend/postgis/query.py
+++ b/django/contrib/gis/db/backend/postgis/query.py
@@ -2,9 +2,10 @@
This module contains the spatial lookup types, and the get_geo_where_clause()
routine for PostGIS.
"""
-from django.db import backend
+from django.db import connection
from django.contrib.gis.db.backend.postgis.management import postgis_version_tuple
from types import StringType, UnicodeType
+quote_name = connection.ops.quote_name
# Getting the PostGIS version information
POSTGIS_VERSION, MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2 = postgis_version_tuple()
@@ -120,8 +121,8 @@ def get_geom_func(lookup_type):
def get_geo_where_clause(lookup_type, table_prefix, field_name, value):
"Returns the SQL WHERE clause for use in PostGIS SQL construction."
if table_prefix.endswith('.'):
- table_prefix = backend.quote_name(table_prefix[:-1])+'.'
- field_name = backend.quote_name(field_name)
+ table_prefix = quote_name(table_prefix[:-1])+'.'
+ field_name = quote_name(field_name)
# See if a PostGIS operator matches the lookup type first
try:
diff --git a/django/contrib/gis/db/models/fields/__init__.py b/django/contrib/gis/db/models/fields/__init__.py
index e004d3bbea..8d329fd97c 100644
--- a/django/contrib/gis/db/models/fields/__init__.py
+++ b/django/contrib/gis/db/models/fields/__init__.py
@@ -45,6 +45,11 @@ class GeometryField(GeoBackendField):
def get_internal_type(self):
return "NoField"
+
+ def db_type(self):
+ # Geometry columns are added by stored procedures, and thus should
+ # be None.
+ return None
def get_manipulator_field_objs(self):
"Using the WKTField (defined above) to be our manipulator."
diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py
index 8c1cba3c45..b8d77da94f 100644
--- a/django/contrib/gis/db/models/query.py
+++ b/django/contrib/gis/db/models/query.py
@@ -1,6 +1,6 @@
import operator
from django.core.exceptions import ImproperlyConfigured
-from django.db import backend
+from django.db import connection
from django.db.models.query import Q, QuerySet, handle_legacy_orderlist, quote_only_if_word
from django.db.models.fields import FieldDoesNotExist
from django.utils.datastructures import SortedDict
@@ -16,6 +16,8 @@ class GeoQ(Q):
class GeoQuerySet(QuerySet):
"Geographical-enabled QuerySet object."
+
+ quote_name = connection.ops.quote_name
#### Overloaded QuerySet Routines ####
def __init__(self, model=None):
@@ -79,10 +81,10 @@ class GeoQuerySet(QuerySet):
# Add any additional SELECTs.
if self._select:
- select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
+ select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), self.quote_name(s[0])) for s in self._select.items()])
# Start composing the body of the SQL statement.
- sql = [" FROM", backend.quote_name(opts.db_table)]
+ sql = [" FROM", self.quote_name(opts.db_table)]
# Compose the join dictionary into SQL describing the joins.
if joins:
@@ -115,15 +117,15 @@ class GeoQuerySet(QuerySet):
order = "ASC"
if "." in col_name:
table_prefix, col_name = col_name.split('.', 1)
- table_prefix = backend.quote_name(table_prefix) + '.'
+ table_prefix = self.quote_name(table_prefix) + '.'
else:
# Use the database table as a column prefix if it wasn't given,
# and if the requested column isn't a custom SELECT.
if "." not in col_name and col_name not in (self._select or ()):
- table_prefix = backend.quote_name(opts.db_table) + '.'
+ table_prefix = self.quote_name(opts.db_table) + '.'
else:
table_prefix = ''
- order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
+ order_by.append('%s%s %s' % (table_prefix, self.quote_name(orderfield2column(col_name, opts)), order))
if order_by:
sql.append("ORDER BY " + ", ".join(order_by))
@@ -142,8 +144,8 @@ class GeoQuerySet(QuerySet):
#### Methods specific to the GeoQuerySet ####
def _field_column(self, field):
- return "%s.%s" % (backend.quote_name(self.model._meta.db_table),
- backend.quote_name(field.column))
+ return "%s.%s" % (self.quote_name(self.model._meta.db_table),
+ self.quote_name(field.column))
def kml(self, field_name, precision=8):
"""Returns KML representation of the given field name in a `kml`
@@ -174,7 +176,7 @@ class GeoQuerySet(QuerySet):
# override the geometry column returned from the database.
self._custom_select[field.column] = \
'(ST_Transform(%s, %s)) AS %s' % (self._field_column(field), srid,
- backend.quote_name(field.column))
+ self.quote_name(field.column))
return self._clone()
diff --git a/django/contrib/gis/gdal/srs.py b/django/contrib/gis/gdal/srs.py
index d5639f1b0a..08b9381eb0 100644
--- a/django/contrib/gis/gdal/srs.py
+++ b/django/contrib/gis/gdal/srs.py
@@ -1,6 +1,6 @@
# Getting what we need from ctypes
import re
-from types import StringType, TupleType
+from types import StringType, UnicodeType, TupleType
from ctypes import \
c_char_p, c_int, c_double, c_void_p, POINTER, \
byref, string_at, create_string_buffer
@@ -84,6 +84,9 @@ class SpatialReference(object):
# Creating an initial empty string buffer.
buf = c_char_p('')
+ if isinstance(input, UnicodeType):
+ input = input.encode('ascii')
+
if isinstance(input, StringType):
# Is this an EPSG well known name?
m = self._epsg_regex.match(input)
@@ -113,7 +116,7 @@ class SpatialReference(object):
# If the pointer is NULL, throw an exception.
if not srs:
- raise SRSException, 'Could not create spatial reference from WKT!'
+ raise SRSException, 'Could not create spatial reference from WKT! (%s)' % input
else:
self._srs = srs
@@ -304,6 +307,7 @@ class SpatialReference(object):
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
return string_at(w)
+ @property
def proj4(self):
"Alias for proj()."
return self.proj
diff --git a/django/contrib/gis/models.py b/django/contrib/gis/models.py
index bfcd10c8f3..ad3d68d40d 100644
--- a/django/contrib/gis/models.py
+++ b/django/contrib/gis/models.py
@@ -42,7 +42,7 @@ class SpatialRefSys(models.Model):
auth_name = models.CharField(maxlength=256)
auth_srid = models.IntegerField()
srtext = models.CharField(maxlength=2048)
- proj4 = models.CharField(maxlength=2048, db_column='proj4text')
+ proj4text = models.CharField(maxlength=2048)
class Meta:
db_table = 'spatial_ref_sys'
@@ -55,17 +55,17 @@ class SpatialRefSys(models.Model):
try:
self._srs = SpatialReference(self.srtext, 'wkt')
return
- except:
+ except Exception, msg:
pass
# Trying the proj4 text next
try:
- self._srs = SpatialReference(self.proj4, 'proj4')
+ self._srs = SpatialReference(self.proj4text, 'proj4')
return
- except:
+ except Exception, msg:
pass
- raise Exception, 'Could not get a OSR Spatial Reference.'
+ raise Exception, 'Could not get a OSR Spatial Reference: %s' % msg
else:
raise Exception, 'GDAL is not installed!'
diff --git a/django/contrib/gis/tests/__init__.py b/django/contrib/gis/tests/__init__.py
index 5b95df99e2..efe356d8e5 100644
--- a/django/contrib/gis/tests/__init__.py
+++ b/django/contrib/gis/tests/__init__.py
@@ -25,7 +25,7 @@ def run(verbosity=1):
"Runs the tests that do not require geographic (GEOS, GDAL, etc.) models."
TextTestRunner(verbosity=verbosity).run(suite())
-def run_tests(module_list, verbosity=1):
+def run_tests(module_list, verbosity=1, interactive=True):
"""Run the tests that require creation of a spatial database. Does not
yet work on Windows platforms.
diff --git a/django/contrib/gis/tests/test_spatialrefsys.py b/django/contrib/gis/tests/test_spatialrefsys.py
index a5bd10a328..554f55175f 100644
--- a/django/contrib/gis/tests/test_spatialrefsys.py
+++ b/django/contrib/gis/tests/test_spatialrefsys.py
@@ -29,11 +29,11 @@ class SpatialRefSysTest(unittest.TestCase):
"Testing retrieval of SpatialRefSys model objects."
for sd in test_srs:
srs = SpatialRefSys.objects.get(srid=sd['srid'])
- self.assertEqual(srs.srid, sd['srid'])
- self.assertEqual(srs.auth_name, sd['auth_name'])
- self.assertEqual(srs.auth_srid, sd['auth_srid'])
- self.assertEqual(srs.srtext, sd['srtext'])
- self.assertEqual(srs.proj4, sd['proj4'])
+ self.assertEqual(sd['srid'], srs.srid)
+ self.assertEqual(sd['auth_name'], srs.auth_name)
+ self.assertEqual(sd['auth_srid'], srs.auth_srid)
+ self.assertEqual(sd['srtext'], srs.srtext)
+ self.assertEqual(sd['proj4'], srs.proj4text)
def test02_osr(self):
"Testing getting OSR objects from SpatialRefSys model objects."
@@ -46,11 +46,12 @@ class SpatialRefSysTest(unittest.TestCase):
# Testing the SpatialReference object directly.
srs = sr.srs
- self.assertEqual(sd['proj4'], srs.proj)
+ self.assertEqual(sd['proj4'], srs.proj4)
self.assertEqual(sd['srtext'], srs.wkt)
def test03_ellipsoid(self):
"Testing the ellipsoid property."
+ return
for sd in test_srs:
# Getting the ellipsoid and precision parameters.
ellps1 = sd['ellipsoid']
diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py
index a16cbcc9bb..19591606f9 100644
--- a/django/contrib/humanize/templatetags/humanize.py
+++ b/django/contrib/humanize/templatetags/humanize.py
@@ -1,6 +1,9 @@
-from django.utils.translation import ngettext
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ungettext, ugettext as _
+from django.utils.encoding import force_unicode
from django import template
+from django.template import defaultfilters
+from django.conf import settings
+from datetime import date, timedelta
import re
register = template.Library()
@@ -16,8 +19,8 @@ def ordinal(value):
return value
t = (_('th'), _('st'), _('nd'), _('rd'), _('th'), _('th'), _('th'), _('th'), _('th'), _('th'))
if value % 100 in (11, 12, 13): # special case
- return "%d%s" % (value, t[0])
- return '%d%s' % (value, t[value % 10])
+ return u"%d%s" % (value, t[0])
+ return u'%d%s' % (value, t[value % 10])
register.filter(ordinal)
def intcomma(value):
@@ -25,8 +28,8 @@ def intcomma(value):
Converts an integer to a string containing commas every three digits.
For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
"""
- orig = str(value)
- new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
+ orig = force_unicode(value)
+ new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
if orig == new:
return new
else:
@@ -44,13 +47,13 @@ def intword(value):
return value
if value < 1000000000:
new_value = value / 1000000.0
- return ngettext('%(value).1f million', '%(value).1f million', new_value) % {'value': new_value}
+ return ungettext('%(value).1f million', '%(value).1f million', new_value) % {'value': new_value}
if value < 1000000000000:
new_value = value / 1000000000.0
- return ngettext('%(value).1f billion', '%(value).1f billion', new_value) % {'value': new_value}
+ return ungettext('%(value).1f billion', '%(value).1f billion', new_value) % {'value': new_value}
if value < 1000000000000000:
new_value = value / 1000000000000.0
- return ngettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value}
+ return ungettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value}
return value
register.filter(intword)
@@ -67,3 +70,27 @@ def apnumber(value):
return value
return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
register.filter(apnumber)
+
+def naturalday(value, arg=None):
+ """
+ For date values that are tomorrow, today or yesterday compared to
+ present day returns representing string. Otherwise, returns a string
+ formatted according to settings.DATE_FORMAT.
+ """
+ try:
+ value = date(value.year, value.month, value.day)
+ except AttributeError:
+ # Passed value wasn't a date object
+ return value
+ except ValueError:
+ # Date arguments out of range
+ return value
+ delta = value - date.today()
+ if delta.days == 0:
+ return _(u'today')
+ elif delta.days == 1:
+ return _(u'tomorrow')
+ elif delta.days == -1:
+ return _(u'yesterday')
+ return defaultfilters.date(value, arg)
+register.filter(naturalday)
diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py
index b81a903d13..33e883511b 100644
--- a/django/contrib/localflavor/au/forms.py
+++ b/django/contrib/localflavor/au/forms.py
@@ -5,7 +5,7 @@ Australian-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.newforms.util import smart_unicode
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
PHONE_DIGITS_RE = re.compile(r'^(\d{10})$')
@@ -15,14 +15,14 @@ class AUPostCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(AUPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a 4 digit post code.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a 4 digit post code.'),
+ *args, **kwargs)
class AUPhoneNumberField(Field):
"""Australian phone number field."""
def clean(self, value):
- """Validate a phone number. Strips parentheses, whitespace and
- hyphens.
+ """
+ Validate a phone number. Strips parentheses, whitespace and hyphens.
"""
super(AUPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@@ -39,5 +39,5 @@ class AUStateSelect(Select):
choices.
"""
def __init__(self, attrs=None):
- from au_states import STATE_CHOICES # relative import
+ from au_states import STATE_CHOICES
super(AUStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py
index 3487787643..c7082c0f9e 100644
--- a/django/contrib/localflavor/br/forms.py
+++ b/django/contrib/localflavor/br/forms.py
@@ -6,7 +6,7 @@ BR-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
@@ -15,8 +15,8 @@ class BRZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
max_length=None, min_length=None,
- error_message=gettext('Enter a zip code in the format XXXXX-XXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXXX-XXX.'),
+ *args, **kwargs)
class BRPhoneNumberField(Field):
def clean(self, value):
@@ -27,7 +27,7 @@ class BRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
- raise ValidationError(gettext(u'Phone numbers must be in XX-XXXX-XXXX format.'))
+ raise ValidationError(ugettext('Phone numbers must be in XX-XXXX-XXXX format.'))
class BRStateSelect(Select):
"""
@@ -35,7 +35,7 @@ class BRStateSelect(Select):
as its choices.
"""
def __init__(self, attrs=None):
- from br_states import STATE_CHOICES # relative import
+ from br_states import STATE_CHOICES
super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
@@ -69,9 +69,9 @@ class BRCPFField(CharField):
try:
int(value)
except ValueError:
- raise ValidationError(gettext("This field requires only numbers."))
+ raise ValidationError(ugettext("This field requires only numbers."))
if len(value) != 11:
- raise ValidationError(gettext("This field requires at most 11 digits or 14 characters."))
+ raise ValidationError(ugettext("This field requires at most 11 digits or 14 characters."))
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
@@ -81,7 +81,7 @@ class BRCPFField(CharField):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
- raise ValidationError(gettext("Invalid CPF number."))
+ raise ValidationError(ugettext("Invalid CPF number."))
return orig_value
@@ -103,7 +103,7 @@ class BRCNPJField(Field):
raise ValidationError("This field requires only numbers.")
if len(value) != 14:
raise ValidationError(
- gettext("This field requires at least 14 digits"))
+ ugettext("This field requires at least 14 digits"))
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
@@ -113,7 +113,7 @@ class BRCNPJField(Field):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
- raise ValidationError(gettext("Invalid CNPJ number."))
+ raise ValidationError(ugettext("Invalid CNPJ number."))
return orig_value
diff --git a/django/contrib/localflavor/ch/ch_states.py b/django/contrib/localflavor/ch/ch_states.py
index e9bbcc6268..ba5934a4d4 100644
--- a/django/contrib/localflavor/ch/ch_states.py
+++ b/django/contrib/localflavor/ch/ch_states.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
STATE_CHOICES = (
('AG', _('Aargau')),
diff --git a/django/contrib/localflavor/ch/forms.py b/django/contrib/localflavor/ch/forms.py
index 51e52dc0e9..5e601f5d74 100644
--- a/django/contrib/localflavor/ch/forms.py
+++ b/django/contrib/localflavor/ch/forms.py
@@ -5,7 +5,7 @@ Swiss-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$")
@@ -15,7 +15,7 @@ class CHZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(CHZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
- error_message=gettext('Enter a zip code in the format XXXX.'),
+ error_message=ugettext('Enter a zip code in the format XXXX.'),
*args, **kwargs)
class CHPhoneNumberField(Field):
@@ -87,7 +87,7 @@ class CHIdentityCardNumberField(Field):
def clean(self, value):
super(CHIdentityCardNumberField, self).clean(value)
- error_msg = gettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
+ error_msg = ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
if value in EMPTY_VALUES:
return u''
diff --git a/django/contrib/localflavor/cl/cl_regions.py b/django/contrib/localflavor/cl/cl_regions.py
new file mode 100644
index 0000000000..47db6d3912
--- /dev/null
+++ b/django/contrib/localflavor/cl/cl_regions.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+"""
+A list of Chilean regions as `choices` in a formfield.
+
+This exists in this standalone file so that it's only imported into memory
+when explicitly needed.
+"""
+
+REGION_CHOICES = (
+ ('RM', u'Región Metropolitana de Santiago'),
+ ('I', u'Región de Tarapacá'),
+ ('II', u'Región de Antofagasta'),
+ ('III', u'Región de Atacama'),
+ ('IV', u'Región de Coquimbo'),
+ ('V', u'Región de Valparaíso'),
+ ('VI', u'Región del Libertador Bernardo O\'Higgins'),
+ ('VII', u'Región del Maule'),
+ ('VIII',u'Región del Bío Bío'),
+ ('IX', u'Región de la Araucanía'),
+ ('X', u'Región de los Lagos'),
+ ('XI', u'Región de Aysén del General Carlos Ibáñez del Campo'),
+ ('XII', u'Región de Magallanes y la Antártica Chilena'),
+ ('XIV', u'Región de Los Ríos'),
+ ('XV', u'Región de Arica-Parinacota'),
+)
diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py
index 87c8093407..d2d37a3712 100644
--- a/django/contrib/localflavor/cl/forms.py
+++ b/django/contrib/localflavor/cl/forms.py
@@ -3,8 +3,19 @@ Chile specific form helpers.
"""
from django.newforms import ValidationError
-from django.newforms.fields import RegexField, EMPTY_VALUES
-from django.utils.translation import gettext
+from django.newforms.fields import RegexField, Select, EMPTY_VALUES
+from django.utils.translation import ugettext
+from django.utils.encoding import smart_unicode
+
+
+class CLRegionSelect(Select):
+ """
+ A Select widget that uses a list of Chilean Regions (Regiones)
+ as its choices.
+ """
+ def __init__(self, attrs=None):
+ from cl_regions import REGION_CHOICES
+ super(CLRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
class CLRutField(RegexField):
"""
@@ -18,12 +29,12 @@ class CLRutField(RegexField):
if 'strict' in kwargs:
del kwargs['strict']
super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
- error_message=gettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
- *args, **kwargs)
+ error_message=ugettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
+ *args, **kwargs)
else:
# In non-strict mode, accept RUTs that validate but do not exist in
# the real world.
- super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=gettext(u'Enter valid a Chilean RUT'), *args, **kwargs)
+ super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=ugettext('Enter valid a Chilean RUT'), *args, **kwargs)
def clean(self, value):
"""
@@ -49,14 +60,14 @@ class CLRutField(RegexField):
multi += 1
if multi == 8:
multi = 2
- return '0123456789K0'[11 - suma % 11]
+ return u'0123456789K0'[11 - suma % 11]
def _canonify(self, rut):
"""
Turns the RUT into one normalized format. Returns a (rut, verifier)
tuple.
"""
- rut = str(rut).replace(' ', '').replace('.', '').replace('-', '')
+ rut = smart_unicode(rut).replace(' ', '').replace('.', '').replace('-', '')
return rut[:-1], rut[-1]
def _format(self, code, verifier=None):
@@ -74,5 +85,5 @@ class CLRutField(RegexField):
else:
new_dot = pos - 3
code = code[:new_dot] + '.' + code[new_dot:]
- return '%s-%s' % (code, verifier)
+ return u'%s-%s' % (code, verifier)
diff --git a/django/contrib/localflavor/de/de_states.py b/django/contrib/localflavor/de/de_states.py
index c00fd2e293..2872a7871a 100644
--- a/django/contrib/localflavor/de/de_states.py
+++ b/django/contrib/localflavor/de/de_states.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
STATE_CHOICES = (
('BW', _('Baden-Wuerttemberg')),
diff --git a/django/contrib/localflavor/de/forms.py b/django/contrib/localflavor/de/forms.py
index 8e140c125f..1a0b8587a6 100644
--- a/django/contrib/localflavor/de/forms.py
+++ b/django/contrib/localflavor/de/forms.py
@@ -4,7 +4,7 @@ DE-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
id_re = re.compile(r"^(?P<residence>\d{10})(?P<origin>\w{1,3})[-\ ]?(?P<birthday>\d{7})[-\ ]?(?P<validity>\d{7})[-\ ]?(?P<checksum>\d{1})$")
@@ -13,15 +13,15 @@ class DEZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(DEZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXXX.'),
+ *args, **kwargs)
class DEStateSelect(Select):
"""
A Select widget that uses a list of DE states as its choices.
"""
def __init__(self, attrs=None):
- from de_states import STATE_CHOICES # relative import
+ from de_states import STATE_CHOICES
super(DEStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
class DEIdentityCardNumberField(Field):
@@ -57,7 +57,7 @@ class DEIdentityCardNumberField(Field):
def clean(self, value):
super(DEIdentityCardNumberField, self).clean(value)
- error_msg = gettext(u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.')
+ error_msg = ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.')
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
@@ -71,7 +71,7 @@ class DEIdentityCardNumberField(Field):
if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
raise ValidationError(error_msg)
- all_digits = "%s%s%s%s" % (residence, birthday, validity, checksum)
+ all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
raise ValidationError(error_msg)
diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py
index da5cb5f2a8..82e024f7b1 100644
--- a/django/contrib/localflavor/fi/forms.py
+++ b/django/contrib/localflavor/fi/forms.py
@@ -5,21 +5,21 @@ FI-specific Form helpers
import re
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
class FIZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(FIZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXXX.'),
+ *args, **kwargs)
class FIMunicipalitySelect(Select):
"""
A Select widget that uses a list of Finnish municipalities as its choices.
"""
def __init__(self, attrs=None):
- from fi_municipalities import MUNICIPALITY_CHOICES # relative import
+ from fi_municipalities import MUNICIPALITY_CHOICES
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
class FISocialSecurityNumber(Field):
@@ -37,9 +37,9 @@ class FISocialSecurityNumber(Field):
(?P<serial>(\d{3}))
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
if not result:
- raise ValidationError(gettext(u'Enter a valid Finnish social security number.'))
+ raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
gd = result.groupdict()
checksum = int(gd['date'] + gd['serial'])
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
return u'%s' % value.upper()
- raise ValidationError(gettext(u'Enter a valid Finnish social security number.'))
+ raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
diff --git a/django/contrib/localflavor/fr/forms.py b/django/contrib/localflavor/fr/forms.py
index 550596b880..cc0a5db259 100644
--- a/django/contrib/localflavor/fr/forms.py
+++ b/django/contrib/localflavor/fr/forms.py
@@ -5,7 +5,7 @@ FR-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
@@ -14,8 +14,8 @@ class FRZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(FRZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXXX.'),
+ *args, **kwargs)
class FRPhoneNumberField(Field):
"""
@@ -39,6 +39,6 @@ class FRDepartmentSelect(Select):
A Select widget that uses a list of FR departments as its choices.
"""
def __init__(self, attrs=None):
- from fr_department import DEPARTMENT_ASCII_CHOICES # relative import
+ from fr_department import DEPARTMENT_ASCII_CHOICES
super(FRDepartmentSelect, self).__init__(attrs, choices=DEPARTMENT_ASCII_CHOICES)
diff --git a/django/contrib/localflavor/in_/__init__.py b/django/contrib/localflavor/in_/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/localflavor/in_/__init__.py
diff --git a/django/contrib/localflavor/in_/forms.py b/django/contrib/localflavor/in_/forms.py
new file mode 100644
index 0000000000..5febc40e67
--- /dev/null
+++ b/django/contrib/localflavor/in_/forms.py
@@ -0,0 +1,49 @@
+"""
+India-specific Form helpers.
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.utils.encoding import smart_unicode
+from django.utils.translation import gettext
+import re
+
+
+class INZipCodeField(RegexField):
+ def __init__(self, *args, **kwargs):
+ super(INZipCodeField, self).__init__(r'^\d{6}$',
+ max_length=None, min_length=None,
+ error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
+ *args, **kwargs)
+
+class INStateField(Field):
+ """
+ A form field that validates its input is a Indian state name or
+ abbreviation. It normalizes the input to the standard two-letter vehicle
+ registration abbreviation for the given state or union territory
+ """
+ def clean(self, value):
+ from in_states import STATES_NORMALIZED
+ super(INStateField, self).clean(value)
+ if value in EMPTY_VALUES:
+ return u''
+ try:
+ value = value.strip().lower()
+ except AttributeError:
+ pass
+ else:
+ try:
+ return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
+ except KeyError:
+ pass
+ raise ValidationError(u'Enter a Indian state or territory.')
+
+class INStateSelect(Select):
+ """
+ A Select widget that uses a list of Indian states/territories as its
+ choices.
+ """
+ def __init__(self, attrs=None):
+ from in_states import STATE_CHOICES
+ super(INStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
+
diff --git a/django/contrib/localflavor/in_/in_states.py b/django/contrib/localflavor/in_/in_states.py
new file mode 100644
index 0000000000..498efe7069
--- /dev/null
+++ b/django/contrib/localflavor/in_/in_states.py
@@ -0,0 +1,84 @@
+"""
+A mapping of state misspellings/abbreviations to normalized abbreviations, and
+an alphabetical list of states for use as `choices` in a formfield.
+
+This exists in this standalone file so that it's only imported into memory
+when explicitly needed.
+"""
+
+STATE_CHOICES = (
+ 'KA', 'Karnataka',
+ 'AP', 'Andhra Pradesh',
+ 'KL', 'Kerala',
+ 'TN', 'Tamil Nadu',
+ 'MH', 'Maharashtra',
+ 'UP', 'Uttar Pradesh',
+ 'GA', 'Goa',
+ 'GJ', 'Gujarat',
+ 'RJ', 'Rajasthan',
+ 'HP', 'Himachal Pradesh',
+ 'JK', 'Jammu and Kashmir',
+ 'AR', 'Arunachal Pradesh',
+ 'AS', 'Assam',
+ 'BR', 'Bihar',
+ 'CG', 'Chattisgarh',
+ 'HR', 'Haryana',
+ 'JH', 'Jharkhand',
+ 'MP', 'Madhya Pradesh',
+ 'MN', 'Manipur',
+ 'ML', 'Meghalaya',
+ 'MZ', 'Mizoram',
+ 'NL', 'Nagaland',
+ 'OR', 'Orissa',
+ 'PB', 'Punjab',
+ 'SK', 'Sikkim',
+ 'TR', 'Tripura',
+ 'UA', 'Uttarakhand',
+ 'WB', 'West Bengal',
+
+ # Union Territories
+ 'AN', 'Andaman and Nicobar',
+ 'CH', 'Chandigarh',
+ 'DN', 'Dadra and Nagar Haveli',
+ 'DD', 'Daman and Diu',
+ 'DL', 'Delhi',
+ 'LD', 'Lakshadweep',
+ 'PY', 'Pondicherry',
+)
+
+STATES_NORMALIZED = {
+ 'ka': 'KA',
+ 'karnatka': 'KA',
+ 'tn': 'TN',
+ 'tamilnad': 'TN',
+ 'tamilnadu': 'TN',
+ 'andra pradesh': 'AP',
+ 'andrapradesh': 'AP',
+ 'andhrapradesh': 'AP',
+ 'maharastra': 'MH',
+ 'mh': 'MH',
+ 'ap': 'AP',
+ 'dl': 'DL',
+ 'dd': 'DD',
+ 'br': 'BR',
+ 'ar': 'AR',
+ 'sk': 'SK',
+ 'kl': 'KL',
+ 'ga': 'GA',
+ 'rj': 'RJ',
+ 'rajastan': 'RJ',
+ 'rajasthan': 'RJ',
+ 'hp': 'HP',
+ 'ua': 'UA',
+ 'up': 'UP',
+ 'mp': 'MP',
+ 'mz': 'MZ',
+ 'bengal': 'WB',
+ 'westbengal': 'WB',
+ 'mizo': 'MZ',
+ 'orisa': 'OR',
+ 'odisa': 'OR',
+ 'or': 'OR',
+ 'ar': 'AR',
+}
+
diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py
index 41727d8fa3..ef8799e29c 100644
--- a/django/contrib/localflavor/is_/forms.py
+++ b/django/contrib/localflavor/is_/forms.py
@@ -5,7 +5,8 @@ Iceland specific form helpers.
from django.newforms import ValidationError
from django.newforms.fields import RegexField, EMPTY_VALUES
from django.newforms.widgets import Select
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
+from django.utils.encoding import smart_unicode
class ISIdNumberField(RegexField):
"""
@@ -13,7 +14,7 @@ class ISIdNumberField(RegexField):
of Iceland has.
"""
def __init__(self, *args, **kwargs):
- error_msg = gettext(u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.')
+ error_msg = ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.')
kwargs['min_length'],kwargs['max_length'] = 10,11
super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs)
@@ -27,7 +28,7 @@ class ISIdNumberField(RegexField):
if self._validate(value):
return self._format(value)
else:
- raise ValidationError(gettext(u'The Icelandic identification number is not valid.'))
+ raise ValidationError(ugettext(u'The Icelandic identification number is not valid.'))
def _canonify(self, value):
"""
@@ -48,7 +49,7 @@ class ISIdNumberField(RegexField):
Takes in the value in canonical form and returns it in the common
display format.
"""
- return value[:6]+'-'+value[6:]
+ return smart_unicode(value[:6]+'-'+value[6:])
class ISPhoneNumberField(RegexField):
"""
diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py
index bb1bb2e6a4..0b6eecec45 100644
--- a/django/contrib/localflavor/it/forms.py
+++ b/django/contrib/localflavor/it/forms.py
@@ -4,7 +4,7 @@ IT-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
from django.utils.encoding import smart_unicode
from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit
import re
@@ -13,15 +13,15 @@ class ITZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(ITZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a valid zip code.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a valid zip code.'),
+ *args, **kwargs)
class ITRegionSelect(Select):
"""
A Select widget that uses a list of IT regions as its choices.
"""
def __init__(self, attrs=None):
- from it_region import REGION_CHOICES # relative import
+ from it_region import REGION_CHOICES
super(ITRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
class ITProvinceSelect(Select):
@@ -29,7 +29,7 @@ class ITProvinceSelect(Select):
A Select widget that uses a list of IT regions as its choices.
"""
def __init__(self, attrs=None):
- from it_province import PROVINCE_CHOICES # relative import
+ from it_province import PROVINCE_CHOICES
super(ITProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
class ITSocialSecurityNumberField(RegexField):
@@ -38,7 +38,7 @@ class ITSocialSecurityNumberField(RegexField):
For reference see http://www.agenziaentrate.it/ and search for
'Informazioni sulla codificazione delle persone fisiche'.
"""
- err_msg = gettext(u'Enter a valid Social Security number.')
+ err_msg = ugettext(u'Enter a valid Social Security number.')
def __init__(self, *args, **kwargs):
super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
max_length=None, min_length=None, error_message=self.err_msg,
@@ -65,7 +65,7 @@ class ITVatNumberField(Field):
value = super(ITVatNumberField, self).clean(value)
if value == u'':
return value
- err_msg = gettext(u'Enter a valid VAT number.')
+ err_msg = ugettext(u'Enter a valid VAT number.')
try:
vat_number = int(value)
except ValueError:
diff --git a/django/contrib/localflavor/it/it_province.py b/django/contrib/localflavor/it/it_province.py
index 1867191b31..669ecd7f95 100644
--- a/django/contrib/localflavor/it/it_province.py
+++ b/django/contrib/localflavor/it/it_province.py
@@ -33,7 +33,7 @@ PROVINCE_CHOICES = (
('KR', 'Crotone'),
('CN', 'Cuneo'),
('EN', 'Enna'),
-# ('FM', 'Fermo'), # active starting from 2009
+# ('FM', 'Fermo'), # active starting from 2009
('FE', 'Ferrara'),
('FI', 'Firenze'),
('FG', 'Foggia'),
diff --git a/django/contrib/localflavor/it/util.py b/django/contrib/localflavor/it/util.py
index 49b607f160..c162ff7eff 100644
--- a/django/contrib/localflavor/it/util.py
+++ b/django/contrib/localflavor/it/util.py
@@ -1,23 +1,27 @@
+from django.utils.encoding import smart_str, smart_unicode
+
def ssn_check_digit(value):
"Calculate Italian social security number check digit."
ssn_even_chars = {
- '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
- 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9,
- 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18,
- 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25
+ '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
+ '9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7,
+ 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15,
+ 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23,
+ 'Y': 24, 'Z': 25
}
ssn_odd_chars = {
- '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19, '9': 21,
- 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17, 'I': 19, 'J': 21,
- 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6, 'R': 8, 'S': 12,
- 'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23
+ '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8':
+ 19, '9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15,
+ 'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11,
+ 'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22,
+ 'X': 25, 'Y': 24, 'Z': 23
}
# Chars from 'A' to 'Z'
ssn_check_digits = [chr(x) for x in range(65, 91)]
ssn = value.upper()
total = 0
- for i in range(0,15):
+ for i in range(0, 15):
try:
if i % 2 == 0:
total += ssn_odd_chars[ssn[i]]
@@ -30,11 +34,11 @@ def ssn_check_digit(value):
def vat_number_check_digit(vat_number):
"Calculate Italian VAT number check digit."
- normalized_vat_number = str(vat_number).zfill(10)
+ normalized_vat_number = smart_str(vat_number).zfill(10)
total = 0
for i in range(0, 10, 2):
total += int(normalized_vat_number[i])
for i in range(1, 11, 2):
quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
total += quotient + remainder
- return str((10 - total % 10) % 10)
+ return smart_unicode((10 - total % 10) % 10)
diff --git a/django/contrib/localflavor/jp/forms.py b/django/contrib/localflavor/jp/forms.py
index 4d93a21227..682ffb8c31 100644
--- a/django/contrib/localflavor/jp/forms.py
+++ b/django/contrib/localflavor/jp/forms.py
@@ -4,7 +4,7 @@ JP-specific Form helpers
from django.core import validators
from django.newforms import ValidationError
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
from django.newforms.fields import RegexField, Select
import re
@@ -18,8 +18,8 @@ class JPPostalCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
+ *args, **kwargs)
def clean(self, value):
"""
diff --git a/django/contrib/localflavor/jp/jp_prefectures.py b/django/contrib/localflavor/jp/jp_prefectures.py
index 72ac4f9474..f079fe6a3d 100644
--- a/django/contrib/localflavor/jp/jp_prefectures.py
+++ b/django/contrib/localflavor/jp/jp_prefectures.py
@@ -1,51 +1,51 @@
-from django.utils.translation import gettext_lazy as gettext_lazy
+from django.utils.translation import ugettext_lazy
JP_PREFECTURES = (
- ('hokkaido', gettext_lazy('Hokkaido'),),
- ('aomori', gettext_lazy('Aomori'),),
- ('iwate', gettext_lazy('Iwate'),),
- ('miyagi', gettext_lazy('Miyagi'),),
- ('akita', gettext_lazy('Akita'),),
- ('yamagata', gettext_lazy('Yamagata'),),
- ('fukushima', gettext_lazy('Fukushima'),),
- ('ibaraki', gettext_lazy('Ibaraki'),),
- ('tochigi', gettext_lazy('Tochigi'),),
- ('gunma', gettext_lazy('Gunma'),),
- ('saitama', gettext_lazy('Saitama'),),
- ('chiba', gettext_lazy('Chiba'),),
- ('tokyo', gettext_lazy('Tokyo'),),
- ('kanagawa', gettext_lazy('Kanagawa'),),
- ('yamanashi', gettext_lazy('Yamanashi'),),
- ('nagano', gettext_lazy('Nagano'),),
- ('niigata', gettext_lazy('Niigata'),),
- ('toyama', gettext_lazy('Toyama'),),
- ('ishikawa', gettext_lazy('Ishikawa'),),
- ('fukui', gettext_lazy('Fukui'),),
- ('gifu', gettext_lazy('Gifu'),),
- ('shizuoka', gettext_lazy('Shizuoka'),),
- ('aichi', gettext_lazy('Aichi'),),
- ('mie', gettext_lazy('Mie'),),
- ('shiga', gettext_lazy('Shiga'),),
- ('kyoto', gettext_lazy('Kyoto'),),
- ('osaka', gettext_lazy('Osaka'),),
- ('hyogo', gettext_lazy('Hyogo'),),
- ('nara', gettext_lazy('Nara'),),
- ('wakayama', gettext_lazy('Wakayama'),),
- ('tottori', gettext_lazy('Tottori'),),
- ('shimane', gettext_lazy('Shimane'),),
- ('okayama', gettext_lazy('Okayama'),),
- ('hiroshima', gettext_lazy('Hiroshima'),),
- ('yamaguchi', gettext_lazy('Yamaguchi'),),
- ('tokushima', gettext_lazy('Tokushima'),),
- ('kagawa', gettext_lazy('Kagawa'),),
- ('ehime', gettext_lazy('Ehime'),),
- ('kochi', gettext_lazy('Kochi'),),
- ('fukuoka', gettext_lazy('Fukuoka'),),
- ('saga', gettext_lazy('Saga'),),
- ('nagasaki', gettext_lazy('Nagasaki'),),
- ('kumamoto', gettext_lazy('Kumamoto'),),
- ('oita', gettext_lazy('Oita'),),
- ('miyazaki', gettext_lazy('Miyazaki'),),
- ('kagoshima', gettext_lazy('Kagoshima'),),
- ('okinawa', gettext_lazy('Okinawa'),),
+ ('hokkaido', ugettext_lazy('Hokkaido'),),
+ ('aomori', ugettext_lazy('Aomori'),),
+ ('iwate', ugettext_lazy('Iwate'),),
+ ('miyagi', ugettext_lazy('Miyagi'),),
+ ('akita', ugettext_lazy('Akita'),),
+ ('yamagata', ugettext_lazy('Yamagata'),),
+ ('fukushima', ugettext_lazy('Fukushima'),),
+ ('ibaraki', ugettext_lazy('Ibaraki'),),
+ ('tochigi', ugettext_lazy('Tochigi'),),
+ ('gunma', ugettext_lazy('Gunma'),),
+ ('saitama', ugettext_lazy('Saitama'),),
+ ('chiba', ugettext_lazy('Chiba'),),
+ ('tokyo', ugettext_lazy('Tokyo'),),
+ ('kanagawa', ugettext_lazy('Kanagawa'),),
+ ('yamanashi', ugettext_lazy('Yamanashi'),),
+ ('nagano', ugettext_lazy('Nagano'),),
+ ('niigata', ugettext_lazy('Niigata'),),
+ ('toyama', ugettext_lazy('Toyama'),),
+ ('ishikawa', ugettext_lazy('Ishikawa'),),
+ ('fukui', ugettext_lazy('Fukui'),),
+ ('gifu', ugettext_lazy('Gifu'),),
+ ('shizuoka', ugettext_lazy('Shizuoka'),),
+ ('aichi', ugettext_lazy('Aichi'),),
+ ('mie', ugettext_lazy('Mie'),),
+ ('shiga', ugettext_lazy('Shiga'),),
+ ('kyoto', ugettext_lazy('Kyoto'),),
+ ('osaka', ugettext_lazy('Osaka'),),
+ ('hyogo', ugettext_lazy('Hyogo'),),
+ ('nara', ugettext_lazy('Nara'),),
+ ('wakayama', ugettext_lazy('Wakayama'),),
+ ('tottori', ugettext_lazy('Tottori'),),
+ ('shimane', ugettext_lazy('Shimane'),),
+ ('okayama', ugettext_lazy('Okayama'),),
+ ('hiroshima', ugettext_lazy('Hiroshima'),),
+ ('yamaguchi', ugettext_lazy('Yamaguchi'),),
+ ('tokushima', ugettext_lazy('Tokushima'),),
+ ('kagawa', ugettext_lazy('Kagawa'),),
+ ('ehime', ugettext_lazy('Ehime'),),
+ ('kochi', ugettext_lazy('Kochi'),),
+ ('fukuoka', ugettext_lazy('Fukuoka'),),
+ ('saga', ugettext_lazy('Saga'),),
+ ('nagasaki', ugettext_lazy('Nagasaki'),),
+ ('kumamoto', ugettext_lazy('Kumamoto'),),
+ ('oita', ugettext_lazy('Oita'),),
+ ('miyazaki', ugettext_lazy('Miyazaki'),),
+ ('kagoshima', ugettext_lazy('Kagoshima'),),
+ ('okinawa', ugettext_lazy('Okinawa'),),
)
diff --git a/django/contrib/localflavor/no/forms.py b/django/contrib/localflavor/no/forms.py
index 22099005b9..2de3df14d8 100644
--- a/django/contrib/localflavor/no/forms.py
+++ b/django/contrib/localflavor/no/forms.py
@@ -1,4 +1,3 @@
-# -*- coding: iso-8859-1 -*-
"""
Norwegian-specific Form helpers
"""
@@ -6,14 +5,14 @@ Norwegian-specific Form helpers
import re, datetime
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
class NOZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(NOZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXX.'),
+ *args, **kwargs)
class NOMunicipalitySelect(Select):
"""
@@ -33,7 +32,7 @@ class NOSocialSecurityNumber(Field):
if value in EMPTY_VALUES:
return u''
- msg = gettext(u'Enter a valid Norwegian social security number.')
+ msg = ugettext(u'Enter a valid Norwegian social security number.')
if not re.match(r'^\d{11}$', value):
raise ValidationError(msg)
@@ -60,13 +59,13 @@ class NOSocialSecurityNumber(Field):
self.gender = 'F'
else:
self.gender = 'M'
-
+
digits = map(int, list(value))
weight_1 = [3, 7, 6, 1, 8, 9, 4, 5, 2, 1, 0]
weight_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1]
def multiply_reduce(aval, bval):
- return sum((a * b) for (a, b) in zip(aval, bval))
+ return sum([(a * b) for (a, b) in zip(aval, bval)])
if multiply_reduce(digits, weight_1) % 11 != 0:
raise ValidationError(msg)
@@ -74,4 +73,4 @@ class NOSocialSecurityNumber(Field):
raise ValidationError(msg)
return value
-
+
diff --git a/django/contrib/localflavor/no/no_municipalities.py b/django/contrib/localflavor/no/no_municipalities.py
index d66fef514c..d6bacda275 100644
--- a/django/contrib/localflavor/no/no_municipalities.py
+++ b/django/contrib/localflavor/no/no_municipalities.py
@@ -1,4 +1,4 @@
-# -*- coding: iso-8859-1 -*-
+# -*- coding: utf-8 -*-
"""
An alphabetical list of Norwegian municipalities (fylker) fro use as `choices`
in a formfield.
@@ -15,18 +15,18 @@ MUNICIPALITY_CHOICES = (
('hedmark', u'Hedmark'),
('hordaland', u'Hordaland'),
('janmayen', u'Jan Mayen'),
- ('moreogromsdal', u'Mre og Romsdal'),
- ('nordtrondelag', u'Nord-Trndelag'),
+ ('moreogromsdal', u'Møre og Romsdal'),
+ ('nordtrondelag', u'Nord-Trøndelag'),
('nordland', u'Nordland'),
('oppland', u'Oppland'),
('oslo', u'Oslo'),
('rogaland', u'Rogaland'),
('sognogfjordane', u'Sogn og Fjordane'),
('svalbard', u'Svalbard'),
- ('sortrondelag', u'Sr-Trndelag'),
+ ('sortrondelag', u'Sør-Trøndelag'),
('telemark', u'Telemark'),
('troms', u'Troms'),
('vestagder', u'Vest-Agder'),
('vestfold', u'Vestfold'),
- ('ostfold', u'stfold')
+ ('ostfold', u'Østfold')
)
diff --git a/django/contrib/localflavor/pl/__init__.py b/django/contrib/localflavor/pl/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/localflavor/pl/__init__.py
diff --git a/django/contrib/localflavor/pl/forms.py b/django/contrib/localflavor/pl/forms.py
new file mode 100644
index 0000000000..62806362dc
--- /dev/null
+++ b/django/contrib/localflavor/pl/forms.py
@@ -0,0 +1,84 @@
+"""
+Polish-specific form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Select, RegexField
+from django.utils.translation import ugettext as _
+
+class PLVoivodeshipSelect(Select):
+ """
+ A select widget with list of Polish voivodeships (administrative provinces)
+ as choices.
+ """
+ def __init__(self, attrs=None):
+ from pl_voivodeships import VOIVODESHIP_CHOICES
+ super(PLVoivodeshipSelect, self).__init__(attrs, choices=VOIVODESHIP_CHOICES)
+
+class PLAdministrativeUnitSelect(Select):
+ """
+ A select widget with list of Polish administrative units as choices.
+ """
+ def __init__(self, attrs=None):
+ from pl_administrativeunits import ADMINISTRATIVE_UNIT_CHOICES
+ super(PLAdministrativeUnitSelect, self).__init__(attrs, choices=ADMINISTRATIVE_UNIT_CHOICES)
+
+class PLNationalIdentificationNumberField(RegexField):
+ """
+ A form field that validates as Polish Identification Number (PESEL).
+
+ Checks the following rules:
+ * the length consist of 11 digits
+ * has a valid checksum
+
+ The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
+ """
+
+ def has_valid_checksum(self, number):
+ """
+ Calculates a checksum with the provided algorithm.
+ """
+ multiple_table = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1)
+ result = 0
+ for i in range(len(number)):
+ result += int(number[i])*multiple_table[i]
+
+ if result % 10 == 0:
+ return True
+ else:
+ return False
+
+ def __init__(self, *args, **kwargs):
+ super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
+ max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
+ *args, **kwargs)
+
+ def clean(self,value):
+ super(PLNationalIdentificationNumberField, self).clean(value)
+ if not self.has_valid_checksum(value):
+ raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
+ return u'%s' % value
+
+
+class PLTaxNumberField(RegexField):
+ """
+ A form field that validates as Polish Tax Number (NIP).
+ Valid forms are: XXX-XXX-YY-YY or XX-XX-YYY-YYY.
+ """
+ def __init__(self, *args, **kwargs):
+ super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
+ max_length=None, min_length=None,
+ error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
+
+
+class PLPostalCodeField(RegexField):
+ """
+ A form field that validates as Polish postal code.
+ Valid code is XX-XXX where X is digit.
+ """
+ def __init__(self, *args, **kwargs):
+ super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
+ max_length=None, min_length=None,
+ error_message=_(u'Enter a postal code in the format XX-XXX.'),
+ *args, **kwargs)
+
diff --git a/django/contrib/localflavor/pl/pl_administrativeunits.py b/django/contrib/localflavor/pl/pl_administrativeunits.py
new file mode 100644
index 0000000000..9777ea2b61
--- /dev/null
+++ b/django/contrib/localflavor/pl/pl_administrativeunits.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+"""
+Polish administrative units as in http://pl.wikipedia.org/wiki/Podzia%C5%82_administracyjny_Polski
+"""
+
+
+ADMINISTRATIVE_UNIT_CHOICES = (
+ ('wroclaw', u'Wrocław'),
+ ('jeleniagora', u'Jelenia Góra'),
+ ('legnica', u'Legnica'),
+ ('boleslawiecki', u'bolesławiecki'),
+ ('dzierzoniowski', u'dzierżoniowski'),
+ ('glogowski', u'głogowski'),
+ ('gorowski', u'górowski'),
+ ('jaworski', u'jaworski'),
+ ('jeleniogorski', u'jeleniogórski'),
+ ('kamiennogorski', u'kamiennogórski'),
+ ('klodzki', u'kłodzki'),
+ ('legnicki', u'legnicki'),
+ ('lubanski', u'lubański'),
+ ('lubinski', u'lubiński'),
+ ('lwowecki', u'lwówecki'),
+ ('milicki', u'milicki'),
+ ('olesnicki', u'oleśnicki'),
+ ('olawski', u'oławski'),
+ ('polkowicki', u'polkowicki'),
+ ('strzelinski', u'strzeliński'),
+ ('sredzki', u'średzki'),
+ ('swidnicki', u'świdnicki'),
+ ('trzebnicki', u'trzebnicki'),
+ ('walbrzyski', u'wałbrzyski'),
+ ('wolowski', u'wołowski'),
+ ('wroclawski', u'wrocławski'),
+ ('zabkowicki', u'ząbkowicki'),
+ ('zgorzelecki', u'zgorzelecki'),
+ ('zlotoryjski', u'złotoryjski'),
+ ('bydgoszcz', u'Bydgoszcz'),
+ ('torun', u'Toruń'),
+ ('wloclawek', u'Włocławek'),
+ ('grudziadz', u'Grudziądz'),
+ ('aleksandrowski', u'aleksandrowski'),
+ ('brodnicki', u'brodnicki'),
+ ('bydgoski', u'bydgoski'),
+ ('chelminski', u'chełmiński'),
+ ('golubsko-dobrzynski', u'golubsko-dobrzyński'),
+ ('grudziadzki', u'grudziądzki'),
+ ('inowroclawski', u'inowrocławski'),
+ ('lipnowski', u'lipnowski'),
+ ('mogilenski', u'mogileński'),
+ ('nakielski', u'nakielski'),
+ ('radziejowski', u'radziejowski'),
+ ('rypinski', u'rypiński'),
+ ('sepolenski', u'sępoleński'),
+ ('swiecki', u'świecki'),
+ ('torunski', u'toruński'),
+ ('tucholski', u'tucholski'),
+ ('wabrzeski', u'wąbrzeski'),
+ ('wloclawski', u'wrocławski'),
+ ('zninski', u'źniński'),
+ ('lublin', u'Lublin'),
+ ('biala-podlaska', u'Biała Podlaska'),
+ ('chelm', u'Chełm'),
+ ('zamosc', u'Zamość'),
+ ('bialski', u'bialski'),
+ ('bilgorajski', u'biłgorajski'),
+ ('chelmski', u'chełmski'),
+ ('hrubieszowski', u'hrubieszowski'),
+ ('janowski', u'janowski'),
+ ('krasnostawski', u'krasnostawski'),
+ ('krasnicki', u'kraśnicki'),
+ ('lubartowski', u'lubartowski'),
+ ('lubelski', u'lubelski'),
+ ('leczynski', u'łęczyński'),
+ ('lukowski', u'łukowski'),
+ ('opolski', u'opolski'),
+ ('parczewski', u'parczewski'),
+ ('pulawski', u'puławski'),
+ ('radzynski', u'radzyński'),
+ ('rycki', u'rycki'),
+ ('swidnicki', u'świdnicki'),
+ ('tomaszowski', u'tomaszowski'),
+ ('wlodawski', u'włodawski'),
+ ('zamojski', u'zamojski'),
+ ('gorzow-wielkopolski', u'Gorzów Wielkopolski'),
+ ('zielona-gora', u'Zielona Góra'),
+ ('gorzowski', u'gorzowski'),
+ ('krosnienski', u'krośnieński'),
+ ('miedzyrzecki', u'międzyrzecki'),
+ ('nowosolski', u'nowosolski'),
+ ('slubicki', u'słubicki'),
+ ('strzelecko-drezdenecki', u'strzelecko-drezdenecki'),
+ ('sulecinski', u'suleńciński'),
+ ('swiebodzinski', u'świebodziński'),
+ ('wschowski', u'wschowski'),
+ ('zielonogorski', u'zielonogórski'),
+ ('zaganski', u'żagański'),
+ ('zarski', u'żarski'),
+ ('lodz', u'Łódź'),
+ ('piotrkow-trybunalski', u'Piotrków Trybunalski'),
+ ('skierniewice', u'Skierniewice'),
+ ('belchatowski', u'bełchatowski'),
+ ('brzezinski', u'brzeziński'),
+ ('kutnowski', u'kutnowski'),
+ ('laski', u'łaski'),
+ ('leczycki', u'łęczycki'),
+ ('lowicki', u'łowicki'),
+ ('lodzki wschodni', u'łódzki wschodni'),
+ ('opoczynski', u'opoczyński'),
+ ('pabianicki', u'pabianicki'),
+ ('pajeczanski', u'pajęczański'),
+ ('piotrkowski', u'piotrkowski'),
+ ('poddebicki', u'poddębicki'),
+ ('radomszczanski', u'radomszczański'),
+ ('rawski', u'rawski'),
+ ('sieradzki', u'sieradzki'),
+ ('skierniewicki', u'skierniewicki'),
+ ('tomaszowski', u'tomaszowski'),
+ ('wielunski', u'wieluński'),
+ ('wieruszowski', u'wieruszowski'),
+ ('zdunskowolski', u'zduńskowolski'),
+ ('zgierski', u'zgierski'),
+ ('krakow', u'Kraków'),
+ ('tarnow', u'Tarnów'),
+ ('nowy-sacz', u'Nowy Sącz'),
+ ('bochenski', u'bocheński'),
+ ('brzeski', u'brzeski'),
+ ('chrzanowski', u'chrzanowski'),
+ ('dabrowski', u'dąbrowski'),
+ ('gorlicki', u'gorlicki'),
+ ('krakowski', u'krakowski'),
+ ('limanowski', u'limanowski'),
+ ('miechowski', u'miechowski'),
+ ('myslenicki', u'myślenicki'),
+ ('nowosadecki', u'nowosądecki'),
+ ('nowotarski', u'nowotarski'),
+ ('olkuski', u'olkuski'),
+ ('oswiecimski', u'oświęcimski'),
+ ('proszowicki', u'proszowicki'),
+ ('suski', u'suski'),
+ ('tarnowski', u'tarnowski'),
+ ('tatrzanski', u'tatrzański'),
+ ('wadowicki', u'wadowicki'),
+ ('wielicki', u'wielicki'),
+ ('warszawa', u'Warszawa'),
+ ('ostroleka', u'Ostrołęka'),
+ ('plock', u'Płock'),
+ ('radom', u'Radom'),
+ ('siedlce', u'Siedlce'),
+ ('bialobrzeski', u'białobrzeski'),
+ ('ciechanowski', u'ciechanowski'),
+ ('garwolinski', u'garwoliński'),
+ ('gostyninski', u'gostyniński'),
+ ('grodziski', u'grodziski'),
+ ('grojecki', u'grójecki'),
+ ('kozienicki', u'kozenicki'),
+ ('legionowski', u'legionowski'),
+ ('lipski', u'lipski'),
+ ('losicki', u'łosicki'),
+ ('makowski', u'makowski'),
+ ('minski', u'miński'),
+ ('mlawski', u'mławski'),
+ ('nowodworski', u'nowodworski'),
+ ('ostrolecki', u'ostrołęcki'),
+ ('ostrowski', u'ostrowski'),
+ ('otwocki', u'otwocki'),
+ ('piaseczynski', u'piaseczyński'),
+ ('plocki', u'płocki'),
+ ('plonski', u'płoński'),
+ ('pruszkowski', u'pruszkowski'),
+ ('przasnyski', u'przasnyski'),
+ ('przysuski', u'przysuski'),
+ ('pultuski', u'pułtuski'),
+ ('radomski', u'radomski'),
+ ('siedlecki', u'siedlecki'),
+ ('sierpecki', u'sierpecki'),
+ ('sochaczewski', u'sochaczewski'),
+ ('sokolowski', u'sokołowski'),
+ ('szydlowiecki', u'szydłowiecki'),
+ ('warszawski-zachodni', u'warszawski zachodni'),
+ ('wegrowski', u'węgrowski'),
+ ('wolominski', u'wołomiński'),
+ ('wyszkowski', u'wyszkowski'),
+ ('zwolenski', u'zwoleński'),
+ ('zurominski', u'żuromiński'),
+ ('zyrardowski', u'żyrardowski'),
+ ('opole', u'Opole'),
+ ('brzeski', u'brzeski'),
+ ('glubczycki', u'głubczyski'),
+ ('kedzierzynsko-kozielski', u'kędzierzyński-kozielski'),
+ ('kluczborski', u'kluczborski'),
+ ('krapkowicki', u'krapkowicki'),
+ ('namyslowski', u'namysłowski'),
+ ('nyski', u'nyski'),
+ ('oleski', u'oleski'),
+ ('opolski', u'opolski'),
+ ('prudnicki', u'prudnicki'),
+ ('strzelecki', u'strzelecki'),
+ ('rzeszow', u'Rzeszów'),
+ ('krosno', u'Krosno'),
+ ('przemysl', u'Przemyśl'),
+ ('tarnobrzeg', u'Tarnobrzeg'),
+ ('bieszczadzki', u'bieszczadzki'),
+ ('brzozowski', u'brzozowski'),
+ ('debicki', u'dębicki'),
+ ('jaroslawski', u'jarosławski'),
+ ('jasielski', u'jasielski'),
+ ('kolbuszowski', u'kolbuszowski'),
+ ('krosnienski', u'krośnieński'),
+ ('leski', u'leski'),
+ ('lezajski', u'leżajski'),
+ ('lubaczowski', u'lubaczowski'),
+ ('lancucki', u'łańcucki'),
+ ('mielecki', u'mielecki'),
+ ('nizanski', u'niżański'),
+ ('przemyski', u'przemyski'),
+ ('przeworski', u'przeworski'),
+ ('ropczycko-sedziszowski', u'ropczycko-sędziszowski'),
+ ('rzeszowski', u'rzeszowski'),
+ ('sanocki', u'sanocki'),
+ ('stalowowolski', u'stalowowolski'),
+ ('strzyzowski', u'strzyżowski'),
+ ('tarnobrzeski', u'tarnobrzeski'),
+ ('bialystok', u'Białystok'),
+ ('lomza', u'Łomża'),
+ ('suwalki', u'Suwałki'),
+ ('augustowski', u'augustowski'),
+ ('bialostocki', u'białostocki'),
+ ('bielski', u'bielski'),
+ ('grajewski', u'grajewski'),
+ ('hajnowski', u'hajnowski'),
+ ('kolnenski', u'kolneński'),
+ ('łomzynski', u'łomżyński'),
+ ('moniecki', u'moniecki'),
+ ('sejnenski', u'sejneński'),
+ ('siemiatycki', u'siematycki'),
+ ('sokolski', u'sokólski'),
+ ('suwalski', u'suwalski'),
+ ('wysokomazowiecki', u'wysokomazowiecki'),
+ ('zambrowski', u'zambrowski'),
+ ('gdansk', u'Gdańsk'),
+ ('gdynia', u'Gdynia'),
+ ('slupsk', u'Słupsk'),
+ ('sopot', u'Sopot'),
+ ('bytowski', u'bytowski'),
+ ('chojnicki', u'chojnicki'),
+ ('czluchowski', u'człuchowski'),
+ ('kartuski', u'kartuski'),
+ ('koscierski', u'kościerski'),
+ ('kwidzynski', u'kwidzyński'),
+ ('leborski', u'lęborski'),
+ ('malborski', u'malborski'),
+ ('nowodworski', u'nowodworski'),
+ ('gdanski', u'gdański'),
+ ('pucki', u'pucki'),
+ ('slupski', u'słupski'),
+ ('starogardzki', u'starogardzki'),
+ ('sztumski', u'sztumski'),
+ ('tczewski', u'tczewski'),
+ ('wejherowski', u'wejcherowski'),
+ ('katowice', u'Katowice'),
+ ('bielsko-biala', u'Bielsko-Biała'),
+ ('bytom', u'Bytom'),
+ ('chorzow', u'Chorzów'),
+ ('czestochowa', u'Częstochowa'),
+ ('dabrowa-gornicza', u'Dąbrowa Górnicza'),
+ ('gliwice', u'Gliwice'),
+ ('jastrzebie-zdroj', u'Jastrzębie Zdrój'),
+ ('jaworzno', u'Jaworzno'),
+ ('myslowice', u'Mysłowice'),
+ ('piekary-slaskie', u'Piekary Śląskie'),
+ ('ruda-slaska', u'Ruda Śląska'),
+ ('rybnik', u'Rybnik'),
+ ('siemianowice-slaskie', u'Siemianowice Śląskie'),
+ ('sosnowiec', u'Sosnowiec'),
+ ('swietochlowice', u'Świętochłowice'),
+ ('tychy', u'Tychy'),
+ ('zabrze', u'Zabrze'),
+ ('zory', u'Żory'),
+ ('bedzinski', u'będziński'),
+ ('bielski', u'bielski'),
+ ('bierunsko-ledzinski', u'bieruńsko-lędziński'),
+ ('cieszynski', u'cieszyński'),
+ ('czestochowski', u'częstochowski'),
+ ('gliwicki', u'gliwicki'),
+ ('klobucki', u'kłobucki'),
+ ('lubliniecki', u'lubliniecki'),
+ ('mikolowski', u'mikołowski'),
+ ('myszkowski', u'myszkowski'),
+ ('pszczynski', u'pszczyński'),
+ ('raciborski', u'raciborski'),
+ ('rybnicki', u'rybnicki'),
+ ('tarnogorski', u'tarnogórski'),
+ ('wodzislawski', u'wodzisławski'),
+ ('zawiercianski', u'zawierciański'),
+ ('zywiecki', u'żywiecki'),
+ ('kielce', u'Kielce'),
+ ('buski', u'buski'),
+ ('jedrzejowski', u'jędrzejowski'),
+ ('kazimierski', u'kazimierski'),
+ ('kielecki', u'kielecki'),
+ ('konecki', u'konecki'),
+ ('opatowski', u'opatowski'),
+ ('ostrowiecki', u'ostrowiecki'),
+ ('pinczowski', u'pińczowski'),
+ ('sandomierski', u'sandomierski'),
+ ('skarzyski', u'skarżyski'),
+ ('starachowicki', u'starachowicki'),
+ ('staszowski', u'staszowski'),
+ ('wloszczowski', u'włoszczowski'),
+ ('olsztyn', u'Olsztyn'),
+ ('elblag', u'Elbląg'),
+ ('bartoszycki', u'bartoszycki'),
+ ('braniewski', u'braniewski'),
+ ('dzialdowski', u'działdowski'),
+ ('elblaski', u'elbląski'),
+ ('elcki', u'ełcki'),
+ ('gizycki', u'giżycki'),
+ ('goldapski', u'gołdapski'),
+ ('ilawski', u'iławski'),
+ ('ketrzynski', u'kętrzyński'),
+ ('lidzbarski', u'lidzbarski'),
+ ('mragowski', u'mrągowski'),
+ ('nidzicki', u'nidzicki'),
+ ('nowomiejski', u'nowomiejski'),
+ ('olecki', u'olecki'),
+ ('olsztynski', u'olsztyński'),
+ ('ostrodzki', u'ostródzki'),
+ ('piski', u'piski'),
+ ('szczycienski', u'szczycieński'),
+ ('wegorzewski', u'węgorzewski'),
+ ('poznan', u'Poznań'),
+ ('kalisz', u'Kalisz'),
+ ('konin', u'Konin'),
+ ('leszno', u'Leszno'),
+ ('chodzieski', u'chodziejski'),
+ ('czarnkowsko-trzcianecki', u'czarnkowsko-trzcianecki'),
+ ('gnieznienski', u'gnieźnieński'),
+ ('gostynski', u'gostyński'),
+ ('grodziski', u'grodziski'),
+ ('jarocinski', u'jarociński'),
+ ('kaliski', u'kaliski'),
+ ('kepinski', u'kępiński'),
+ ('kolski', u'kolski'),
+ ('koninski', u'koniński'),
+ ('koscianski', u'kościański'),
+ ('krotoszynski', u'krotoszyński'),
+ ('leszczynski', u'leszczyński'),
+ ('miedzychodzki', u'międzychodzki'),
+ ('nowotomyski', u'nowotomyski'),
+ ('obornicki', u'obornicki'),
+ ('ostrowski', u'ostrowski'),
+ ('ostrzeszowski', u'ostrzeszowski'),
+ ('pilski', u'pilski'),
+ ('pleszewski', u'pleszewski'),
+ ('poznanski', u'poznański'),
+ ('rawicki', u'rawicki'),
+ ('slupecki', u'słupecki'),
+ ('szamotulski', u'szamotulski'),
+ ('sredzki', u'średzki'),
+ ('sremski', u'śremski'),
+ ('turecki', u'turecki'),
+ ('wagrowiecki', u'wągrowiecki'),
+ ('wolsztynski', u'wolsztyński'),
+ ('wrzesinski', u'wrzesiński'),
+ ('zlotowski', u'złotowski'),
+ ('bialogardzki', u'białogardzki'),
+ ('choszczenski', u'choszczeński'),
+ ('drawski', u'drawski'),
+ ('goleniowski', u'goleniowski'),
+ ('gryficki', u'gryficki'),
+ ('gryfinski', u'gryfiński'),
+ ('kamienski', u'kamieński'),
+ ('kolobrzeski', u'kołobrzeski'),
+ ('koszalinski', u'koszaliński'),
+ ('lobeski', u'łobeski'),
+ ('mysliborski', u'myśliborski'),
+ ('policki', u'policki'),
+ ('pyrzycki', u'pyrzycki'),
+ ('slawienski', u'sławieński'),
+ ('stargardzki', u'stargardzki'),
+ ('szczecinecki', u'szczecinecki'),
+ ('swidwinski', u'świdwiński'),
+ ('walecki', u'wałecki'),
+)
+
diff --git a/django/contrib/localflavor/pl/pl_voivodeships.py b/django/contrib/localflavor/pl/pl_voivodeships.py
new file mode 100644
index 0000000000..d8caede3c8
--- /dev/null
+++ b/django/contrib/localflavor/pl/pl_voivodeships.py
@@ -0,0 +1,24 @@
+"""
+Polish voivodeship as in http://en.wikipedia.org/wiki/Poland#Administrative_division
+"""
+
+from django.utils.translation import ugettext_lazy as _
+
+VOIVODESHIP_CHOICES = (
+ ('lower_silesia', _('Lower Silesia')),
+ ('kuyavia-pomerania', _('Kuyavia-Pomerania')),
+ ('lublin', _('Lublin')),
+ ('lubusz', _('Lubusz')),
+ ('lodz', _('Lodz')),
+ ('lesser_poland', _('Lesser Poland')),
+ ('masovia', _('Masovia')),
+ ('opole', _('Opole')),
+ ('subcarpatia', _('Subcarpatia')),
+ ('podlasie', _('Podlasie')),
+ ('pomerania', _('Pomerania')),
+ ('silesia', _('Silesia')),
+ ('swietokrzyskie', _('Swietokrzyskie')),
+ ('warmia-masuria', _('Warmia-Masuria')),
+ ('greater_poland', _('Greater Poland')),
+ ('west_pomerania', _('West Pomerania')),
+)
diff --git a/django/contrib/localflavor/sk/__init__.py b/django/contrib/localflavor/sk/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/localflavor/sk/__init__.py
diff --git a/django/contrib/localflavor/sk/forms.py b/django/contrib/localflavor/sk/forms.py
new file mode 100644
index 0000000000..0aa000a0a5
--- /dev/null
+++ b/django/contrib/localflavor/sk/forms.py
@@ -0,0 +1,41 @@
+"""
+Slovak-specific form helpers
+"""
+
+from django.newforms.fields import Select, RegexField
+from django.utils.translation import ugettext
+
+class SKRegionSelect(Select):
+ """
+ A select widget widget with list of Slovak regions as choices.
+ """
+ def __init__(self, attrs=None):
+ from sk_regions import REGION_CHOICES
+ super(SKRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
+
+class SKDistrictSelect(Select):
+ """
+ A select widget with list of Slovak districts as choices.
+ """
+ def __init__(self, attrs=None):
+ from sk_districts import DISTRICT_CHOICES
+ super(SKDistrictSelect, self).__init__(attrs, choices=DISTRICT_CHOICES)
+
+class SKPostalCodeField(RegexField):
+ """
+ A form field that validates its input as Slovak postal code.
+ Valid form is XXXXX or XXX XX, where X represents integer.
+ """
+ def __init__(self, *args, **kwargs):
+ super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
+ max_length=None, min_length=None,
+ error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
+ *args, **kwargs)
+
+ def clean(self, value):
+ """
+ Validates the input and returns a string that contains only numbers.
+ Returns an empty string for empty values.
+ """
+ v = super(SKPostalCodeField, self).clean(value)
+ return v.replace(' ', '')
diff --git a/django/contrib/localflavor/sk/sk_districts.py b/django/contrib/localflavor/sk/sk_districts.py
new file mode 100644
index 0000000000..95e87967b9
--- /dev/null
+++ b/django/contrib/localflavor/sk/sk_districts.py
@@ -0,0 +1,87 @@
+"""
+Slovak districts according to http://sk.wikipedia.org/wiki/Administrat%C3%ADvne_%C4%8Dlenenie_Slovenska
+"""
+
+from django.utils.translation import ugettext_lazy as _
+
+DISTRICT_CHOICES = (
+ ('BB', _('Banska Bystrica')),
+ ('BS', _('Banska Stiavnica')),
+ ('BJ', _('Bardejov')),
+ ('BN', _('Banovce nad Bebravou')),
+ ('BR', _('Brezno')),
+ ('BA1', _('Bratislava I')),
+ ('BA2', _('Bratislava II')),
+ ('BA3', _('Bratislava III')),
+ ('BA4', _('Bratislava IV')),
+ ('BA5', _('Bratislava V')),
+ ('BY', _('Bytca')),
+ ('CA', _('Cadca')),
+ ('DT', _('Detva')),
+ ('DK', _('Dolny Kubin')),
+ ('DS', _('Dunajska Streda')),
+ ('GA', _('Galanta')),
+ ('GL', _('Gelnica')),
+ ('HC', _('Hlohovec')),
+ ('HE', _('Humenne')),
+ ('IL', _('Ilava')),
+ ('KK', _('Kezmarok')),
+ ('KN', _('Komarno')),
+ ('KE1', _('Kosice I')),
+ ('KE2', _('Kosice II')),
+ ('KE3', _('Kosice III')),
+ ('KE4', _('Kosice IV')),
+ ('KEO', _('Kosice - okolie')),
+ ('KA', _('Krupina')),
+ ('KM', _('Kysucke Nove Mesto')),
+ ('LV', _('Levice')),
+ ('LE', _('Levoca')),
+ ('LM', _('Liptovsky Mikulas')),
+ ('LC', _('Lucenec')),
+ ('MA', _('Malacky')),
+ ('MT', _('Martin')),
+ ('ML', _('Medzilaborce')),
+ ('MI', _('Michalovce')),
+ ('MY', _('Myjava')),
+ ('NO', _('Namestovo')),
+ ('NR', _('Nitra')),
+ ('NM', _('Nove Mesto nad Vahom')),
+ ('NZ', _('Nove Zamky')),
+ ('PE', _('Partizanske')),
+ ('PK', _('Pezinok')),
+ ('PN', _('Piestany')),
+ ('PT', _('Poltar')),
+ ('PP', _('Poprad')),
+ ('PB', _('Povazska Bystrica')),
+ ('PO', _('Presov')),
+ ('PD', _('Prievidza')),
+ ('PU', _('Puchov')),
+ ('RA', _('Revuca')),
+ ('RS', _('Rimavska Sobota')),
+ ('RV', _('Roznava')),
+ ('RK', _('Ruzomberok')),
+ ('SB', _('Sabinov')),
+ ('SC', _('Senec')),
+ ('SE', _('Senica')),
+ ('SI', _('Skalica')),
+ ('SV', _('Snina')),
+ ('SO', _('Sobrance')),
+ ('SN', _('Spisska Nova Ves')),
+ ('SL', _('Stara Lubovna')),
+ ('SP', _('Stropkov')),
+ ('SK', _('Svidnik')),
+ ('SA', _('Sala')),
+ ('TO', _('Topolcany')),
+ ('TV', _('Trebisov')),
+ ('TN', _('Trencin')),
+ ('TT', _('Trnava')),
+ ('TR', _('Turcianske Teplice')),
+ ('TS', _('Tvrdosin')),
+ ('VK', _('Velky Krtis')),
+ ('VT', _('Vranov nad Toplou')),
+ ('ZM', _('Zlate Moravce')),
+ ('ZV', _('Zvolen')),
+ ('ZC', _('Zarnovica')),
+ ('ZH', _('Ziar nad Hronom')),
+ ('ZA', _('Zilina')),
+)
diff --git a/django/contrib/localflavor/sk/sk_regions.py b/django/contrib/localflavor/sk/sk_regions.py
new file mode 100644
index 0000000000..66de814e01
--- /dev/null
+++ b/django/contrib/localflavor/sk/sk_regions.py
@@ -0,0 +1,16 @@
+"""
+Slovak regions according to http://sk.wikipedia.org/wiki/Administrat%C3%ADvne_%C4%8Dlenenie_Slovenska
+"""
+
+from django.utils.translation import ugettext_lazy as _
+
+REGION_CHOICES = (
+ ('BB', _('Banska Bystrica region')),
+ ('BA', _('Bratislava region')),
+ ('KE', _('Kosice region')),
+ ('NR', _('Nitra region')),
+ ('PO', _('Presov region')),
+ ('TN', _('Trencin region')),
+ ('TT', _('Trnava region')),
+ ('ZA', _('Zilina region')),
+)
diff --git a/django/contrib/localflavor/uk/forms.py b/django/contrib/localflavor/uk/forms.py
index ddd033e1e0..84d6c0e157 100644
--- a/django/contrib/localflavor/uk/forms.py
+++ b/django/contrib/localflavor/uk/forms.py
@@ -3,7 +3,7 @@ UK-specific Form helpers
"""
from django.newforms.fields import RegexField
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
class UKPostcodeField(RegexField):
"""
@@ -15,5 +15,5 @@ class UKPostcodeField(RegexField):
def __init__(self, *args, **kwargs):
super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a postcode. A space is required between the two postcode parts.'),
+ error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
*args, **kwargs)
diff --git a/django/contrib/localflavor/us/forms.py b/django/contrib/localflavor/us/forms.py
index feda68291b..259a7f7058 100644
--- a/django/contrib/localflavor/us/forms.py
+++ b/django/contrib/localflavor/us/forms.py
@@ -5,7 +5,7 @@ USA-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
import re
phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
@@ -15,8 +15,8 @@ class USZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
- *args, **kwargs)
+ error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
+ *args, **kwargs)
class USPhoneNumberField(Field):
def clean(self, value):
@@ -38,17 +38,17 @@ class USSocialSecurityNumberField(Field):
* Conforms to the XXX-XX-XXXX format.
* No group consists entirely of zeroes.
* The leading group is not "666" (block "666" will never be allocated).
- * The number is not in the promotional block 987-65-4320 through 987-65-4329,
- which are permanently invalid.
+ * The number is not in the promotional block 987-65-4320 through
+ 987-65-4329, which are permanently invalid.
* The number is not one known to be invalid due to otherwise widespread
- promotional use or distribution (e.g., the Woolworth's number or the 1962
- promotional number).
+ promotional use or distribution (e.g., the Woolworth's number or the
+ 1962 promotional number).
"""
def clean(self, value):
super(USSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
- msg = gettext(u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
+ msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
match = re.match(ssn_re, value)
if not match:
raise ValidationError(msg)
@@ -75,7 +75,7 @@ class USStateField(Field):
abbreviation for the given state.
"""
def clean(self, value):
- from us_states import STATES_NORMALIZED # relative import
+ from us_states import STATES_NORMALIZED
super(USStateField, self).clean(value)
if value in EMPTY_VALUES:
return u''
@@ -95,5 +95,5 @@ class USStateSelect(Select):
A Select widget that uses a list of U.S. states/territories as its choices.
"""
def __init__(self, attrs=None):
- from us_states import STATE_CHOICES # relative import
+ from us_states import STATE_CHOICES
super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
diff --git a/django/contrib/markup/templatetags/markup.py b/django/contrib/markup/templatetags/markup.py
index 4bb135cc32..5d1f0ff1fb 100644
--- a/django/contrib/markup/templatetags/markup.py
+++ b/django/contrib/markup/templatetags/markup.py
@@ -16,6 +16,7 @@ silently fail and return the un-marked-up text.
from django import template
from django.conf import settings
+from django.utils.encoding import smart_str, force_unicode
register = template.Library()
@@ -25,9 +26,9 @@ def textile(value):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError, "Error in {% textile %} filter: The Python textile library isn't installed."
- return value
+ return force_unicode(value)
else:
- return textile.textile(value, encoding=settings.DEFAULT_CHARSET, output=settings.DEFAULT_CHARSET)
+ return force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8'))
def markdown(value):
try:
@@ -35,9 +36,9 @@ def markdown(value):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError, "Error in {% markdown %} filter: The Python markdown library isn't installed."
- return value
+ return force_unicode(value)
else:
- return markdown.markdown(value)
+ return force_unicode(markdown.markdown(smart_str(value)))
def restructuredtext(value):
try:
@@ -45,11 +46,11 @@ def restructuredtext(value):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError, "Error in {% restructuredtext %} filter: The Python docutils library isn't installed."
- return value
+ return force_unicode(value)
else:
docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
- parts = publish_parts(source=value, writer_name="html4css1", settings_overrides=docutils_settings)
- return parts["fragment"]
+ parts = publish_parts(source=smart_str(value), writer_name="html4css1", settings_overrides=docutils_settings)
+ return force_unicode(parts["fragment"])
register.filter(textile)
register.filter(markdown)
diff --git a/django/contrib/redirects/models.py b/django/contrib/redirects/models.py
index 60205e29f3..ac2e8d5bac 100644
--- a/django/contrib/redirects/models.py
+++ b/django/contrib/redirects/models.py
@@ -1,12 +1,12 @@
from django.db import models
from django.contrib.sites.models import Site
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
class Redirect(models.Model):
site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
- old_path = models.CharField(_('redirect from'), maxlength=200, db_index=True,
+ old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
- new_path = models.CharField(_('redirect to'), maxlength=200, blank=True,
+ new_path = models.CharField(_('redirect to'), max_length=200, blank=True,
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
class Meta:
@@ -20,5 +20,5 @@ class Redirect(models.Model):
list_filter = ('site',)
search_fields = ('old_path', 'new_path')
- def __str__(self):
- return "%s ---> %s" % (self.old_path, self.new_path)
+ def __unicode__(self):
+ return u"%s ---> %s" % (self.old_path, self.new_path)
diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py
index 434997d616..2531c8e244 100644
--- a/django/contrib/sessions/middleware.py
+++ b/django/contrib/sessions/middleware.py
@@ -2,7 +2,9 @@ from django.conf import settings
from django.contrib.sessions.models import Session
from django.core.exceptions import SuspiciousOperation
from django.utils.cache import patch_vary_headers
+from email.Utils import formatdate
import datetime
+import time
TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked'
@@ -37,6 +39,7 @@ class SessionWrapper(object):
return self._session.get(key, default)
def pop(self, key, *args):
+ self.modified = self.modified or key in self._session
return self._session.pop(key, *args)
def set_test_cookie(self):
@@ -97,7 +100,11 @@ class SessionMiddleware(object):
expires = None
else:
max_age = settings.SESSION_COOKIE_AGE
- expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
+ rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
+ # Fixed length date must have '-' separation in the format
+ # DD-MMM-YYYY for compliance with Netscape cookie standard
+ expires = (rfcdate[:7] + "-" + rfcdate[8:11]
+ + "-" + rfcdate[12:26] + "GMT")
new_session = Session.objects.save(session_key, request.session._session,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py
index 521a2abee9..29adc6e30c 100644
--- a/django/contrib/sessions/models.py
+++ b/django/contrib/sessions/models.py
@@ -1,7 +1,7 @@
import base64, md5, random, sys, datetime, os, time
import cPickle as pickle
from django.db import models
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
from django.conf import settings
class SessionManager(models.Manager):
@@ -65,7 +65,7 @@ class Session(models.Model):
the sessions documentation that is shipped with Django (also available
on the Django website).
"""
- session_key = models.CharField(_('session key'), maxlength=40, primary_key=True)
+ session_key = models.CharField(_('session key'), max_length=40, primary_key=True)
session_data = models.TextField(_('session data'))
expire_date = models.DateTimeField(_('expire date'))
objects = SessionManager()
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 5a28effa86..e83442123e 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -5,8 +5,24 @@ Inject data into the session cache.
>>> s._session_cache = {}
>>> s._session_cache['some key'] = 'exists'
+>>> s.accessed
+False
+>>> s.modified
+False
+
+>>> s.pop('non existant key', 'does not exist')
+'does not exist'
+>>> s.accessed
+True
+>>> s.modified
+False
+
>>> s.pop('some key')
'exists'
+>>> s.accessed
+True
+>>> s.modified
+True
>>> s.pop('some key', 'does not exist')
'does not exist'
diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py
index d615c8e661..86ef1e3526 100644
--- a/django/contrib/sitemaps/views.py
+++ b/django/contrib/sitemaps/views.py
@@ -2,6 +2,7 @@ from django.http import HttpResponse, Http404
from django.template import loader
from django.contrib.sites.models import Site
from django.core import urlresolvers
+from django.utils.encoding import smart_str
def index(request, sitemaps):
current_site = Site.objects.get_current()
@@ -26,5 +27,5 @@ def sitemap(request, sitemaps, section=None):
urls.extend(site().get_urls())
else:
urls.extend(site.get_urls())
- xml = loader.render_to_string('sitemap.xml', {'urlset': urls})
+ xml = smart_str(loader.render_to_string('sitemap.xml', {'urlset': urls}))
return HttpResponse(xml, mimetype='application/xml')
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index df93c543d2..191d5d0a3e 100644
--- a/django/contrib/sites/models.py
+++ b/django/contrib/sites/models.py
@@ -1,14 +1,19 @@
from django.db import models
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
class SiteManager(models.Manager):
def get_current(self):
from django.conf import settings
- return self.get(pk=settings.SITE_ID)
+ try:
+ sid = settings.SITE_ID
+ except AttributeError:
+ from django.core.exceptions import ImproperlyConfigured
+ raise ImproperlyConfigured("You're using the Django \"sites framework\" without having set the SITE_ID setting. Create a site in your database and set the SITE_ID setting to fix this error.")
+ return self.get(pk=sid)
class Site(models.Model):
- domain = models.CharField(_('domain name'), maxlength=100)
- name = models.CharField(_('display name'), maxlength=50)
+ domain = models.CharField(_('domain name'), max_length=100)
+ name = models.CharField(_('display name'), max_length=50)
objects = SiteManager()
class Meta:
db_table = 'django_site'
@@ -19,5 +24,22 @@ class Site(models.Model):
list_display = ('domain', 'name')
search_fields = ('domain', 'name')
- def __str__(self):
+ def __unicode__(self):
return self.domain
+
+class RequestSite(object):
+ """
+ A class that shares the primary interface of Site (i.e., it has
+ ``domain`` and ``name`` attributes) but gets its data from a Django
+ HttpRequest object rather than from a database.
+
+ The save() and delete() methods raise NotImplementedError.
+ """
+ def __init__(self, request):
+ self.domain = self.name = request.META['SERVER_NAME']
+
+ def save(self):
+ raise NotImplementedError('RequestSite cannot be saved.')
+
+ def delete(self):
+ raise NotImplementedError('RequestSite cannot be deleted.')
diff --git a/django/contrib/syndication/feeds.py b/django/contrib/syndication/feeds.py
index af00bdc3e9..eb5a9f0607 100644
--- a/django/contrib/syndication/feeds.py
+++ b/django/contrib/syndication/feeds.py
@@ -1,12 +1,15 @@
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.template import Context, loader, Template, TemplateDoesNotExist
-from django.contrib.sites.models import Site
+from django.contrib.sites.models import Site, RequestSite
from django.utils import feedgenerator
+from django.utils.encoding import smart_unicode, iri_to_uri
from django.conf import settings
def add_domain(domain, url):
if not url.startswith('http://'):
- url = u'http://%s%s' % (domain, url)
+ # 'url' must already be ASCII and URL-quoted, so no need for encoding
+ # conversions here.
+ url = iri_to_uri(u'http://%s%s' % (domain, url))
return url
class FeedDoesNotExist(ObjectDoesNotExist):
@@ -19,9 +22,10 @@ class Feed(object):
title_template = None
description_template = None
- def __init__(self, slug, feed_url):
+ def __init__(self, slug, request):
self.slug = slug
- self.feed_url = feed_url
+ self.request = request
+ self.feed_url = request.path
self.title_template_name = self.title_template or ('feeds/%s_title.html' % slug)
self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug)
@@ -64,7 +68,11 @@ class Feed(object):
else:
obj = None
- current_site = Site.objects.get_current()
+ if Site._meta.installed:
+ current_site = Site.objects.get_current()
+ else:
+ current_site = RequestSite(self.request)
+
link = self.__get_dynamic_attr('link', obj)
link = add_domain(current_site.domain, link)
@@ -80,6 +88,7 @@ class Feed(object):
author_email = self.__get_dynamic_attr('author_email', obj),
categories = self.__get_dynamic_attr('categories', obj),
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
+ feed_guid = self.__get_dynamic_attr('feed_guid', obj),
)
try:
@@ -97,9 +106,9 @@ class Feed(object):
enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
if enc_url:
enc = feedgenerator.Enclosure(
- url = enc_url.decode('utf-8'),
- length = str(self.__get_dynamic_attr('item_enclosure_length', item)).decode('utf-8'),
- mime_type = self.__get_dynamic_attr('item_enclosure_mime_type', item).decode('utf-8'),
+ url = smart_unicode(enc_url),
+ length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
+ mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
)
author_name = self.__get_dynamic_attr('item_author_name', item)
if author_name is not None:
@@ -108,10 +117,10 @@ class Feed(object):
else:
author_email = author_link = None
feed.add_item(
- title = title_tmp.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
+ title = title_tmp.render(Context({'obj': item, 'site': current_site})),
link = link,
- description = description_tmp.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
- unique_id = link,
+ description = description_tmp.render(Context({'obj': item, 'site': current_site})),
+ unique_id = self.__get_dynamic_attr('item_guid', item, link),
enclosure = enc,
pubdate = self.__get_dynamic_attr('item_pubdate', item),
author_name = author_name,
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index 621665d4d4..423d333991 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -16,7 +16,7 @@ def feed(request, url, feed_dict=None):
raise Http404, "Slug %r isn't registered." % slug
try:
- feedgen = f(slug, request.path).get_feed(param)
+ feedgen = f(slug, request).get_feed(param)
except feeds.FeedDoesNotExist:
raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
diff --git a/django/contrib/webdesign/lorem_ipsum.py b/django/contrib/webdesign/lorem_ipsum.py
index 6226bbef1b..4ad175d033 100644
--- a/django/contrib/webdesign/lorem_ipsum.py
+++ b/django/contrib/webdesign/lorem_ipsum.py
@@ -5,8 +5,40 @@ Utility functions for generating "lorem ipsum" Latin text.
import random
COMMON_P = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
-WORDS = ('exercitationem', 'perferendis', 'perspiciatis', 'laborum', 'eveniet', 'sunt', 'iure', 'nam', 'nobis', 'eum', 'cum', 'officiis', 'excepturi', 'odio', 'consectetur', 'quasi', 'aut', 'quisquam', 'vel', 'eligendi', 'itaque', 'non', 'odit', 'tempore', 'quaerat', 'dignissimos', 'facilis', 'neque', 'nihil', 'expedita', 'vitae', 'vero', 'ipsum', 'nisi', 'animi', 'cumque', 'pariatur', 'velit', 'modi', 'natus', 'iusto', 'eaque', 'sequi', 'illo', 'sed', 'ex', 'et', 'voluptatibus', 'tempora', 'veritatis', 'ratione', 'assumenda', 'incidunt', 'nostrum', 'placeat', 'aliquid', 'fuga', 'provident', 'praesentium', 'rem', 'necessitatibus', 'suscipit', 'adipisci', 'quidem', 'possimus', 'voluptas', 'debitis', 'sint', 'accusantium', 'unde', 'sapiente', 'voluptate', 'qui', 'aspernatur', 'laudantium', 'soluta', 'amet', 'quo', 'aliquam', 'saepe', 'culpa', 'libero', 'ipsa', 'dicta', 'reiciendis', 'nesciunt', 'doloribus', 'autem', 'impedit', 'minima', 'maiores', 'repudiandae', 'ipsam', 'obcaecati', 'ullam', 'enim', 'totam', 'delectus', 'ducimus', 'quis', 'voluptates', 'dolores', 'molestiae', 'harum', 'dolorem', 'quia', 'voluptatem', 'molestias', 'magni', 'distinctio', 'omnis', 'illum', 'dolorum', 'voluptatum', 'ea', 'quas', 'quam', 'corporis', 'quae', 'blanditiis', 'atque', 'deserunt', 'laboriosam', 'earum', 'consequuntur', 'hic', 'cupiditate', 'quibusdam', 'accusamus', 'ut', 'rerum', 'error', 'minus', 'eius', 'ab', 'ad', 'nemo', 'fugit', 'officia', 'at', 'in', 'id', 'quos', 'reprehenderit', 'numquam', 'iste', 'fugiat', 'sit', 'inventore', 'beatae', 'repellendus', 'magnam', 'recusandae', 'quod', 'explicabo', 'doloremque', 'aperiam', 'consequatur', 'asperiores', 'commodi', 'optio', 'dolor', 'labore', 'temporibus', 'repellat', 'veniam', 'architecto', 'est', 'esse', 'mollitia', 'nulla', 'a', 'similique', 'eos', 'alias', 'dolore', 'tenetur', 'deleniti', 'porro', 'facere', 'maxime', 'corrupti')
-COMMON_WORDS = ('lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua')
+
+WORDS = ('exercitationem', 'perferendis', 'perspiciatis', 'laborum', 'eveniet',
+ 'sunt', 'iure', 'nam', 'nobis', 'eum', 'cum', 'officiis', 'excepturi',
+ 'odio', 'consectetur', 'quasi', 'aut', 'quisquam', 'vel', 'eligendi',
+ 'itaque', 'non', 'odit', 'tempore', 'quaerat', 'dignissimos',
+ 'facilis', 'neque', 'nihil', 'expedita', 'vitae', 'vero', 'ipsum',
+ 'nisi', 'animi', 'cumque', 'pariatur', 'velit', 'modi', 'natus',
+ 'iusto', 'eaque', 'sequi', 'illo', 'sed', 'ex', 'et', 'voluptatibus',
+ 'tempora', 'veritatis', 'ratione', 'assumenda', 'incidunt', 'nostrum',
+ 'placeat', 'aliquid', 'fuga', 'provident', 'praesentium', 'rem',
+ 'necessitatibus', 'suscipit', 'adipisci', 'quidem', 'possimus',
+ 'voluptas', 'debitis', 'sint', 'accusantium', 'unde', 'sapiente',
+ 'voluptate', 'qui', 'aspernatur', 'laudantium', 'soluta', 'amet',
+ 'quo', 'aliquam', 'saepe', 'culpa', 'libero', 'ipsa', 'dicta',
+ 'reiciendis', 'nesciunt', 'doloribus', 'autem', 'impedit', 'minima',
+ 'maiores', 'repudiandae', 'ipsam', 'obcaecati', 'ullam', 'enim',
+ 'totam', 'delectus', 'ducimus', 'quis', 'voluptates', 'dolores',
+ 'molestiae', 'harum', 'dolorem', 'quia', 'voluptatem', 'molestias',
+ 'magni', 'distinctio', 'omnis', 'illum', 'dolorum', 'voluptatum', 'ea',
+ 'quas', 'quam', 'corporis', 'quae', 'blanditiis', 'atque', 'deserunt',
+ 'laboriosam', 'earum', 'consequuntur', 'hic', 'cupiditate',
+ 'quibusdam', 'accusamus', 'ut', 'rerum', 'error', 'minus', 'eius',
+ 'ab', 'ad', 'nemo', 'fugit', 'officia', 'at', 'in', 'id', 'quos',
+ 'reprehenderit', 'numquam', 'iste', 'fugiat', 'sit', 'inventore',
+ 'beatae', 'repellendus', 'magnam', 'recusandae', 'quod', 'explicabo',
+ 'doloremque', 'aperiam', 'consequatur', 'asperiores', 'commodi',
+ 'optio', 'dolor', 'labore', 'temporibus', 'repellat', 'veniam',
+ 'architecto', 'est', 'esse', 'mollitia', 'nulla', 'a', 'similique',
+ 'eos', 'alias', 'dolore', 'tenetur', 'deleniti', 'porro', 'facere',
+ 'maxime', 'corrupti')
+
+COMMON_WORDS = ('lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
+ 'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt',
+ 'ut', 'labore', 'et', 'dolore', 'magna', 'aliqua')
def sentence():
"""
@@ -17,10 +49,10 @@ def sentence():
"""
# Determine the number of comma-separated sections and number of words in
# each section for this sentence.
- sections = [' '.join(random.sample(WORDS, random.randint(3, 12))) for i in range(random.randint(1, 5))]
- s = ', '.join(sections)
+ sections = [u' '.join(random.sample(WORDS, random.randint(3, 12))) for i in range(random.randint(1, 5))]
+ s = u', '.join(sections)
# Convert to sentence case and add end punctuation.
- return '%s%s%s' % (s[0].upper(), s[1:], random.choice('?.'))
+ return u'%s%s%s' % (s[0].upper(), s[1:], random.choice('?.'))
def paragraph():
"""
@@ -28,7 +60,7 @@ def paragraph():
The paragraph consists of between 1 and 4 sentences, inclusive.
"""
- return ' '.join([sentence() for i in range(random.randint(1, 4))])
+ return u' '.join([sentence() for i in range(random.randint(1, 4))])
def paragraphs(count, common=True):
"""
@@ -66,4 +98,4 @@ def words(count, common=True):
word_list += random.sample(WORDS, c)
else:
word_list = word_list[:count]
- return ' '.join(word_list)
+ return u' '.join(word_list)
diff --git a/django/contrib/webdesign/templatetags/webdesign.py b/django/contrib/webdesign/templatetags/webdesign.py
index e5117093f8..2370659f1d 100644
--- a/django/contrib/webdesign/templatetags/webdesign.py
+++ b/django/contrib/webdesign/templatetags/webdesign.py
@@ -18,7 +18,7 @@ class LoremNode(template.Node):
paras = paragraphs(count, common=self.common)
if self.method == 'p':
paras = ['<p>%s</p>' % p for p in paras]
- return '\n\n'.join(paras)
+ return u'\n\n'.join(paras)
#@register.tag
def lorem(parser, token):
diff --git a/django/contrib/webdesign/tests.py b/django/contrib/webdesign/tests.py
index d20ebf110a..eeb1956a01 100644
--- a/django/contrib/webdesign/tests.py
+++ b/django/contrib/webdesign/tests.py
@@ -2,7 +2,7 @@
r"""
>>> words(7)
-'lorem ipsum dolor sit amet consectetur adipisicing'
+u'lorem ipsum dolor sit amet consectetur adipisicing'
>>> paragraphs(1)
['Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.']
@@ -14,4 +14,4 @@ import datetime
if __name__ == '__main__':
import doctest
- doctest.testmod() \ No newline at end of file
+ doctest.testmod()
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index faaf8910ce..d5415c8ace 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -1,7 +1,8 @@
"File-based cache backend"
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
-import os, time, urllib
+from django.utils.http import urlquote_plus
+import os, time
try:
import cPickle as pickle
except ImportError:
@@ -77,4 +78,4 @@ class CacheClass(SimpleCacheClass):
raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir
def _key_to_file(self, key):
- return os.path.join(self._dir, urllib.quote_plus(key))
+ return os.path.join(self._dir, urlquote_plus(key))
diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
index 0e21b80ed8..4c48c571b7 100644
--- a/django/core/cache/backends/locmem.py
+++ b/django/core/cache/backends/locmem.py
@@ -1,8 +1,13 @@
"Thread-safe in-memory cache backend."
+import time
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
from django.utils.synch import RWLock
-import copy, time
class CacheClass(SimpleCacheClass):
def __init__(self, host, params):
@@ -20,7 +25,10 @@ class CacheClass(SimpleCacheClass):
elif exp < now:
should_delete = True
else:
- return copy.deepcopy(self._cache[key])
+ try:
+ return pickle.loads(self._cache[key])
+ except pickle.PickleError:
+ return default
finally:
self._lock.reader_leaves()
if should_delete:
@@ -35,7 +43,10 @@ class CacheClass(SimpleCacheClass):
def set(self, key, value, timeout=None):
self._lock.writer_enters()
try:
- SimpleCacheClass.set(self, key, value, timeout)
+ try:
+ super(CacheClass, self).set(key, pickle.dumps(value), timeout)
+ except pickle.PickleError:
+ pass
finally:
self._lock.writer_leaves()
diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py
index 1ab019221a..52610daef1 100644
--- a/django/core/cache/backends/memcached.py
+++ b/django/core/cache/backends/memcached.py
@@ -1,6 +1,7 @@
"Memcached cache backend"
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
+from django.utils.encoding import smart_unicode, smart_str
try:
import cmemcache as memcache
@@ -16,17 +17,22 @@ class CacheClass(BaseCache):
self._cache = memcache.Client(server.split(';'))
def get(self, key, default=None):
- val = self._cache.get(key)
+ val = self._cache.get(smart_str(key))
if val is None:
return default
else:
- return val
+ if isinstance(val, basestring):
+ return smart_unicode(val)
+ else:
+ return val
def set(self, key, value, timeout=0):
- self._cache.set(key, value, timeout or self.default_timeout)
+ if isinstance(value, unicode):
+ value = value.encode('utf-8')
+ self._cache.set(smart_str(key), value, timeout or self.default_timeout)
def delete(self, key):
- self._cache.delete(key)
+ self._cache.delete(smart_str(key))
def get_many(self, keys):
- return self._cache.get_multi(keys)
+ return self._cache.get_multi(map(smart_str,keys))
diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py
index 6370cab47c..7c4bbb3082 100644
--- a/django/core/handlers/modpython.py
+++ b/django/core/handlers/modpython.py
@@ -2,6 +2,7 @@ from django.core.handlers.base import BaseHandler
from django.core import signals
from django.dispatch import dispatcher
from django.utils import datastructures
+from django.utils.encoding import force_unicode
from django import http
from pprint import pformat
import os
@@ -13,7 +14,7 @@ import os
class ModPythonRequest(http.HttpRequest):
def __init__(self, req):
self._req = req
- self.path = req.uri
+ self.path = force_unicode(req.uri)
def __repr__(self):
# Since this is called as part of error handling, we need to be very
@@ -49,7 +50,7 @@ class ModPythonRequest(http.HttpRequest):
if 'content-type' in self._req.headers_in and self._req.headers_in['content-type'].startswith('multipart'):
self._post, self._files = http.parse_file_upload(self._req.headers_in, self.raw_post_data)
else:
- self._post, self._files = http.QueryDict(self.raw_post_data), datastructures.MultiValueDict()
+ self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()
def _get_request(self):
if not hasattr(self, '_request'):
@@ -58,7 +59,7 @@ class ModPythonRequest(http.HttpRequest):
def _get_get(self):
if not hasattr(self, '_get'):
- self._get = http.QueryDict(self._req.args)
+ self._get = http.QueryDict(self._req.args, encoding=self._encoding)
return self._get
def _set_get(self, get):
@@ -160,7 +161,7 @@ class ModPythonHandler(BaseHandler):
req.content_type = response['Content-Type']
for key, value in response.headers.items():
if key != 'Content-Type':
- req.headers_out[key] = value
+ req.headers_out[str(key)] = str(value)
for c in response.cookies.values():
req.headers_out.add('Set-Cookie', c.output(header=''))
req.status = response.status_code
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
index 4320b69627..99d400d1bb 100644
--- a/django/core/handlers/wsgi.py
+++ b/django/core/handlers/wsgi.py
@@ -2,9 +2,11 @@ from django.core.handlers.base import BaseHandler
from django.core import signals
from django.dispatch import dispatcher
from django.utils import datastructures
+from django.utils.encoding import force_unicode
from django import http
from pprint import pformat
from shutil import copyfileobj
+from threading import Lock
try:
from cStringIO import StringIO
except ImportError:
@@ -73,7 +75,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
class WSGIRequest(http.HttpRequest):
def __init__(self, environ):
self.environ = environ
- self.path = environ['PATH_INFO']
+ self.path = force_unicode(environ['PATH_INFO'])
self.META = environ
self.method = environ['REQUEST_METHOD'].upper()
@@ -113,9 +115,9 @@ class WSGIRequest(http.HttpRequest):
header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '')
self._post, self._files = http.parse_file_upload(header_dict, self.raw_post_data)
else:
- self._post, self._files = http.QueryDict(self.raw_post_data), datastructures.MultiValueDict()
+ self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()
else:
- self._post, self._files = http.QueryDict(''), datastructures.MultiValueDict()
+ self._post, self._files = http.QueryDict('', encoding=self._encoding), datastructures.MultiValueDict()
def _get_request(self):
if not hasattr(self, '_request'):
@@ -125,7 +127,7 @@ class WSGIRequest(http.HttpRequest):
def _get_get(self):
if not hasattr(self, '_get'):
# The WSGI spec says 'QUERY_STRING' may be absent.
- self._get = http.QueryDict(self.environ.get('QUERY_STRING', ''))
+ self._get = http.QueryDict(self.environ.get('QUERY_STRING', ''), encoding=self._encoding)
return self._get
def _set_get(self, get):
@@ -175,13 +177,19 @@ class WSGIRequest(http.HttpRequest):
raw_post_data = property(_get_raw_post_data)
class WSGIHandler(BaseHandler):
+ initLock = Lock()
+
def __call__(self, environ, start_response):
from django.conf import settings
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
if self._request_middleware is None:
- self.load_middleware()
+ self.initLock.acquire()
+ # Check that middleware is still uninitialised.
+ if self._request_middleware is None:
+ self.load_middleware()
+ self.initLock.release()
dispatcher.send(signal=signals.request_started)
try:
@@ -200,8 +208,8 @@ class WSGIHandler(BaseHandler):
except KeyError:
status_text = 'UNKNOWN STATUS CODE'
status = '%s %s' % (response.status_code, status_text)
- response_headers = response.headers.items()
+ response_headers = [(str(k), str(v)) for k, v in response.headers.items()]
for c in response.cookies.values():
- response_headers.append(('Set-Cookie', c.output(header='')))
+ response_headers.append(('Set-Cookie', str(c.output(header=''))))
start_response(status, response_headers)
return response
diff --git a/django/core/mail.py b/django/core/mail.py
index 2f252df724..ff653400f9 100644
--- a/django/core/mail.py
+++ b/django/core/mail.py
@@ -3,12 +3,13 @@ Tools for sending email.
"""
from django.conf import settings
+from django.utils.encoding import smart_str, force_unicode
from email import Charset, Encoders
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.Header import Header
-from email.Utils import formatdate
+from email.Utils import formatdate, parseaddr, formataddr
import mimetypes
import os
import smtplib
@@ -67,8 +68,18 @@ class SafeMIMEText(MIMEText):
"Forbids multi-line headers, to prevent header injection."
if '\n' in val or '\r' in val:
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
- if name == "Subject":
- val = Header(val, settings.DEFAULT_CHARSET)
+ try:
+ val = str(force_unicode(val))
+ except UnicodeEncodeError:
+ if name.lower() in ('to', 'from', 'cc'):
+ result = []
+ for item in val.split(', '):
+ nm, addr = parseaddr(item)
+ nm = str(Header(nm, settings.DEFAULT_CHARSET))
+ result.append(formataddr((nm, str(addr))))
+ val = ', '.join(result)
+ else:
+ val = Header(force_unicode(val), settings.DEFAULT_CHARSET)
MIMEText.__setitem__(self, name, val)
class SafeMIMEMultipart(MIMEMultipart):
@@ -76,8 +87,18 @@ class SafeMIMEMultipart(MIMEMultipart):
"Forbids multi-line headers, to prevent header injection."
if '\n' in val or '\r' in val:
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
- if name == "Subject":
- val = Header(val, settings.DEFAULT_CHARSET)
+ try:
+ val = str(force_unicode(val))
+ except UnicodeEncodeError:
+ if name.lower() in ('to', 'from', 'cc'):
+ result = []
+ for item in val.split(', '):
+ nm, addr = parseaddr(item)
+ nm = str(Header(nm, settings.DEFAULT_CHARSET))
+ result.append(formataddr((nm, str(addr))))
+ val = ', '.join(result)
+ else:
+ val = Header(force_unicode(val), settings.DEFAULT_CHARSET)
MIMEMultipart.__setitem__(self, name, val)
class SMTPConnection(object):
@@ -176,6 +197,14 @@ class EmailMessage(object):
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None):
+ """
+ Initialise a single email message (which can be sent to multiple
+ recipients).
+
+ All strings used to create the message can be unicode strings (or UTF-8
+ bytestrings). The SafeMIMEText class will handle any necessary encoding
+ conversions.
+ """
self.to = to or []
self.bcc = bcc or []
self.from_email = from_email or settings.DEFAULT_FROM_EMAIL
@@ -192,7 +221,7 @@ class EmailMessage(object):
def message(self):
encoding = self.encoding or settings.DEFAULT_CHARSET
- msg = SafeMIMEText(self.body, self.content_subtype, encoding)
+ msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET), self.content_subtype, encoding)
if self.attachments:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.multipart_subtype)
@@ -236,7 +265,7 @@ class EmailMessage(object):
"""
if isinstance(filename, MIMEBase):
assert content == mimetype == None
- self.attachements.append(filename)
+ self.attachments.append(filename)
else:
assert content is not None
self.attachments.append((filename, content, mimetype))
@@ -258,7 +287,8 @@ class EmailMessage(object):
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
- attachment = SafeMIMEText(content, subtype, settings.DEFAULT_CHARSET)
+ attachment = SafeMIMEText(smart_str(content,
+ settings.DEFAULT_CHARSET), subtype, settings.DEFAULT_CHARSET)
else:
# Encode non-text attachments with base64.
attachment = MIMEBase(basetype, subtype)
diff --git a/django/core/management.py b/django/core/management.py
deleted file mode 100644
index dd501aa9db..0000000000
--- a/django/core/management.py
+++ /dev/null
@@ -1,1747 +0,0 @@
-# Django management-related functions, including "CREATE TABLE" generation and
-# development-server initialization.
-
-import django
-from django.core.exceptions import ImproperlyConfigured
-from optparse import OptionParser
-from django.utils import termcolors
-import os, re, shutil, sys, textwrap
-
-try:
- set
-except NameError:
- from sets import Set as set # Python 2.3 fallback
-
-# For backwards compatibility: get_version() used to be in this module.
-get_version = django.get_version
-
-MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
- <tr>
- <th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
- <td class="x50">{%% if perms.%(app)s.%(addperm)s %%}<a href="%(app)s/%(mod)s/add/" class="addlink">{%% endif %%}Add{%% if perms.%(app)s.%(addperm)s %%}</a>{%% endif %%}</td>
- <td class="x75">{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/" class="changelink">{%% endif %%}Change{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</td>
- </tr>
- {%% endif %%}'''
-
-APP_ARGS = '[appname ...]'
-
-# Use django.__path__[0] because we don't know which directory django into
-# which has been installed.
-PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
-
-INVALID_PROJECT_NAMES = ('django', 'site', 'test')
-
-# Set up the terminal color scheme.
-class dummy: pass
-style = dummy()
-style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
-style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
-style.NOTICE = termcolors.make_style(fg='red')
-style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
-style.SQL_COLTYPE = termcolors.make_style(fg='green')
-style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
-style.SQL_TABLE = termcolors.make_style(opts=('bold',))
-del dummy
-
-def disable_termcolors():
- class dummy:
- def __getattr__(self, attr):
- return lambda x: x
- global style
- style = dummy()
-
-# Disable terminal coloring on Windows, Pocket PC, or if somebody's piping the output.
-if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
- disable_termcolors()
-
-def _is_valid_dir_name(s):
- return bool(re.search(r'^\w+$', s))
-
-def _get_installed_models(table_list):
- "Gets a set of all models that are installed, given a list of existing tables"
- from django.db import backend, models
- all_models = []
- for app in models.get_apps():
- for model in models.get_models(app):
- all_models.append(model)
- if backend.uses_case_insensitive_names:
- converter = str.upper
- else:
- converter = lambda x: x
- return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
-
-def _get_table_list():
- "Gets a list of all db tables that are physically installed."
- from django.db import connection, get_introspection_module
- cursor = connection.cursor()
- return get_introspection_module().get_table_list(cursor)
-
-def _get_sequence_list():
- "Returns a list of information about all DB sequences for all models in all apps"
- from django.db import models
-
- apps = models.get_apps()
- sequence_list = []
-
- for app in apps:
- for model in models.get_models(app):
- for f in model._meta.fields:
- if isinstance(f, models.AutoField):
- sequence_list.append({'table':model._meta.db_table,'column':f.column,})
- break # Only one AutoField is allowed per model, so don't bother continuing.
-
- for f in model._meta.many_to_many:
- sequence_list.append({'table':f.m2m_db_table(),'column':None,})
-
- return sequence_list
-
-# If the foreign key points to an AutoField, a PositiveIntegerField or a
-# PositiveSmallIntegerField, the foreign key should be an IntegerField, not the
-# referred field type. Otherwise, the foreign key should be the same type of
-# field as the field to which it points.
-get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type()
-
-def get_sql_create(app):
- "Returns a list of the CREATE TABLE SQL statements for the given app."
- from django.db import get_creation_module, models
-
- data_types = get_creation_module().DATA_TYPES
-
- if not data_types:
- # This must be the "dummy" database backend, which means the user
- # hasn't set DATABASE_ENGINE.
- sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
- "because you haven't specified the DATABASE_ENGINE setting.\n" +
- "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
- sys.exit(1)
-
- # Get installed models, so we generate REFERENCES right.
- # We trim models from the current app so that the sqlreset command does not
- # generate invalid SQL (leaving models out of known_models is harmless, so
- # we can be conservative).
- app_models = models.get_models(app)
- final_output = []
- known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
- pending_references = {}
-
- for model in app_models:
- output, references = _get_sql_model_create(model, known_models)
- final_output.extend(output)
- for refto, refs in references.items():
- pending_references.setdefault(refto,[]).extend(refs)
- final_output.extend(_get_sql_for_pending_references(model, pending_references))
- # Keep track of the fact that we've created the table for this model.
- known_models.add(model)
-
- # Create the many-to-many join tables.
- for model in app_models:
- final_output.extend(_get_many_to_many_sql_for_model(model))
-
- # Handle references to tables that are from other apps
- # but don't exist physically
- not_installed_models = set(pending_references.keys())
- if not_installed_models:
- alter_sql = []
- for model in not_installed_models:
- alter_sql.extend(['-- ' + sql for sql in
- _get_sql_for_pending_references(model, pending_references)])
- if alter_sql:
- final_output.append('-- The following references should be added but depend on non-existent tables:')
- final_output.extend(alter_sql)
-
- return final_output
-get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
-get_sql_create.args = APP_ARGS
-
-def _get_sql_model_create(model, known_models=set()):
- """
- Get the SQL required to create a single model.
-
- Returns list_of_sql, pending_references_dict
- """
- from django.db import backend, get_creation_module, models
- data_types = get_creation_module().DATA_TYPES
-
- opts = model._meta
- final_output = []
- table_output = []
- pending_references = {}
- for f in opts.fields:
- if isinstance(f, (models.ForeignKey, models.OneToOneField)):
- rel_field = f.rel.get_related_field()
- while isinstance(rel_field, (models.ForeignKey, models.OneToOneField)):
- rel_field = rel_field.rel.get_related_field()
- data_type = get_rel_data_type(rel_field)
- else:
- rel_field = f
- data_type = f.get_internal_type()
- col_type = data_types[data_type]
- tablespace = f.db_tablespace or opts.db_tablespace
- if col_type is not None:
- # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
- field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
- style.SQL_COLTYPE(col_type % rel_field.__dict__)]
- field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
- if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
- field_output.append(style.SQL_KEYWORD('UNIQUE'))
- if f.primary_key:
- field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
- if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
- # We must specify the index tablespace inline, because we
- # won't be generating a CREATE INDEX statement for this field.
- field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
- if f.rel:
- if f.rel.to in known_models:
- field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
- style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
- style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
- backend.get_deferrable_sql()
- )
- else:
- # We haven't yet created the table to which this field
- # is related, so save it for later.
- pr = pending_references.setdefault(f.rel.to, []).append((model, f))
- table_output.append(' '.join(field_output))
- if opts.order_with_respect_to:
- table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
- style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \
- style.SQL_KEYWORD('NULL'))
- for field_constraints in opts.unique_together:
- table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
- ", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
-
- full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
- for i, line in enumerate(table_output): # Combine and add commas.
- full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
- full_statement.append(')')
- if opts.db_tablespace and backend.supports_tablespaces:
- full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
- full_statement.append(';')
- final_output.append('\n'.join(full_statement))
-
- if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
- # Add any extra SQL needed to support auto-incrementing primary keys
- autoinc_sql = backend.get_autoinc_sql(opts.db_table)
- if autoinc_sql:
- for stmt in autoinc_sql:
- final_output.append(stmt)
-
- return final_output, pending_references
-
-def _get_sql_for_pending_references(model, pending_references):
- """
- Get any ALTER TABLE statements to add constraints after the fact.
- """
- from django.db import backend, get_creation_module
- from django.db.backends.util import truncate_name
- data_types = get_creation_module().DATA_TYPES
-
- final_output = []
- if backend.supports_constraints:
- opts = model._meta
- if model in pending_references:
- for rel_class, f in pending_references[model]:
- rel_opts = rel_class._meta
- r_table = rel_opts.db_table
- r_col = f.column
- table = opts.db_table
- col = opts.get_field(f.rel.field_name).column
- # For MySQL, r_name must be unique in the first 64 characters.
- # So we are careful with character usage here.
- r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
- final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
- (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
- backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
- backend.get_deferrable_sql()))
- del pending_references[model]
- return final_output
-
-def _get_many_to_many_sql_for_model(model):
- from django.db import backend, get_creation_module
- from django.contrib.contenttypes import generic
-
- data_types = get_creation_module().DATA_TYPES
-
- opts = model._meta
- final_output = []
- for f in opts.many_to_many:
- if not isinstance(f.rel, generic.GenericRel):
- tablespace = f.db_tablespace or opts.db_tablespace
- if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
- tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
- else:
- tablespace_sql = ''
- table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
- style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
- table_output.append(' %s %s %s%s,' % \
- (style.SQL_FIELD(backend.quote_name('id')),
- style.SQL_COLTYPE(data_types['AutoField']),
- style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
- tablespace_sql))
- table_output.append(' %s %s %s %s (%s)%s,' % \
- (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
- style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
- style.SQL_KEYWORD('NOT NULL REFERENCES'),
- style.SQL_TABLE(backend.quote_name(opts.db_table)),
- style.SQL_FIELD(backend.quote_name(opts.pk.column)),
- backend.get_deferrable_sql()))
- table_output.append(' %s %s %s %s (%s)%s,' % \
- (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
- style.SQL_COLTYPE(data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__),
- style.SQL_KEYWORD('NOT NULL REFERENCES'),
- style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
- style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
- backend.get_deferrable_sql()))
- table_output.append(' %s (%s, %s)%s' % \
- (style.SQL_KEYWORD('UNIQUE'),
- style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
- style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
- tablespace_sql))
- table_output.append(')')
- if opts.db_tablespace and backend.supports_tablespaces:
- # f.db_tablespace is only for indices, so ignore its value here.
- table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
- table_output.append(';')
- final_output.append('\n'.join(table_output))
-
- # Add any extra SQL needed to support auto-incrementing PKs
- autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
- if autoinc_sql:
- for stmt in autoinc_sql:
- final_output.append(stmt)
-
- return final_output
-
-def get_sql_delete(app):
- "Returns a list of the DROP TABLE SQL statements for the given app."
- from django.db import backend, connection, models, get_introspection_module
- from django.db.backends.util import truncate_name
- introspection = get_introspection_module()
-
- # This should work even if a connection isn't available
- try:
- cursor = connection.cursor()
- except:
- cursor = None
-
- # Figure out which tables already exist
- if cursor:
- table_names = introspection.get_table_list(cursor)
- else:
- table_names = []
- if backend.uses_case_insensitive_names:
- table_name_converter = str.upper
- else:
- table_name_converter = lambda x: x
-
- output = []
-
- # Output DROP TABLE statements for standard application tables.
- to_delete = set()
-
- references_to_delete = {}
- app_models = models.get_models(app)
- for model in app_models:
- if cursor and table_name_converter(model._meta.db_table) in table_names:
- # The table exists, so it needs to be dropped
- opts = model._meta
- for f in opts.fields:
- if f.rel and f.rel.to not in to_delete:
- references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
-
- to_delete.add(model)
-
- for model in app_models:
- if cursor and table_name_converter(model._meta.db_table) in table_names:
- # Drop the table now
- output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
- style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
- if backend.supports_constraints and model in references_to_delete:
- for rel_class, f in references_to_delete[model]:
- table = rel_class._meta.db_table
- col = f.column
- r_table = model._meta.db_table
- r_col = model._meta.get_field(f.rel.field_name).column
- r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
- output.append('%s %s %s %s;' % \
- (style.SQL_KEYWORD('ALTER TABLE'),
- style.SQL_TABLE(backend.quote_name(table)),
- style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
- style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
- del references_to_delete[model]
- if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
- output.append(backend.get_drop_sequence(model._meta.db_table))
-
- # Output DROP TABLE statements for many-to-many tables.
- for model in app_models:
- opts = model._meta
- for f in opts.many_to_many:
- if cursor and table_name_converter(f.m2m_db_table()) in table_names:
- output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
- style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
- if hasattr(backend, 'get_drop_sequence'):
- output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
-
- # Any post deletion needed? (e.g., DropGeometryColumn() in PostGIS)
- for model in app_models:
- opts = model._meta
- for f in opts.fields:
- if hasattr(f, '_post_delete_sql'):
- output.append(f._post_delete_sql(style, model._meta.db_table))
-
- app_label = app_models[0]._meta.app_label
-
- # Close database connection explicitly, in case this output is being piped
- # directly into a database client, to avoid locking issues.
- if cursor:
- cursor.close()
- connection.close()
-
- return output[::-1] # Reverse it, to deal with table dependencies.
-get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given app name(s)."
-get_sql_delete.args = APP_ARGS
-
-def get_sql_reset(app):
- "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
- return get_sql_delete(app) + get_sql_all(app)
-get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
-get_sql_reset.args = APP_ARGS
-
-def get_sql_flush():
- "Returns a list of the SQL statements used to flush the database"
- from django.db import backend
- statements = backend.get_sql_flush(style, _get_table_list(), _get_sequence_list())
- return statements
-get_sql_flush.help_doc = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
-get_sql_flush.args = ''
-
-def get_custom_sql_for_model(model):
- from django.db import models
- from django.conf import settings
-
- opts = model._meta
- app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
- output = []
-
- # Post-creation SQL should come before any initial SQL data is loaded.
- for f in opts.fields:
- if hasattr(f, '_post_create_sql'):
- output.append(f._post_create_sql(style, model._meta.db_table))
-
- # Some backends can't execute more than one SQL statement at a time,
- # so split into separate statements.
- statements = re.compile(r";[ \t]*$", re.M)
-
- # Find custom SQL, if it's available.
- sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
- os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
- for sql_file in sql_files:
- if os.path.exists(sql_file):
- fp = open(sql_file, 'U')
- for statement in statements.split(fp.read()):
- # Remove any comments from the file
- statement = re.sub(r"--.*[\n\Z]", "", statement)
- if statement.strip():
- output.append(statement + ";")
- fp.close()
-
- return output
-
-def get_custom_sql(app):
- "Returns a list of the custom table modifying SQL statements for the given app."
- from django.db.models import get_models
- output = []
-
- app_models = get_models(app)
- app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
-
- for model in app_models:
- output.extend(get_custom_sql_for_model(model))
-
- return output
-get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)."
-get_custom_sql.args = APP_ARGS
-
-def get_sql_initial_data(apps):
- "Returns a list of the initial INSERT SQL statements for the given app."
- return style.ERROR("This action has been renamed. Try './manage.py sqlcustom %s'." % ' '.join(apps and apps or ['app1', 'app2']))
-get_sql_initial_data.help_doc = "RENAMED: see 'sqlcustom'"
-get_sql_initial_data.args = ''
-
-def get_sql_sequence_reset(app):
- "Returns a list of the SQL statements to reset sequences for the given app."
- from django.db import backend, models
- return backend.get_sql_sequence_reset(style, models.get_models(app))
-get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting sequences for the given app name(s)."
-get_sql_sequence_reset.args = APP_ARGS
-
-def get_sql_indexes(app):
- "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
- from django.db import models
- output = []
- for model in models.get_models(app):
- output.extend(get_sql_indexes_for_model(model))
- return output
-get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
-get_sql_indexes.args = APP_ARGS
-
-def get_sql_indexes_for_model(model):
- "Returns the CREATE INDEX SQL statements for a single model"
- from django.db import backend
- output = []
-
- for f in model._meta.fields:
- if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
- unique = f.unique and 'UNIQUE ' or ''
- tablespace = f.db_tablespace or model._meta.db_tablespace
- if tablespace and backend.supports_tablespaces:
- tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
- else:
- tablespace_sql = ''
- output.append(
- style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
- style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
- style.SQL_KEYWORD('ON') + ' ' + \
- style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
- "(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
- "%s;" % tablespace_sql
- )
- return output
-
-def get_sql_all(app):
- "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
- return get_sql_create(app) + get_custom_sql(app) + get_sql_indexes(app)
-get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
-get_sql_all.args = APP_ARGS
-
-def _emit_post_sync_signal(created_models, verbosity, interactive):
- from django.db import models
- from django.dispatch import dispatcher
- # Emit the post_sync signal for every application.
- for app in models.get_apps():
- app_name = app.__name__.split('.')[-2]
- if verbosity >= 2:
- print "Running post-sync handlers for application", app_name
- dispatcher.send(signal=models.signals.post_syncdb, sender=app,
- app=app, created_models=created_models,
- verbosity=verbosity, interactive=interactive)
-
-def syncdb(verbosity=1, interactive=True):
- "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
- from django.db import backend, connection, transaction, models, get_creation_module
- from django.conf import settings
-
- disable_termcolors()
-
- # First, try validating the models.
- _check_for_validation_errors()
-
- # Import the 'management' module within each installed app, to register
- # dispatcher events.
- for app_name in settings.INSTALLED_APPS:
- try:
- __import__(app_name + '.management', {}, {}, [''])
- except ImportError:
- pass
-
- data_types = get_creation_module().DATA_TYPES
-
- cursor = connection.cursor()
-
- # Get a list of all existing database tables,
- # so we know what needs to be added.
- table_list = _get_table_list()
- if backend.uses_case_insensitive_names:
- table_name_converter = str.upper
- else:
- table_name_converter = lambda x: x
-
- # Get a list of already installed *models* so that references work right.
- seen_models = _get_installed_models(table_list)
- created_models = set()
- pending_references = {}
-
- # Create the tables for each model
- for app in models.get_apps():
- app_name = app.__name__.split('.')[-2]
- model_list = models.get_models(app)
- for model in model_list:
- # Create the model's database table, if it doesn't already exist.
- if verbosity >= 2:
- print "Processing %s.%s model" % (app_name, model._meta.object_name)
- if table_name_converter(model._meta.db_table) in table_list:
- continue
- sql, references = _get_sql_model_create(model, seen_models)
- seen_models.add(model)
- created_models.add(model)
- for refto, refs in references.items():
- pending_references.setdefault(refto, []).extend(refs)
- sql.extend(_get_sql_for_pending_references(model, pending_references))
- if verbosity >= 1:
- print "Creating table %s" % model._meta.db_table
- for statement in sql:
- cursor.execute(statement)
- table_list.append(table_name_converter(model._meta.db_table))
-
- # Create the m2m tables. This must be done after all tables have been created
- # to ensure that all referred tables will exist.
- for app in models.get_apps():
- app_name = app.__name__.split('.')[-2]
- model_list = models.get_models(app)
- for model in model_list:
- if model in created_models:
- sql = _get_many_to_many_sql_for_model(model)
- if sql:
- if verbosity >= 2:
- print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
- for statement in sql:
- cursor.execute(statement)
-
- transaction.commit_unless_managed()
-
- # Send the post_syncdb signal, so individual apps can do whatever they need
- # to do at this point.
- _emit_post_sync_signal(created_models, verbosity, interactive)
-
- # Install custom SQL for the app (but only if this
- # is a model we've just created)
- for app in models.get_apps():
- app_name = app.__name__.split('.')[-2]
- for model in models.get_models(app):
- if model in created_models:
- custom_sql = get_custom_sql_for_model(model)
- if custom_sql:
- if verbosity >= 1:
- print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
- try:
- for sql in custom_sql:
- cursor.execute(sql)
- except Exception, e:
- sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \
- (app_name, model._meta.object_name, e))
- transaction.rollback_unless_managed()
- else:
- transaction.commit_unless_managed()
-
- # Install SQL indicies for all newly created models
- for app in models.get_apps():
- app_name = app.__name__.split('.')[-2]
- for model in models.get_models(app):
- if model in created_models:
- index_sql = get_sql_indexes_for_model(model)
- if index_sql:
- if verbosity >= 1:
- print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
- try:
- for sql in index_sql:
- cursor.execute(sql)
- except Exception, e:
- sys.stderr.write("Failed to install index for %s.%s model: %s" % \
- (app_name, model._meta.object_name, e))
- transaction.rollback_unless_managed()
- else:
- transaction.commit_unless_managed()
-
- # Install the 'initialdata' fixture, using format discovery
- load_data(['initial_data'], verbosity=verbosity)
-syncdb.help_doc = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
-syncdb.args = '[--verbosity] [--noinput]'
-
-def get_admin_index(app):
- "Returns admin-index template snippet (in list form) for the given app."
- from django.utils.text import capfirst
- from django.db.models import get_models
- output = []
- app_models = get_models(app)
- app_label = app_models[0]._meta.app_label
- output.append('{%% if perms.%s %%}' % app_label)
- output.append('<div class="module"><h2>%s</h2><table>' % app_label.title())
- for model in app_models:
- if model._meta.admin:
- output.append(MODULE_TEMPLATE % {
- 'app': app_label,
- 'mod': model._meta.module_name,
- 'name': capfirst(model._meta.verbose_name_plural),
- 'addperm': model._meta.get_add_permission(),
- 'changeperm': model._meta.get_change_permission(),
- })
- output.append('</table></div>')
- output.append('{% endif %}')
- return output
-get_admin_index.help_doc = "Prints the admin-index template snippet for the given app name(s)."
-get_admin_index.args = APP_ARGS
-
-def _module_to_dict(module, omittable=lambda k: k.startswith('_')):
- "Converts a module namespace to a Python dictionary. Used by get_settings_diff."
- return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])
-
-def diffsettings():
- """
- Displays differences between the current settings.py and Django's
- default settings. Settings that don't appear in the defaults are
- followed by "###".
- """
- # Inspired by Postfix's "postconf -n".
- from django.conf import settings, global_settings
-
- user_settings = _module_to_dict(settings._target)
- default_settings = _module_to_dict(global_settings)
-
- output = []
- keys = user_settings.keys()
- keys.sort()
- for key in keys:
- if key not in default_settings:
- output.append("%s = %s ###" % (key, user_settings[key]))
- elif user_settings[key] != default_settings[key]:
- output.append("%s = %s" % (key, user_settings[key]))
- print '\n'.join(output)
-diffsettings.args = ""
-
-def reset(app, interactive=True):
- "Executes the equivalent of 'get_sql_reset' in the current database."
- from django.db import connection, transaction
- from django.conf import settings
- app_name = app.__name__.split('.')[-2]
-
- disable_termcolors()
-
- # First, try validating the models.
- _check_for_validation_errors(app)
- sql_list = get_sql_reset(app)
-
- if interactive:
- confirm = raw_input("""
-You have requested a database reset.
-This will IRREVERSIBLY DESTROY any data for
-the "%s" application in the database "%s".
-Are you sure you want to do this?
-
-Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
- else:
- confirm = 'yes'
-
- if confirm == 'yes':
- try:
- cursor = connection.cursor()
- for sql in sql_list:
- cursor.execute(sql)
- except Exception, e:
- sys.stderr.write(style.ERROR("""Error: %s couldn't be reset. Possible reasons:
- * The database isn't running or isn't configured correctly.
- * At least one of the database tables doesn't exist.
- * The SQL was invalid.
-Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
-The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
- transaction.rollback_unless_managed()
- sys.exit(1)
- transaction.commit_unless_managed()
- else:
- print "Reset cancelled."
-reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
-reset.args = '[--noinput]' + APP_ARGS
-
-def flush(verbosity=1, interactive=True):
- "Returns all tables in the database to the same state they were in immediately after syncdb."
- from django.conf import settings
- from django.db import connection, transaction, models
- from django.dispatch import dispatcher
-
- disable_termcolors()
-
- # First, try validating the models.
- _check_for_validation_errors()
-
- # Import the 'management' module within each installed app, to register
- # dispatcher events.
- for app_name in settings.INSTALLED_APPS:
- try:
- __import__(app_name + '.management', {}, {}, [''])
- except ImportError:
- pass
-
- sql_list = get_sql_flush()
-
- if interactive:
- confirm = raw_input("""
-You have requested a flush of the database.
-This will IRREVERSIBLY DESTROY all data currently in the database,
-and return each table to the state it was in after syncdb.
-Are you sure you want to do this?
-
-Type 'yes' to continue, or 'no' to cancel: """)
- else:
- confirm = 'yes'
-
- if confirm == 'yes':
- try:
- cursor = connection.cursor()
- for sql in sql_list:
- cursor.execute(sql)
- except Exception, e:
- sys.stderr.write(style.ERROR("""Error: Database %s couldn't be flushed. Possible reasons:
- * The database isn't running or isn't configured correctly.
- * At least one of the expected database tables doesn't exist.
- * The SQL was invalid.
-Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
-The full error: """ % settings.DATABASE_NAME + style.ERROR_OUTPUT(str(e)) + '\n'))
- transaction.rollback_unless_managed()
- sys.exit(1)
- transaction.commit_unless_managed()
-
- # Emit the post sync signal. This allows individual
- # applications to respond as if the database had been
- # sync'd from scratch.
- _emit_post_sync_signal(models.get_models(), verbosity, interactive)
-
- # Reinstall the initial_data fixture
- load_data(['initial_data'], verbosity=verbosity)
-
- else:
- print "Flush cancelled."
-flush.help_doc = "Executes ``sqlflush`` on the current database."
-flush.args = '[--verbosity] [--noinput]'
-
-def _start_helper(app_or_project, name, directory, other_name=''):
- other = {'project': 'app', 'app': 'project'}[app_or_project]
- if not _is_valid_dir_name(name):
- sys.stderr.write(style.ERROR("Error: %r is not a valid %s name. Please use only numbers, letters and underscores.\n" % (name, app_or_project)))
- sys.exit(1)
- top_dir = os.path.join(directory, name)
- try:
- os.mkdir(top_dir)
- except OSError, e:
- sys.stderr.write(style.ERROR("Error: %s\n" % e))
- sys.exit(1)
- template_dir = PROJECT_TEMPLATE_DIR % app_or_project
- for d, subdirs, files in os.walk(template_dir):
- relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
- if relative_dir:
- os.mkdir(os.path.join(top_dir, relative_dir))
- for i, subdir in enumerate(subdirs):
- if subdir.startswith('.'):
- del subdirs[i]
- for f in files:
- if f.endswith('.pyc'):
- continue
- path_old = os.path.join(d, f)
- path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
- fp_old = open(path_old, 'r')
- fp_new = open(path_new, 'w')
- fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
- fp_old.close()
- fp_new.close()
- try:
- shutil.copymode(path_old, path_new)
- except OSError:
- sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
-
-def startproject(project_name, directory):
- "Creates a Django project for the given project_name in the given directory."
- from random import choice
- if project_name in INVALID_PROJECT_NAMES:
- sys.stderr.write(style.ERROR("Error: '%r' conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name.\n" % project_name))
- sys.exit(1)
- _start_helper('project', project_name, directory)
- # Create a random SECRET_KEY hash, and put it in the main settings.
- main_settings_file = os.path.join(directory, project_name, 'settings.py')
- settings_contents = open(main_settings_file, 'r').read()
- fp = open(main_settings_file, 'w')
- secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
- settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
- fp.write(settings_contents)
- fp.close()
-startproject.help_doc = "Creates a Django project directory structure for the given project name in the current directory."
-startproject.args = "[projectname]"
-
-def startapp(app_name, directory):
- "Creates a Django app for the given app_name in the given directory."
- # Determine the project_name a bit naively -- by looking at the name of
- # the parent directory.
- project_dir = os.path.normpath(os.path.join(directory, '..'))
- parent_dir = os.path.basename(project_dir)
- project_name = os.path.basename(directory)
- if app_name == project_name:
- sys.stderr.write(style.ERROR("Error: You cannot create an app with the same name (%r) as your project.\n" % app_name))
- sys.exit(1)
- _start_helper('app', app_name, directory, parent_dir)
-startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
-startapp.args = "[appname]"
-
-def inspectdb():
- "Generator that introspects the tables in the given database name and returns a Django model, one line at a time."
- from django.db import connection, get_introspection_module
- import keyword
-
- introspection_module = get_introspection_module()
-
- table2model = lambda table_name: table_name.title().replace('_', '')
-
- cursor = connection.cursor()
- yield "# This is an auto-generated Django model module."
- yield "# You'll have to do the following manually to clean this up:"
- yield "# * Rearrange models' order"
- yield "# * Make sure each model has one field with primary_key=True"
- yield "# Feel free to rename the models, but don't rename db_table values or field names."
- yield "#"
- yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
- yield "# into your database."
- yield ''
- yield 'from django.db import models'
- yield ''
- for table_name in introspection_module.get_table_list(cursor):
- yield 'class %s(models.Model):' % table2model(table_name)
- try:
- relations = introspection_module.get_relations(cursor, table_name)
- except NotImplementedError:
- relations = {}
- try:
- indexes = introspection_module.get_indexes(cursor, table_name)
- except NotImplementedError:
- indexes = {}
- for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
- att_name = row[0].lower()
- comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
- extra_params = {} # Holds Field parameters such as 'db_column'.
-
- if ' ' in att_name:
- extra_params['db_column'] = att_name
- att_name = att_name.replace(' ', '')
- comment_notes.append('Field renamed to remove spaces.')
- if keyword.iskeyword(att_name):
- extra_params['db_column'] = att_name
- att_name += '_field'
- comment_notes.append('Field renamed because it was a Python reserved word.')
-
- if i in relations:
- rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
- field_type = 'ForeignKey(%s' % rel_to
- if att_name.endswith('_id'):
- att_name = att_name[:-3]
- else:
- extra_params['db_column'] = att_name
- else:
- try:
- field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
- except KeyError:
- field_type = 'TextField'
- comment_notes.append('This field type is a guess.')
-
- # This is a hook for DATA_TYPES_REVERSE to return a tuple of
- # (field_type, extra_params_dict).
- if type(field_type) is tuple:
- field_type, new_params = field_type
- extra_params.update(new_params)
-
- # Add maxlength for all CharFields.
- if field_type == 'CharField' and row[3]:
- extra_params['maxlength'] = row[3]
-
- if field_type == 'DecimalField':
- extra_params['max_digits'] = row[4]
- extra_params['decimal_places'] = row[5]
-
- # Add primary_key and unique, if necessary.
- column_name = extra_params.get('db_column', att_name)
- if column_name in indexes:
- if indexes[column_name]['primary_key']:
- extra_params['primary_key'] = True
- elif indexes[column_name]['unique']:
- extra_params['unique'] = True
-
- field_type += '('
-
- # Don't output 'id = meta.AutoField(primary_key=True)', because
- # that's assumed if it doesn't exist.
- if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
- continue
-
- # Add 'null' and 'blank', if the 'null_ok' flag was present in the
- # table description.
- if row[6]: # If it's NULL...
- extra_params['blank'] = True
- if not field_type in ('TextField(', 'CharField('):
- extra_params['null'] = True
-
- field_desc = '%s = models.%s' % (att_name, field_type)
- if extra_params:
- if not field_desc.endswith('('):
- field_desc += ', '
- field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
- field_desc += ')'
- if comment_notes:
- field_desc += ' # ' + ' '.join(comment_notes)
- yield ' %s' % field_desc
- yield ' class Meta:'
- yield ' db_table = %r' % table_name
- yield ''
-inspectdb.help_doc = "Introspects the database tables in the given database and outputs a Django model module."
-inspectdb.args = ""
-
-class ModelErrorCollection:
- def __init__(self, outfile=sys.stdout):
- self.errors = []
- self.outfile = outfile
-
- def add(self, context, error):
- self.errors.append((context, error))
- self.outfile.write(style.ERROR("%s: %s\n" % (context, error)))
-
-def get_validation_errors(outfile, app=None):
- """
- Validates all models that are part of the specified app. If no app name is provided,
- validates all models of all installed apps. Writes errors, if any, to outfile.
- Returns number of errors.
- """
- from django.conf import settings
- from django.db import models, connection
- from django.db.models.loading import get_app_errors
- from django.db.models.fields.related import RelatedObject
-
- e = ModelErrorCollection(outfile)
-
- for (app_name, error) in get_app_errors().items():
- e.add(app_name, error)
-
- for cls in models.get_models(app):
- opts = cls._meta
-
- # Do field-specific validation.
- for f in opts.fields:
- if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
- e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
- if isinstance(f, models.CharField) and f.maxlength in (None, 0):
- e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
- if isinstance(f, models.DecimalField):
- if f.decimal_places is None:
- e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
- if f.max_digits is None:
- e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
- if isinstance(f, models.FileField) and not f.upload_to:
- e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
- if isinstance(f, models.ImageField):
- try:
- from PIL import Image
- except ImportError:
- e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name)
- if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
- e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
- if f.choices:
- if not hasattr(f.choices, '__iter__'):
- e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
- else:
- for c in f.choices:
- if not type(c) in (tuple, list) or len(c) != 2:
- e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name)
- if f.db_index not in (None, True, False):
- e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
-
- # Check that maxlength <= 255 if using older MySQL versions.
- if settings.DATABASE_ENGINE == 'mysql':
- db_version = connection.get_server_version()
- if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
- e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
-
- # Check to see if the related field will clash with any
- # existing fields, m2m fields, m2m related objects or related objects
- if f.rel:
- rel_opts = f.rel.to._meta
- if f.rel.to not in models.get_models():
- e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
-
- rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
- rel_query_name = f.related_query_name()
- for r in rel_opts.fields:
- if r.name == rel_name:
- e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- if r.name == rel_query_name:
- e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- for r in rel_opts.many_to_many:
- if r.name == rel_name:
- e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- if r.name == rel_query_name:
- e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- for r in rel_opts.get_all_related_many_to_many_objects():
- if r.get_accessor_name() == rel_name:
- e.add(opts, "Accessor for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- if r.get_accessor_name() == rel_query_name:
- e.add(opts, "Reverse query name for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- for r in rel_opts.get_all_related_objects():
- if r.field is not f:
- if r.get_accessor_name() == rel_name:
- e.add(opts, "Accessor for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- if r.get_accessor_name() == rel_query_name:
- e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
-
-
- for i, f in enumerate(opts.many_to_many):
- # Check to see if the related m2m field will clash with any
- # existing fields, m2m fields, m2m related objects or related objects
- rel_opts = f.rel.to._meta
- if f.rel.to not in models.get_models():
- e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
-
- rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
- rel_query_name = f.related_query_name()
- # If rel_name is none, there is no reverse accessor.
- # (This only occurs for symmetrical m2m relations to self).
- # If this is the case, there are no clashes to check for this field, as
- # there are no reverse descriptors for this field.
- if rel_name is not None:
- for r in rel_opts.fields:
- if r.name == rel_name:
- e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- if r.name == rel_query_name:
- e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- for r in rel_opts.many_to_many:
- if r.name == rel_name:
- e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- if r.name == rel_query_name:
- e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
- for r in rel_opts.get_all_related_many_to_many_objects():
- if r.field is not f:
- if r.get_accessor_name() == rel_name:
- e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- if r.get_accessor_name() == rel_query_name:
- e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- for r in rel_opts.get_all_related_objects():
- if r.get_accessor_name() == rel_name:
- e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
- if r.get_accessor_name() == rel_query_name:
- e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
-
- # Check admin attribute.
- if opts.admin is not None:
- if not isinstance(opts.admin, models.AdminOptions):
- e.add(opts, '"admin" attribute, if given, must be set to a models.AdminOptions() instance.')
- else:
- # list_display
- if not isinstance(opts.admin.list_display, (list, tuple)):
- e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.')
- else:
- for fn in opts.admin.list_display:
- try:
- f = opts.get_field(fn)
- except models.FieldDoesNotExist:
- if not hasattr(cls, fn):
- e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn)
- else:
- if isinstance(f, models.ManyToManyField):
- e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn)
- # list_display_links
- if opts.admin.list_display_links and not opts.admin.list_display:
- e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.')
- if not isinstance(opts.admin.list_display_links, (list, tuple)):
- e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.')
- else:
- for fn in opts.admin.list_display_links:
- try:
- f = opts.get_field(fn)
- except models.FieldDoesNotExist:
- if not hasattr(cls, fn):
- e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
- if fn not in opts.admin.list_display:
- e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
- # list_filter
- if not isinstance(opts.admin.list_filter, (list, tuple)):
- e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.')
- else:
- for fn in opts.admin.list_filter:
- try:
- f = opts.get_field(fn)
- except models.FieldDoesNotExist:
- e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
- # date_hierarchy
- if opts.admin.date_hierarchy:
- try:
- f = opts.get_field(opts.admin.date_hierarchy)
- except models.FieldDoesNotExist:
- e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
-
- # Check ordering attribute.
- if opts.ordering:
- for field_name in opts.ordering:
- if field_name == '?': continue
- if field_name.startswith('-'):
- field_name = field_name[1:]
- if opts.order_with_respect_to and field_name == '_order':
- continue
- if '.' in field_name: continue # Skip ordering in the format 'table.field'.
- try:
- opts.get_field(field_name, many_to_many=False)
- except models.FieldDoesNotExist:
- e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name)
-
- # Check core=True, if needed.
- for related in opts.get_followed_related_objects():
- if not related.edit_inline:
- continue
- try:
- for f in related.opts.fields:
- if f.core:
- raise StopIteration
- e.add(related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name))
- except StopIteration:
- pass
-
- # Check unique_together.
- for ut in opts.unique_together:
- for field_name in ut:
- try:
- f = opts.get_field(field_name, many_to_many=True)
- except models.FieldDoesNotExist:
- e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name)
- else:
- if isinstance(f.rel, models.ManyToManyRel):
- e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name)
-
- return len(e.errors)
-
-def validate(outfile=sys.stdout, silent_success=False):
- "Validates all installed models."
- try:
- num_errors = get_validation_errors(outfile)
- if silent_success and num_errors == 0:
- return
- outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
- except ImproperlyConfigured:
- outfile.write("Skipping validation because things aren't configured properly.\n")
-validate.args = ''
-
-def _check_for_validation_errors(app=None):
- """Check that an app has no validation errors, and exit with errors if it does."""
- try:
- from cStringIO import StringIO
- except ImportError:
- from StringIO import StringIO
- s = StringIO()
- num_errors = get_validation_errors(s, app)
- if num_errors:
- if app:
- sys.stderr.write(style.ERROR("Error: %s couldn't be installed, because there were errors in your model:\n" % app))
- else:
- sys.stderr.write(style.ERROR("Error: Couldn't install apps, because there were errors in one or more models:\n"))
- s.seek(0)
- sys.stderr.write(s.read())
- sys.exit(1)
-
-def runserver(addr, port, use_reloader=True, admin_media_dir=''):
- "Starts a lightweight Web server for development."
- from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
- from django.core.handlers.wsgi import WSGIHandler
- if not addr:
- addr = '127.0.0.1'
- if not port.isdigit():
- sys.stderr.write(style.ERROR("Error: %r is not a valid port number.\n" % port))
- sys.exit(1)
- quit_command = sys.platform == 'win32' and 'CTRL-BREAK' or 'CONTROL-C'
- def inner_run():
- from django.conf import settings
- print "Validating models..."
- validate()
- print "\nDjango version %s, using settings %r" % (get_version(), settings.SETTINGS_MODULE)
- print "Development server is running at http://%s:%s/" % (addr, port)
- print "Quit the server with %s." % quit_command
- try:
- import django
- path = admin_media_dir or django.__path__[0] + '/contrib/admin/media'
- handler = AdminMediaHandler(WSGIHandler(), path)
- run(addr, int(port), handler)
- except WSGIServerException, e:
- # Use helpful error messages instead of ugly tracebacks.
- ERRORS = {
- 13: "You don't have permission to access that port.",
- 98: "That port is already in use.",
- 99: "That IP address can't be assigned-to.",
- }
- try:
- error_text = ERRORS[e.args[0].args[0]]
- except (AttributeError, KeyError):
- error_text = str(e)
- sys.stderr.write(style.ERROR("Error: %s" % error_text) + '\n')
- sys.exit(1)
- except KeyboardInterrupt:
- sys.exit(0)
- if use_reloader:
- from django.utils import autoreload
- autoreload.main(inner_run)
- else:
- inner_run()
-runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
-
-def createcachetable(tablename):
- "Creates the table needed to use the SQL cache backend"
- from django.db import backend, connection, transaction, get_creation_module, models
- data_types = get_creation_module().DATA_TYPES
- fields = (
- # "key" is a reserved word in MySQL, so use "cache_key" instead.
- models.CharField(name='cache_key', maxlength=255, unique=True, primary_key=True),
- models.TextField(name='value'),
- models.DateTimeField(name='expires', db_index=True),
- )
- table_output = []
- index_output = []
- for f in fields:
- field_output = [backend.quote_name(f.name), data_types[f.get_internal_type()] % f.__dict__]
- field_output.append("%sNULL" % (not f.null and "NOT " or ""))
- if f.unique:
- field_output.append("UNIQUE")
- if f.primary_key:
- field_output.append("PRIMARY KEY")
- if f.db_index:
- unique = f.unique and "UNIQUE " or ""
- index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
- (unique, tablename, f.name, backend.quote_name(tablename),
- backend.quote_name(f.name)))
- table_output.append(" ".join(field_output))
- full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)]
- for i, line in enumerate(table_output):
- full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
- full_statement.append(');')
- curs = connection.cursor()
- curs.execute("\n".join(full_statement))
- for statement in index_output:
- curs.execute(statement)
- transaction.commit_unless_managed()
-createcachetable.args = "[tablename]"
-
-def run_shell(use_plain=False):
- "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
- # XXX: (Temporary) workaround for ticket #1796: force early loading of all
- # models from installed apps.
- from django.db.models.loading import get_models
- loaded_models = get_models()
-
- try:
- if use_plain:
- # Don't bother loading IPython, because the user wants plain Python.
- raise ImportError
- import IPython
- # Explicitly pass an empty list as arguments, because otherwise IPython
- # would use sys.argv from this script.
- shell = IPython.Shell.IPShell(argv=[])
- shell.mainloop()
- except ImportError:
- import code
- try: # Try activating rlcompleter, because it's handy.
- import readline
- except ImportError:
- pass
- else:
- # We don't have to wrap the following import in a 'try', because
- # we already know 'readline' was imported successfully.
- import rlcompleter
- readline.parse_and_bind("tab:complete")
- code.interact()
-run_shell.args = '[--plain]'
-
-def dbshell():
- "Runs the command-line client for the current DATABASE_ENGINE."
- from django.db import runshell
- runshell()
-dbshell.args = ""
-
-def runfcgi(args):
- "Runs this project as a FastCGI application. Requires flup."
- from django.conf import settings
- from django.utils import translation
- # Activate the current language, because it won't get activated later.
- try:
- translation.activate(settings.LANGUAGE_CODE)
- except AttributeError:
- pass
- from django.core.servers.fastcgi import runfastcgi
- runfastcgi(args)
-runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
-
-def test(app_labels, verbosity=1):
- "Runs the test suite for the specified applications"
- from django.conf import settings
- from django.db.models import get_app, get_apps
-
- if len(app_labels) == 0:
- app_list = get_apps()
- else:
- app_list = [get_app(app_label) for app_label in app_labels]
-
- test_path = settings.TEST_RUNNER.split('.')
- # Allow for Python 2.5 relative paths
- if len(test_path) > 1:
- test_module_name = '.'.join(test_path[:-1])
- else:
- test_module_name = '.'
- test_module = __import__(test_module_name, {}, {}, test_path[-1])
- test_runner = getattr(test_module, test_path[-1])
-
- failures = test_runner(app_list, verbosity)
- if failures:
- sys.exit(failures)
-
-test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
-test.args = '[--verbosity] ' + APP_ARGS
-
-def load_data(fixture_labels, verbosity=1):
- "Installs the provided fixture file(s) as data in the database."
- from django.db.models import get_apps
- from django.core import serializers
- from django.db import connection, transaction, backend
- from django.conf import settings
- import sys
-
- disable_termcolors()
-
- # Keep a count of the installed objects and fixtures
- count = [0,0]
- models = set()
-
- humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
-
- # Get a cursor (even though we don't need one yet). This has
- # the side effect of initializing the test database (if
- # it isn't already initialized).
- cursor = connection.cursor()
-
- # Start transaction management. All fixtures are installed in a
- # single transaction to ensure that all references are resolved.
- transaction.commit_unless_managed()
- transaction.enter_transaction_management()
- transaction.managed(True)
-
- app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()]
- for fixture_label in fixture_labels:
- parts = fixture_label.split('.')
- if len(parts) == 1:
- fixture_name = fixture_label
- formats = serializers.get_serializer_formats()
- else:
- fixture_name, format = '.'.join(parts[:-1]), parts[-1]
- if format in serializers.get_serializer_formats():
- formats = [format]
- else:
- formats = []
-
- if verbosity > 0:
- if formats:
- print "Loading '%s' fixtures..." % fixture_name
- else:
- print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
-
- for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
- if verbosity > 1:
- print "Checking %s for fixtures..." % humanize(fixture_dir)
-
- label_found = False
- for format in formats:
- serializer = serializers.get_serializer(format)
- if verbosity > 1:
- print "Trying %s for %s fixture '%s'..." % \
- (humanize(fixture_dir), format, fixture_name)
- try:
- full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format]))
- fixture = open(full_path, 'r')
- if label_found:
- fixture.close()
- print style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
- (fixture_name, humanize(fixture_dir)))
- transaction.rollback()
- transaction.leave_transaction_management()
- return
- else:
- count[1] += 1
- if verbosity > 0:
- print "Installing %s fixture '%s' from %s." % \
- (format, fixture_name, humanize(fixture_dir))
- try:
- objects = serializers.deserialize(format, fixture)
- for obj in objects:
- count[0] += 1
- models.add(obj.object.__class__)
- obj.save()
- label_found = True
- except Exception, e:
- fixture.close()
- sys.stderr.write(
- style.ERROR("Problem installing fixture '%s': %s\n" %
- (full_path, str(e))))
- transaction.rollback()
- transaction.leave_transaction_management()
- return
- fixture.close()
- except:
- if verbosity > 1:
- print "No %s fixture '%s' in %s." % \
- (format, fixture_name, humanize(fixture_dir))
-
- if count[0] > 0:
- sequence_sql = backend.get_sql_sequence_reset(style, models)
- if sequence_sql:
- if verbosity > 1:
- print "Resetting sequences"
- for line in sequence_sql:
- cursor.execute(line)
-
- transaction.commit()
- transaction.leave_transaction_management()
-
- if count[0] == 0:
- if verbosity > 0:
- print "No fixtures found."
- else:
- if verbosity > 0:
- print "Installed %d object(s) from %d fixture(s)" % tuple(count)
-
-load_data.help_doc = 'Installs the named fixture(s) in the database'
-load_data.args = "[--verbosity] fixture, fixture, ..."
-
-def dump_data(app_labels, format='json', indent=None):
- "Output the current contents of the database as a fixture of the given format"
- from django.db.models import get_app, get_apps, get_models
- from django.core import serializers
-
- if len(app_labels) == 0:
- app_list = get_apps()
- else:
- app_list = [get_app(app_label) for app_label in app_labels]
-
- # Check that the serialization format exists; this is a shortcut to
- # avoid collating all the objects and _then_ failing.
- try:
- serializers.get_serializer(format)
- except KeyError:
- sys.stderr.write(style.ERROR("Unknown serialization format: %s\n" % format))
-
- objects = []
- for app in app_list:
- for model in get_models(app):
- objects.extend(model.objects.all())
- try:
- return serializers.serialize(format, objects, indent=indent)
- except Exception, e:
- sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e))
-dump_data.help_doc = 'Output the contents of the database as a fixture of the given format'
-dump_data.args = '[--format] [--indent]' + APP_ARGS
-
-# Utilities for command-line script
-
-DEFAULT_ACTION_MAPPING = {
- 'adminindex': get_admin_index,
- 'createcachetable' : createcachetable,
- 'dbshell': dbshell,
- 'diffsettings': diffsettings,
- 'dumpdata': dump_data,
- 'flush': flush,
- 'inspectdb': inspectdb,
- 'loaddata': load_data,
- 'reset': reset,
- 'runfcgi': runfcgi,
- 'runserver': runserver,
- 'shell': run_shell,
- 'sql': get_sql_create,
- 'sqlall': get_sql_all,
- 'sqlclear': get_sql_delete,
- 'sqlcustom': get_custom_sql,
- 'sqlflush': get_sql_flush,
- 'sqlindexes': get_sql_indexes,
- 'sqlinitialdata': get_sql_initial_data,
- 'sqlreset': get_sql_reset,
- 'sqlsequencereset': get_sql_sequence_reset,
- 'startapp': startapp,
- 'startproject': startproject,
- 'syncdb': syncdb,
- 'validate': validate,
- 'test':test,
-}
-
-NO_SQL_TRANSACTION = (
- 'adminindex',
- 'createcachetable',
- 'dbshell',
- 'diffsettings',
- 'reset',
- 'sqlindexes',
- 'syncdb',
-)
-
-class DjangoOptionParser(OptionParser):
- def print_usage_and_exit(self):
- self.print_help(sys.stderr)
- sys.exit(1)
-
-def get_usage(action_mapping):
- """
- Returns a usage string. Doesn't do the options stuff, because optparse
- takes care of that.
- """
- usage = ["%prog action [options]\nactions:"]
- available_actions = action_mapping.keys()
- available_actions.sort()
- for a in available_actions:
- func = action_mapping[a]
- usage.append(" %s %s" % (a, func.args))
- usage.extend(textwrap.wrap(getattr(func, 'help_doc', textwrap.dedent(func.__doc__.strip())), initial_indent=' ', subsequent_indent=' '))
- usage.append("")
- return '\n'.join(usage[:-1]) # Cut off last list element, an empty space.
-
-def print_error(msg, cmd):
- sys.stderr.write(style.ERROR('Error: %s' % msg) + '\nRun "%s --help" for help.\n' % cmd)
- sys.exit(1)
-
-def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
- # Use sys.argv if we've not passed in a custom argv
- if argv is None:
- argv = sys.argv
-
- # Parse the command-line arguments. optparse handles the dirty work.
- parser = DjangoOptionParser(usage=get_usage(action_mapping), version=get_version())
- parser.add_option('--settings',
- help='Python path to settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
- parser.add_option('--pythonpath',
- help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".')
- parser.add_option('--plain', action='store_true', dest='plain',
- help='Tells Django to use plain Python, not IPython, for "shell" command.')
- parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
- help='Tells Django to NOT prompt the user for input of any kind.')
- parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
- help='Tells Django to NOT use the auto-reloader when running the development server.')
- parser.add_option('--format', default='json', dest='format',
- help='Specifies the output serialization format for fixtures')
- parser.add_option('--indent', default=None, dest='indent',
- type='int', help='Specifies the indent level to use when pretty-printing output')
- parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
- type='choice', choices=['0', '1', '2'],
- help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
- parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'),
-
- options, args = parser.parse_args(argv[1:])
-
- # Take care of options.
- if options.settings:
- os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
- if options.pythonpath:
- sys.path.insert(0, options.pythonpath)
-
- # Run the appropriate action. Unfortunately, optparse can't handle
- # positional arguments, so this has to parse/validate them.
- try:
- action = args[0]
- except IndexError:
- parser.print_usage_and_exit()
- if action not in action_mapping:
- print_error("Your action, %r, was invalid." % action, argv[0])
-
- # Switch to English, because django-admin.py creates database content
- # like permissions, and those shouldn't contain any translations.
- # But only do this if we should have a working settings file.
- if action not in ('startproject', 'startapp'):
- from django.utils import translation
- translation.activate('en-us')
-
- if action == 'shell':
- action_mapping[action](options.plain is True)
- elif action in ('validate', 'diffsettings', 'dbshell'):
- action_mapping[action]()
- elif action in ('flush', 'syncdb'):
- action_mapping[action](int(options.verbosity), options.interactive)
- elif action == 'inspectdb':
- try:
- for line in action_mapping[action]():
- print line
- except NotImplementedError:
- sys.stderr.write(style.ERROR("Error: %r isn't supported for the currently selected database backend.\n" % action))
- sys.exit(1)
- elif action == 'createcachetable':
- try:
- action_mapping[action](args[1])
- except IndexError:
- parser.print_usage_and_exit()
- elif action in ('test', 'loaddata'):
- try:
- action_mapping[action](args[1:], int(options.verbosity))
- except IndexError:
- parser.print_usage_and_exit()
- elif action == 'dumpdata':
- try:
- print action_mapping[action](args[1:], options.format, options.indent)
- except IndexError:
- parser.print_usage_and_exit()
- elif action in ('startapp', 'startproject'):
- try:
- name = args[1]
- except IndexError:
- parser.print_usage_and_exit()
- action_mapping[action](name, os.getcwd())
- elif action == 'runserver':
- if len(args) < 2:
- addr = ''
- port = '8000'
- else:
- try:
- addr, port = args[1].split(':')
- except ValueError:
- addr, port = '', args[1]
- action_mapping[action](addr, port, options.use_reloader, options.admin_media_path)
- elif action == 'runfcgi':
- action_mapping[action](args[1:])
- elif action == 'sqlinitialdata':
- print action_mapping[action](args[1:])
- elif action == 'sqlflush':
- print '\n'.join(action_mapping[action]())
- else:
- from django.db import models
- validate(silent_success=True)
- try:
- mod_list = [models.get_app(app_label) for app_label in args[1:]]
- except ImportError, e:
- sys.stderr.write(style.ERROR("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e))
- sys.exit(1)
- if not mod_list:
- parser.print_usage_and_exit()
- if action not in NO_SQL_TRANSACTION:
- from django.db import backend
- if backend.get_start_transaction_sql():
- print style.SQL_KEYWORD(backend.get_start_transaction_sql())
- for mod in mod_list:
- if action == 'reset':
- output = action_mapping[action](mod, options.interactive)
- else:
- output = action_mapping[action](mod)
- if output:
- print '\n'.join(output)
- if action not in NO_SQL_TRANSACTION:
- print style.SQL_KEYWORD("COMMIT;")
-
-def setup_environ(settings_mod):
- """
- Configure the runtime environment. This can also be used by external
- scripts wanting to set up a similar environment to manage.py.
- """
- # Add this project to sys.path so that it's importable in the conventional
- # way. For example, if this file (manage.py) lives in a directory
- # "myproject", this code would add "/path/to/myproject" to sys.path.
- project_directory = os.path.dirname(settings_mod.__file__)
- project_name = os.path.basename(project_directory)
- sys.path.append(os.path.join(project_directory, '..'))
- project_module = __import__(project_name, {}, {}, [''])
- sys.path.pop()
-
- # Set DJANGO_SETTINGS_MODULE appropriately.
- os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
- return project_directory
-
-def execute_manager(settings_mod, argv=None):
- project_directory = setup_environ(settings_mod)
- action_mapping = DEFAULT_ACTION_MAPPING.copy()
-
- # Remove the "startproject" command from the action_mapping, because that's
- # a django-admin.py command, not a manage.py command.
- del action_mapping['startproject']
-
- # Override the startapp handler so that it always uses the
- # project_directory, not the current working directory (which is default).
- action_mapping['startapp'] = lambda app_name, directory: startapp(app_name, project_directory)
- action_mapping['startapp'].__doc__ = startapp.__doc__
- action_mapping['startapp'].help_doc = startapp.help_doc
- action_mapping['startapp'].args = startapp.args
-
- # Run the django-admin.py command.
- execute_from_command_line(action_mapping, argv)
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
new file mode 100644
index 0000000000..7a3f9ca7a5
--- /dev/null
+++ b/django/core/management/__init__.py
@@ -0,0 +1,180 @@
+import django
+from optparse import OptionParser
+import os
+import sys
+import textwrap
+
+# For backwards compatibility: get_version() used to be in this module.
+get_version = django.get_version
+
+def load_command_class(name):
+ """
+ Given a command name, returns the Command class instance. Raises
+ ImportError if it doesn't exist.
+ """
+ # Let the ImportError propogate.
+ return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')()
+
+def call_command(name, *args, **options):
+ """
+ Calls the given command, with the given options and args/kwargs.
+
+ This is the primary API you should use for calling specific commands.
+
+ Some examples:
+ call_command('syncdb')
+ call_command('shell', plain=True)
+ call_command('sqlall', 'myapp')
+ """
+ klass = load_command_class(name)
+ return klass.execute(*args, **options)
+
+class ManagementUtility(object):
+ """
+ Encapsulates the logic of the django-admin.py and manage.py utilities.
+
+ A ManagementUtility has a number of commands, which can be manipulated
+ by editing the self.commands dictionary.
+ """
+ def __init__(self):
+ self.commands = self.default_commands()
+
+ def default_commands(self):
+ """
+ Returns a dictionary of instances of all available Command classes.
+
+ This works by looking for and loading all Python modules in the
+ django.core.management.commands package.
+
+ The dictionary is in the format {name: command_instance}.
+ """
+ command_dir = os.path.join(__path__[0], 'commands')
+ names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
+ return dict([(name, load_command_class(name)) for name in names])
+
+ def usage(self):
+ """
+ Returns a usage string, for use with optparse.
+
+ The string doesn't include the options (e.g., "--verbose"), because
+ optparse puts those in automatically.
+ """
+ usage = ["%prog command [options]\nactions:"]
+ commands = self.commands.items()
+ commands.sort()
+ for name, cmd in commands:
+ usage.append(' %s %s' % (name, cmd.args))
+ usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' '))
+ usage.append('')
+ return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.
+
+ def execute(self, argv=None):
+ """
+ Parses the given argv from the command line, determines which command
+ to run and runs the command.
+ """
+ if argv is None:
+ argv = sys.argv
+
+ # Create the parser object and parse the command-line args.
+ # TODO: Ideally each Command class would register its own options for
+ # add_option(), but we'd need to figure out how to allow for multiple
+ # Commands using the same options. The optparse library gets in the way
+ # by checking for conflicts:
+ # http://docs.python.org/lib/optparse-conflicts-between-options.html
+ parser = OptionParser(usage=self.usage(), version=get_version())
+ parser.add_option('--settings',
+ help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
+ parser.add_option('--pythonpath',
+ help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
+ parser.add_option('--plain', action='store_true', dest='plain',
+ help='When using "shell": Tells Django to use plain Python, not IPython.')
+ parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
+ help='Tells Django to NOT prompt the user for input of any kind.')
+ parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
+ help='When using "runserver": Tells Django to NOT use the auto-reloader.')
+ parser.add_option('--format', default='json', dest='format',
+ help='Specifies the output serialization format for fixtures')
+ parser.add_option('--indent', default=None, dest='indent',
+ type='int', help='Specifies the indent level to use when pretty-printing output')
+ parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
+ type='choice', choices=['0', '1', '2'],
+ help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
+ parser.add_option('--adminmedia', dest='admin_media_path', default='',
+ help='When using "runserver": Specifies the directory from which to serve admin media.')
+ options, args = parser.parse_args(argv[1:])
+
+ # If the 'settings' or 'pythonpath' options were submitted, activate those.
+ if options.settings:
+ os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
+ if options.pythonpath:
+ sys.path.insert(0, options.pythonpath)
+
+ # Run the appropriate command.
+ try:
+ command_name = args[0]
+ except IndexError:
+ sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
+ sys.exit(1)
+ try:
+ command = self.commands[command_name]
+ except KeyError:
+ sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
+ sys.exit(1)
+ command.execute(*args[1:], **options.__dict__)
+
+class ProjectManagementUtility(ManagementUtility):
+ """
+ A ManagementUtility that is specific to a particular Django project.
+ As such, its commands are slightly different than those of its parent
+ class.
+
+ In practice, this class represents manage.py, whereas ManagementUtility
+ represents django-admin.py.
+ """
+ def __init__(self, project_directory):
+ super(ProjectManagementUtility, self).__init__()
+
+ # Remove the "startproject" command from self.commands, because
+ # that's a django-admin.py command, not a manage.py command.
+ del self.commands['startproject']
+
+ # Override the startapp command so that it always uses the
+ # project_directory, not the current working directory (which is default).
+ from django.core.management.commands.startapp import ProjectCommand
+ self.commands['startapp'] = ProjectCommand(project_directory)
+
+def setup_environ(settings_mod):
+ """
+ Configure the runtime environment. This can also be used by external
+ scripts wanting to set up a similar environment to manage.py.
+ """
+ # Add this project to sys.path so that it's importable in the conventional
+ # way. For example, if this file (manage.py) lives in a directory
+ # "myproject", this code would add "/path/to/myproject" to sys.path.
+ project_directory, settings_filename = os.path.split(settings_mod.__file__)
+ project_name = os.path.basename(project_directory)
+ settings_name = os.path.splitext(settings_filename)[0]
+ sys.path.append(os.path.join(project_directory, '..'))
+ project_module = __import__(project_name, {}, {}, [''])
+ sys.path.pop()
+
+ # Set DJANGO_SETTINGS_MODULE appropriately.
+ os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
+ return project_directory
+
+def execute_from_command_line(argv=None):
+ """
+ A simple method that runs a ManagementUtility.
+ """
+ utility = ManagementUtility()
+ utility.execute(argv)
+
+def execute_manager(settings_mod, argv=None):
+ """
+ Like execute_from_command_line(), but for use by manage.py, a
+ project-specific django-admin.py utility.
+ """
+ project_directory = setup_environ(settings_mod)
+ utility = ProjectManagementUtility(project_directory)
+ utility.execute(argv)
diff --git a/django/core/management/base.py b/django/core/management/base.py
new file mode 100644
index 0000000000..866dec4407
--- /dev/null
+++ b/django/core/management/base.py
@@ -0,0 +1,159 @@
+from django.core.exceptions import ImproperlyConfigured
+from django.core.management.color import color_style
+import sys
+
+class CommandError(Exception):
+ pass
+
+class BaseCommand(object):
+ # Metadata about this command.
+ help = ''
+ args = ''
+
+ # Configuration shortcuts that alter various logic.
+ can_import_settings = True
+ requires_model_validation = True
+ output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;"
+
+ def __init__(self):
+ self.style = color_style()
+
+ def execute(self, *args, **options):
+ # Switch to English, because django-admin.py creates database content
+ # like permissions, and those shouldn't contain any translations.
+ # But only do this if we can assume we have a working settings file,
+ # because django.utils.translation requires settings.
+ if self.can_import_settings:
+ from django.utils import translation
+ translation.activate('en-us')
+
+ try:
+ if self.requires_model_validation:
+ self.validate()
+ output = self.handle(*args, **options)
+ if output:
+ if self.output_transaction:
+ # This needs to be imported here, because it relies on settings.
+ from django.db import connection
+ if connection.ops.start_transaction_sql():
+ print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql())
+ print output
+ if self.output_transaction:
+ print self.style.SQL_KEYWORD("COMMIT;")
+ except CommandError, e:
+ sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e)))
+ sys.exit(1)
+
+ def validate(self, app=None):
+ """
+ Validates the given app, raising CommandError for any errors.
+
+ If app is None, then this will validate all installed apps.
+ """
+ from django.core.management.validation import get_validation_errors
+ try:
+ from cStringIO import StringIO
+ except ImportError:
+ from StringIO import StringIO
+ s = StringIO()
+ num_errors = get_validation_errors(s, app)
+ if num_errors:
+ s.seek(0)
+ error_text = s.read()
+ raise CommandError("One or more models did not validate:\n%s" % error_text)
+
+ def handle(self, *args, **options):
+ raise NotImplementedError()
+
+class AppCommand(BaseCommand):
+ args = '[appname ...]'
+
+ def handle(self, *app_labels, **options):
+ from django.db import models
+ if not app_labels:
+ raise CommandError('Enter at least one appname.')
+ try:
+ app_list = [models.get_app(app_label) for app_label in app_labels]
+ except (ImproperlyConfigured, ImportError), e:
+ raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
+ output = []
+ for app in app_list:
+ app_output = self.handle_app(app, **options)
+ if app_output:
+ output.append(app_output)
+ return '\n'.join(output)
+
+ def handle_app(self, app, **options):
+ raise NotImplementedError()
+
+class LabelCommand(BaseCommand):
+ args = '[label ...]'
+ label = 'label'
+
+ def handle(self, *labels, **options):
+ if not labels:
+ raise CommandError('Enter at least one %s.' % self.label)
+
+ output = []
+ for label in labels:
+ label_output = self.handle_label(label, **options)
+ if label_output:
+ output.append(label_output)
+ return '\n'.join(output)
+
+ def handle_label(self, label, **options):
+ raise NotImplementedError()
+
+class NoArgsCommand(BaseCommand):
+ args = ''
+
+ def handle(self, *args, **options):
+ from django.db import models
+ if len(args) != 0:
+ raise CommandError("Command doesn't accept any arguments")
+
+ return self.handle_noargs(**options)
+
+ def handle_noargs(self, **options):
+ raise NotImplementedError()
+
+def copy_helper(style, app_or_project, name, directory, other_name=''):
+ import django
+ import os
+ import re
+ import shutil
+ other = {'project': 'app', 'app': 'project'}[app_or_project]
+ if not re.search(r'^\w+$', name): # If it's not a valid directory name.
+ raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project))
+ top_dir = os.path.join(directory, name)
+ try:
+ os.mkdir(top_dir)
+ except OSError, e:
+ raise CommandError(e)
+
+ # Determine where the app or project templates are. Use
+ # django.__path__[0] because we don't know into which directory
+ # django has been installed.
+ template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project)
+
+ for d, subdirs, files in os.walk(template_dir):
+ relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
+ if relative_dir:
+ os.mkdir(os.path.join(top_dir, relative_dir))
+ for i, subdir in enumerate(subdirs):
+ if subdir.startswith('.'):
+ del subdirs[i]
+ for f in files:
+ if f.endswith('.pyc'):
+ continue
+ path_old = os.path.join(d, f)
+ path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
+ fp_old = open(path_old, 'r')
+ fp_new = open(path_new, 'w')
+ fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
+ fp_old.close()
+ fp_new.close()
+ try:
+ shutil.copymode(path_old, path_new)
+ except OSError:
+ sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
diff --git a/django/core/management/color.py b/django/core/management/color.py
new file mode 100644
index 0000000000..06edb6066b
--- /dev/null
+++ b/django/core/management/color.py
@@ -0,0 +1,28 @@
+"""
+Sets up the terminal color scheme.
+"""
+
+from django.utils import termcolors
+import sys
+
+def color_style():
+ "Returns a Style object with the Django color scheme."
+ if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
+ return no_style()
+ class dummy: pass
+ style = dummy()
+ style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
+ style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
+ style.NOTICE = termcolors.make_style(fg='red')
+ style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
+ style.SQL_COLTYPE = termcolors.make_style(fg='green')
+ style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
+ style.SQL_TABLE = termcolors.make_style(opts=('bold',))
+ return style
+
+def no_style():
+ "Returns a Style object that has no colors."
+ class dummy:
+ def __getattr__(self, attr):
+ return lambda x: x
+ return dummy()
diff --git a/django/core/management/commands/__init__.py b/django/core/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/core/management/commands/__init__.py
diff --git a/django/core/management/commands/adminindex.py b/django/core/management/commands/adminindex.py
new file mode 100644
index 0000000000..e3dd493fd3
--- /dev/null
+++ b/django/core/management/commands/adminindex.py
@@ -0,0 +1,33 @@
+from django.core.management.base import AppCommand
+from django.utils.text import capfirst
+
+MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
+ <tr>
+ <th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
+ <td class="x50">{%% if perms.%(app)s.%(addperm)s %%}<a href="%(app)s/%(mod)s/add/" class="addlink">{%% endif %%}Add{%% if perms.%(app)s.%(addperm)s %%}</a>{%% endif %%}</td>
+ <td class="x75">{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/" class="changelink">{%% endif %%}Change{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</td>
+ </tr>
+ {%% endif %%}'''
+
+class Command(AppCommand):
+ help = 'Prints the admin-index template snippet for the given app name(s).'
+
+ def handle_app(self, app, **options):
+ from django.db.models import get_models
+ output = []
+ app_models = get_models(app)
+ app_label = app_models[0]._meta.app_label
+ output.append('{%% if perms.%s %%}' % app_label)
+ output.append('<div class="module"><h2>%s</h2><table>' % app_label.title())
+ for model in app_models:
+ if model._meta.admin:
+ output.append(MODULE_TEMPLATE % {
+ 'app': app_label,
+ 'mod': model._meta.module_name,
+ 'name': capfirst(model._meta.verbose_name_plural),
+ 'addperm': model._meta.get_add_permission(),
+ 'changeperm': model._meta.get_change_permission(),
+ })
+ output.append('</table></div>')
+ output.append('{% endif %}')
+ return '\n'.join(output)
diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py
new file mode 100644
index 0000000000..c1fa1a26a5
--- /dev/null
+++ b/django/core/management/commands/createcachetable.py
@@ -0,0 +1,42 @@
+from django.core.management.base import LabelCommand
+
+class Command(LabelCommand):
+ help = "Creates the table needed to use the SQL cache backend."
+ args = "[tablename]"
+ label = 'tablename'
+
+ requires_model_validation = False
+
+ def handle_label(self, tablename, **options):
+ from django.db import connection, transaction, models
+ fields = (
+ # "key" is a reserved word in MySQL, so use "cache_key" instead.
+ models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
+ models.TextField(name='value'),
+ models.DateTimeField(name='expires', db_index=True),
+ )
+ table_output = []
+ index_output = []
+ qn = connection.ops.quote_name
+ for f in fields:
+ field_output = [qn(f.name), f.db_type()]
+ field_output.append("%sNULL" % (not f.null and "NOT " or ""))
+ if f.unique:
+ field_output.append("UNIQUE")
+ if f.primary_key:
+ field_output.append("PRIMARY KEY")
+ if f.db_index:
+ unique = f.unique and "UNIQUE " or ""
+ index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
+ (unique, tablename, f.name, qn(tablename),
+ qn(f.name)))
+ table_output.append(" ".join(field_output))
+ full_statement = ["CREATE TABLE %s (" % qn(tablename)]
+ for i, line in enumerate(table_output):
+ full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
+ full_statement.append(');')
+ curs = connection.cursor()
+ curs.execute("\n".join(full_statement))
+ for statement in index_output:
+ curs.execute(statement)
+ transaction.commit_unless_managed()
diff --git a/django/core/management/commands/dbshell.py b/django/core/management/commands/dbshell.py
new file mode 100644
index 0000000000..ec2a961530
--- /dev/null
+++ b/django/core/management/commands/dbshell.py
@@ -0,0 +1,10 @@
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = "Runs the command-line client for the current DATABASE_ENGINE."
+
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ from django.db import runshell
+ runshell()
diff --git a/django/core/management/commands/diffsettings.py b/django/core/management/commands/diffsettings.py
new file mode 100644
index 0000000000..2459f11700
--- /dev/null
+++ b/django/core/management/commands/diffsettings.py
@@ -0,0 +1,32 @@
+from django.core.management.base import NoArgsCommand
+
+def module_to_dict(module, omittable=lambda k: k.startswith('_')):
+ "Converts a module namespace to a Python dictionary. Used by get_settings_diff."
+ return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])
+
+class Command(NoArgsCommand):
+ help = """Displays differences between the current settings.py and Django's
+ default settings. Settings that don't appear in the defaults are
+ followed by "###"."""
+
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ # Inspired by Postfix's "postconf -n".
+ from django.conf import settings, global_settings
+
+ # Because settings are imported lazily, we need to explicitly load them.
+ settings._import_settings()
+
+ user_settings = module_to_dict(settings._target)
+ default_settings = module_to_dict(global_settings)
+
+ output = []
+ keys = user_settings.keys()
+ keys.sort()
+ for key in keys:
+ if key not in default_settings:
+ output.append("%s = %s ###" % (key, user_settings[key]))
+ elif user_settings[key] != default_settings[key]:
+ output.append("%s = %s" % (key, user_settings[key]))
+ print '\n'.join(output)
diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py
new file mode 100644
index 0000000000..48677ca5fa
--- /dev/null
+++ b/django/core/management/commands/dumpdata.py
@@ -0,0 +1,33 @@
+from django.core.management.base import BaseCommand, CommandError
+
+class Command(BaseCommand):
+ help = 'Output the contents of the database as a fixture of the given format.'
+ args = '[--format] [--indent] [appname ...]'
+
+ def handle(self, *app_labels, **options):
+ from django.db.models import get_app, get_apps, get_models
+ from django.core import serializers
+
+ format = options.get('format', 'json')
+ indent = options.get('indent', None)
+
+ if len(app_labels) == 0:
+ app_list = get_apps()
+ else:
+ app_list = [get_app(app_label) for app_label in app_labels]
+
+ # Check that the serialization format exists; this is a shortcut to
+ # avoid collating all the objects and _then_ failing.
+ try:
+ serializers.get_serializer(format)
+ except KeyError:
+ raise CommandError("Unknown serialization format: %s" % format)
+
+ objects = []
+ for app in app_list:
+ for model in get_models(app):
+ objects.extend(model.objects.all())
+ try:
+ return serializers.serialize(format, objects, indent=indent)
+ except Exception, e:
+ raise CommandError("Unable to serialize database: %s" % e)
diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
new file mode 100644
index 0000000000..bd1dc204d2
--- /dev/null
+++ b/django/core/management/commands/flush.py
@@ -0,0 +1,64 @@
+from django.core.management.base import NoArgsCommand, CommandError
+from django.core.management.color import no_style
+
+class Command(NoArgsCommand):
+ help = "Executes ``sqlflush`` on the current database."
+ args = '[--verbosity] [--noinput]'
+
+ def handle_noargs(self, **options):
+ from django.conf import settings
+ from django.db import connection, transaction, models
+ from django.dispatch import dispatcher
+ from django.core.management.sql import sql_flush, emit_post_sync_signal
+
+ verbosity = int(options.get('verbosity', 1))
+ interactive = options.get('interactive')
+
+ self.style = no_style()
+
+ # Import the 'management' module within each installed app, to register
+ # dispatcher events.
+ for app_name in settings.INSTALLED_APPS:
+ try:
+ __import__(app_name + '.management', {}, {}, [''])
+ except ImportError:
+ pass
+
+ sql_list = sql_flush(self.style)
+
+ if interactive:
+ confirm = raw_input("""You have requested a flush of the database.
+This will IRREVERSIBLY DESTROY all data currently in the %r database,
+and return each table to the state it was in after syncdb.
+Are you sure you want to do this?
+
+ Type 'yes' to continue, or 'no' to cancel: """ % settings.DATABASE_NAME)
+ else:
+ confirm = 'yes'
+
+ if confirm == 'yes':
+ try:
+ cursor = connection.cursor()
+ for sql in sql_list:
+ cursor.execute(sql)
+ except Exception, e:
+ transaction.rollback_unless_managed()
+ raise CommandError("""Database %s couldn't be flushed. Possible reasons:
+ * The database isn't running or isn't configured correctly.
+ * At least one of the expected database tables doesn't exist.
+ * The SQL was invalid.
+ Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
+ The full error: %s""" % (settings.DATABASE_NAME, e))
+ transaction.commit_unless_managed()
+
+ # Emit the post sync signal. This allows individual
+ # applications to respond as if the database had been
+ # sync'd from scratch.
+ emit_post_sync_signal(models.get_models(), verbosity, interactive)
+
+ # Reinstall the initial_data fixture.
+ from django.core.management import call_command
+ call_command('loaddata', 'initial_data', **options)
+
+ else:
+ print "Flush cancelled."
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
new file mode 100644
index 0000000000..11bc390289
--- /dev/null
+++ b/django/core/management/commands/inspectdb.py
@@ -0,0 +1,120 @@
+from django.core.management.base import NoArgsCommand, CommandError
+
+class Command(NoArgsCommand):
+ help = "Introspects the database tables in the given database and outputs a Django model module."
+
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ try:
+ for line in self.handle_inspection():
+ print line
+ except NotImplementedError:
+ raise CommandError("Database inspection isn't supported for the currently selected database backend.")
+
+ def handle_inspection(self):
+ from django.db import connection, get_introspection_module
+ import keyword
+
+ introspection_module = get_introspection_module()
+
+ table2model = lambda table_name: table_name.title().replace('_', '')
+
+ cursor = connection.cursor()
+ yield "# This is an auto-generated Django model module."
+ yield "# You'll have to do the following manually to clean this up:"
+ yield "# * Rearrange models' order"
+ yield "# * Make sure each model has one field with primary_key=True"
+ yield "# Feel free to rename the models, but don't rename db_table values or field names."
+ yield "#"
+ yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
+ yield "# into your database."
+ yield ''
+ yield 'from django.db import models'
+ yield ''
+ for table_name in introspection_module.get_table_list(cursor):
+ yield 'class %s(models.Model):' % table2model(table_name)
+ try:
+ relations = introspection_module.get_relations(cursor, table_name)
+ except NotImplementedError:
+ relations = {}
+ try:
+ indexes = introspection_module.get_indexes(cursor, table_name)
+ except NotImplementedError:
+ indexes = {}
+ for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
+ att_name = row[0].lower()
+ comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
+ extra_params = {} # Holds Field parameters such as 'db_column'.
+
+ if ' ' in att_name:
+ extra_params['db_column'] = att_name
+ att_name = att_name.replace(' ', '')
+ comment_notes.append('Field renamed to remove spaces.')
+ if keyword.iskeyword(att_name):
+ extra_params['db_column'] = att_name
+ att_name += '_field'
+ comment_notes.append('Field renamed because it was a Python reserved word.')
+
+ if i in relations:
+ rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
+ field_type = 'ForeignKey(%s' % rel_to
+ if att_name.endswith('_id'):
+ att_name = att_name[:-3]
+ else:
+ extra_params['db_column'] = att_name
+ else:
+ try:
+ field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
+ except KeyError:
+ field_type = 'TextField'
+ comment_notes.append('This field type is a guess.')
+
+ # This is a hook for DATA_TYPES_REVERSE to return a tuple of
+ # (field_type, extra_params_dict).
+ if type(field_type) is tuple:
+ field_type, new_params = field_type
+ extra_params.update(new_params)
+
+ # Add max_length for all CharFields.
+ if field_type == 'CharField' and row[3]:
+ extra_params['max_length'] = row[3]
+
+ if field_type == 'DecimalField':
+ extra_params['max_digits'] = row[4]
+ extra_params['decimal_places'] = row[5]
+
+ # Add primary_key and unique, if necessary.
+ column_name = extra_params.get('db_column', att_name)
+ if column_name in indexes:
+ if indexes[column_name]['primary_key']:
+ extra_params['primary_key'] = True
+ elif indexes[column_name]['unique']:
+ extra_params['unique'] = True
+
+ field_type += '('
+
+ # Don't output 'id = meta.AutoField(primary_key=True)', because
+ # that's assumed if it doesn't exist.
+ if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
+ continue
+
+ # Add 'null' and 'blank', if the 'null_ok' flag was present in the
+ # table description.
+ if row[6]: # If it's NULL...
+ extra_params['blank'] = True
+ if not field_type in ('TextField(', 'CharField('):
+ extra_params['null'] = True
+
+ field_desc = '%s = models.%s' % (att_name, field_type)
+ if extra_params:
+ if not field_desc.endswith('('):
+ field_desc += ', '
+ field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
+ field_desc += ')'
+ if comment_notes:
+ field_desc += ' # ' + ' '.join(comment_notes)
+ yield ' %s' % field_desc
+ yield ' class Meta:'
+ yield ' db_table = %r' % table_name
+ yield ''
diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
new file mode 100644
index 0000000000..4cbdb55c67
--- /dev/null
+++ b/django/core/management/commands/loaddata.py
@@ -0,0 +1,123 @@
+from django.core.management.base import BaseCommand
+from django.core.management.color import no_style
+import sys
+import os
+
+try:
+ set
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
+
+class Command(BaseCommand):
+ help = 'Installs the named fixture(s) in the database.'
+ args = "[--verbosity] fixture, fixture, ..."
+
+ def handle(self, *fixture_labels, **options):
+ from django.db.models import get_apps
+ from django.core import serializers
+ from django.db import connection, transaction
+ from django.conf import settings
+
+ self.style = no_style()
+
+ verbosity = int(options.get('verbosity', 1))
+
+ # Keep a count of the installed objects and fixtures
+ count = [0, 0]
+ models = set()
+
+ humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
+
+ # Get a cursor (even though we don't need one yet). This has
+ # the side effect of initializing the test database (if
+ # it isn't already initialized).
+ cursor = connection.cursor()
+
+ # Start transaction management. All fixtures are installed in a
+ # single transaction to ensure that all references are resolved.
+ transaction.commit_unless_managed()
+ transaction.enter_transaction_management()
+ transaction.managed(True)
+
+ app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
+ for fixture_label in fixture_labels:
+ parts = fixture_label.split('.')
+ if len(parts) == 1:
+ fixture_name = fixture_label
+ formats = serializers.get_serializer_formats()
+ else:
+ fixture_name, format = '.'.join(parts[:-1]), parts[-1]
+ if format in serializers.get_serializer_formats():
+ formats = [format]
+ else:
+ formats = []
+
+ if verbosity > 0:
+ if formats:
+ print "Loading '%s' fixtures..." % fixture_name
+ else:
+ print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
+
+ for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
+ if verbosity > 1:
+ print "Checking %s for fixtures..." % humanize(fixture_dir)
+
+ label_found = False
+ for format in formats:
+ serializer = serializers.get_serializer(format)
+ if verbosity > 1:
+ print "Trying %s for %s fixture '%s'..." % \
+ (humanize(fixture_dir), format, fixture_name)
+ try:
+ full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format]))
+ fixture = open(full_path, 'r')
+ if label_found:
+ fixture.close()
+ print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
+ (fixture_name, humanize(fixture_dir)))
+ transaction.rollback()
+ transaction.leave_transaction_management()
+ return
+ else:
+ count[1] += 1
+ if verbosity > 0:
+ print "Installing %s fixture '%s' from %s." % \
+ (format, fixture_name, humanize(fixture_dir))
+ try:
+ objects = serializers.deserialize(format, fixture)
+ for obj in objects:
+ count[0] += 1
+ models.add(obj.object.__class__)
+ obj.save()
+ label_found = True
+ except Exception, e:
+ fixture.close()
+ sys.stderr.write(
+ self.style.ERROR("Problem installing fixture '%s': %s\n" %
+ (full_path, str(e))))
+ transaction.rollback()
+ transaction.leave_transaction_management()
+ return
+ fixture.close()
+ except:
+ if verbosity > 1:
+ print "No %s fixture '%s' in %s." % \
+ (format, fixture_name, humanize(fixture_dir))
+
+ if count[0] > 0:
+ sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
+ if sequence_sql:
+ if verbosity > 1:
+ print "Resetting sequences"
+ for line in sequence_sql:
+ cursor.execute(line)
+
+ transaction.commit()
+ transaction.leave_transaction_management()
+
+ if count[0] == 0:
+ if verbosity > 0:
+ print "No fixtures found."
+ else:
+ if verbosity > 0:
+ print "Installed %d object(s) from %d fixture(s)" % tuple(count)
diff --git a/django/core/management/commands/reset.py b/django/core/management/commands/reset.py
new file mode 100644
index 0000000000..5c89d94678
--- /dev/null
+++ b/django/core/management/commands/reset.py
@@ -0,0 +1,47 @@
+from django.core.management.base import AppCommand, CommandError
+from django.core.management.color import no_style
+
+class Command(AppCommand):
+ help = "Executes ``sqlreset`` for the given app(s) in the current database."
+ args = '[--noinput] [appname ...]'
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.db import connection, transaction
+ from django.conf import settings
+ from django.core.management.sql import sql_reset
+
+ app_name = app.__name__.split('.')[-2]
+
+ self.style = no_style()
+
+ sql_list = sql_reset(app, self.style)
+
+ if options.get('interactive'):
+ confirm = raw_input("""
+You have requested a database reset.
+This will IRREVERSIBLY DESTROY any data for
+the "%s" application in the database "%s".
+Are you sure you want to do this?
+
+Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
+ else:
+ confirm = 'yes'
+
+ if confirm == 'yes':
+ try:
+ cursor = connection.cursor()
+ for sql in sql_list:
+ cursor.execute(sql)
+ except Exception, e:
+ transaction.rollback_unless_managed()
+ raise CommandError("""Error: %s couldn't be reset. Possible reasons:
+ * The database isn't running or isn't configured correctly.
+ * At least one of the database tables doesn't exist.
+ * The SQL was invalid.
+Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
+The full error: %s""" % (app_name, app_name, e))
+ transaction.commit_unless_managed()
+ else:
+ print "Reset cancelled."
diff --git a/django/core/management/commands/runfcgi.py b/django/core/management/commands/runfcgi.py
new file mode 100644
index 0000000000..406a27b8c3
--- /dev/null
+++ b/django/core/management/commands/runfcgi.py
@@ -0,0 +1,16 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+ help = "Runs this project as a FastCGI application. Requires flup."
+ args = '[various KEY=val options, use `runfcgi help` for help]'
+
+ def handle(self, *args, **options):
+ from django.conf import settings
+ from django.utils import translation
+ # Activate the current language, because it won't get activated later.
+ try:
+ translation.activate(settings.LANGUAGE_CODE)
+ except AttributeError:
+ pass
+ from django.core.servers.fastcgi import runfastcgi
+ runfastcgi(args)
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
new file mode 100644
index 0000000000..f089e80b16
--- /dev/null
+++ b/django/core/management/commands/runserver.py
@@ -0,0 +1,70 @@
+from django.core.management.base import BaseCommand, CommandError
+import os
+import sys
+
+class Command(BaseCommand):
+ help = "Starts a lightweight Web server for development."
+ args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
+
+ # Validation is called explicitly each time the server is reloaded.
+ requires_model_validation = False
+
+ def handle(self, addrport='', *args, **options):
+ import django
+ from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
+ from django.core.handlers.wsgi import WSGIHandler
+ if len(args) != 0:
+ raise CommandError('Usage is runserver %s' % self.args)
+ if not addrport:
+ addr = ''
+ port = '8000'
+ else:
+ try:
+ addr, port = addrport.split(':')
+ except ValueError:
+ addr, port = '', addrport
+ if not addr:
+ addr = '127.0.0.1'
+
+ if not port.isdigit():
+ raise CommandError("%r is not a valid port number." % port)
+
+ use_reloader = options.get('use_reloader', True)
+ admin_media_dir = options.get('admin_media_dir', '')
+ shutdown_message = options.get('shutdown_message', '')
+ quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C'
+
+ def inner_run():
+ from django.conf import settings
+ print "Validating models..."
+ self.validate()
+ print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)
+ print "Development server is running at http://%s:%s/" % (addr, port)
+ print "Quit the server with %s." % quit_command
+ try:
+ path = admin_media_dir or django.__path__[0] + '/contrib/admin/media'
+ handler = AdminMediaHandler(WSGIHandler(), path)
+ run(addr, int(port), handler)
+ except WSGIServerException, e:
+ # Use helpful error messages instead of ugly tracebacks.
+ ERRORS = {
+ 13: "You don't have permission to access that port.",
+ 98: "That port is already in use.",
+ 99: "That IP address can't be assigned-to.",
+ }
+ try:
+ error_text = ERRORS[e.args[0].args[0]]
+ except (AttributeError, KeyError):
+ error_text = str(e)
+ sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n')
+ # Need to use an OS exit because sys.exit doesn't work in a thread
+ os._exit(1)
+ except KeyboardInterrupt:
+ if shutdown_message:
+ print shutdown_message
+ sys.exit(0)
+ if use_reloader:
+ from django.utils import autoreload
+ autoreload.main(inner_run)
+ else:
+ inner_run()
diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py
new file mode 100644
index 0000000000..bc76c44b97
--- /dev/null
+++ b/django/core/management/commands/shell.py
@@ -0,0 +1,42 @@
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
+ args = '[--plain]'
+
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ # XXX: (Temporary) workaround for ticket #1796: force early loading of all
+ # models from installed apps.
+ from django.db.models.loading import get_models
+ loaded_models = get_models()
+
+ use_plain = options.get('plain', False)
+
+ try:
+ if use_plain:
+ # Don't bother loading IPython, because the user wants plain Python.
+ raise ImportError
+ import IPython
+ # Explicitly pass an empty list as arguments, because otherwise IPython
+ # would use sys.argv from this script.
+ shell = IPython.Shell.IPShell(argv=[])
+ shell.mainloop()
+ except ImportError:
+ import code
+ # Set up a dictionary to serve as the environment for the shell, so
+ # that tab completion works on objects that are imported at runtime.
+ # See ticket 5082.
+ imported_objects = {}
+ try: # Try activating rlcompleter, because it's handy.
+ import readline
+ except ImportError:
+ pass
+ else:
+ # We don't have to wrap the following import in a 'try', because
+ # we already know 'readline' was imported successfully.
+ import rlcompleter
+ readline.set_completer(rlcompleter.Completer(imported_objects).complete)
+ readline.parse_and_bind("tab:complete")
+ code.interact(local=imported_objects)
diff --git a/django/core/management/commands/sql.py b/django/core/management/commands/sql.py
new file mode 100644
index 0000000000..4a0107ac02
--- /dev/null
+++ b/django/core/management/commands/sql.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the CREATE TABLE SQL statements for the given app name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_create
+ return '\n'.join(sql_create(app, self.style))
diff --git a/django/core/management/commands/sqlall.py b/django/core/management/commands/sqlall.py
new file mode 100644
index 0000000000..d63dfb4b10
--- /dev/null
+++ b/django/core/management/commands/sqlall.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_all
+ return '\n'.join(sql_all(app, self.style))
diff --git a/django/core/management/commands/sqlclear.py b/django/core/management/commands/sqlclear.py
new file mode 100644
index 0000000000..d76d6f4de2
--- /dev/null
+++ b/django/core/management/commands/sqlclear.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the DROP TABLE SQL statements for the given app name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_delete
+ return '\n'.join(sql_delete(app, self.style))
diff --git a/django/core/management/commands/sqlcustom.py b/django/core/management/commands/sqlcustom.py
new file mode 100644
index 0000000000..2148a9f307
--- /dev/null
+++ b/django/core/management/commands/sqlcustom.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the custom table modifying SQL statements for the given app name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_custom
+ return '\n'.join(sql_custom(app))
diff --git a/django/core/management/commands/sqlflush.py b/django/core/management/commands/sqlflush.py
new file mode 100644
index 0000000000..7d14fe61e1
--- /dev/null
+++ b/django/core/management/commands/sqlflush.py
@@ -0,0 +1,10 @@
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
+
+ output_transaction = True
+
+ def handle_noargs(self, **options):
+ from django.core.management.sql import sql_flush
+ return '\n'.join(sql_flush(self.style))
diff --git a/django/core/management/commands/sqlindexes.py b/django/core/management/commands/sqlindexes.py
new file mode 100644
index 0000000000..b5e86f26d6
--- /dev/null
+++ b/django/core/management/commands/sqlindexes.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_indexes
+ return '\n'.join(sql_indexes(app, self.style))
diff --git a/django/core/management/commands/sqlinitialdata.py b/django/core/management/commands/sqlinitialdata.py
new file mode 100644
index 0000000000..b9e2249c29
--- /dev/null
+++ b/django/core/management/commands/sqlinitialdata.py
@@ -0,0 +1,7 @@
+from django.core.management.base import AppCommand, CommandError
+
+class Command(AppCommand):
+ help = "RENAMED: see 'sqlcustom'"
+
+ def handle(self, *apps, **options):
+ raise CommandError("This command has been renamed. Use the 'sqlcustom' command instead.")
diff --git a/django/core/management/commands/sqlreset.py b/django/core/management/commands/sqlreset.py
new file mode 100644
index 0000000000..a2abb855cf
--- /dev/null
+++ b/django/core/management/commands/sqlreset.py
@@ -0,0 +1,10 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
+
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.core.management.sql import sql_reset
+ return '\n'.join(sql_reset(app, self.style))
diff --git a/django/core/management/commands/sqlsequencereset.py b/django/core/management/commands/sqlsequencereset.py
new file mode 100644
index 0000000000..6b12d83843
--- /dev/null
+++ b/django/core/management/commands/sqlsequencereset.py
@@ -0,0 +1,9 @@
+from django.core.management.base import AppCommand
+
+class Command(AppCommand):
+ help = 'Prints the SQL statements for resetting sequences for the given app name(s).'
+ output_transaction = True
+
+ def handle_app(self, app, **options):
+ from django.db import connection, models
+ return '\n'.join(connection.ops.sequence_reset_sql(self.style, models.get_models(app)))
diff --git a/django/core/management/commands/startapp.py b/django/core/management/commands/startapp.py
new file mode 100644
index 0000000000..1da2776cf5
--- /dev/null
+++ b/django/core/management/commands/startapp.py
@@ -0,0 +1,34 @@
+from django.core.management.base import copy_helper, CommandError, LabelCommand
+import os
+
+class Command(LabelCommand):
+ help = "Creates a Django app directory structure for the given app name in the current directory."
+ args = "[appname]"
+ label = 'application name'
+
+ requires_model_validation = False
+ # Can't import settings during this command, because they haven't
+ # necessarily been created.
+ can_import_settings = False
+
+ def handle_label(self, app_name, directory=None, **options):
+ if directory is None:
+ directory = os.getcwd()
+ # Determine the project_name a bit naively -- by looking at the name of
+ # the parent directory.
+ project_dir = os.path.normpath(os.path.join(directory, '..'))
+ parent_dir = os.path.basename(project_dir)
+ project_name = os.path.basename(directory)
+ if app_name == project_name:
+ raise CommandError("You cannot create an app with the same name (%r) as your project." % app_name)
+ copy_helper(self.style, 'app', app_name, directory, parent_dir)
+
+class ProjectCommand(Command):
+ help = "Creates a Django app directory structure for the given app name in this project's directory."
+
+ def __init__(self, project_directory):
+ super(ProjectCommand, self).__init__()
+ self.project_directory = project_directory
+
+ def handle_label(self, app_name, **options):
+ super(ProjectCommand, self).handle_label(app_name, self.project_directory, **options)
diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py
new file mode 100644
index 0000000000..0d9e4bd381
--- /dev/null
+++ b/django/core/management/commands/startproject.py
@@ -0,0 +1,40 @@
+from django.core.management.base import copy_helper, CommandError, LabelCommand
+import os
+import re
+from random import choice
+
+INVALID_PROJECT_NAMES = ('django', 'site', 'test')
+
+class Command(LabelCommand):
+ help = "Creates a Django project directory structure for the given project name in the current directory."
+ args = "[projectname]"
+ label = 'project name'
+
+ requires_model_validation = False
+ # Can't import settings during this command, because they haven't
+ # necessarily been created.
+ can_import_settings = False
+
+ def handle_label(self, project_name, **options):
+ # Determine the project_name a bit naively -- by looking at the name of
+ # the parent directory.
+ directory = os.getcwd()
+
+ if project_name in INVALID_PROJECT_NAMES:
+ raise CommandError("%r conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name." % project_name)
+
+ copy_helper(self.style, 'project', project_name, directory)
+
+ # Create a random SECRET_KEY hash, and put it in the main settings.
+ main_settings_file = os.path.join(directory, project_name, 'settings.py')
+ settings_contents = open(main_settings_file, 'r').read()
+
+ # If settings.py was copied from a read-only source, make it writeable.
+ if not os.access(main_settings_file, os.W_OK):
+ os.chmod(main_settings_file, 0600)
+
+ fp = open(main_settings_file, 'w')
+ secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
+ settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
+ fp.write(settings_contents)
+ fp.close()
diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
new file mode 100644
index 0000000000..2e272b541b
--- /dev/null
+++ b/django/core/management/commands/syncdb.py
@@ -0,0 +1,130 @@
+from django.core.management.base import NoArgsCommand
+from django.core.management.color import no_style
+import sys
+
+try:
+ set
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
+
+class Command(NoArgsCommand):
+ help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
+ args = '[--verbosity] [--noinput]'
+
+ def handle_noargs(self, **options):
+ from django.db import connection, transaction, models
+ from django.conf import settings
+ from django.core.management.sql import table_list, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
+
+ verbosity = int(options.get('verbosity', 1))
+ interactive = options.get('interactive')
+
+ self.style = no_style()
+
+ # Import the 'management' module within each installed app, to register
+ # dispatcher events.
+ for app_name in settings.INSTALLED_APPS:
+ try:
+ __import__(app_name + '.management', {}, {}, [''])
+ except ImportError:
+ pass
+
+ cursor = connection.cursor()
+
+ # Get a list of all existing database tables,
+ # so we know what needs to be added.
+ table_list = table_list()
+ if connection.features.uses_case_insensitive_names:
+ table_name_converter = str.upper
+ else:
+ table_name_converter = lambda x: x
+
+ # Get a list of already installed *models* so that references work right.
+ seen_models = installed_models(table_list)
+ created_models = set()
+ pending_references = {}
+
+ # Create the tables for each model
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ model_list = models.get_models(app)
+ for model in model_list:
+ # Create the model's database table, if it doesn't already exist.
+ if verbosity >= 2:
+ print "Processing %s.%s model" % (app_name, model._meta.object_name)
+ if table_name_converter(model._meta.db_table) in table_list:
+ continue
+ sql, references = sql_model_create(model, self.style, seen_models)
+ seen_models.add(model)
+ created_models.add(model)
+ for refto, refs in references.items():
+ pending_references.setdefault(refto, []).extend(refs)
+ sql.extend(sql_for_pending_references(model, self.style, pending_references))
+ if verbosity >= 1:
+ print "Creating table %s" % model._meta.db_table
+ for statement in sql:
+ cursor.execute(statement)
+ table_list.append(table_name_converter(model._meta.db_table))
+
+ # Create the m2m tables. This must be done after all tables have been created
+ # to ensure that all referred tables will exist.
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ model_list = models.get_models(app)
+ for model in model_list:
+ if model in created_models:
+ sql = many_to_many_sql_for_model(model, self.style)
+ if sql:
+ if verbosity >= 2:
+ print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
+ for statement in sql:
+ cursor.execute(statement)
+
+ transaction.commit_unless_managed()
+
+ # Send the post_syncdb signal, so individual apps can do whatever they need
+ # to do at this point.
+ emit_post_sync_signal(created_models, verbosity, interactive)
+
+ # Install custom SQL for the app (but only if this
+ # is a model we've just created)
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ for model in models.get_models(app):
+ if model in created_models:
+ custom_sql = custom_sql_for_model(model, self.style)
+ if custom_sql:
+ if verbosity >= 1:
+ print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
+ try:
+ for sql in custom_sql:
+ cursor.execute(sql)
+ except Exception, e:
+ sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \
+ (app_name, model._meta.object_name, e))
+ transaction.rollback_unless_managed()
+ else:
+ transaction.commit_unless_managed()
+
+ # Install SQL indicies for all newly created models
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ for model in models.get_models(app):
+ if model in created_models:
+ index_sql = sql_indexes_for_model(model, self.style)
+ if index_sql:
+ if verbosity >= 1:
+ print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
+ try:
+ for sql in index_sql:
+ cursor.execute(sql)
+ except Exception, e:
+ sys.stderr.write("Failed to install index for %s.%s model: %s" % \
+ (app_name, model._meta.object_name, e))
+ transaction.rollback_unless_managed()
+ else:
+ transaction.commit_unless_managed()
+
+ # Install the 'initial_data' fixture, using format discovery
+ from django.core.management import call_command
+ call_command('loaddata', 'initial_data', verbosity=verbosity)
diff --git a/django/core/management/commands/test.py b/django/core/management/commands/test.py
new file mode 100644
index 0000000000..8e27fd5606
--- /dev/null
+++ b/django/core/management/commands/test.py
@@ -0,0 +1,28 @@
+from django.core.management.base import BaseCommand
+import sys
+
+class Command(BaseCommand):
+ help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
+ args = '[--verbosity] [--noinput] [appname ...]'
+
+ requires_model_validation = False
+
+ def handle(self, *test_labels, **options):
+ from django.conf import settings
+ from django.db.models import get_app, get_apps
+
+ verbosity = int(options.get('verbosity', 1))
+ interactive = options.get('interactive', True)
+
+ test_path = settings.TEST_RUNNER.split('.')
+ # Allow for Python 2.5 relative paths
+ if len(test_path) > 1:
+ test_module_name = '.'.join(test_path[:-1])
+ else:
+ test_module_name = '.'
+ test_module = __import__(test_module_name, {}, {}, test_path[-1])
+ test_runner = getattr(test_module, test_path[-1])
+
+ failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
+ if failures:
+ sys.exit(failures)
diff --git a/django/core/management/commands/testserver.py b/django/core/management/commands/testserver.py
new file mode 100644
index 0000000000..907960894c
--- /dev/null
+++ b/django/core/management/commands/testserver.py
@@ -0,0 +1,26 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+ help = 'Runs a development server with data from the given fixture(s).'
+ args = '[fixture ...]'
+
+ requires_model_validation = False
+
+ def handle(self, *fixture_labels, **options):
+ from django.conf import settings
+ from django.core.management import call_command
+ from django.test.utils import create_test_db
+
+ verbosity = int(options.get('verbosity', 1))
+
+ # Create a test database.
+ db_name = create_test_db(verbosity=verbosity)
+
+ # Import the fixture data into the test database.
+ call_command('loaddata', *fixture_labels, **{'verbosity': verbosity})
+
+ # Run the development server. Turn off auto-reloading because it causes
+ # a strange error -- it causes this handle() method to be called
+ # multiple times.
+ shutdown_message = '\nServer stopped.\nNote that the test database, %r, has not been deleted. You can explore it on your own.' % db_name
+ call_command('runserver', shutdown_message=shutdown_message, use_reloader=False)
diff --git a/django/core/management/commands/validate.py b/django/core/management/commands/validate.py
new file mode 100644
index 0000000000..2751f41abd
--- /dev/null
+++ b/django/core/management/commands/validate.py
@@ -0,0 +1,9 @@
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = "Validates all installed models."
+
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ self.validate()
diff --git a/django/core/management/sql.py b/django/core/management/sql.py
new file mode 100644
index 0000000000..b984d74d4b
--- /dev/null
+++ b/django/core/management/sql.py
@@ -0,0 +1,433 @@
+from django.core.management.base import CommandError
+import os
+import re
+
+try:
+ set
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
+
+def table_list():
+ "Returns a list of all table names that exist in the database."
+ from django.db import connection, get_introspection_module
+ cursor = connection.cursor()
+ return get_introspection_module().get_table_list(cursor)
+
+def installed_models(table_list):
+ "Returns a set of all models that are installed, given a list of existing table names."
+ from django.db import connection, models
+ all_models = []
+ for app in models.get_apps():
+ for model in models.get_models(app):
+ all_models.append(model)
+ if connection.features.uses_case_insensitive_names:
+ converter = lambda x: x.upper()
+ else:
+ converter = lambda x: x
+ return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
+
+def sequence_list():
+ "Returns a list of information about all DB sequences for all models in all apps."
+ from django.db import models
+
+ apps = models.get_apps()
+ sequence_list = []
+
+ for app in apps:
+ for model in models.get_models(app):
+ for f in model._meta.fields:
+ if isinstance(f, models.AutoField):
+ sequence_list.append({'table': model._meta.db_table, 'column': f.column})
+ break # Only one AutoField is allowed per model, so don't bother continuing.
+
+ for f in model._meta.many_to_many:
+ sequence_list.append({'table': f.m2m_db_table(), 'column': None})
+
+ return sequence_list
+
+def sql_create(app, style):
+ "Returns a list of the CREATE TABLE SQL statements for the given app."
+ from django.db import models
+ from django.conf import settings
+
+ if settings.DATABASE_ENGINE == 'dummy':
+ # This must be the "dummy" database backend, which means the user
+ # hasn't set DATABASE_ENGINE.
+ raise CommandError("Django doesn't know which syntax to use for your SQL statements,\n" +
+ "because you haven't specified the DATABASE_ENGINE setting.\n" +
+ "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.")
+
+ # Get installed models, so we generate REFERENCES right.
+ # We trim models from the current app so that the sqlreset command does not
+ # generate invalid SQL (leaving models out of known_models is harmless, so
+ # we can be conservative).
+ app_models = models.get_models(app)
+ final_output = []
+ known_models = set([model for model in installed_models(table_list()) if model not in app_models])
+ pending_references = {}
+
+ for model in app_models:
+ output, references = sql_model_create(model, style, known_models)
+ final_output.extend(output)
+ for refto, refs in references.items():
+ pending_references.setdefault(refto, []).extend(refs)
+ final_output.extend(sql_for_pending_references(model, style, pending_references))
+ # Keep track of the fact that we've created the table for this model.
+ known_models.add(model)
+
+ # Create the many-to-many join tables.
+ for model in app_models:
+ final_output.extend(many_to_many_sql_for_model(model, style))
+
+ # Handle references to tables that are from other apps
+ # but don't exist physically.
+ not_installed_models = set(pending_references.keys())
+ if not_installed_models:
+ alter_sql = []
+ for model in not_installed_models:
+ alter_sql.extend(['-- ' + sql for sql in
+ sql_for_pending_references(model, style, pending_references)])
+ if alter_sql:
+ final_output.append('-- The following references should be added but depend on non-existent tables:')
+ final_output.extend(alter_sql)
+
+ return final_output
+
+def sql_delete(app, style):
+ "Returns a list of the DROP TABLE SQL statements for the given app."
+ from django.db import connection, models, get_introspection_module
+ from django.db.backends.util import truncate_name
+ introspection = get_introspection_module()
+
+ # This should work even if a connection isn't available
+ try:
+ cursor = connection.cursor()
+ except:
+ cursor = None
+
+ # Figure out which tables already exist
+ if cursor:
+ table_names = introspection.get_table_list(cursor)
+ else:
+ table_names = []
+ if connection.features.uses_case_insensitive_names:
+ table_name_converter = str.upper
+ else:
+ table_name_converter = lambda x: x
+
+ output = []
+ qn = connection.ops.quote_name
+
+ # Output DROP TABLE statements for standard application tables.
+ to_delete = set()
+
+ references_to_delete = {}
+ app_models = models.get_models(app)
+ for model in app_models:
+ if cursor and table_name_converter(model._meta.db_table) in table_names:
+ # The table exists, so it needs to be dropped
+ opts = model._meta
+ for f in opts.fields:
+ if f.rel and f.rel.to not in to_delete:
+ references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
+
+ to_delete.add(model)
+
+ for model in app_models:
+ if cursor and table_name_converter(model._meta.db_table) in table_names:
+ # Drop the table now
+ output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
+ style.SQL_TABLE(qn(model._meta.db_table))))
+ if connection.features.supports_constraints and model in references_to_delete:
+ for rel_class, f in references_to_delete[model]:
+ table = rel_class._meta.db_table
+ col = f.column
+ r_table = model._meta.db_table
+ r_col = model._meta.get_field(f.rel.field_name).column
+ r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
+ output.append('%s %s %s %s;' % \
+ (style.SQL_KEYWORD('ALTER TABLE'),
+ style.SQL_TABLE(qn(table)),
+ style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
+ style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
+ del references_to_delete[model]
+ if model._meta.has_auto_field:
+ ds = connection.ops.drop_sequence_sql(model._meta.db_table)
+ if ds:
+ output.append(ds)
+
+ # Output DROP TABLE statements for many-to-many tables.
+ for model in app_models:
+ opts = model._meta
+ for f in opts.many_to_many:
+ if cursor and table_name_converter(f.m2m_db_table()) in table_names:
+ output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
+ style.SQL_TABLE(qn(f.m2m_db_table()))))
+ ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
+ if ds:
+ output.append(ds)
+
+ app_label = app_models[0]._meta.app_label
+
+ # Close database connection explicitly, in case this output is being piped
+ # directly into a database client, to avoid locking issues.
+ if cursor:
+ cursor.close()
+ connection.close()
+
+ return output[::-1] # Reverse it, to deal with table dependencies.
+
+def sql_reset(app, style):
+ "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
+ return sql_delete(app, style) + sql_all(app, style)
+
+def sql_flush(style):
+ "Returns a list of the SQL statements used to flush the database."
+ from django.db import connection
+ statements = connection.ops.sql_flush(style, table_list(), sequence_list())
+ return statements
+
+def sql_custom(app, style):
+ "Returns a list of the custom table modifying SQL statements for the given app."
+ from django.db.models import get_models
+ output = []
+
+ app_models = get_models(app)
+ app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
+
+ for model in app_models:
+ output.extend(custom_sql_for_model(model, style))
+
+ return output
+
+def sql_indexes(app, style):
+ "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
+ from django.db import models
+ output = []
+ for model in models.get_models(app):
+ output.extend(sql_indexes_for_model(model, style))
+ return output
+
+def sql_all(app, style):
+ "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
+ return sql_create(app, style) + sql_custom(app) + sql_indexes(app, style)
+
+def sql_model_create(model, style, known_models=set()):
+ """
+ Returns the SQL required to create a single model, as a tuple of:
+ (list_of_sql, pending_references_dict)
+ """
+ from django.db import connection, models
+
+ opts = model._meta
+ final_output = []
+ table_output = []
+ pending_references = {}
+ qn = connection.ops.quote_name
+ for f in opts.fields:
+ col_type = f.db_type()
+ tablespace = f.db_tablespace or opts.db_tablespace
+ if col_type is None:
+ # Skip ManyToManyFields, because they're not represented as
+ # database columns in this table.
+ continue
+ # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
+ field_output = [style.SQL_FIELD(qn(f.column)),
+ style.SQL_COLTYPE(col_type)]
+ field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
+ if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
+ field_output.append(style.SQL_KEYWORD('UNIQUE'))
+ if f.primary_key:
+ field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
+ if tablespace and connection.features.supports_tablespaces and (f.unique or f.primary_key) and connection.features.autoindexes_primary_keys:
+ # We must specify the index tablespace inline, because we
+ # won't be generating a CREATE INDEX statement for this field.
+ field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
+ if f.rel:
+ if f.rel.to in known_models:
+ field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
+ style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
+ style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
+ connection.ops.deferrable_sql()
+ )
+ else:
+ # We haven't yet created the table to which this field
+ # is related, so save it for later.
+ pr = pending_references.setdefault(f.rel.to, []).append((model, f))
+ table_output.append(' '.join(field_output))
+ if opts.order_with_respect_to:
+ table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
+ style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
+ style.SQL_KEYWORD('NULL'))
+ for field_constraints in opts.unique_together:
+ table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
+ ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
+
+ full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
+ for i, line in enumerate(table_output): # Combine and add commas.
+ full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
+ full_statement.append(')')
+ if opts.db_tablespace and connection.features.supports_tablespaces:
+ full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
+ full_statement.append(';')
+ final_output.append('\n'.join(full_statement))
+
+ if opts.has_auto_field:
+ # Add any extra SQL needed to support auto-incrementing primary keys.
+ autoinc_sql = connection.ops.autoinc_sql(opts.db_table)
+ if autoinc_sql:
+ for stmt in autoinc_sql:
+ final_output.append(stmt)
+
+ return final_output, pending_references
+
+def sql_for_pending_references(model, style, pending_references):
+ """
+ Returns any ALTER TABLE statements to add constraints after the fact.
+ """
+ from django.db import connection
+ from django.db.backends.util import truncate_name
+
+ qn = connection.ops.quote_name
+ final_output = []
+ if connection.features.supports_constraints:
+ opts = model._meta
+ if model in pending_references:
+ for rel_class, f in pending_references[model]:
+ rel_opts = rel_class._meta
+ r_table = rel_opts.db_table
+ r_col = f.column
+ table = opts.db_table
+ col = opts.get_field(f.rel.field_name).column
+ # For MySQL, r_name must be unique in the first 64 characters.
+ # So we are careful with character usage here.
+ r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
+ final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
+ (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
+ qn(r_col), qn(table), qn(col),
+ connection.ops.deferrable_sql()))
+ del pending_references[model]
+ return final_output
+
+def many_to_many_sql_for_model(model, style):
+ from django.db import connection, models
+ from django.contrib.contenttypes import generic
+
+ opts = model._meta
+ final_output = []
+ qn = connection.ops.quote_name
+ for f in opts.many_to_many:
+ if not isinstance(f.rel, generic.GenericRel):
+ tablespace = f.db_tablespace or opts.db_tablespace
+ if tablespace and connection.features.supports_tablespaces and connection.features.autoindexes_primary_keys:
+ tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
+ else:
+ tablespace_sql = ''
+ table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
+ style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
+ table_output.append(' %s %s %s%s,' % \
+ (style.SQL_FIELD(qn('id')),
+ style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
+ style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
+ tablespace_sql))
+ table_output.append(' %s %s %s %s (%s)%s,' % \
+ (style.SQL_FIELD(qn(f.m2m_column_name())),
+ style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+ style.SQL_KEYWORD('NOT NULL REFERENCES'),
+ style.SQL_TABLE(qn(opts.db_table)),
+ style.SQL_FIELD(qn(opts.pk.column)),
+ connection.ops.deferrable_sql()))
+ table_output.append(' %s %s %s %s (%s)%s,' % \
+ (style.SQL_FIELD(qn(f.m2m_reverse_name())),
+ style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
+ style.SQL_KEYWORD('NOT NULL REFERENCES'),
+ style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
+ style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
+ connection.ops.deferrable_sql()))
+ table_output.append(' %s (%s, %s)%s' % \
+ (style.SQL_KEYWORD('UNIQUE'),
+ style.SQL_FIELD(qn(f.m2m_column_name())),
+ style.SQL_FIELD(qn(f.m2m_reverse_name())),
+ tablespace_sql))
+ table_output.append(')')
+ if opts.db_tablespace and connection.features.supports_tablespaces:
+ # f.db_tablespace is only for indices, so ignore its value here.
+ table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))
+ table_output.append(';')
+ final_output.append('\n'.join(table_output))
+
+ # Add any extra SQL needed to support auto-incrementing PKs
+ autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table())
+ if autoinc_sql:
+ for stmt in autoinc_sql:
+ final_output.append(stmt)
+
+ return final_output
+
+def custom_sql_for_model(model, style):
+ from django.db import models
+ from django.conf import settings
+
+ opts = model._meta
+ app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
+ output = []
+
+ # Post-creation SQL should come before any initial SQL data is loaded.
+ for f in opts.fields:
+ if hasattr(f, '_post_create_sql'):
+ output.append(f._post_create_sql(style, model._meta.db_table))
+
+ # Some backends can't execute more than one SQL statement at a time,
+ # so split into separate statements.
+ statements = re.compile(r";[ \t]*$", re.M)
+
+ # Find custom SQL, if it's available.
+ sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
+ os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
+ for sql_file in sql_files:
+ if os.path.exists(sql_file):
+ fp = open(sql_file, 'U')
+ for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
+ # Remove any comments from the file
+ statement = re.sub(ur"--.*[\n\Z]", "", statement)
+ if statement.strip():
+ output.append(statement + u";")
+ fp.close()
+
+ return output
+
+def sql_indexes_for_model(model, style):
+ "Returns the CREATE INDEX SQL statements for a single model"
+ from django.db import connection
+ output = []
+
+ qn = connection.ops.quote_name
+ for f in model._meta.fields:
+ if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
+ unique = f.unique and 'UNIQUE ' or ''
+ tablespace = f.db_tablespace or model._meta.db_tablespace
+ if tablespace and connection.features.supports_tablespaces:
+ tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
+ else:
+ tablespace_sql = ''
+ output.append(
+ style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
+ style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
+ style.SQL_KEYWORD('ON') + ' ' + \
+ style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
+ "(%s)" % style.SQL_FIELD(qn(f.column)) + \
+ "%s;" % tablespace_sql
+ )
+ return output
+
+def emit_post_sync_signal(created_models, verbosity, interactive):
+ from django.db import models
+ from django.dispatch import dispatcher
+ # Emit the post_sync signal for every application.
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ if verbosity >= 2:
+ print "Running post-sync handlers for application", app_name
+ dispatcher.send(signal=models.signals.post_syncdb, sender=app,
+ app=app, created_models=created_models,
+ verbosity=verbosity, interactive=interactive)
diff --git a/django/core/management/validation.py b/django/core/management/validation.py
new file mode 100644
index 0000000000..aa4ef47c2f
--- /dev/null
+++ b/django/core/management/validation.py
@@ -0,0 +1,221 @@
+import sys
+from django.core.management.color import color_style
+
+class ModelErrorCollection:
+ def __init__(self, outfile=sys.stdout):
+ self.errors = []
+ self.outfile = outfile
+ self.style = color_style()
+
+ def add(self, context, error):
+ self.errors.append((context, error))
+ self.outfile.write(self.style.ERROR("%s: %s\n" % (context, error)))
+
+def get_validation_errors(outfile, app=None):
+ """
+ Validates all models that are part of the specified app. If no app name is provided,
+ validates all models of all installed apps. Writes errors, if any, to outfile.
+ Returns number of errors.
+ """
+ from django.conf import settings
+ from django.db import models, connection
+ from django.db.models.loading import get_app_errors
+ from django.db.models.fields.related import RelatedObject
+
+ e = ModelErrorCollection(outfile)
+
+ for (app_name, error) in get_app_errors().items():
+ e.add(app_name, error)
+
+ for cls in models.get_models(app):
+ opts = cls._meta
+
+ # Do field-specific validation.
+ for f in opts.fields:
+ if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
+ e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
+ if isinstance(f, models.CharField) and f.max_length in (None, 0):
+ e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
+ if isinstance(f, models.DecimalField):
+ if f.decimal_places is None:
+ e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
+ if f.max_digits is None:
+ e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
+ if isinstance(f, models.FileField) and not f.upload_to:
+ e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
+ if isinstance(f, models.ImageField):
+ try:
+ from PIL import Image
+ except ImportError:
+ e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name)
+ if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
+ e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
+ if f.choices:
+ if not hasattr(f.choices, '__iter__'):
+ e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
+ else:
+ for c in f.choices:
+ if not type(c) in (tuple, list) or len(c) != 2:
+ e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name)
+ if f.db_index not in (None, True, False):
+ e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
+
+ # Check that max_length <= 255 if using older MySQL versions.
+ if settings.DATABASE_ENGINE == 'mysql':
+ db_version = connection.get_server_version()
+ if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
+ e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
+
+ # Check to see if the related field will clash with any
+ # existing fields, m2m fields, m2m related objects or related objects
+ if f.rel:
+ rel_opts = f.rel.to._meta
+ if f.rel.to not in models.get_models():
+ e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
+
+ rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
+ rel_query_name = f.related_query_name()
+ for r in rel_opts.fields:
+ if r.name == rel_name:
+ e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ for r in rel_opts.many_to_many:
+ if r.name == rel_name:
+ e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ for r in rel_opts.get_all_related_many_to_many_objects():
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ for r in rel_opts.get_all_related_objects():
+ if r.field is not f:
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+
+ for i, f in enumerate(opts.many_to_many):
+ # Check to see if the related m2m field will clash with any
+ # existing fields, m2m fields, m2m related objects or related objects
+ rel_opts = f.rel.to._meta
+ if f.rel.to not in models.get_models():
+ e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
+
+ rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
+ rel_query_name = f.related_query_name()
+ # If rel_name is none, there is no reverse accessor.
+ # (This only occurs for symmetrical m2m relations to self).
+ # If this is the case, there are no clashes to check for this field, as
+ # there are no reverse descriptors for this field.
+ if rel_name is not None:
+ for r in rel_opts.fields:
+ if r.name == rel_name:
+ e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ for r in rel_opts.many_to_many:
+ if r.name == rel_name:
+ e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ if r.name == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
+ for r in rel_opts.get_all_related_many_to_many_objects():
+ if r.field is not f:
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ for r in rel_opts.get_all_related_objects():
+ if r.get_accessor_name() == rel_name:
+ e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+ if r.get_accessor_name() == rel_query_name:
+ e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
+
+ # Check admin attribute.
+ if opts.admin is not None:
+ if not isinstance(opts.admin, models.AdminOptions):
+ e.add(opts, '"admin" attribute, if given, must be set to a models.AdminOptions() instance.')
+ else:
+ # list_display
+ if not isinstance(opts.admin.list_display, (list, tuple)):
+ e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.')
+ else:
+ for fn in opts.admin.list_display:
+ try:
+ f = opts.get_field(fn)
+ except models.FieldDoesNotExist:
+ if not hasattr(cls, fn):
+ e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn)
+ else:
+ if isinstance(f, models.ManyToManyField):
+ e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn)
+ # list_display_links
+ if opts.admin.list_display_links and not opts.admin.list_display:
+ e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.')
+ if not isinstance(opts.admin.list_display_links, (list, tuple)):
+ e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.')
+ else:
+ for fn in opts.admin.list_display_links:
+ try:
+ f = opts.get_field(fn)
+ except models.FieldDoesNotExist:
+ if not hasattr(cls, fn):
+ e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
+ if fn not in opts.admin.list_display:
+ e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
+ # list_filter
+ if not isinstance(opts.admin.list_filter, (list, tuple)):
+ e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.')
+ else:
+ for fn in opts.admin.list_filter:
+ try:
+ f = opts.get_field(fn)
+ except models.FieldDoesNotExist:
+ e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
+ # date_hierarchy
+ if opts.admin.date_hierarchy:
+ try:
+ f = opts.get_field(opts.admin.date_hierarchy)
+ except models.FieldDoesNotExist:
+ e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
+
+ # Check ordering attribute.
+ if opts.ordering:
+ for field_name in opts.ordering:
+ if field_name == '?': continue
+ if field_name.startswith('-'):
+ field_name = field_name[1:]
+ if opts.order_with_respect_to and field_name == '_order':
+ continue
+ if '.' in field_name: continue # Skip ordering in the format 'table.field'.
+ try:
+ opts.get_field(field_name, many_to_many=False)
+ except models.FieldDoesNotExist:
+ e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name)
+
+ # Check core=True, if needed.
+ for related in opts.get_followed_related_objects():
+ if not related.edit_inline:
+ continue
+ try:
+ for f in related.opts.fields:
+ if f.core:
+ raise StopIteration
+ e.add(related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name))
+ except StopIteration:
+ pass
+
+ # Check unique_together.
+ for ut in opts.unique_together:
+ for field_name in ut:
+ try:
+ f = opts.get_field(field_name, many_to_many=True)
+ except models.FieldDoesNotExist:
+ e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name)
+ else:
+ if isinstance(f.rel, models.ManyToManyRel):
+ e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name)
+
+ return len(e.errors)
diff --git a/django/core/serializers/__init__.py b/django/core/serializers/__init__.py
index 494393f3cf..049edf7521 100644
--- a/django/core/serializers/__init__.py
+++ b/django/core/serializers/__init__.py
@@ -6,7 +6,7 @@ Usage::
>>> from django.core import serializers
>>> json = serializers.serialize("json", some_query_set)
>>> objects = list(serializers.deserialize("json", json))
-
+
To add your own serializers, use the SERIALIZATION_MODULES setting::
SERIALIZATION_MODULES = {
@@ -30,19 +30,19 @@ try:
import yaml
BUILTIN_SERIALIZERS["yaml"] = "django.core.serializers.pyyaml"
except ImportError:
- pass
+ pass
_serializers = {}
-
+
def register_serializer(format, serializer_module):
"""Register a new serializer by passing in a module name."""
module = __import__(serializer_module, {}, {}, [''])
_serializers[format] = module
-
+
def unregister_serializer(format):
"""Unregister a given serializer"""
del _serializers[format]
-
+
def get_serializer(format):
if not _serializers:
_load_serializers()
@@ -52,12 +52,12 @@ def get_serializer_formats():
if not _serializers:
_load_serializers()
return _serializers.keys()
-
+
def get_deserializer(format):
if not _serializers:
_load_serializers()
return _serializers[format].Deserializer
-
+
def serialize(format, queryset, **options):
"""
Serialize a queryset (or any iterator that returns database objects) using
@@ -87,4 +87,4 @@ def _load_serializers():
register_serializer(format, BUILTIN_SERIALIZERS[format])
if hasattr(settings, "SERIALIZATION_MODULES"):
for format in settings.SERIALIZATION_MODULES:
- register_serializer(format, settings.SERIALIZATION_MODULES[format]) \ No newline at end of file
+ register_serializer(format, settings.SERIALIZATION_MODULES[format])
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 86d0037c17..ee9e4dd621 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -7,6 +7,7 @@ try:
except ImportError:
from StringIO import StringIO
from django.db import models
+from django.utils.encoding import smart_str, smart_unicode
class SerializationError(Exception):
"""Something bad happened during serialization."""
@@ -59,7 +60,7 @@ class Serializer(object):
value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
else:
value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
- return str(value)
+ return smart_unicode(value)
def start_serialization(self):
"""
@@ -154,10 +155,15 @@ class DeserializedObject(object):
self.m2m_data = m2m_data
def __repr__(self):
- return "<DeserializedObject: %s>" % str(self.object)
+ return "<DeserializedObject: %s>" % smart_str(self.object)
def save(self, save_m2m=True):
- self.object.save()
+ # Call save on the Model baseclass directly. This bypasses any
+ # model-defined save. The save is also forced to be raw.
+ # This ensures that the data that is deserialized is literally
+ # what came from the file, not post-processed by pre_save/save
+ # methods.
+ models.Model.save(self.object, raw=True)
if self.m2m_data and save_m2m:
for accessor_name, object_list in self.m2m_data.items():
setattr(self.object, accessor_name, object_list)
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index 5fbb3163f7..f61a2fa4a2 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -7,33 +7,34 @@ other serializers.
from django.conf import settings
from django.core.serializers import base
from django.db import models
+from django.utils.encoding import smart_unicode
class Serializer(base.Serializer):
"""
Serializes a QuerySet to basic Python objects.
"""
-
+
def start_serialization(self):
self._current = None
self.objects = []
-
+
def end_serialization(self):
pass
-
+
def start_object(self, obj):
self._current = {}
-
+
def end_object(self, obj):
self.objects.append({
- "model" : str(obj._meta),
- "pk" : str(obj._get_pk_val()),
+ "model" : smart_unicode(obj._meta),
+ "pk" : smart_unicode(obj._get_pk_val()),
"fields" : self._current
})
self._current = None
-
+
def handle_field(self, obj, field):
self._current[field.name] = getattr(obj, field.name)
-
+
def handle_fk_field(self, obj, field):
related = getattr(obj, field.name)
if related is not None:
@@ -44,17 +45,17 @@ class Serializer(base.Serializer):
# Related to remote object via other field
related = getattr(related, field.rel.field_name)
self._current[field.name] = related
-
+
def handle_m2m_field(self, obj, field):
self._current[field.name] = [related._get_pk_val() for related in getattr(obj, field.name).iterator()]
-
+
def getvalue(self):
return self.objects
def Deserializer(object_list, **options):
"""
Deserialize simple Python objects back into Django ORM instances.
-
+
It's expected that you pass the Python objects themselves (instead of a
stream or a string) to the constructor
"""
@@ -64,36 +65,30 @@ def Deserializer(object_list, **options):
Model = _get_model(d["model"])
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
m2m_data = {}
-
+
# Handle each field
for (field_name, field_value) in d["fields"].iteritems():
- if isinstance(field_value, unicode):
- field_value = field_value.encode(options.get("encoding", settings.DEFAULT_CHARSET))
-
+ if isinstance(field_value, str):
+ field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
+
field = Model._meta.get_field(field_name)
-
+
# Handle M2M relations
if field.rel and isinstance(field.rel, models.ManyToManyRel):
- pks = []
m2m_convert = field.rel.to._meta.pk.to_python
- for pk in field_value:
- if isinstance(pk, unicode):
- pks.append(m2m_convert(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))))
- else:
- pks.append(m2m_convert(pk))
- m2m_data[field.name] = pks
-
+ m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
+
# Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
if field_value:
data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
else:
data[field.attname] = None
-
+
# Handle all other fields
else:
data[field.name] = field.to_python(field_value)
-
+
yield base.DeserializedObject(Model(**data), m2m_data)
def _get_model(model_identifier):
@@ -105,5 +100,5 @@ def _get_model(model_identifier):
except TypeError:
Model = None
if Model is None:
- raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
+ raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
return Model
diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py
index d3444280c5..92159dbbe3 100644
--- a/django/core/serializers/pyyaml.py
+++ b/django/core/serializers/pyyaml.py
@@ -21,7 +21,7 @@ class Serializer(PythonSerializer):
self.options.pop('stream', None)
self.options.pop('fields', None)
yaml.dump(self.objects, self.stream, **self.options)
-
+
def getvalue(self):
return self.stream.getvalue()
@@ -35,4 +35,4 @@ def Deserializer(stream_or_string, **options):
stream = stream_or_string
for obj in PythonDeserializer(yaml.load(stream)):
yield obj
-
+
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index 3e4a6f3e79..667faf7c5e 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -6,13 +6,14 @@ from django.conf import settings
from django.core.serializers import base
from django.db import models
from django.utils.xmlutils import SimplerXMLGenerator
+from django.utils.encoding import smart_unicode
from xml.dom import pulldom
class Serializer(base.Serializer):
"""
Serializes a QuerySet to XML.
"""
-
+
def indent(self, level):
if self.options.get('indent', None) is not None:
self.xml.ignorableWhitespace('\n' + ' ' * self.options.get('indent', None) * level)
@@ -24,7 +25,7 @@ class Serializer(base.Serializer):
self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
self.xml.startDocument()
self.xml.startElement("django-objects", {"version" : "1.0"})
-
+
def end_serialization(self):
"""
End serialization -- end the document.
@@ -32,27 +33,27 @@ class Serializer(base.Serializer):
self.indent(0)
self.xml.endElement("django-objects")
self.xml.endDocument()
-
+
def start_object(self, obj):
"""
Called as each object is handled.
"""
if not hasattr(obj, "_meta"):
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
-
+
self.indent(1)
self.xml.startElement("object", {
- "pk" : str(obj._get_pk_val()),
- "model" : str(obj._meta),
+ "pk" : smart_unicode(obj._get_pk_val()),
+ "model" : smart_unicode(obj._meta),
})
-
+
def end_object(self, obj):
"""
Called after handling all fields for an object.
"""
self.indent(1)
self.xml.endElement("object")
-
+
def handle_field(self, obj, field):
"""
Called to handle each field on an object (except for ForeignKeys and
@@ -63,17 +64,17 @@ class Serializer(base.Serializer):
"name" : field.name,
"type" : field.get_internal_type()
})
-
+
# Get a "string version" of the object's data (this is handled by the
- # serializer base class).
+ # serializer base class).
if getattr(obj, field.name) is not None:
value = self.get_string_value(obj, field)
- self.xml.characters(str(value))
+ self.xml.characters(smart_unicode(value))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
-
+
def handle_fk_field(self, obj, field):
"""
Called to handle a ForeignKey (we need to treat them slightly
@@ -88,11 +89,11 @@ class Serializer(base.Serializer):
else:
# Related to remote object via other field
related = getattr(related, field.rel.field_name)
- self.xml.characters(str(related))
+ self.xml.characters(smart_unicode(related))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
-
+
def handle_m2m_field(self, obj, field):
"""
Called to handle a ManyToManyField. Related objects are only
@@ -101,9 +102,9 @@ class Serializer(base.Serializer):
"""
self._start_relational_field(field)
for relobj in getattr(obj, field.name).iterator():
- self.xml.addQuickElement("object", attrs={"pk" : str(relobj._get_pk_val())})
+ self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
self.xml.endElement("field")
-
+
def _start_relational_field(self, field):
"""
Helper to output the <field> element for relational fields
@@ -112,33 +113,33 @@ class Serializer(base.Serializer):
self.xml.startElement("field", {
"name" : field.name,
"rel" : field.rel.__class__.__name__,
- "to" : str(field.rel.to._meta),
+ "to" : smart_unicode(field.rel.to._meta),
})
-
+
class Deserializer(base.Deserializer):
"""
Deserialize XML.
"""
-
+
def __init__(self, stream_or_string, **options):
super(Deserializer, self).__init__(stream_or_string, **options)
- self.encoding = self.options.get("encoding", settings.DEFAULT_CHARSET)
- self.event_stream = pulldom.parse(self.stream)
-
+ self.event_stream = pulldom.parse(self.stream)
+
def next(self):
for event, node in self.event_stream:
if event == "START_ELEMENT" and node.nodeName == "object":
self.event_stream.expandNode(node)
return self._handle_object(node)
raise StopIteration
-
+
def _handle_object(self, node):
"""
Convert an <object> node to a DeserializedObject.
"""
- # Look up the model using the model loading mechanism. If this fails, bail.
+ # Look up the model using the model loading mechanism. If this fails,
+ # bail.
Model = self._get_model_from_node(node, "model")
-
+
# Start building a data dictionary from the object. If the node is
# missing the pk attribute, bail.
pk = node.getAttribute("pk")
@@ -146,11 +147,11 @@ class Deserializer(base.Deserializer):
raise base.DeserializationError("<object> node is missing the 'pk' attribute")
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
-
+
# Also start building a dict of m2m data (this is saved as
# {m2m_accessor_attribute : [list_of_related_objects]})
m2m_data = {}
-
+
# Deseralize each field.
for field_node in node.getElementsByTagName("field"):
# If the field is missing the name attribute, bail (are you
@@ -158,46 +159,46 @@ class Deserializer(base.Deserializer):
field_name = field_node.getAttribute("name")
if not field_name:
raise base.DeserializationError("<field> node is missing the 'name' attribute")
-
+
# Get the field from the Model. This will raise a
# FieldDoesNotExist if, well, the field doesn't exist, which will
# be propagated correctly.
field = Model._meta.get_field(field_name)
-
+
# As is usually the case, relation fields get the special treatment.
if field.rel and isinstance(field.rel, models.ManyToManyRel):
m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
data[field.attname] = self._handle_fk_field_node(field_node, field)
else:
- if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
+ if field_node.getElementsByTagName('None'):
value = None
else:
- value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
+ value = field.to_python(getInnerText(field_node).strip())
data[field.name] = value
-
+
# Return a DeserializedObject so that the m2m data has a place to live.
return base.DeserializedObject(Model(**data), m2m_data)
-
+
def _handle_fk_field_node(self, node, field):
"""
Handle a <field> node for a ForeignKey
"""
# Check if there is a child node named 'None', returning None if so.
- if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
+ if node.getElementsByTagName('None'):
return None
else:
return field.rel.to._meta.get_field(field.rel.field_name).to_python(
- getInnerText(node).strip().encode(self.encoding))
-
+ getInnerText(node).strip())
+
def _handle_m2m_field_node(self, node, field):
"""
- Handle a <field> node for a ManyToManyField
+ Handle a <field> node for a ManyToManyField.
"""
return [field.rel.to._meta.pk.to_python(
- c.getAttribute("pk").encode(self.encoding))
+ c.getAttribute("pk"))
for c in node.getElementsByTagName("object")]
-
+
def _get_model_from_node(self, node, attr):
"""
Helper to look up a model from a <object model=...> or a <field
@@ -217,8 +218,8 @@ class Deserializer(base.Deserializer):
"<%s> node has invalid model identifier: '%s'" % \
(node.nodeName, model_identifier))
return Model
-
-
+
+
def getInnerText(node):
"""
Get all the inner text of a DOM node (recursively).
@@ -232,4 +233,5 @@ def getInnerText(node):
inner_text.extend(getInnerText(child))
else:
pass
- return "".join(inner_text) \ No newline at end of file
+ return u"".join(inner_text)
+
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index 64ed739473..411068b2f5 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -9,7 +9,13 @@ been reviewed for security issues. Don't use it for production use.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from types import ListType, StringType
-import os, re, sys, time, urllib, mimetypes
+from email.Utils import formatdate
+import mimetypes
+import os
+import re
+import sys
+import time
+import urllib
__version__ = "0.1"
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
@@ -370,7 +376,7 @@ class ServerHandler(object):
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
if 'Date' not in self.headers:
self._write(
- 'Date: %s\r\n' % time.asctime(time.gmtime(time.time()))
+ 'Date: %s\r\n' % (formatdate()[:26] + "GMT")
)
if self.server_software and 'Server' not in self.headers:
self._write('Server: %s\r\n' % self.server_software)
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index f4c2dc4677..c512c37b96 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -9,6 +9,7 @@ a string) and returns a tuple in this format:
from django.http import Http404
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
+from django.utils.encoding import iri_to_uri, force_unicode, smart_str
from django.utils.functional import memoize
import re
@@ -38,22 +39,26 @@ def get_callable(lookup_view, can_fail=False):
during the import fail and the string is returned.
"""
if not callable(lookup_view):
- mod_name, func_name = get_mod_func(lookup_view)
try:
+ # Bail early for non-ASCII strings (they can't be functions).
+ lookup_view = lookup_view.encode('ascii')
+ mod_name, func_name = get_mod_func(lookup_view)
if func_name != '':
lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
except (ImportError, AttributeError):
if not can_fail:
raise
+ except UnicodeEncodeError:
+ pass
return lookup_view
-get_callable = memoize(get_callable, _callable_cache)
+get_callable = memoize(get_callable, _callable_cache, 1)
def get_resolver(urlconf):
if urlconf is None:
from django.conf import settings
urlconf = settings.ROOT_URLCONF
return RegexURLResolver(r'^/', urlconf)
-get_resolver = memoize(get_resolver, _resolver_cache)
+get_resolver = memoize(get_resolver, _resolver_cache, 1)
def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to
@@ -94,7 +99,7 @@ class MatchChecker(object):
# First we need to figure out whether it's a named or unnamed group.
#
grouped = match_obj.group(1)
- m = re.search(r'^\?P<(\w+)>(.*?)$', grouped)
+ m = re.search(r'^\?P<(\w+)>(.*?)$', grouped, re.UNICODE)
if m: # If this was a named group...
# m.group(1) is the name of the group
# m.group(2) is the regex.
@@ -120,9 +125,9 @@ class MatchChecker(object):
test_regex = grouped
# Note we're using re.match here on purpose because the start of
# to string needs to match.
- if not re.match(test_regex + '$', str(value)): # TODO: Unicode?
+ if not re.match(test_regex + '$', force_unicode(value), re.UNICODE):
raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
- return str(value) # TODO: Unicode?
+ return force_unicode(value)
class RegexURLPattern(object):
def __init__(self, regex, callback, default_args=None, name=None):
@@ -130,7 +135,7 @@ class RegexURLPattern(object):
# callback is either a string like 'foo.views.news.stories.story_detail'
# which represents the path to a module and a view function name, or a
# callable object (view).
- self.regex = re.compile(regex)
+ self.regex = re.compile(regex, re.UNICODE)
if callable(callback):
self._callback = callback
else:
@@ -139,6 +144,9 @@ class RegexURLPattern(object):
self.default_args = default_args or {}
self.name = name
+ def __repr__(self):
+ return '<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern)
+
def add_prefix(self, prefix):
"""
Adds the prefix string to a string-based callback.
@@ -194,12 +202,15 @@ class RegexURLResolver(object):
def __init__(self, regex, urlconf_name, default_kwargs=None):
# regex is a string representing a regular expression.
# urlconf_name is a string representing the module containing urlconfs.
- self.regex = re.compile(regex)
+ self.regex = re.compile(regex, re.UNICODE)
self.urlconf_name = urlconf_name
self.callback = None
self.default_kwargs = default_kwargs or {}
self._reverse_dict = {}
+ def __repr__(self):
+ return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern)
+
def _get_reverse_dict(self):
if not self._reverse_dict and hasattr(self.urlconf_module, 'urlpatterns'):
for pattern in reversed(self.urlconf_module.urlpatterns):
@@ -224,8 +235,11 @@ class RegexURLResolver(object):
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
else:
if sub_match:
- sub_match_dict = dict(self.default_kwargs, **sub_match[2])
- return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict)
+ sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
+ sub_match_dict.update(self.default_kwargs)
+ for k, v in sub_match[2].iteritems():
+ sub_match_dict[smart_str(k)] = v
+ return sub_match[0], sub_match[1], sub_match_dict
tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path}
@@ -265,7 +279,7 @@ class RegexURLResolver(object):
except (ImportError, AttributeError):
raise NoReverseMatch
if lookup_view in self.reverse_dict:
- return ''.join([reverse_helper(part.regex, *args, **kwargs) for part in self.reverse_dict[lookup_view]])
+ return u''.join([reverse_helper(part.regex, *args, **kwargs) for part in self.reverse_dict[lookup_view]])
raise NoReverseMatch
def reverse_helper(self, lookup_view, *args, **kwargs):
@@ -279,5 +293,5 @@ def resolve(path, urlconf=None):
def reverse(viewname, urlconf=None, args=None, kwargs=None):
args = args or []
kwargs = kwargs or {}
- return '/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs)
+ return iri_to_uri(u'/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs))
diff --git a/django/core/validators.py b/django/core/validators.py
index 293f0e1a8c..8a93462b21 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -10,9 +10,14 @@ form field is required.
import urllib2
from django.conf import settings
-from django.utils.translation import gettext, gettext_lazy, ngettext
+from django.utils.translation import ugettext as _, ugettext_lazy, ungettext
from django.utils.functional import Promise, lazy
+from django.utils.encoding import force_unicode
import re
+try:
+ from decimal import Decimal, DecimalException
+except ImportError:
+ from django.utils._decimal import Decimal, DecimalException # Python 2.3
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
@@ -23,25 +28,25 @@ ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
+ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
-decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
slug_re = re.compile(r'^[-\w]+$')
url_re = re.compile(r'^https?://\S+$')
-lazy_inter = lazy(lambda a,b: str(a) % b, str)
+lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode)
class ValidationError(Exception):
def __init__(self, message):
"ValidationError can be passed a string or a list."
if isinstance(message, list):
- self.messages = message
+ self.messages = [force_unicode(msg) for msg in message]
else:
assert isinstance(message, (basestring, Promise)), ("%s should be a string" % repr(message))
- self.messages = [message]
+ self.messages = [force_unicode(message)]
+
def __str__(self):
# This is needed because, without a __str__(), printing an exception
# instance would result in this:
@@ -53,39 +58,40 @@ class CriticalValidationError(Exception):
def __init__(self, message):
"ValidationError can be passed a string or a list."
if isinstance(message, list):
- self.messages = message
+ self.messages = [force_unicode(msg) for msg in message]
else:
assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message)
- self.messages = [message]
+ self.messages = [force_unicode(message)]
+
def __str__(self):
return str(self.messages)
def isAlphaNumeric(field_data, all_data):
if not alnum_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers and underscores.")
+ raise ValidationError, _("This value must contain only letters, numbers and underscores.")
def isAlphaNumericURL(field_data, all_data):
if not alnumurl_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers, underscores, dashes or slashes.")
+ raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.")
def isSlug(field_data, all_data):
if not slug_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers, underscores or hyphens.")
+ raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.")
def isLowerCase(field_data, all_data):
if field_data.lower() != field_data:
- raise ValidationError, gettext("Uppercase letters are not allowed here.")
+ raise ValidationError, _("Uppercase letters are not allowed here.")
def isUpperCase(field_data, all_data):
if field_data.upper() != field_data:
- raise ValidationError, gettext("Lowercase letters are not allowed here.")
+ raise ValidationError, _("Lowercase letters are not allowed here.")
def isCommaSeparatedIntegerList(field_data, all_data):
for supposed_int in field_data.split(','):
try:
int(supposed_int)
except ValueError:
- raise ValidationError, gettext("Enter only digits separated by commas.")
+ raise ValidationError, _("Enter only digits separated by commas.")
def isCommaSeparatedEmailList(field_data, all_data):
"""
@@ -97,32 +103,32 @@ def isCommaSeparatedEmailList(field_data, all_data):
try:
isValidEmail(supposed_email.strip(), '')
except ValidationError:
- raise ValidationError, gettext("Enter valid e-mail addresses separated by commas.")
+ raise ValidationError, _("Enter valid e-mail addresses separated by commas.")
def isValidIPAddress4(field_data, all_data):
if not ip4_re.search(field_data):
- raise ValidationError, gettext("Please enter a valid IP address.")
+ raise ValidationError, _("Please enter a valid IP address.")
def isNotEmpty(field_data, all_data):
if field_data.strip() == '':
- raise ValidationError, gettext("Empty values are not allowed here.")
+ raise ValidationError, _("Empty values are not allowed here.")
def isOnlyDigits(field_data, all_data):
if not field_data.isdigit():
- raise ValidationError, gettext("Non-numeric characters aren't allowed here.")
+ raise ValidationError, _("Non-numeric characters aren't allowed here.")
def isNotOnlyDigits(field_data, all_data):
if field_data.isdigit():
- raise ValidationError, gettext("This value can't be comprised solely of digits.")
+ raise ValidationError, _("This value can't be comprised solely of digits.")
def isInteger(field_data, all_data):
# This differs from isOnlyDigits because this accepts the negative sign
if not integer_re.search(field_data):
- raise ValidationError, gettext("Enter a whole number.")
+ raise ValidationError, _("Enter a whole number.")
def isOnlyLetters(field_data, all_data):
if not field_data.isalpha():
- raise ValidationError, gettext("Only alphabetical characters are allowed here.")
+ raise ValidationError, _("Only alphabetical characters are allowed here.")
def _isValidDate(date_string):
"""
@@ -137,30 +143,30 @@ def _isValidDate(date_string):
# This check is needed because strftime is used when saving the date
# value to the database, and strftime requires that the year be >=1900.
if year < 1900:
- raise ValidationError, gettext('Year must be 1900 or later.')
+ raise ValidationError, _('Year must be 1900 or later.')
try:
date(year, month, day)
except ValueError, e:
- msg = gettext('Invalid date: %s') % gettext(str(e))
+ msg = _('Invalid date: %s') % _(str(e))
raise ValidationError, msg
def isValidANSIDate(field_data, all_data):
if not ansi_date_re.search(field_data):
- raise ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
+ raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
_isValidDate(field_data)
def isValidANSITime(field_data, all_data):
if not ansi_time_re.search(field_data):
- raise ValidationError, gettext('Enter a valid time in HH:MM format.')
+ raise ValidationError, _('Enter a valid time in HH:MM format.')
def isValidANSIDatetime(field_data, all_data):
if not ansi_datetime_re.search(field_data):
- raise ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
+ raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
_isValidDate(field_data.split()[0])
def isValidEmail(field_data, all_data):
if not email_re.search(field_data):
- raise ValidationError, gettext('Enter a valid e-mail address.')
+ raise ValidationError, _('Enter a valid e-mail address.')
def isValidImage(field_data, all_data):
"""
@@ -172,22 +178,22 @@ def isValidImage(field_data, all_data):
try:
content = field_data['content']
except TypeError:
- raise ValidationError, gettext("No file was submitted. Check the encoding type on the form.")
+ raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
try:
Image.open(StringIO(content))
except IOError: # Python Imaging Library doesn't recognize it as an image
- raise ValidationError, gettext("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
+ raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
def isValidImageURL(field_data, all_data):
uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png'))
try:
uc(field_data, all_data)
except URLMimeTypeCheck.InvalidContentType:
- raise ValidationError, gettext("The URL %s does not point to a valid image.") % field_data
+ raise ValidationError, _("The URL %s does not point to a valid image.") % field_data
def isValidPhone(field_data, all_data):
if not phone_re.search(field_data):
- raise ValidationError, gettext('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data
+ raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data
def isValidQuicktimeVideoURL(field_data, all_data):
"Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)"
@@ -195,11 +201,11 @@ def isValidQuicktimeVideoURL(field_data, all_data):
try:
uc(field_data, all_data)
except URLMimeTypeCheck.InvalidContentType:
- raise ValidationError, gettext("The URL %s does not point to a valid QuickTime video.") % field_data
+ raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data
def isValidURL(field_data, all_data):
if not url_re.search(field_data):
- raise ValidationError, gettext("A valid URL is required.")
+ raise ValidationError, _("A valid URL is required.")
def isValidHTML(field_data, all_data):
import urllib, urllib2
@@ -213,14 +219,14 @@ def isValidHTML(field_data, all_data):
return
from xml.dom.minidom import parseString
error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')]
- raise ValidationError, gettext("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages)
+ raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages)
def isWellFormedXml(field_data, all_data):
from xml.dom.minidom import parseString
try:
parseString(field_data)
except Exception, e: # Naked except because we're not sure what will be thrown
- raise ValidationError, gettext("Badly formed XML: %s") % str(e)
+ raise ValidationError, _("Badly formed XML: %s") % str(e)
def isWellFormedXmlFragment(field_data, all_data):
isWellFormedXml('<root>%s</root>' % field_data, all_data)
@@ -250,7 +256,7 @@ def isValidUSState(field_data, all_data):
"Checks that the given string is a valid two-letter U.S. state abbreviation"
states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY']
if field_data.upper() not in states:
- raise ValidationError, gettext("Enter a valid U.S. state abbreviation.")
+ raise ValidationError, _("Enter a valid U.S. state abbreviation.")
def hasNoProfanities(field_data, all_data):
"""
@@ -263,15 +269,15 @@ def hasNoProfanities(field_data, all_data):
words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data]
if words_seen:
from django.utils.text import get_text_list
- plural = len(words_seen) > 1
- raise ValidationError, ngettext("Watch your mouth! The word %s is not allowed here.",
+ plural = len(words_seen)
+ raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.",
"Watch your mouth! The words %s are not allowed here.", plural) % \
- get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and')
+ get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and'))
class AlwaysMatchesOtherField(object):
def __init__(self, other_field_name, error_message=None):
self.other = other_field_name
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must match the '%s' field."), self.other)
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other)
self.always_test = True
def __call__(self, field_data, all_data):
@@ -290,7 +296,7 @@ class ValidateIfOtherFieldEquals(object):
v(field_data, all_data)
class RequiredIfOtherFieldNotGiven(object):
- def __init__(self, other_field_name, error_message=gettext_lazy("Please enter something for at least one field.")):
+ def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")):
self.other, self.error_message = other_field_name, error_message
self.always_test = True
@@ -299,7 +305,7 @@ class RequiredIfOtherFieldNotGiven(object):
raise ValidationError, self.error_message
class RequiredIfOtherFieldsGiven(object):
- def __init__(self, other_field_names, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
+ def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):
self.other, self.error_message = other_field_names, error_message
self.always_test = True
@@ -310,7 +316,7 @@ class RequiredIfOtherFieldsGiven(object):
class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven):
"Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list."
- def __init__(self, other_field_name, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
+ def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):
RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)
class RequiredIfOtherFieldEquals(object):
@@ -318,7 +324,7 @@ class RequiredIfOtherFieldEquals(object):
self.other_field = other_field
self.other_value = other_value
other_label = other_label or other_value
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is %(value)s"), {
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), {
'field': other_field, 'value': other_label})
self.always_test = True
@@ -331,7 +337,7 @@ class RequiredIfOtherFieldDoesNotEqual(object):
self.other_field = other_field
self.other_value = other_value
other_label = other_label or other_value
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is not %(value)s"), {
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), {
'field': other_field, 'value': other_label})
self.always_test = True
@@ -350,7 +356,7 @@ class IsLessThanOtherField(object):
class UniqueAmongstFieldsWithPrefix(object):
def __init__(self, field_name, prefix, error_message):
self.field_name, self.prefix = field_name, prefix
- self.error_message = error_message or gettext_lazy("Duplicate values are not allowed.")
+ self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.")
def __call__(self, field_data, all_data):
for field_name, value in all_data.items():
@@ -365,11 +371,11 @@ class NumberIsInRange(object):
self.lower, self.upper = lower, upper
if not error_message:
if lower and upper:
- self.error_message = gettext("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
+ self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
elif lower:
- self.error_message = gettext("This value must be at least %s.") % lower
+ self.error_message = _("This value must be at least %s.") % lower
elif upper:
- self.error_message = gettext("This value must be no more than %s.") % upper
+ self.error_message = _("This value must be no more than %s.") % upper
else:
self.error_message = error_message
@@ -405,28 +411,30 @@ class IsAPowerOf(object):
from math import log
val = log(int(field_data)) / log(self.power_of)
if val != int(val):
- raise ValidationError, gettext("This value must be a power of %s.") % self.power_of
+ raise ValidationError, _("This value must be a power of %s.") % self.power_of
class IsValidDecimal(object):
def __init__(self, max_digits, decimal_places):
self.max_digits, self.decimal_places = max_digits, decimal_places
def __call__(self, field_data, all_data):
- match = decimal_re.search(str(field_data))
- if not match:
- raise ValidationError, gettext("Please enter a valid decimal number.")
-
- digits = len(match.group('digits') or '')
- decimals = len(match.group('decimals') or '')
-
+ try:
+ val = Decimal(field_data)
+ except DecimalException:
+ raise ValidationError, _("Please enter a valid decimal number.")
+
+ pieces = str(val).split('.')
+ decimals = (len(pieces) == 2) and len(pieces[1]) or 0
+ digits = len(pieces[0])
+
if digits + decimals > self.max_digits:
- raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
+ raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
if digits > (self.max_digits - self.decimal_places):
- raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
+ raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
if decimals > self.decimal_places:
- raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
+ raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.",
"Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
def isValidFloat(field_data, all_data):
@@ -434,7 +442,7 @@ def isValidFloat(field_data, all_data):
try:
float(data)
except ValueError:
- raise ValidationError, gettext("Please enter a valid floating point number.")
+ raise ValidationError, _("Please enter a valid floating point number.")
class HasAllowableSize(object):
"""
@@ -443,14 +451,14 @@ class HasAllowableSize(object):
"""
def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None):
self.min_size, self.max_size = min_size, max_size
- self.min_error_message = min_error_message or lazy_inter(gettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size)
- self.max_error_message = max_error_message or lazy_inter(gettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)
+ self.min_error_message = min_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size)
+ self.max_error_message = max_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)
def __call__(self, field_data, all_data):
try:
content = field_data['content']
except TypeError:
- raise ValidationError, gettext_lazy("No file was submitted. Check the encoding type on the form.")
+ raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.")
if self.min_size is not None and len(content) < self.min_size:
raise ValidationError, self.min_error_message
if self.max_size is not None and len(content) > self.max_size:
@@ -461,7 +469,7 @@ class MatchesRegularExpression(object):
Checks that the field matches the given regular-expression. The regex
should be in string format, not already compiled.
"""
- def __init__(self, regexp, error_message=gettext_lazy("The format for this field is wrong.")):
+ def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")):
self.regexp = re.compile(regexp)
self.error_message = error_message
@@ -476,7 +484,7 @@ class AnyValidator(object):
as a validation error. The message is rather unspecific, so it's best to
specify one on instantiation.
"""
- def __init__(self, validator_list=None, error_message=gettext_lazy("This field is invalid.")):
+ def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")):
if validator_list is None: validator_list = []
self.validator_list = validator_list
self.error_message = error_message
@@ -512,10 +520,10 @@ class URLMimeTypeCheck(object):
try:
info = urllib2.urlopen(field_data).info()
except (urllib2.HTTPError, urllib2.URLError):
- raise URLMimeTypeCheck.CouldNotRetrieve, gettext("Could not retrieve anything from %s.") % field_data
+ raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data
content_type = info['content-type']
if content_type not in self.mime_type_list:
- raise URLMimeTypeCheck.InvalidContentType, gettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
+ raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
'url': field_data, 'contenttype': content_type}
class RelaxNGCompact(object):
diff --git a/django/core/xheaders.py b/django/core/xheaders.py
index 3beb930158..34335f12c5 100644
--- a/django/core/xheaders.py
+++ b/django/core/xheaders.py
@@ -4,7 +4,7 @@ information about those pages -- namely, the content type and object ID.
This module contains utility functions for retrieving and doing interesting
things with these special "X-Headers" (so called because the HTTP spec demands
-that custom headers are prefxed with "X-").
+that custom headers are prefixed with "X-").
Next time you're at slashdot.org, watch out for X-Fry and X-Bender. :)
"""
@@ -17,6 +17,8 @@ def populate_xheaders(request, response, model, object_id):
or if the request is from a logged in staff member.
"""
from django.conf import settings
- if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (hasattr(request, 'user') and request.user.is_authenticated() and request.user.is_staff):
+ if (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS
+ or (hasattr(request, 'user') and request.user.is_authenticated()
+ and request.user.is_staff)):
response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())
response['X-Object-Id'] = str(object_id)
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index e69de29bb2..f3c6f59258 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -0,0 +1,218 @@
+try:
+ # Only exists in Python 2.4+
+ from threading import local
+except ImportError:
+ # Import copy of _thread_local.py from Python 2.4
+ from django.utils._threading_local import local
+
+class BaseDatabaseWrapper(local):
+ """
+ Represents a database connection.
+ """
+ ops = None
+ def __init__(self, **kwargs):
+ self.connection = None
+ self.queries = []
+ self.options = kwargs
+
+ def _commit(self):
+ if self.connection is not None:
+ return self.connection.commit()
+
+ def _rollback(self):
+ if self.connection is not None:
+ return self.connection.rollback()
+
+ def close(self):
+ if self.connection is not None:
+ self.connection.close()
+ self.connection = None
+
+ def cursor(self):
+ from django.conf import settings
+ cursor = self._cursor(settings)
+ if settings.DEBUG:
+ return self.make_debug_cursor(cursor)
+ return cursor
+
+ def make_debug_cursor(self, cursor):
+ from django.db.backends import util
+ return util.CursorDebugWrapper(cursor, self)
+
+class BaseDatabaseFeatures(object):
+ allows_group_by_ordinal = True
+ allows_unique_and_pk = True
+ autoindexes_primary_keys = True
+ needs_datetime_string_cast = True
+ needs_upper_for_iops = False
+ supports_constraints = True
+ supports_tablespaces = False
+ uses_case_insensitive_names = False
+ uses_custom_queryset = False
+
+class BaseDatabaseOperations(object):
+ """
+ This class encapsulates all backend-specific differences, such as the way
+ a backend performs ordering or calculates the ID of a recently-inserted
+ row.
+ """
+ def autoinc_sql(self, table):
+ """
+ Returns any SQL needed to support auto-incrementing primary keys, or
+ None if no SQL is necessary.
+
+ This SQL is executed when a table is created.
+ """
+ return None
+
+ def date_extract_sql(self, lookup_type, field_name):
+ """
+ Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
+ extracts a value from the given date field field_name.
+ """
+ raise NotImplementedError()
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ """
+ Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
+ truncates the given date field field_name to a DATE object with only
+ the given specificity.
+ """
+ raise NotImplementedError()
+
+ def datetime_cast_sql(self):
+ """
+ Returns the SQL necessary to cast a datetime value so that it will be
+ retrieved as a Python datetime object instead of a string.
+
+ This SQL should include a '%s' in place of the field's name. This
+ method should return None if no casting is necessary.
+ """
+ return None
+
+ def deferrable_sql(self):
+ """
+ Returns the SQL necessary to make a constraint "initially deferred"
+ during a CREATE TABLE statement.
+ """
+ return ''
+
+ def drop_foreignkey_sql(self):
+ """
+ Returns the SQL command that drops a foreign key.
+ """
+ return "DROP CONSTRAINT"
+
+ def drop_sequence_sql(self, table):
+ """
+ Returns any SQL necessary to drop the sequence for the given table.
+ Returns None if no SQL is necessary.
+ """
+ return None
+
+ def field_cast_sql(self, db_type):
+ """
+ Given a column type (e.g. 'BLOB', 'VARCHAR'), returns the SQL necessary
+ to cast it before using it in a WHERE statement. Note that the
+ resulting string should contain a '%s' placeholder for the column being
+ searched against.
+ """
+ return '%s'
+
+ def fulltext_search_sql(self, field_name):
+ """
+ Returns the SQL WHERE clause to use in order to perform a full-text
+ search of the given field_name. Note that the resulting string should
+ contain a '%s' placeholder for the value being searched against.
+ """
+ raise NotImplementedError('Full-text search is not implemented for this database backend')
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ """
+ Given a cursor object that has just performed an INSERT statement into
+ a table that has an auto-incrementing ID, returns the newly created ID.
+
+ This method also receives the table name and the name of the primary-key
+ column.
+ """
+ return cursor.lastrowid
+
+ def limit_offset_sql(self, limit, offset=None):
+ """
+ Returns a LIMIT/OFFSET SQL clause, given a limit and optional offset.
+ """
+ # 'LIMIT 40 OFFSET 20'
+ sql = "LIMIT %s" % limit
+ if offset and offset != 0:
+ sql += " OFFSET %s" % offset
+ return sql
+
+ def max_name_length(self):
+ """
+ Returns the maximum length of table and column names, or None if there
+ is no limit.
+ """
+ return None
+
+ def pk_default_value(self):
+ """
+ Returns the value to use during an INSERT statement to specify that
+ the field should use its default value.
+ """
+ return 'DEFAULT'
+
+ def query_set_class(self, DefaultQuerySet):
+ """
+ Given the default QuerySet class, returns a custom QuerySet class
+ to use for this backend. Returns None if a custom QuerySet isn't used.
+ See also BaseDatabaseFeatures.uses_custom_queryset, which regulates
+ whether this method is called at all.
+ """
+ return None
+
+ def quote_name(self, name):
+ """
+ Returns a quoted version of the given table, index or column name. Does
+ not quote the given name if it's already been quoted.
+ """
+ raise NotImplementedError()
+
+ def random_function_sql(self):
+ """
+ Returns a SQL expression that returns a random value.
+ """
+ return 'RANDOM()'
+
+ def sql_flush(self, style, tables, sequences):
+ """
+ Returns a list of SQL statements required to remove all data from
+ the given database tables (without actually removing the tables
+ themselves).
+
+ The `style` argument is a Style object as returned by either
+ color_style() or no_style() in django.core.management.color.
+ """
+ raise NotImplementedError()
+
+ def sequence_reset_sql(self, style, model_list):
+ """
+ Returns a list of the SQL statements required to reset sequences for
+ the given models.
+
+ The `style` argument is a Style object as returned by either
+ color_style() or no_style() in django.core.management.color.
+ """
+ return [] # No sequence reset required by default.
+
+ def start_transaction_sql(self):
+ """
+ Returns the SQL statement required to start a transaction.
+ """
+ return "BEGIN;"
+
+ def tablespace_sql(self, tablespace, inline=False):
+ """
+ Returns the tablespace SQL, or None if the backend doesn't use
+ tablespaces.
+ """
+ return None
diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py
index 0deb6aae64..07ce02d591 100644
--- a/django/db/backends/ado_mssql/base.py
+++ b/django/db/backends/ado_mssql/base.py
@@ -4,12 +4,12 @@ ADO MSSQL database backend for Django.
Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
try:
import adodbapi as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e
+ raise ImproperlyConfigured("Error loading adodbapi module: %s" % e)
import datetime
try:
import mx
@@ -48,148 +48,65 @@ def variantToPython(variant, adType):
return res
Database.convertVariantToPython = variantToPython
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseFeatures(BaseDatabaseFeatures):
+ supports_tablespaces = True
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ return "DATEPART(%s, %s)" % (lookup_type, field_name)
- def cursor(self):
- from django.conf import settings
+ def date_trunc_sql(self, lookup_type, field_name):
+ if lookup_type == 'year':
+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
+ if lookup_type == 'month':
+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)
+ if lookup_type == 'day':
+ return "Convert(datetime, Convert(varchar(12), %s))" % field_name
+
+ def deferrable_sql(self):
+ return " DEFERRABLE INITIALLY DEFERRED"
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
+ return cursor.fetchone()[0]
+
+ def quote_name(self, name):
+ if name.startswith('[') and name.endswith(']'):
+ return name # Quoting once is enough.
+ return '[%s]' % name
+
+ def random_function_sql(self):
+ return 'RAND()'
+
+ def tablespace_sql(self, tablespace, inline=False):
+ return "ON %s" % self.quote_name(tablespace)
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'LIKE %s',
+ 'contains': 'LIKE %s',
+ 'icontains': 'LIKE %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE %s',
+ 'endswith': 'LIKE %s',
+ 'istartswith': 'LIKE %s',
+ 'iendswith': 'LIKE %s',
+ }
+
+ def _cursor(self, settings):
if self.connection is None:
if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '':
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file."
+ raise ImproperlyConfigured("You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file.")
if not settings.DATABASE_HOST:
settings.DATABASE_HOST = "127.0.0.1"
# TODO: Handle DATABASE_PORT.
conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
self.connection = Database.connect(conn_string)
- cursor = self.connection.cursor()
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
- return cursor
-
- def _commit(self):
- if self.connection is not None:
- return self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = True
-needs_datetime_string_cast = True
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = True
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith('[') and name.endswith(']'):
- return name # Quoting once is enough.
- return '[%s]' % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- return "DATEPART(%s, %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- if lookup_type=='year':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
- if lookup_type=='month':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)
- if lookup_type=='day':
- return "Convert(datetime, Convert(varchar(12), %s))" % field_name
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- # TODO: This is a guess. Make sure this is correct.
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_deferrable_sql():
- return " DEFERRABLE INITIALLY DEFERRED"
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return "DROP CONSTRAINT"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_tablespace_sql(tablespace, inline=False):
- return "ON %s" % quote_name(tablespace)
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
- """
- # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
- # TODO - SQL not actually tested against ADO MSSQL yet!
- # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
- sql_list = ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- # No sequence reset required
- return []
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'LIKE %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
+ return self.connection.cursor()
diff --git a/django/db/backends/ado_mssql/creation.py b/django/db/backends/ado_mssql/creation.py
index a426dd590f..3aa13a31b4 100644
--- a/django/db/backends/ado_mssql/creation.py
+++ b/django/db/backends/ado_mssql/creation.py
@@ -1,8 +1,8 @@
DATA_TYPES = {
'AutoField': 'int IDENTITY (1, 1)',
'BooleanField': 'bit',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'smalldatetime',
'DateTimeField': 'smalldatetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
@@ -17,7 +17,7 @@ DATA_TYPES = {
'PhoneNumberField': 'varchar(20)',
'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)',
- 'SlugField': 'varchar(%(maxlength)s)',
+ 'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'text',
'TimeField': 'time',
diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py
index f47cbdf3d4..50191f88fe 100644
--- a/django/db/backends/dummy/base.py
+++ b/django/db/backends/dummy/base.py
@@ -21,7 +21,14 @@ class DatabaseError(Exception):
class IntegrityError(DatabaseError):
pass
-class DatabaseWrapper:
+class ComplainOnGetattr(object):
+ def __getattr__(self, *args, **kwargs):
+ complain()
+
+class DatabaseWrapper(object):
+ features = ComplainOnGetattr()
+ ops = ComplainOnGetattr()
+ operators = {}
cursor = complain
_commit = complain
_rollback = ignore
@@ -30,28 +37,4 @@ class DatabaseWrapper:
pass
def close(self):
- pass # close()
-
-supports_constraints = False
-supports_tablespaces = False
-quote_name = complain
-dictfetchone = complain
-dictfetchmany = complain
-dictfetchall = complain
-get_last_insert_id = complain
-get_date_extract_sql = complain
-get_date_trunc_sql = complain
-get_datetime_cast_sql = complain
-get_limit_offset_sql = complain
-get_random_function_sql = complain
-get_deferrable_sql = complain
-get_fulltext_search_sql = complain
-get_drop_foreignkey_sql = complain
-get_pk_default_value = complain
-get_max_name_length = ignore
-get_start_transaction_sql = complain
-get_autoinc_sql = complain
-get_sql_flush = complain
-get_sql_sequence_reset = complain
-
-OPERATOR_MAPPING = {}
+ pass
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 4c64134118..f913b88709 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -4,12 +4,12 @@ MySQL database backend for Django.
Requires MySQLdb: http://sourceforge.net/projects/mysql-python
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
try:
import MySQLdb as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading MySQLdb module: %s" % e
+ raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
# We want version (1, 2, 1, 'final', 2) or later. We can't just use
# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
@@ -17,7 +17,7 @@ except ImportError, e:
version = Database.version_info
if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
(len(version) < 5 or version[3] != 'final' or version[4] < 2))):
- raise ImportError, "MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__
+ raise ImportError("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
@@ -53,19 +53,94 @@ server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
# standard util.CursorDebugWrapper can be used. Also, using sql_mode
# TRADITIONAL will automatically cause most warnings to be treated as errors.
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseFeatures(BaseDatabaseFeatures):
+ autoindexes_primary_keys = False
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
+ return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
+ format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
+ format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
+ try:
+ i = fields.index(lookup_type) + 1
+ except ValueError:
+ sql = field_name
+ else:
+ format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
+ sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
+ return sql
+
+ def drop_foreignkey_sql(self):
+ return "DROP FOREIGN KEY"
+
+ def fulltext_search_sql(self, field_name):
+ return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
+
+ def limit_offset_sql(self, limit, offset=None):
+ # 'LIMIT 20,40'
+ sql = "LIMIT "
+ if offset and offset != 0:
+ sql += "%s," % offset
+ return sql + str(limit)
+
+ def quote_name(self, name):
+ if name.startswith("`") and name.endswith("`"):
+ return name # Quoting once is enough.
+ return "`%s`" % name
+
+ def random_function_sql(self):
+ return 'RAND()'
+
+ def sql_flush(self, style, tables, sequences):
+ # NB: The generated SQL below is specific to MySQL
+ # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+ # to clear all tables of all data
+ if tables:
+ sql = ['SET FOREIGN_KEY_CHECKS = 0;']
+ for table in tables:
+ sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
+ sql.append('SET FOREIGN_KEY_CHECKS = 1;')
+
+ # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
+ # to reset sequence indices
+ sql.extend(["%s %s %s %s %s;" % \
+ (style.SQL_KEYWORD('ALTER'),
+ style.SQL_KEYWORD('TABLE'),
+ style.SQL_TABLE(self.quote_name(sequence['table'])),
+ style.SQL_KEYWORD('AUTO_INCREMENT'),
+ style.SQL_FIELD('= 1'),
+ ) for sequence in sequences])
+ return sql
+ else:
+ return []
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'LIKE %s',
+ 'contains': 'LIKE BINARY %s',
+ 'icontains': 'LIKE %s',
+ 'regex': 'REGEXP BINARY %s',
+ 'iregex': 'REGEXP %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE BINARY %s',
+ 'endswith': 'LIKE BINARY %s',
+ 'istartswith': 'LIKE %s',
+ 'iendswith': 'LIKE %s',
+ }
-class DatabaseWrapper(local):
def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
+ super(DatabaseWrapper, self).__init__(**kwargs)
self.server_version = None
- self.options = kwargs
def _valid_connection(self):
if self.connection is not None:
@@ -77,14 +152,13 @@ class DatabaseWrapper(local):
self.connection = None
return False
- def cursor(self):
- from django.conf import settings
+ def _cursor(self, settings):
from warnings import filterwarnings
if not self._valid_connection():
kwargs = {
'conv': django_conversions,
'charset': 'utf8',
- 'use_unicode': False,
+ 'use_unicode': True,
}
if settings.DATABASE_USER:
kwargs['user'] = settings.DATABASE_USER
@@ -100,29 +174,16 @@ class DatabaseWrapper(local):
kwargs['port'] = int(settings.DATABASE_PORT)
kwargs.update(self.options)
self.connection = Database.connect(**kwargs)
- cursor = self.connection.cursor()
- else:
- cursor = self.connection.cursor()
+ cursor = self.connection.cursor()
if settings.DEBUG:
filterwarnings("error", category=Database.Warning)
- return util.CursorDebugWrapper(cursor, self)
return cursor
- def _commit(self):
- if self.connection is not None:
- self.connection.commit()
-
def _rollback(self):
- if self.connection is not None:
- try:
- self.connection.rollback()
- except Database.NotSupportedError:
- pass
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
+ try:
+ BaseDatabaseWrapper._rollback(self)
+ except Database.NotSupportedError:
+ pass
def get_server_version(self):
if not self.server_version:
@@ -133,128 +194,3 @@ class DatabaseWrapper(local):
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
self.server_version = tuple([int(x) for x in m.groups()])
return self.server_version
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = False
-needs_datetime_string_cast = True # MySQLdb requires a typecast for dates
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = False
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith("`") and name.endswith("`"):
- return name # Quoting once is enough.
- return "`%s`" % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- return cursor.lastrowid
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
- return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
- format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
- format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
- try:
- i = fields.index(lookup_type) + 1
- except ValueError:
- sql = field_name
- else:
- format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
- sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
- return sql
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT "
- if offset and offset != 0:
- sql += "%s," % offset
- return sql + str(limit)
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_deferrable_sql():
- return ""
-
-def get_fulltext_search_sql(field_name):
- return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
-
-def get_drop_foreignkey_sql():
- return "DROP FOREIGN KEY"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None;
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
-
- """
- # NB: The generated SQL below is specific to MySQL
- # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
- # to clear all tables of all data
- if tables:
- sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + \
- ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables] + \
- ['SET FOREIGN_KEY_CHECKS = 1;']
-
- # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
- # to reset sequence indices
- sql.extend(["%s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('TABLE'),
- style.SQL_TABLE(quote_name(sequence['table'])),
- style.SQL_KEYWORD('AUTO_INCREMENT'),
- style.SQL_FIELD('= 1'),
- ) for sequence in sequences])
- return sql
- else:
- return []
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- # No sequence reset required
- return []
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE BINARY %s',
- 'icontains': 'LIKE %s',
- 'regex': 'REGEXP BINARY %s',
- 'iregex': 'REGEXP %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE BINARY %s',
- 'endswith': 'LIKE BINARY %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py
index 99fa491104..e63ca09c35 100644
--- a/django/db/backends/mysql/creation.py
+++ b/django/db/backends/mysql/creation.py
@@ -5,8 +5,8 @@
DATA_TYPES = {
'AutoField': 'integer AUTO_INCREMENT',
'BooleanField': 'bool',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
@@ -21,7 +21,7 @@ DATA_TYPES = {
'PhoneNumberField': 'varchar(20)',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
- 'SlugField': 'varchar(%(maxlength)s)',
+ 'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py
index 39733311c5..68fe5d99e6 100644
--- a/django/db/backends/mysql/introspection.py
+++ b/django/db/backends/mysql/introspection.py
@@ -1,8 +1,9 @@
-from django.db.backends.mysql.base import quote_name
+from django.db.backends.mysql.base import DatabaseOperations
from MySQLdb import ProgrammingError, OperationalError
from MySQLdb.constants import FIELD_TYPE
import re
+quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor):
diff --git a/django/db/backends/mysql_old/base.py b/django/db/backends/mysql_old/base.py
index ca9d2c8b50..0777c1dc93 100644
--- a/django/db/backends/mysql_old/base.py
+++ b/django/db/backends/mysql_old/base.py
@@ -4,12 +4,13 @@ MySQL database backend for Django.
Requires MySQLdb: http://sourceforge.net/projects/mysql-python
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
+from django.utils.encoding import force_unicode
try:
import MySQLdb as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading MySQLdb module: %s" % e
+ raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
import types
@@ -25,6 +26,9 @@ django_conversions.update({
FIELD_TYPE.DATE: util.typecast_date,
FIELD_TYPE.TIME: util.typecast_time,
FIELD_TYPE.DECIMAL: util.typecast_decimal,
+ FIELD_TYPE.STRING: force_unicode,
+ FIELD_TYPE.VAR_STRING: force_unicode,
+ # Note: We don't add a convertor for BLOB here. Doesn't seem to be required.
})
# This should match the numerical portion of the version numbers (we can treat
@@ -44,14 +48,14 @@ class MysqlDebugWrapper:
return self.cursor.execute(sql, params)
except Database.Warning, w:
self.cursor.execute("SHOW WARNINGS")
- raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
+ raise Database.Warning("%s: %s" % (w, self.cursor.fetchall()))
def executemany(self, sql, param_list):
try:
return self.cursor.executemany(sql, param_list)
except Database.Warning, w:
self.cursor.execute("SHOW WARNINGS")
- raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
+ raise Database.Warning("%s: %s" % (w, self.cursor.fetchall()))
def __getattr__(self, attr):
if attr in self.__dict__:
@@ -59,19 +63,94 @@ class MysqlDebugWrapper:
else:
return getattr(self.cursor, attr)
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseFeatures(BaseDatabaseFeatures):
+ autoindexes_primary_keys = False
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
+ return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
+ format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
+ format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
+ try:
+ i = fields.index(lookup_type) + 1
+ except ValueError:
+ sql = field_name
+ else:
+ format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
+ sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
+ return sql
+
+ def drop_foreignkey_sql(self):
+ return "DROP FOREIGN KEY"
+
+ def fulltext_search_sql(self, field_name):
+ return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
+
+ def limit_offset_sql(self, limit, offset=None):
+ # 'LIMIT 20,40'
+ sql = "LIMIT "
+ if offset and offset != 0:
+ sql += "%s," % offset
+ return sql + str(limit)
+
+ def quote_name(self, name):
+ if name.startswith("`") and name.endswith("`"):
+ return name # Quoting once is enough.
+ return "`%s`" % name
+
+ def random_function_sql(self):
+ return 'RAND()'
+
+ def sql_flush(self, style, tables, sequences):
+ # NB: The generated SQL below is specific to MySQL
+ # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+ # to clear all tables of all data
+ if tables:
+ sql = ['SET FOREIGN_KEY_CHECKS = 0;']
+ for table in tables:
+ sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
+ sql.append('SET FOREIGN_KEY_CHECKS = 1;')
+
+ # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
+ # to reset sequence indices
+ sql.extend(["%s %s %s %s %s;" % \
+ (style.SQL_KEYWORD('ALTER'),
+ style.SQL_KEYWORD('TABLE'),
+ style.SQL_TABLE(self.quote_name(sequence['table'])),
+ style.SQL_KEYWORD('AUTO_INCREMENT'),
+ style.SQL_FIELD('= 1'),
+ ) for sequence in sequences])
+ return sql
+ else:
+ return []
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'LIKE %s',
+ 'contains': 'LIKE BINARY %s',
+ 'icontains': 'LIKE %s',
+ 'regex': 'REGEXP BINARY %s',
+ 'iregex': 'REGEXP %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE BINARY %s',
+ 'endswith': 'LIKE BINARY %s',
+ 'istartswith': 'LIKE %s',
+ 'iendswith': 'LIKE %s',
+ }
-class DatabaseWrapper(local):
def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
+ super(DatabaseWrapper, self).__init__(**kwargs)
self.server_version = None
- self.options = kwargs
def _valid_connection(self):
if self.connection is not None:
@@ -83,10 +162,11 @@ class DatabaseWrapper(local):
self.connection = None
return False
- def cursor(self):
- from django.conf import settings
+ def _cursor(self, settings):
if not self._valid_connection():
kwargs = {
+ # Note: use_unicode intentonally not set to work around some
+ # backwards-compat issues. We do it manually.
'user': settings.DATABASE_USER,
'db': settings.DATABASE_NAME,
'passwd': settings.DATABASE_PASSWORD,
@@ -101,29 +181,28 @@ class DatabaseWrapper(local):
kwargs.update(self.options)
self.connection = Database.connect(**kwargs)
cursor = self.connection.cursor()
- if self.connection.get_server_info() >= '4.1':
- cursor.execute("SET NAMES 'utf8'")
+ if self.connection.get_server_info() >= '4.1' and not self.connection.character_set_name().startswith('utf8'):
+ if hasattr(self.connection, 'charset'):
+ # MySQLdb < 1.2.1 backwards-compat hacks.
+ conn = self.connection
+ cursor.execute("SET NAMES 'utf8'")
+ cursor.execute("SET CHARACTER SET 'utf8'")
+ to_str = lambda u, dummy=None, c=conn: c.literal(u.encode('utf-8'))
+ conn.converter[unicode] = to_str
+ else:
+ self.connection.set_character_set('utf8')
else:
cursor = self.connection.cursor()
- if settings.DEBUG:
- return util.CursorDebugWrapper(MysqlDebugWrapper(cursor), self)
return cursor
- def _commit(self):
- if self.connection is not None:
- self.connection.commit()
+ def make_debug_cursor(self, cursor):
+ return BaseDatabaseWrapper.make_debug_cursor(self, MysqlDebugWrapper(cursor))
def _rollback(self):
- if self.connection is not None:
- try:
- self.connection.rollback()
- except Database.NotSupportedError:
- pass
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
+ try:
+ BaseDatabaseWrapper._rollback(self)
+ except Database.NotSupportedError:
+ pass
def get_server_version(self):
if not self.server_version:
@@ -134,128 +213,3 @@ class DatabaseWrapper(local):
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
self.server_version = tuple([int(x) for x in m.groups()])
return self.server_version
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = False
-needs_datetime_string_cast = True # MySQLdb requires a typecast for dates
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = False
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith("`") and name.endswith("`"):
- return name # Quoting once is enough.
- return "`%s`" % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- return cursor.lastrowid
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
- return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
- format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
- format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
- try:
- i = fields.index(lookup_type) + 1
- except ValueError:
- sql = field_name
- else:
- format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
- sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
- return sql
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT "
- if offset and offset != 0:
- sql += "%s," % offset
- return sql + str(limit)
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_deferrable_sql():
- return ""
-
-def get_fulltext_search_sql(field_name):
- return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
-
-def get_drop_foreignkey_sql():
- return "DROP FOREIGN KEY"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None;
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
-
- """
- # NB: The generated SQL below is specific to MySQL
- # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
- # to clear all tables of all data
- if tables:
- sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + \
- ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables] + \
- ['SET FOREIGN_KEY_CHECKS = 1;']
-
- # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
- # to reset sequence indices
- sql.extend(["%s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('TABLE'),
- style.SQL_TABLE(quote_name(sequence['table'])),
- style.SQL_KEYWORD('AUTO_INCREMENT'),
- style.SQL_FIELD('= 1'),
- ) for sequence in sequences])
- return sql
- else:
- return []
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- # No sequence reset required
- return []
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE BINARY %s',
- 'icontains': 'LIKE %s',
- 'regex': 'REGEXP BINARY %s',
- 'iregex': 'REGEXP %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE BINARY %s',
- 'endswith': 'LIKE BINARY %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
diff --git a/django/db/backends/mysql_old/creation.py b/django/db/backends/mysql_old/creation.py
index 1b23fbff6e..b2b3992651 100644
--- a/django/db/backends/mysql_old/creation.py
+++ b/django/db/backends/mysql_old/creation.py
@@ -5,8 +5,8 @@
DATA_TYPES = {
'AutoField': 'integer AUTO_INCREMENT',
'BooleanField': 'bool',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
@@ -16,13 +16,12 @@ DATA_TYPES = {
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',
- 'ManyToManyField': None,
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PhoneNumberField': 'varchar(20)',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
- 'SlugField': 'varchar(%(maxlength)s)',
+ 'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
diff --git a/django/db/backends/mysql_old/introspection.py b/django/db/backends/mysql_old/introspection.py
index cb5b8320d9..b910774b95 100644
--- a/django/db/backends/mysql_old/introspection.py
+++ b/django/db/backends/mysql_old/introspection.py
@@ -1,8 +1,9 @@
-from django.db.backends.mysql_old.base import quote_name
+from django.db.backends.mysql_old.base import DatabaseOperations
from MySQLdb import ProgrammingError, OperationalError
from MySQLdb.constants import FIELD_TYPE
import re
+quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor):
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 48b3c27355..23ce30f37e 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -4,37 +4,404 @@ Oracle database backend for Django.
Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/
"""
-from django.conf import settings
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
+from django.utils.datastructures import SortedDict
+from django.utils.encoding import smart_str, force_unicode
+import datetime
+import os
+
+# Oracle takes client-side character set encoding from the environment.
+os.environ['NLS_LANG'] = '.UTF8'
try:
import cx_Oracle as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e
-import datetime
-from django.utils.datastructures import SortedDict
-
+ raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
DatabaseError = Database.Error
IntegrityError = Database.IntegrityError
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseFeatures(BaseDatabaseFeatures):
+ allows_group_by_ordinal = False
+ allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259)
+ needs_datetime_string_cast = False
+ needs_upper_for_iops = True
+ supports_tablespaces = True
+ uses_case_insensitive_names = True
+ uses_custom_queryset = True
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def autoinc_sql(self, table):
+ # To simulate auto-incrementing primary keys in Oracle, we have to
+ # create a sequence and a trigger.
+ sq_name = get_sequence_name(table)
+ tr_name = get_trigger_name(table)
+ sequence_sql = 'CREATE SEQUENCE %s;' % sq_name
+ trigger_sql = """
+ CREATE OR REPLACE TRIGGER %s
+ BEFORE INSERT ON %s
+ FOR EACH ROW
+ WHEN (new.id IS NULL)
+ BEGIN
+ SELECT %s.nextval INTO :new.id FROM dual;
+ END;/""" % (tr_name, self.quote_name(table), sq_name)
+ return sequence_sql, trigger_sql
+
+ def date_extract_sql(self, lookup_type, field_name):
+ # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
+ return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ # Oracle uses TRUNC() for both dates and numbers.
+ # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151
+ if lookup_type == 'day':
+ sql = 'TRUNC(%s)' % field_name
+ else:
+ sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
+ return sql
+
+ def datetime_cast_sql(self):
+ return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
+
+ def deferrable_sql(self):
+ return " DEFERRABLE INITIALLY DEFERRED"
+
+ def drop_sequence_sql(self, table):
+ return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table))
+
+ def field_cast_sql(self, db_type):
+ if db_type and db_type.endswith('LOB'):
+ return "DBMS_LOB.SUBSTR(%s)"
+ else:
+ return "%s"
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ sq_name = util.truncate_name(table_name, self.max_name_length() - 3)
+ cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
+ return cursor.fetchone()[0]
+
+ def limit_offset_sql(self, limit, offset=None):
+ # Limits and offset are too complicated to be handled here.
+ # Instead, they are handled in django/db/backends/oracle/query.py.
+ return ""
+
+ def max_name_length(self):
+ return 30
+
+ def query_set_class(self, DefaultQuerySet):
+ from django.db import connection
+ from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
+
+ class OracleQuerySet(DefaultQuerySet):
+
+ def iterator(self):
+ "Performs the SELECT database lookup of this QuerySet."
+
+ from django.db.models.query import get_cached_row
+
+ # self._select is a dictionary, and dictionaries' key order is
+ # undefined, so we convert it to a list of tuples.
+ extra_select = self._select.items()
+
+ full_query = None
+
+ try:
+ try:
+ select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
+ except TypeError:
+ select, sql, params = self._get_sql_clause()
+ except EmptyResultSet:
+ raise StopIteration
+ if not full_query:
+ full_query = "SELECT %s%s\n%s" % ((self._distinct and "DISTINCT " or ""), ', '.join(select), sql)
+
+ cursor = connection.cursor()
+ cursor.execute(full_query, params)
+
+ fill_cache = self._select_related
+ fields = self.model._meta.fields
+ index_end = len(fields)
+
+ # so here's the logic;
+ # 1. retrieve each row in turn
+ # 2. convert NCLOBs
+
+ while 1:
+ rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
+ if not rows:
+ raise StopIteration
+ for row in rows:
+ row = self.resolve_columns(row, fields)
+ if fill_cache:
+ obj, index_end = get_cached_row(klass=self.model, row=row,
+ index_start=0, max_depth=self._max_related_depth)
+ else:
+ obj = self.model(*row[:index_end])
+ for i, k in enumerate(extra_select):
+ setattr(obj, k[0], row[index_end+i])
+ yield obj
+
+
+ def _get_sql_clause(self, get_full_query=False):
+ from django.db.models.query import fill_table_cache, \
+ handle_legacy_orderlist, orderfield2column
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
- self.options = kwargs
+ opts = self.model._meta
+ qn = connection.ops.quote_name
+
+ # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
+ select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
+ tables = [quote_only_if_word(t) for t in self._tables]
+ joins = SortedDict()
+ where = self._where[:]
+ params = self._params[:]
+
+ # Convert self._filters into SQL.
+ joins2, where2, params2 = self._filters.get_sql(opts)
+ joins.update(joins2)
+ where.extend(where2)
+ params.extend(params2)
+
+ # Add additional tables and WHERE clauses based on select_related.
+ if self._select_related:
+ fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
+
+ # Add any additional SELECTs.
+ if self._select:
+ select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
+
+ # Start composing the body of the SQL statement.
+ sql = [" FROM", qn(opts.db_table)]
+
+ # Compose the join dictionary into SQL describing the joins.
+ if joins:
+ sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
+ for (alias, (table, join_type, condition)) in joins.items()]))
+
+ # Compose the tables clause into SQL.
+ if tables:
+ sql.append(", " + ", ".join(tables))
+
+ # Compose the where clause into SQL.
+ if where:
+ sql.append(where and "WHERE " + " AND ".join(where))
+
+ # ORDER BY clause
+ order_by = []
+ if self._order_by is not None:
+ ordering_to_use = self._order_by
+ else:
+ ordering_to_use = opts.ordering
+ for f in handle_legacy_orderlist(ordering_to_use):
+ if f == '?': # Special case.
+ order_by.append(DatabaseOperations().random_function_sql())
+ else:
+ if f.startswith('-'):
+ col_name = f[1:]
+ order = "DESC"
+ else:
+ col_name = f
+ order = "ASC"
+ if "." in col_name:
+ table_prefix, col_name = col_name.split('.', 1)
+ table_prefix = qn(table_prefix) + '.'
+ else:
+ # Use the database table as a column prefix if it wasn't given,
+ # and if the requested column isn't a custom SELECT.
+ if "." not in col_name and col_name not in (self._select or ()):
+ table_prefix = qn(opts.db_table) + '.'
+ else:
+ table_prefix = ''
+ order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
+ if order_by:
+ sql.append("ORDER BY " + ", ".join(order_by))
+
+ # Look for column name collisions in the select elements
+ # and fix them with an AS alias. This allows us to do a
+ # SELECT * later in the paging query.
+ cols = [clause.split('.')[-1] for clause in select]
+ for index, col in enumerate(cols):
+ if cols.count(col) > 1:
+ col = '%s%d' % (col.replace('"', ''), index)
+ cols[index] = col
+ select[index] = '%s AS %s' % (select[index], col)
+
+ # LIMIT and OFFSET clauses
+ # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
+ select_clause = ",".join(select)
+ distinct = (self._distinct and "DISTINCT " or "")
+
+ if order_by:
+ order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
+ else:
+ #Oracle's row_number() function always requires an order-by clause.
+ #So we need to define a default order-by, since none was provided.
+ order_by_clause = " OVER (ORDER BY %s.%s)" % \
+ (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column))
+ # limit_and_offset_clause
+ if self._limit is None:
+ assert self._offset is None, "'offset' is not allowed without 'limit'"
+
+ if self._offset is not None:
+ offset = int(self._offset)
+ else:
+ offset = 0
+ if self._limit is not None:
+ limit = int(self._limit)
+ else:
+ limit = None
+
+ limit_and_offset_clause = ''
+ if limit is not None:
+ limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
+ elif offset:
+ limit_and_offset_clause = "WHERE rn > %s" % (offset)
+
+ if len(limit_and_offset_clause) > 0:
+ fmt = \
+ """SELECT * FROM
+ (SELECT %s%s,
+ ROW_NUMBER()%s AS rn
+ %s)
+ %s"""
+ full_query = fmt % (distinct, select_clause,
+ order_by_clause, ' '.join(sql).strip(),
+ limit_and_offset_clause)
+ else:
+ full_query = None
+
+ if get_full_query:
+ return select, " ".join(sql), params, full_query
+ else:
+ return select, " ".join(sql), params
+
+ def resolve_columns(self, row, fields=()):
+ from django.db.models.fields import DateField, DateTimeField, \
+ TimeField, BooleanField, NullBooleanField, DecimalField, Field
+ values = []
+ for value, field in map(None, row, fields):
+ if isinstance(value, Database.LOB):
+ value = value.read()
+ # Oracle stores empty strings as null. We need to undo this in
+ # order to adhere to the Django convention of using the empty
+ # string instead of null, but only if the field accepts the
+ # empty string.
+ if value is None and isinstance(field, Field) and field.empty_strings_allowed:
+ value = ''
+ # Convert 1 or 0 to True or False
+ elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
+ value = bool(value)
+ # Convert floats to decimals
+ elif value is not None and isinstance(field, DecimalField):
+ value = util.typecast_decimal(field.format_number(value))
+ # cx_Oracle always returns datetime.datetime objects for
+ # DATE and TIMESTAMP columns, but Django wants to see a
+ # python datetime.date, .time, or .datetime. We use the type
+ # of the Field to determine which to cast to, but it's not
+ # always available.
+ # As a workaround, we cast to date if all the time-related
+ # values are 0, or to time if the date is 1/1/1900.
+ # This could be cleaned a bit by adding a method to the Field
+ # classes to normalize values from the database (the to_python
+ # method is used for validation and isn't what we want here).
+ elif isinstance(value, Database.Timestamp):
+ # In Python 2.3, the cx_Oracle driver returns its own
+ # Timestamp object that we must convert to a datetime class.
+ if not isinstance(value, datetime.datetime):
+ value = datetime.datetime(value.year, value.month, value.day, value.hour,
+ value.minute, value.second, value.fsecond)
+ if isinstance(field, DateTimeField):
+ pass # DateTimeField subclasses DateField so must be checked first.
+ elif isinstance(field, DateField):
+ value = value.date()
+ elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
+ value = value.time()
+ elif value.hour == value.minute == value.second == value.microsecond == 0:
+ value = value.date()
+ values.append(value)
+ return values
+
+ return OracleQuerySet
+
+ def quote_name(self, name):
+ # SQL92 requires delimited (quoted) names to be case-sensitive. When
+ # not quoted, Oracle has case-insensitive behavior for identifiers, but
+ # always defaults to uppercase.
+ # We simplify things by making Oracle identifiers always uppercase.
+ if not name.startswith('"') and not name.endswith('"'):
+ name = '"%s"' % util.truncate_name(name.upper(), self.max_name_length())
+ return name.upper()
+
+ def random_function_sql(self):
+ return "DBMS_RANDOM.RANDOM"
+
+ def sql_flush(self, style, tables, sequences):
+ # Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
+ # 'TRUNCATE z;'... style SQL statements
+ if tables:
+ # Oracle does support TRUNCATE, but it seems to get us into
+ # FK referential trouble, whereas DELETE FROM table works.
+ sql = ['%s %s %s;' % \
+ (style.SQL_KEYWORD('DELETE'),
+ style.SQL_KEYWORD('FROM'),
+ style.SQL_FIELD(self.quote_name(table))
+ ) for table in tables]
+ # Since we've just deleted all the rows, running our sequence
+ # ALTER code will reset the sequence to 0.
+ for sequence_info in sequences:
+ table_name = sequence_info['table']
+ seq_name = get_sequence_name(table_name)
+ query = _get_sequence_reset_sql() % {'sequence': seq_name, 'table': self.quote_name(table_name)}
+ sql.append(query)
+ return sql
+ else:
+ return []
+
+ def sequence_reset_sql(self, style, model_list):
+ from django.db import models
+ output = []
+ query = _get_sequence_reset_sql()
+ for model in model_list:
+ for f in model._meta.fields:
+ if isinstance(f, models.AutoField):
+ sequence_name = get_sequence_name(model._meta.db_table)
+ output.append(query % {'sequence':sequence_name,
+ 'table':model._meta.db_table})
+ break # Only one AutoField is allowed per model, so don't bother continuing.
+ for f in model._meta.many_to_many:
+ sequence_name = get_sequence_name(f.m2m_db_table())
+ output.append(query % {'sequence':sequence_name,
+ 'table':f.m2m_db_table()})
+ return output
+
+ def start_transaction_sql(self):
+ return ''
+
+ def tablespace_sql(self, tablespace, inline=False):
+ return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace))
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': '= UPPER(%s)',
+ 'contains': "LIKE %s ESCAPE '\\'",
+ 'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': "LIKE %s ESCAPE '\\'",
+ 'endswith': "LIKE %s ESCAPE '\\'",
+ 'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
+ 'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
+ }
def _valid_connection(self):
return self.connection is not None
- def cursor(self):
+ def _cursor(self, settings):
if not self._valid_connection():
if len(settings.DATABASE_HOST.strip()) == 0:
settings.DATABASE_HOST = 'localhost'
@@ -45,56 +412,31 @@ class DatabaseWrapper(local):
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
self.connection = Database.connect(conn_string, **self.options)
cursor = FormatStylePlaceholderCursor(self.connection)
- # default arraysize of 1 is highly sub-optimal
+ # Default arraysize of 1 is highly sub-optimal.
cursor.arraysize = 100
- # set oracle date to ansi date format
+ # Set oracle date to ansi date format.
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'")
cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
return cursor
- def _commit(self):
- if self.connection is not None:
- return self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
-allows_group_by_ordinal = False
-allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259)
-autoindexes_primary_keys = True
-needs_datetime_string_cast = False
-needs_upper_for_iops = True
-supports_constraints = True
-supports_tablespaces = True
-uses_case_insensitive_names = True
-
class FormatStylePlaceholderCursor(Database.Cursor):
"""
- Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var" style.
- This fixes it -- but note that if you want to use a literal "%s" in a query,
- you'll need to use "%%s".
+ Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var"
+ style. This fixes it -- but note that if you want to use a literal "%s" in
+ a query, you'll need to use "%%s".
+
+ We also do automatic conversion between Unicode on the Python side and
+ UTF-8 -- for talking to Oracle -- in here.
"""
+ charset = 'utf-8'
+
def _rewrite_args(self, query, params=None):
if params is None:
params = []
else:
- # cx_Oracle can't handle unicode parameters, so cast to str for now
- for i, param in enumerate(params):
- if type(param) == unicode:
- try:
- params[i] = param.encode('utf-8')
- except UnicodeError:
- params[i] = str(param)
+ params = self._format_params(params)
args = [(':arg%d' % i) for i in range(len(params))]
- query = query % tuple(args)
+ query = smart_str(query, self.charset) % tuple(args)
# cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
# it does want a trailing ';' but not a trailing '/'. However, these
# characters must be included in the original query in case the query
@@ -103,6 +445,16 @@ class FormatStylePlaceholderCursor(Database.Cursor):
query = query[:-1]
return query, params
+ def _format_params(self, params):
+ if isinstance(params, dict):
+ result = {}
+ charset = self.charset
+ for key, value in params.items():
+ result[smart_str(key, charset)] = smart_str(value, charset)
+ return result
+ else:
+ return tuple([smart_str(p, self.charset, True) for p in params])
+
def execute(self, query, params=None):
query, params = self._rewrite_args(query, params)
return Database.Cursor.execute(self, query, params)
@@ -111,89 +463,25 @@ class FormatStylePlaceholderCursor(Database.Cursor):
query, params = self._rewrite_args(query, params)
return Database.Cursor.executemany(self, query, params)
-def quote_name(name):
- # SQL92 requires delimited (quoted) names to be case-sensitive. When
- # not quoted, Oracle has case-insensitive behavior for identifiers, but
- # always defaults to uppercase.
- # We simplify things by making Oracle identifiers always uppercase.
- if not name.startswith('"') and not name.endswith('"'):
- name = '"%s"' % util.truncate_name(name.upper(), get_max_name_length())
- return name.upper()
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- sq_name = util.truncate_name(table_name, get_max_name_length()-3)
- cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
- return "EXTRACT(%s FROM %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # Oracle uses TRUNC() for both dates and numbers.
- # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151
- if lookup_type == 'day':
- sql = 'TRUNC(%s)' % (field_name,)
- else:
- sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
- return sql
-
-def get_datetime_cast_sql():
- return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
-
-def get_limit_offset_sql(limit, offset=None):
- # Limits and offset are too complicated to be handled here.
- # Instead, they are handled in django/db/backends/oracle/query.py.
- return ""
-
-def get_random_function_sql():
- return "DBMS_RANDOM.RANDOM"
-
-def get_deferrable_sql():
- return " DEFERRABLE INITIALLY DEFERRED"
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return "DROP CONSTRAINT"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return 30
+ def fetchone(self):
+ return to_unicode(Database.Cursor.fetchone(self))
-def get_start_transaction_sql():
- return None
+ def fetchmany(self, size=None):
+ if size is None:
+ size = self.arraysize
+ return tuple([tuple([to_unicode(e) for e in r]) for r in Database.Cursor.fetchmany(self, size)])
-def get_tablespace_sql(tablespace, inline=False):
- return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace))
+ def fetchall(self):
+ return tuple([tuple([to_unicode(e) for e in r]) for r in Database.Cursor.fetchall(self)])
-def get_autoinc_sql(table):
- # To simulate auto-incrementing primary keys in Oracle, we have to
- # create a sequence and a trigger.
- sq_name = get_sequence_name(table)
- tr_name = get_trigger_name(table)
- sequence_sql = 'CREATE SEQUENCE %s;' % sq_name
- trigger_sql = """CREATE OR REPLACE TRIGGER %s
- BEFORE INSERT ON %s
- FOR EACH ROW
- WHEN (new.id IS NULL)
- BEGIN
- SELECT %s.nextval INTO :new.id FROM dual;
- END;
- /""" % (tr_name, quote_name(table), sq_name)
- return sequence_sql, trigger_sql
-
-def get_drop_sequence(table):
- return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table))
+def to_unicode(s):
+ """
+ Convert strings to Unicode objects (and return all other data types
+ unchanged).
+ """
+ if isinstance(s, basestring):
+ return force_unicode(s)
+ return s
def _get_sequence_reset_sql():
# TODO: colorize this SQL code with style.SQL_KEYWORD(), etc.
@@ -215,310 +503,10 @@ def _get_sequence_reset_sql():
END;
/"""
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
- """
- # Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
- # 'TRUNCATE z;'... style SQL statements
- if tables:
- # Oracle does support TRUNCATE, but it seems to get us into
- # FK referential trouble, whereas DELETE FROM table works.
- sql = ['%s %s %s;' % \
- (style.SQL_KEYWORD('DELETE'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
- # Since we've just deleted all the rows, running our sequence
- # ALTER code will reset the sequence to 0.
- for sequence_info in sequences:
- table_name = sequence_info['table']
- seq_name = get_sequence_name(table_name)
- query = _get_sequence_reset_sql() % {'sequence':seq_name,
- 'table':quote_name(table_name)}
- sql.append(query)
- return sql
- else:
- return []
-
def get_sequence_name(table):
- name_length = get_max_name_length() - 3
+ name_length = DatabaseOperations().max_name_length() - 3
return '%s_SQ' % util.truncate_name(table, name_length).upper()
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- from django.db import models
- output = []
- query = _get_sequence_reset_sql()
- for model in model_list:
- for f in model._meta.fields:
- if isinstance(f, models.AutoField):
- sequence_name = get_sequence_name(model._meta.db_table)
- output.append(query % {'sequence':sequence_name,
- 'table':model._meta.db_table})
- break # Only one AutoField is allowed per model, so don't bother continuing.
- for f in model._meta.many_to_many:
- sequence_name = get_sequence_name(f.m2m_db_table())
- output.append(query % {'sequence':sequence_name,
- 'table':f.m2m_db_table()})
- return output
-
def get_trigger_name(table):
- name_length = get_max_name_length() - 3
+ name_length = DatabaseOperations().max_name_length() - 3
return '%s_TR' % util.truncate_name(table, name_length).upper()
-
-def get_query_set_class(DefaultQuerySet):
- "Create a custom QuerySet class for Oracle."
-
- from django.db import backend, connection
- from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
-
- class OracleQuerySet(DefaultQuerySet):
-
- def iterator(self):
- "Performs the SELECT database lookup of this QuerySet."
-
- from django.db.models.query import get_cached_row
-
- # self._select is a dictionary, and dictionaries' key order is
- # undefined, so we convert it to a list of tuples.
- extra_select = self._select.items()
-
- full_query = None
-
- try:
- try:
- select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
- except TypeError:
- select, sql, params = self._get_sql_clause()
- except EmptyResultSet:
- raise StopIteration
- if not full_query:
- full_query = "SELECT %s%s\n%s" % \
- ((self._distinct and "DISTINCT " or ""),
- ', '.join(select), sql)
-
- cursor = connection.cursor()
- cursor.execute(full_query, params)
-
- fill_cache = self._select_related
- fields = self.model._meta.fields
- index_end = len(fields)
-
- # so here's the logic;
- # 1. retrieve each row in turn
- # 2. convert NCLOBs
-
- while 1:
- rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
- if not rows:
- raise StopIteration
- for row in rows:
- row = self.resolve_columns(row, fields)
- if fill_cache:
- obj, index_end = get_cached_row(klass=self.model, row=row,
- index_start=0, max_depth=self._max_related_depth)
- else:
- obj = self.model(*row[:index_end])
- for i, k in enumerate(extra_select):
- setattr(obj, k[0], row[index_end+i])
- yield obj
-
-
- def _get_sql_clause(self, get_full_query=False):
- from django.db.models.query import fill_table_cache, \
- handle_legacy_orderlist, orderfield2column
-
- opts = self.model._meta
-
- # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
- select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
- tables = [quote_only_if_word(t) for t in self._tables]
- joins = SortedDict()
- where = self._where[:]
- params = self._params[:]
-
- # Convert self._filters into SQL.
- joins2, where2, params2 = self._filters.get_sql(opts)
- joins.update(joins2)
- where.extend(where2)
- params.extend(params2)
-
- # Add additional tables and WHERE clauses based on select_related.
- if self._select_related:
- fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
-
- # Add any additional SELECTs.
- if self._select:
- select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
-
- # Start composing the body of the SQL statement.
- sql = [" FROM", backend.quote_name(opts.db_table)]
-
- # Compose the join dictionary into SQL describing the joins.
- if joins:
- sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
- for (alias, (table, join_type, condition)) in joins.items()]))
-
- # Compose the tables clause into SQL.
- if tables:
- sql.append(", " + ", ".join(tables))
-
- # Compose the where clause into SQL.
- if where:
- sql.append(where and "WHERE " + " AND ".join(where))
-
- # ORDER BY clause
- order_by = []
- if self._order_by is not None:
- ordering_to_use = self._order_by
- else:
- ordering_to_use = opts.ordering
- for f in handle_legacy_orderlist(ordering_to_use):
- if f == '?': # Special case.
- order_by.append(backend.get_random_function_sql())
- else:
- if f.startswith('-'):
- col_name = f[1:]
- order = "DESC"
- else:
- col_name = f
- order = "ASC"
- if "." in col_name:
- table_prefix, col_name = col_name.split('.', 1)
- table_prefix = backend.quote_name(table_prefix) + '.'
- else:
- # Use the database table as a column prefix if it wasn't given,
- # and if the requested column isn't a custom SELECT.
- if "." not in col_name and col_name not in (self._select or ()):
- table_prefix = backend.quote_name(opts.db_table) + '.'
- else:
- table_prefix = ''
- order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
- if order_by:
- sql.append("ORDER BY " + ", ".join(order_by))
-
- # Look for column name collisions in the select elements
- # and fix them with an AS alias. This allows us to do a
- # SELECT * later in the paging query.
- cols = [clause.split('.')[-1] for clause in select]
- for index, col in enumerate(cols):
- if cols.count(col) > 1:
- col = '%s%d' % (col.replace('"', ''), index)
- cols[index] = col
- select[index] = '%s AS %s' % (select[index], col)
-
- # LIMIT and OFFSET clauses
- # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
- select_clause = ",".join(select)
- distinct = (self._distinct and "DISTINCT " or "")
-
- if order_by:
- order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
- else:
- #Oracle's row_number() function always requires an order-by clause.
- #So we need to define a default order-by, since none was provided.
- order_by_clause = " OVER (ORDER BY %s.%s)" % \
- (backend.quote_name(opts.db_table),
- backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))
- # limit_and_offset_clause
- if self._limit is None:
- assert self._offset is None, "'offset' is not allowed without 'limit'"
-
- if self._offset is not None:
- offset = int(self._offset)
- else:
- offset = 0
- if self._limit is not None:
- limit = int(self._limit)
- else:
- limit = None
-
- limit_and_offset_clause = ''
- if limit is not None:
- limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
- elif offset:
- limit_and_offset_clause = "WHERE rn > %s" % (offset)
-
- if len(limit_and_offset_clause) > 0:
- fmt = \
-"""SELECT * FROM
- (SELECT %s%s,
- ROW_NUMBER()%s AS rn
- %s)
-%s"""
- full_query = fmt % (distinct, select_clause,
- order_by_clause, ' '.join(sql).strip(),
- limit_and_offset_clause)
- else:
- full_query = None
-
- if get_full_query:
- return select, " ".join(sql), params, full_query
- else:
- return select, " ".join(sql), params
-
- def resolve_columns(self, row, fields=()):
- from django.db.models.fields import DateField, DateTimeField, \
- TimeField, BooleanField, NullBooleanField, DecimalField, Field
- values = []
- for value, field in map(None, row, fields):
- if isinstance(value, Database.LOB):
- value = value.read()
- # Oracle stores empty strings as null. We need to undo this in
- # order to adhere to the Django convention of using the empty
- # string instead of null, but only if the field accepts the
- # empty string.
- if value is None and isinstance(field, Field) and field.empty_strings_allowed:
- value = ''
- # Convert 1 or 0 to True or False
- elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
- value = bool(value)
- # Convert floats to decimals
- elif value is not None and isinstance(field, DecimalField):
- value = util.typecast_decimal(field.format_number(value))
- # cx_Oracle always returns datetime.datetime objects for
- # DATE and TIMESTAMP columns, but Django wants to see a
- # python datetime.date, .time, or .datetime. We use the type
- # of the Field to determine which to cast to, but it's not
- # always available.
- # As a workaround, we cast to date if all the time-related
- # values are 0, or to time if the date is 1/1/1900.
- # This could be cleaned a bit by adding a method to the Field
- # classes to normalize values from the database (the to_python
- # method is used for validation and isn't what we want here).
- elif isinstance(value, Database.Timestamp):
- # In Python 2.3, the cx_Oracle driver returns its own
- # Timestamp object that we must convert to a datetime class.
- if not isinstance(value, datetime.datetime):
- value = datetime.datetime(value.year, value.month, value.day, value.hour,
- value.minute, value.second, value.fsecond)
- if isinstance(field, DateTimeField):
- pass # DateTimeField subclasses DateField so must be checked first.
- elif isinstance(field, DateField):
- value = value.date()
- elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
- value = value.time()
- elif value.hour == value.minute == value.second == value.microsecond == 0:
- value = value.date()
- values.append(value)
- return values
-
- return OracleQuerySet
-
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': '= UPPER(%s)',
- 'contains': "LIKE %s ESCAPE '\\'",
- 'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': "LIKE %s ESCAPE '\\'",
- 'endswith': "LIKE %s ESCAPE '\\'",
- 'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
- 'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
-}
diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py
index 6d5039add8..af8ac58792 100644
--- a/django/db/backends/oracle/creation.py
+++ b/django/db/backends/oracle/creation.py
@@ -8,15 +8,15 @@ from django.core import management
DATA_TYPES = {
'AutoField': 'NUMBER(11)',
'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))',
- 'CharField': 'VARCHAR2(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)',
+ 'CharField': 'NVARCHAR2(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)',
'DateField': 'DATE',
'DateTimeField': 'TIMESTAMP',
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
- 'FileField': 'VARCHAR2(100)',
- 'FilePathField': 'VARCHAR2(100)',
+ 'FileField': 'NVARCHAR2(100)',
+ 'FilePathField': 'NVARCHAR2(100)',
'FloatField': 'DOUBLE PRECISION',
- 'ImageField': 'VARCHAR2(100)',
+ 'ImageField': 'NVARCHAR2(100)',
'IntegerField': 'NUMBER(11)',
'IPAddressField': 'VARCHAR2(15)',
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
@@ -24,7 +24,7 @@ DATA_TYPES = {
'PhoneNumberField': 'VARCHAR2(20)',
'PositiveIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)',
'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)',
- 'SlugField': 'VARCHAR2(50)',
+ 'SlugField': 'NVARCHAR2(50)',
'SmallIntegerField': 'NUMBER(11)',
'TextField': 'NCLOB',
'TimeField': 'TIMESTAMP',
@@ -37,9 +37,7 @@ TEST_DATABASE_PREFIX = 'test_'
PASSWORD = 'Im_a_lumberjack'
REMEMBER = {}
-
-def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False):
-
+def create_test_db(settings, connection, verbosity=1, autoclobber=False):
TEST_DATABASE_NAME = _test_database_name(settings)
TEST_DATABASE_USER = _test_database_user(settings)
TEST_DATABASE_PASSWD = _test_database_passwd(settings)
@@ -110,14 +108,13 @@ def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False
settings.DATABASE_USER = TEST_DATABASE_USER
settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
- management.syncdb(verbosity, interactive=False)
+ management.call_command('syncdb', verbosity=verbosity, interactive=False)
# Get a cursor (even though we don't need one yet). This has
# the side effect of initializing the test database.
cursor = connection.cursor()
-
-def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1):
+def destroy_test_db(settings, connection, old_database_name, verbosity=1):
connection.close()
TEST_DATABASE_NAME = _test_database_name(settings)
@@ -153,7 +150,6 @@ def destroy_test_db(settings, connection, backend, old_database_name, verbosity=
_destroy_test_db(cursor, parameters, verbosity)
connection.close()
-
def _create_test_db(cursor, parameters, verbosity):
if verbosity >= 2:
print "_create_test_db(): dbname = %s" % parameters['dbname']
@@ -169,7 +165,6 @@ def _create_test_db(cursor, parameters, verbosity):
]
_execute_statements(cursor, statements, parameters, verbosity)
-
def _create_test_user(cursor, parameters, verbosity):
if verbosity >= 2:
print "_create_test_user(): username = %s" % parameters['user']
@@ -183,7 +178,6 @@ def _create_test_user(cursor, parameters, verbosity):
]
_execute_statements(cursor, statements, parameters, verbosity)
-
def _destroy_test_db(cursor, parameters, verbosity):
if verbosity >= 2:
print "_destroy_test_db(): dbname=%s" % parameters['dbname']
@@ -193,7 +187,6 @@ def _destroy_test_db(cursor, parameters, verbosity):
]
_execute_statements(cursor, statements, parameters, verbosity)
-
def _destroy_test_user(cursor, parameters, verbosity):
if verbosity >= 2:
print "_destroy_test_user(): user=%s" % parameters['user']
@@ -203,7 +196,6 @@ def _destroy_test_user(cursor, parameters, verbosity):
]
_execute_statements(cursor, statements, parameters, verbosity)
-
def _execute_statements(cursor, statements, parameters, verbosity):
for template in statements:
stmt = template % parameters
@@ -215,7 +207,6 @@ def _execute_statements(cursor, statements, parameters, verbosity):
sys.stderr.write("Failed (%s)\n" % (err))
raise
-
def _test_database_name(settings):
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
try:
@@ -227,7 +218,6 @@ def _test_database_name(settings):
raise
return name
-
def _test_database_create(settings):
name = True
try:
@@ -241,7 +231,6 @@ def _test_database_create(settings):
raise
return name
-
def _test_user_create(settings):
name = True
try:
@@ -255,7 +244,6 @@ def _test_user_create(settings):
raise
return name
-
def _test_database_user(settings):
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
try:
@@ -267,7 +255,6 @@ def _test_database_user(settings):
raise
return name
-
def _test_database_passwd(settings):
name = PASSWORD
try:
@@ -279,7 +266,6 @@ def _test_database_passwd(settings):
raise
return name
-
def _test_database_tblspace(settings):
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
try:
@@ -291,7 +277,6 @@ def _test_database_tblspace(settings):
raise
return name
-
def _test_database_tblspace_tmp(settings):
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp'
try:
diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py
index 44430a0029..6f800c8bb6 100644
--- a/django/db/backends/oracle/introspection.py
+++ b/django/db/backends/oracle/introspection.py
@@ -1,8 +1,8 @@
-from django.db.backends.oracle.base import quote_name
+from django.db.backends.oracle.base import DatabaseOperations
import re
import cx_Oracle
-
+quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor):
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 611852e0dc..ca07ae21d9 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -4,28 +4,18 @@ PostgreSQL database backend for Django.
Requires psycopg 1: http://initd.org/projects/psycopg1
"""
-from django.db.backends import util
+from django.utils.encoding import smart_str, smart_unicode
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, util
+from django.db.backends.postgresql.operations import DatabaseOperations
try:
import psycopg as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading psycopg module: %s" % e
+ raise ImproperlyConfigured("Error loading psycopg module: %s" % e)
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
-
-def smart_basestring(s, charset):
- if isinstance(s, unicode):
- return s.encode(charset)
- return s
-
class UnicodeCursorWrapper(object):
"""
A thin wrapper around psycopg cursors that allows them to accept Unicode
@@ -33,18 +23,31 @@ class UnicodeCursorWrapper(object):
This is necessary because psycopg doesn't apply any DB quoting to
parameters that are Unicode strings. If a param is Unicode, this will
- convert it to a bytestring using DEFAULT_CHARSET before passing it to
- psycopg.
+ convert it to a bytestring using database client's encoding before passing
+ it to psycopg.
+
+ All results retrieved from the database are converted into Unicode strings
+ before being returned to the caller.
"""
def __init__(self, cursor, charset):
self.cursor = cursor
self.charset = charset
+ def format_params(self, params):
+ if isinstance(params, dict):
+ result = {}
+ charset = self.charset
+ for key, value in params.items():
+ result[smart_str(key, charset)] = smart_str(value, charset)
+ return result
+ else:
+ return tuple([smart_str(p, self.charset, True) for p in params])
+
def execute(self, sql, params=()):
- return self.cursor.execute(sql, [smart_basestring(p, self.charset) for p in params])
+ return self.cursor.execute(smart_str(sql, self.charset), self.format_params(params))
def executemany(self, sql, param_list):
- new_param_list = [tuple([smart_basestring(p, self.charset) for p in params]) for params in param_list]
+ new_param_list = [self.format_params(params) for params in param_list]
return self.cursor.executemany(sql, new_param_list)
def __getattr__(self, attr):
@@ -53,22 +56,36 @@ class UnicodeCursorWrapper(object):
else:
return getattr(self.cursor, attr)
-postgres_version = None
+class DatabaseFeatures(BaseDatabaseFeatures):
+ pass # This backend uses all the defaults.
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
- self.options = kwargs
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'ILIKE %s',
+ 'contains': 'LIKE %s',
+ 'icontains': 'ILIKE %s',
+ 'regex': '~ %s',
+ 'iregex': '~* %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE %s',
+ 'endswith': 'LIKE %s',
+ 'istartswith': 'ILIKE %s',
+ 'iendswith': 'ILIKE %s',
+ }
- def cursor(self):
- from django.conf import settings
+ def _cursor(self, settings):
set_tz = False
if self.connection is None:
set_tz = True
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
+ raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.")
conn_string = "dbname=%s" % settings.DATABASE_NAME
if settings.DATABASE_USER:
conn_string = "user=%s %s" % (settings.DATABASE_USER, conn_string)
@@ -83,185 +100,20 @@ class DatabaseWrapper(local):
cursor = self.connection.cursor()
if set_tz:
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
- cursor = UnicodeCursorWrapper(cursor, settings.DEFAULT_CHARSET)
- global postgres_version
- if not postgres_version:
+ cursor.execute("SET client_encoding to 'UNICODE'")
+ cursor = UnicodeCursorWrapper(cursor, 'utf-8')
+ if self.ops.postgres_version is None:
cursor.execute("SELECT version()")
- postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
+ self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
return cursor
- def _commit(self):
- if self.connection is not None:
- return self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = True
-needs_datetime_string_cast = True
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = False
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith('"') and name.endswith('"'):
- return name # Quoting once is enough.
- return '"%s"' % name
-
-def dictfetchone(cursor):
- "Returns a row from the cursor as a dict"
- return cursor.dictfetchone()
-
-def dictfetchmany(cursor, number):
- "Returns a certain number of rows from a cursor as a dict"
- return cursor.dictfetchmany(number)
-
-def dictfetchall(cursor):
- "Returns all rows from a cursor as a dict"
- return cursor.dictfetchall()
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
- return "EXTRACT('%s' FROM %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
- return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RANDOM()"
-
-def get_deferrable_sql():
- return " DEFERRABLE INITIALLY DEFERRED"
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return "DROP CONSTRAINT"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
-
+def typecast_string(s):
"""
- if tables:
- if postgres_version[0] >= 8 and postgres_version[1] >= 1:
- # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
- # truncate tables referenced by a foreign key in any other table. The result is a
- # single SQL TRUNCATE statement.
- sql = ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
- )]
- else:
- # Older versions of Postgres can't do TRUNCATE in a single call, so they must use
- # a simple delete.
- sql = ['%s %s %s;' % \
- (style.SQL_KEYWORD('DELETE'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
-
- # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
- # to reset sequence indices
- for sequence_info in sequences:
- table_name = sequence_info['table']
- column_name = sequence_info['column']
- if column_name and len(column_name)>0:
- # sequence name in this case will be <table>_<column>_seq
- sql.append("%s %s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('SEQUENCE'),
- style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
- style.SQL_KEYWORD('RESTART'),
- style.SQL_KEYWORD('WITH'),
- style.SQL_FIELD('1')
- )
- )
- else:
- # sequence name in this case will be <table>_id_seq
- sql.append("%s %s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('SEQUENCE'),
- style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
- style.SQL_KEYWORD('RESTART'),
- style.SQL_KEYWORD('WITH'),
- style.SQL_FIELD('1')
- )
- )
- return sql
- else:
- return []
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- from django.db import models
- output = []
- for model in model_list:
- # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
- # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
- # if there are records (as the max pk value is already in use), otherwise set it to false.
- for f in model._meta.fields:
- if isinstance(f, models.AutoField):
- output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
- (style.SQL_KEYWORD('SELECT'),
- style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
- style.SQL_FIELD(quote_name(f.column)),
- style.SQL_FIELD(quote_name(f.column)),
- style.SQL_KEYWORD('IS NOT'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_TABLE(quote_name(model._meta.db_table))))
- break # Only one AutoField is allowed per model, so don't bother continuing.
- for f in model._meta.many_to_many:
- output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
- (style.SQL_KEYWORD('SELECT'),
- style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
- style.SQL_FIELD(quote_name('id')),
- style.SQL_FIELD(quote_name('id')),
- style.SQL_KEYWORD('IS NOT'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_TABLE(f.m2m_db_table())))
- return output
+ Cast all returned strings to unicode strings.
+ """
+ if not s and not isinstance(s, str):
+ return s
+ return smart_unicode(s)
# Register these custom typecasts, because Django expects dates/times to be
# in Python's native (standard-library) datetime/time format, whereas psycopg
@@ -269,25 +121,9 @@ def get_sql_sequence_reset(style, model_list):
try:
Database.register_type(Database.new_type((1082,), "DATE", util.typecast_date))
except AttributeError:
- raise Exception, "You appear to be using psycopg version 2. Set your DATABASE_ENGINE to 'postgresql_psycopg2' instead of 'postgresql'."
+ raise Exception("You appear to be using psycopg version 2. Set your DATABASE_ENGINE to 'postgresql_psycopg2' instead of 'postgresql'.")
Database.register_type(Database.new_type((1083,1266), "TIME", util.typecast_time))
Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", util.typecast_timestamp))
Database.register_type(Database.new_type((16,), "BOOLEAN", util.typecast_boolean))
Database.register_type(Database.new_type((1700,), "NUMERIC", util.typecast_decimal))
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'ILIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'ILIKE %s',
- 'regex': '~ %s',
- 'iregex': '~* %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'ILIKE %s',
- 'iendswith': 'ILIKE %s',
-}
+Database.register_type(Database.new_type(Database.types[1043].values, 'STRING', typecast_string))
diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py
index 333dac146e..7dae852a21 100644
--- a/django/db/backends/postgresql/creation.py
+++ b/django/db/backends/postgresql/creation.py
@@ -5,8 +5,8 @@
DATA_TYPES = {
'AutoField': 'serial',
'BooleanField': 'boolean',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'timestamp with time zone',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
@@ -21,10 +21,10 @@ DATA_TYPES = {
'PhoneNumberField': 'varchar(20)',
'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
- 'SlugField': 'varchar(%(maxlength)s)',
+ 'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'text',
'TimeField': 'time',
'USStateField': 'varchar(2)',
- 'NoField': None,
+ 'NoField': '',
}
diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py
index 2605490afd..982c004569 100644
--- a/django/db/backends/postgresql/introspection.py
+++ b/django/db/backends/postgresql/introspection.py
@@ -1,4 +1,6 @@
-from django.db.backends.postgresql.base import quote_name
+from django.db.backends.postgresql.base import DatabaseOperations
+
+quote_name = DatabaseOperations().quote_name
def get_table_list(cursor):
"Returns a list of table names in the current database."
diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
new file mode 100644
index 0000000000..21c017038f
--- /dev/null
+++ b/django/db/backends/postgresql/operations.py
@@ -0,0 +1,109 @@
+from django.db.backends import BaseDatabaseOperations
+
+# This DatabaseOperations class lives in here instead of base.py because it's
+# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def __init__(self, postgres_version=None):
+ self.postgres_version = postgres_version
+
+ def date_extract_sql(self, lookup_type, field_name):
+ # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
+ return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
+ return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
+
+ def deferrable_sql(self):
+ return " DEFERRABLE INITIALLY DEFERRED"
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
+ return cursor.fetchone()[0]
+
+ def quote_name(self, name):
+ if name.startswith('"') and name.endswith('"'):
+ return name # Quoting once is enough.
+ return '"%s"' % name
+
+ def sql_flush(self, style, tables, sequences):
+ if tables:
+ if self.postgres_version[0] >= 8 and self.postgres_version[1] >= 1:
+ # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
+ # in order to be able to truncate tables referenced by a foreign
+ # key in any other table. The result is a single SQL TRUNCATE
+ # statement.
+ sql = ['%s %s;' % \
+ (style.SQL_KEYWORD('TRUNCATE'),
+ style.SQL_FIELD(', '.join([self.quote_name(table) for table in tables]))
+ )]
+ else:
+ # Older versions of Postgres can't do TRUNCATE in a single call, so
+ # they must use a simple delete.
+ sql = ['%s %s %s;' % \
+ (style.SQL_KEYWORD('DELETE'),
+ style.SQL_KEYWORD('FROM'),
+ style.SQL_FIELD(self.quote_name(table))
+ ) for table in tables]
+
+ # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
+ # to reset sequence indices
+ for sequence_info in sequences:
+ table_name = sequence_info['table']
+ column_name = sequence_info['column']
+ if column_name and len(column_name)>0:
+ # sequence name in this case will be <table>_<column>_seq
+ sql.append("%s %s %s %s %s %s;" % \
+ (style.SQL_KEYWORD('ALTER'),
+ style.SQL_KEYWORD('SEQUENCE'),
+ style.SQL_FIELD(self.quote_name('%s_%s_seq' % (table_name, column_name))),
+ style.SQL_KEYWORD('RESTART'),
+ style.SQL_KEYWORD('WITH'),
+ style.SQL_FIELD('1')
+ )
+ )
+ else:
+ # sequence name in this case will be <table>_id_seq
+ sql.append("%s %s %s %s %s %s;" % \
+ (style.SQL_KEYWORD('ALTER'),
+ style.SQL_KEYWORD('SEQUENCE'),
+ style.SQL_FIELD(self.quote_name('%s_id_seq' % table_name)),
+ style.SQL_KEYWORD('RESTART'),
+ style.SQL_KEYWORD('WITH'),
+ style.SQL_FIELD('1')
+ )
+ )
+ return sql
+ else:
+ return []
+
+ def sequence_reset_sql(self, style, model_list):
+ from django.db import models
+ output = []
+ qn = self.quote_name
+ for model in model_list:
+ # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
+ # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
+ # if there are records (as the max pk value is already in use), otherwise set it to false.
+ for f in model._meta.fields:
+ if isinstance(f, models.AutoField):
+ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
+ (style.SQL_KEYWORD('SELECT'),
+ style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
+ style.SQL_FIELD(qn(f.column)),
+ style.SQL_FIELD(qn(f.column)),
+ style.SQL_KEYWORD('IS NOT'),
+ style.SQL_KEYWORD('FROM'),
+ style.SQL_TABLE(qn(model._meta.db_table))))
+ break # Only one AutoField is allowed per model, so don't bother continuing.
+ for f in model._meta.many_to_many:
+ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
+ (style.SQL_KEYWORD('SELECT'),
+ style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
+ style.SQL_FIELD(qn('id')),
+ style.SQL_FIELD(qn('id')),
+ style.SQL_KEYWORD('IS NOT'),
+ style.SQL_KEYWORD('FROM'),
+ style.SQL_TABLE(f.m2m_db_table())))
+ return output \ No newline at end of file
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index 17d36a8613..43ca7a1ec5 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -4,39 +4,50 @@ PostgreSQL database backend for Django.
Requires psycopg 2: http://initd.org/projects/psycopg2
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures
+from django.db.backends.postgresql.operations import DatabaseOperations
try:
import psycopg2 as Database
+ import psycopg2.extensions
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e
+ raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
-postgres_version = None
+class DatabaseFeatures(BaseDatabaseFeatures):
+ needs_datetime_string_cast = False
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
- self.options = kwargs
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'ILIKE %s',
+ 'contains': 'LIKE %s',
+ 'icontains': 'ILIKE %s',
+ 'regex': '~ %s',
+ 'iregex': '~* %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE %s',
+ 'endswith': 'LIKE %s',
+ 'istartswith': 'ILIKE %s',
+ 'iendswith': 'ILIKE %s',
+ }
- def cursor(self):
- from django.conf import settings
+ def _cursor(self, settings):
set_tz = False
if self.connection is None:
set_tz = True
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
+ raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.")
conn_string = "dbname=%s" % settings.DATABASE_NAME
if settings.DATABASE_USER:
conn_string = "user=%s %s" % (settings.DATABASE_USER, conn_string)
@@ -48,191 +59,12 @@ class DatabaseWrapper(local):
conn_string += " port=%s" % settings.DATABASE_PORT
self.connection = Database.connect(conn_string, **self.options)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
+ self.connection.set_client_encoding('UTF8')
cursor = self.connection.cursor()
cursor.tzinfo_factory = None
if set_tz:
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
- global postgres_version
- if not postgres_version:
+ if self.ops.postgres_version is None:
cursor.execute("SELECT version()")
- postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
+ self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
return cursor
-
- def _commit(self):
- if self.connection is not None:
- return self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = True
-needs_datetime_string_cast = False
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = False
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith('"') and name.endswith('"'):
- return name # Quoting once is enough.
- return '"%s"' % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
- return "EXTRACT('%s' FROM %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
- return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RANDOM()"
-
-def get_deferrable_sql():
- return " DEFERRABLE INITIALLY DEFERRED"
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return "DROP CONSTRAINT"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
- """
- if tables:
- if postgres_version[0] >= 8 and postgres_version[1] >= 1:
- # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
- # truncate tables referenced by a foreign key in any other table. The result is a
- # single SQL TRUNCATE statement
- sql = ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
- )]
- else:
- sql = ['%s %s %s;' % \
- (style.SQL_KEYWORD('DELETE'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
-
- # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
- # to reset sequence indices
- for sequence in sequences:
- table_name = sequence['table']
- column_name = sequence['column']
- if column_name and len(column_name) > 0:
- # sequence name in this case will be <table>_<column>_seq
- sql.append("%s %s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('SEQUENCE'),
- style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
- style.SQL_KEYWORD('RESTART'),
- style.SQL_KEYWORD('WITH'),
- style.SQL_FIELD('1')
- )
- )
- else:
- # sequence name in this case will be <table>_id_seq
- sql.append("%s %s %s %s %s %s;" % \
- (style.SQL_KEYWORD('ALTER'),
- style.SQL_KEYWORD('SEQUENCE'),
- style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
- style.SQL_KEYWORD('RESTART'),
- style.SQL_KEYWORD('WITH'),
- style.SQL_FIELD('1')
- )
- )
- return sql
- else:
- return []
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- from django.db import models
- output = []
- for model in model_list:
- # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
- # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
- # if there are records (as the max pk value is already in use), otherwise set it to false.
- for f in model._meta.fields:
- if isinstance(f, models.AutoField):
- output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
- (style.SQL_KEYWORD('SELECT'),
- style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
- style.SQL_FIELD(quote_name(f.column)),
- style.SQL_FIELD(quote_name(f.column)),
- style.SQL_KEYWORD('IS NOT'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_TABLE(quote_name(model._meta.db_table))))
- break # Only one AutoField is allowed per model, so don't bother continuing.
- for f in model._meta.many_to_many:
- output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
- (style.SQL_KEYWORD('SELECT'),
- style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
- style.SQL_FIELD(quote_name('id')),
- style.SQL_FIELD(quote_name('id')),
- style.SQL_KEYWORD('IS NOT'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_TABLE(f.m2m_db_table())))
- return output
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'ILIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'ILIKE %s',
- 'regex': '~ %s',
- 'iregex': '~* %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'ILIKE %s',
- 'iendswith': 'ILIKE %s',
-}
diff --git a/django/db/backends/postgresql_psycopg2/introspection.py b/django/db/backends/postgresql_psycopg2/introspection.py
index aa45fe7db7..bf839c3e95 100644
--- a/django/db/backends/postgresql_psycopg2/introspection.py
+++ b/django/db/backends/postgresql_psycopg2/introspection.py
@@ -1,4 +1,6 @@
-from django.db.backends.postgresql_psycopg2.base import quote_name
+from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
+
+quote_name = DatabaseOperations().quote_name
def get_table_list(cursor):
"Returns a list of table names in the current database."
@@ -30,11 +32,8 @@ def get_relations(cursor, table_name):
AND con.contype = 'f'""", [table_name])
relations = {}
for row in cursor.fetchall():
- try:
- # row[0] and row[1] are like "{2}", so strip the curly braces.
- relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
- except ValueError:
- continue
+ # row[0] and row[1] are single-item lists, so grab the single item.
+ relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
return relations
def get_indexes(cursor, table_name):
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index c4ecf5f578..7919e1cc50 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -2,7 +2,7 @@
SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/).
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
try:
try:
from sqlite3 import dbapi2 as Database
@@ -34,29 +34,69 @@ Database.register_converter("TIMESTAMP", util.typecast_timestamp)
Database.register_converter("decimal", util.typecast_decimal)
Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
-def utf8rowFactory(cursor, row):
- def utf8(s):
- if type(s) == unicode:
- return s.encode("utf-8")
- else:
- return s
- return [utf8(r) for r in row]
+class DatabaseFeatures(BaseDatabaseFeatures):
+ supports_constraints = False
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ # sqlite doesn't support extract, so we fake it with the user-defined
+ # function django_extract that's registered in connect().
+ return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name)
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
- self.options = kwargs
+ def date_trunc_sql(self, lookup_type, field_name):
+ # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined
+ # function django_date_trunc that's registered in connect().
+ return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
- def cursor(self):
- from django.conf import settings
+ def drop_foreignkey_sql(self):
+ return ""
+
+ def pk_default_value(self):
+ return 'NULL'
+
+ def quote_name(self, name):
+ if name.startswith('"') and name.endswith('"'):
+ return name # Quoting once is enough.
+ return '"%s"' % name
+
+ def sql_flush(self, style, tables, sequences):
+ # NB: The generated SQL below is specific to SQLite
+ # Note: The DELETE FROM... SQL generated below works for SQLite databases
+ # because constraints don't exist
+ sql = ['%s %s %s;' % \
+ (style.SQL_KEYWORD('DELETE'),
+ style.SQL_KEYWORD('FROM'),
+ style.SQL_FIELD(self.quote_name(table))
+ ) for table in tables]
+ # Note: No requirement for reset of auto-incremented indices (cf. other
+ # sql_flush() implementations). Just return SQL at this point
+ return sql
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+
+ # SQLite requires LIKE statements to include an ESCAPE clause if the value
+ # being escaped has a percent or underscore in it.
+ # See http://www.sqlite.org/lang_expr.html for an explanation.
+ operators = {
+ 'exact': '= %s',
+ 'iexact': "LIKE %s ESCAPE '\\'",
+ 'contains': "LIKE %s ESCAPE '\\'",
+ 'icontains': "LIKE %s ESCAPE '\\'",
+ 'regex': 'REGEXP %s',
+ 'iregex': "REGEXP '(?i)' || %s",
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': "LIKE %s ESCAPE '\\'",
+ 'endswith': "LIKE %s ESCAPE '\\'",
+ 'istartswith': "LIKE %s ESCAPE '\\'",
+ 'iendswith': "LIKE %s ESCAPE '\\'",
+ }
+
+ def _cursor(self, settings):
if self.connection is None:
kwargs = {
'database': settings.DATABASE_NAME,
@@ -68,28 +108,15 @@ class DatabaseWrapper(local):
self.connection.create_function("django_extract", 2, _sqlite_extract)
self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
self.connection.create_function("regexp", 2, _sqlite_regexp)
- cursor = self.connection.cursor(factory=SQLiteCursorWrapper)
- cursor.row_factory = utf8rowFactory
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
- else:
- return cursor
-
- def _commit(self):
- if self.connection is not None:
- self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- self.connection.rollback()
+ return self.connection.cursor(factory=SQLiteCursorWrapper)
def close(self):
from django.conf import settings
- # If database is in memory, closing the connection destroys the database.
- # To prevent accidental data loss, ignore close requests on an in-memory db.
- if self.connection is not None and settings.DATABASE_NAME != ":memory:":
- self.connection.close()
- self.connection = None
+ # If database is in memory, closing the connection destroys the
+ # database. To prevent accidental data loss, ignore close requests on
+ # an in-memory db.
+ if settings.DATABASE_NAME != ":memory:":
+ BaseDatabaseWrapper.close(self)
class SQLiteCursorWrapper(Database.Cursor):
"""
@@ -108,33 +135,6 @@ class SQLiteCursorWrapper(Database.Cursor):
def convert_query(self, query, num_params):
return query % tuple("?" * num_params)
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = True
-needs_datetime_string_cast = True
-needs_upper_for_iops = False
-supports_constraints = False
-supports_tablespaces = False
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith('"') and name.endswith('"'):
- return name # Quoting once is enough.
- return '"%s"' % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- return cursor.lastrowid
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # sqlite doesn't support extract, so we fake it with the user-defined
- # function _sqlite_extract that's registered in connect(), above.
- return 'django_extract("%s", %s)' % (lookup_type.lower(), table_name)
-
def _sqlite_extract(lookup_type, dt):
try:
dt = util.typecast_timestamp(dt)
@@ -142,67 +142,6 @@ def _sqlite_extract(lookup_type, dt):
return None
return str(getattr(dt, lookup_type))
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # sqlite doesn't support DATE_TRUNC, so we fake it as above.
- return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RANDOM()"
-
-def get_deferrable_sql():
- return ""
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return ""
-
-def get_pk_default_value():
- return "NULL"
-
-def get_max_name_length():
- return None
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
-
- """
- # NB: The generated SQL below is specific to SQLite
- # Note: The DELETE FROM... SQL generated below works for SQLite databases
- # because constraints don't exist
- sql = ['%s %s %s;' % \
- (style.SQL_KEYWORD('DELETE'),
- style.SQL_KEYWORD('FROM'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
- # Note: No requirement for reset of auto-incremented indices (cf. other
- # get_sql_flush() implementations). Just return SQL at this point
- return sql
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- # No sequence reset required
- return []
-
def _sqlite_date_trunc(lookup_type, dt):
try:
dt = util.typecast_timestamp(dt)
@@ -221,23 +160,3 @@ def _sqlite_regexp(re_pattern, re_string):
return bool(re.search(re_pattern, re_string))
except:
return False
-
-# SQLite requires LIKE statements to include an ESCAPE clause if the value
-# being escaped has a percent or underscore in it.
-# See http://www.sqlite.org/lang_expr.html for an explanation.
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': "LIKE %s ESCAPE '\\'",
- 'contains': "LIKE %s ESCAPE '\\'",
- 'icontains': "LIKE %s ESCAPE '\\'",
- 'regex': 'REGEXP %s',
- 'iregex': "REGEXP '(?i)' || %s",
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': "LIKE %s ESCAPE '\\'",
- 'endswith': "LIKE %s ESCAPE '\\'",
- 'istartswith': "LIKE %s ESCAPE '\\'",
- 'iendswith': "LIKE %s ESCAPE '\\'",
-}
diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py
index 29245cb7ed..764f56b422 100644
--- a/django/db/backends/sqlite3/creation.py
+++ b/django/db/backends/sqlite3/creation.py
@@ -4,8 +4,8 @@
DATA_TYPES = {
'AutoField': 'integer',
'BooleanField': 'bool',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'decimal',
@@ -20,7 +20,7 @@ DATA_TYPES = {
'PhoneNumberField': 'varchar(20)',
'PositiveIntegerField': 'integer unsigned',
'PositiveSmallIntegerField': 'smallint unsigned',
- 'SlugField': 'varchar(%(maxlength)s)',
+ 'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'text',
'TimeField': 'time',
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
index 4e22c5ea42..52b880aac2 100644
--- a/django/db/backends/sqlite3/introspection.py
+++ b/django/db/backends/sqlite3/introspection.py
@@ -1,4 +1,6 @@
-from django.db.backends.sqlite3.base import quote_name
+from django.db.backends.sqlite3.base import DatabaseOperations
+
+quote_name = DatabaseOperations().quote_name
def get_table_list(cursor):
"Returns a list of table names in the current database."
@@ -81,7 +83,7 @@ class FlexibleFieldLookupDict:
import re
m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
if m:
- return ('CharField', {'maxlength': int(m.group(1))})
+ return ('CharField', {'max_length': int(m.group(1))})
raise KeyError
DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
diff --git a/django/db/backends/util.py b/django/db/backends/util.py
index 58f2d1e990..fa2df22927 100644
--- a/django/db/backends/util.py
+++ b/django/db/backends/util.py
@@ -1,6 +1,7 @@
import datetime
import md5
from time import time
+from django.utils.encoding import smart_unicode, force_unicode
try:
import decimal
@@ -18,12 +19,8 @@ class CursorDebugWrapper(object):
return self.cursor.execute(sql, params)
finally:
stop = time()
- # If params was a list, convert it to a tuple, because string
- # formatting with '%' only works with tuples or dicts.
- if not isinstance(params, (tuple, dict)):
- params = tuple(params)
self.db.queries.append({
- 'sql': sql % params,
+ 'sql': smart_unicode(sql) % convert_args(params),
'time': "%.3f" % (stop - start),
})
@@ -34,7 +31,7 @@ class CursorDebugWrapper(object):
finally:
stop = time()
self.db.queries.append({
- 'sql': 'MANY: ' + sql + ' ' + str(tuple(param_list)),
+ 'sql': 'MANY: ' + sql + ' ' + smart_unicode(tuple(param_list)),
'time': "%.3f" % (stop - start),
})
@@ -44,6 +41,16 @@ class CursorDebugWrapper(object):
else:
return getattr(self.cursor, attr)
+def convert_args(args):
+ """
+ Convert sequence or dictionary to contain unicode values.
+ """
+ to_unicode = lambda s: force_unicode(s, strings_only=True)
+ if isinstance(args, (list, tuple)):
+ return tuple([to_unicode(val) for val in args])
+ else:
+ return dict([(to_unicode(k), to_unicode(v)) for k, v in args.items()])
+
###############################################
# Converters from database (string) to Python #
###############################################
@@ -117,30 +124,3 @@ def truncate_name(name, length=None):
hash = md5.md5(name).hexdigest()[:4]
return '%s%s' % (name[:length-4], hash)
-
-##################################################################################
-# Helper functions for dictfetch* for databases that don't natively support them #
-##################################################################################
-
-def _dict_helper(desc, row):
- "Returns a dictionary for the given cursor.description and result row."
- return dict(zip([col[0] for col in desc], row))
-
-def dictfetchone(cursor):
- "Returns a row from the cursor as a dict"
- row = cursor.fetchone()
- if not row:
- return None
- return _dict_helper(cursor.description, row)
-
-def dictfetchmany(cursor, number):
- "Returns a certain number of rows from a cursor as a dict"
- desc = cursor.description
- for row in cursor.fetchmany(number):
- yield _dict_helper(desc, row)
-
-def dictfetchall(cursor):
- "Returns all rows from a cursor as a dict"
- desc = cursor.description
- for row in cursor.fetchall():
- yield _dict_helper(desc, row)
diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py
index 6c3abb6b59..4c712a0dc2 100644
--- a/django/db/models/__init__.py
+++ b/django/db/models/__init__.py
@@ -1,7 +1,7 @@
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.core import validators
-from django.db import backend, connection
+from django.db import connection
from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models
from django.db.models.query import Q
from django.db.models.manager import Manager
@@ -15,14 +15,18 @@ from django.utils.text import capfirst
# Admin stages.
ADD, CHANGE, BOTH = 1, 2, 3
-# Decorator. Takes a function that returns a tuple in this format:
-# (viewname, viewargs, viewkwargs)
-# Returns a function that calls urlresolvers.reverse() on that data, to return
-# the URL for those parameters.
def permalink(func):
+ """
+ Decorator that calls urlresolvers.reverse() to return a URL using
+ parameters returned by the decorated function "func".
+
+ "func" should be a function that returns a tuple in one of the
+ following formats:
+ (viewname, viewargs)
+ (viewname, viewargs, viewkwargs)
+ """
from django.core.urlresolvers import reverse
def inner(*args, **kwargs):
bits = func(*args, **kwargs)
- viewname = bits[0]
return reverse(bits[0], None, *bits[1:3])
return inner
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 21225d2623..72ea3e97a3 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -6,12 +6,13 @@ from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
from django.db.models.fields.related import OneToOneRel, ManyToOneRel
from django.db.models.query import delete_objects
from django.db.models.options import Options, AdminOptions
-from django.db import connection, backend, transaction
+from django.db import connection, transaction
from django.db.models import signals
from django.db.models.loading import register_models, get_model
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
from django.utils.functional import curry
+from django.utils.encoding import smart_str, force_unicode
from django.conf import settings
from itertools import izip
import types
@@ -83,9 +84,11 @@ class Model(object):
return getattr(self, self._meta.pk.attname)
def __repr__(self):
- return '<%s: %s>' % (self.__class__.__name__, self)
+ return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
def __str__(self):
+ if hasattr(self, '__unicode__'):
+ return force_unicode(self).encode('utf-8')
return '%s object' % self.__class__.__name__
def __eq__(self, other):
@@ -198,59 +201,62 @@ class Model(object):
_prepare = classmethod(_prepare)
- def save(self):
+ def save(self, raw=False):
dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
non_pks = [f for f in self._meta.fields if not f.primary_key]
cursor = connection.cursor()
+ qn = connection.ops.quote_name
+
# First, try an UPDATE. If that doesn't update anything, do an INSERT.
pk_val = self._get_pk_val()
- pk_set = bool(pk_val)
+ # Note: the comparison with '' is required for compatibility with
+ # oldforms-style model creation.
+ pk_set = pk_val is not None and pk_val != u''
record_exists = True
if pk_set:
# Determine whether a record with the primary key already exists.
- cursor.execute("SELECT COUNT(*) FROM %s WHERE %s=%%s" % \
- (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
+ cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \
+ (qn(self._meta.db_table), qn(self._meta.pk.column)),
self._meta.pk.get_db_prep_lookup('exact', pk_val))
# If it does already exist, do an UPDATE.
- if cursor.fetchone()[0] > 0:
- db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
+ if cursor.fetchone():
+ db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks]
if db_values:
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
- (backend.quote_name(self._meta.db_table),
- ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
- backend.quote_name(self._meta.pk.column)),
+ (qn(self._meta.db_table),
+ ','.join(['%s=%%s' % qn(f.column) for f in non_pks]),
+ qn(self._meta.pk.column)),
db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val))
else:
record_exists = False
if not pk_set or not record_exists:
- field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
- db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
+ field_names = [qn(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
+ db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
placeholders = [f.get_placeholder(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
# If the PK has been manually set, respect that.
if pk_set:
field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
- db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
+ db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
placeholders += [f.get_placeholder(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
if self._meta.order_with_respect_to:
- field_names.append(backend.quote_name('_order'))
+ field_names.append(qn('_order'))
# TODO: This assumes the database supports subqueries.
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
- (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
+ (qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column)))
db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
if db_values:
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
- (backend.quote_name(self._meta.db_table), ','.join(field_names),
+ (qn(self._meta.db_table), ','.join(field_names),
','.join(placeholders)), db_values)
else:
# Create a new record with defaults for everything.
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
- (backend.quote_name(self._meta.db_table),
- backend.quote_name(self._meta.pk.column),
- backend.get_pk_default_value()))
+ (qn(self._meta.db_table), qn(self._meta.pk.column),
+ connection.ops.pk_default_value()))
if self._meta.has_auto_field and not pk_set:
- setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
+ setattr(self, self._meta.pk.attname, connection.ops.last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
transaction.commit_unless_managed()
# Run any post-save hooks.
@@ -319,14 +325,15 @@ class Model(object):
def _get_FIELD_display(self, field):
value = getattr(self, field.attname)
- return dict(field.choices).get(value, value)
+ return force_unicode(dict(field.choices).get(value, value), strings_only=True)
def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
+ qn = connection.ops.quote_name
op = is_next and '>' or '<'
where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \
- (backend.quote_name(field.column), op, backend.quote_name(field.column),
- backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op)
- param = str(getattr(self, field.attname))
+ (qn(field.column), op, qn(field.column),
+ qn(self._meta.db_table), qn(self._meta.pk.column), op)
+ param = smart_str(getattr(self, field.attname))
q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name)
q._where.append(where)
q._params.extend([param, param, getattr(self, self._meta.pk.attname)])
@@ -336,14 +343,15 @@ class Model(object):
raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
def _get_next_or_previous_in_order(self, is_next):
+ qn = connection.ops.quote_name
cachename = "__%s_order_cache" % is_next
if not hasattr(self, cachename):
op = is_next and '>' or '<'
order_field = self._meta.order_with_respect_to
where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
- (backend.quote_name('_order'), op, backend.quote_name('_order'),
- backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
- '%s=%%s' % backend.quote_name(order_field.column)]
+ (qn('_order'), op, qn('_order'),
+ qn(self._meta.db_table), qn(self._meta.pk.column)),
+ '%s=%%s' % qn(order_field.column)]
params = [self._get_pk_val(), getattr(self, order_field.attname)]
obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()
setattr(self, cachename, obj)
@@ -425,24 +433,26 @@ class Model(object):
# ORDERING METHODS #########################
def method_set_order(ordered_obj, self, id_list):
+ qn = connection.ops.quote_name
cursor = connection.cursor()
# Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
- (backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'),
- backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
- backend.quote_name(ordered_obj._meta.pk.column))
+ (qn(ordered_obj._meta.db_table), qn('_order'),
+ qn(ordered_obj._meta.order_with_respect_to.column),
+ qn(ordered_obj._meta.pk.column))
rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
transaction.commit_unless_managed()
def method_get_order(ordered_obj, self):
+ qn = connection.ops.quote_name
cursor = connection.cursor()
# Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
- (backend.quote_name(ordered_obj._meta.pk.column),
- backend.quote_name(ordered_obj._meta.db_table),
- backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
- backend.quote_name('_order'))
+ (qn(ordered_obj._meta.pk.column),
+ qn(ordered_obj._meta.db_table),
+ qn(ordered_obj._meta.order_with_respect_to.column),
+ qn('_order'))
rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
cursor.execute(sql, [rel_val])
return [r[0] for r in cursor.fetchall()]
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 87a6c63289..27a704d343 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -1,3 +1,4 @@
+from django.db import get_creation_module
from django.db.models import signals
from django.dispatch import dispatcher
from django.conf import settings
@@ -8,7 +9,9 @@ from django.core.exceptions import ObjectDoesNotExist
from django.utils.functional import curry
from django.utils.itercompat import tee
from django.utils.text import capfirst
-from django.utils.translation import gettext, gettext_lazy
+from django.utils.translation import ugettext_lazy, ugettext as _
+from django.utils.encoding import smart_unicode, force_unicode, smart_str
+from django.utils.maxlength import LegacyMaxlength
import datetime, os, time
try:
import decimal
@@ -26,7 +29,7 @@ BLANK_CHOICE_DASH = [("", "---------")]
BLANK_CHOICE_NONE = [("", "None")]
# prepares a value for use in a LIKE query
-prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
+prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
# returns the <ul> class for a given radio_admin value
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
@@ -43,7 +46,7 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data):
return
if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val():
return
- raise validators.ValidationError, gettext("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}
+ raise validators.ValidationError, _("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}
# A guide to Field parameters:
#
@@ -61,6 +64,9 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data):
# getattr(obj, opts.pk.attname)
class Field(object):
+ # Provide backwards compatibility for the maxlength attribute and
+ # argument for this class and all subclasses.
+ __metaclass__ = LegacyMaxlength
# Designates whether empty strings fundamentally are allowed at the
# database level.
@@ -70,7 +76,7 @@ class Field(object):
creation_counter = 0
def __init__(self, verbose_name=None, name=None, primary_key=False,
- maxlength=None, unique=False, blank=False, null=False, db_index=False,
+ max_length=None, unique=False, blank=False, null=False, db_index=False,
core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
@@ -78,7 +84,7 @@ class Field(object):
self.name = name
self.verbose_name = verbose_name
self.primary_key = primary_key
- self.maxlength, self.unique = maxlength, unique
+ self.max_length, self.unique = max_length, unique
self.blank, self.null = blank, null
# Oracle treats the empty string ('') as null, so coerce the null
# option whenever '' is a possible value.
@@ -116,6 +122,30 @@ class Field(object):
"""
return value
+ def db_type(self):
+ """
+ Returns the database column data type for this field, taking into
+ account the DATABASE_ENGINE setting.
+ """
+ # The default implementation of this method looks at the
+ # backend-specific DATA_TYPES dictionary, looking up the field by its
+ # "internal type".
+ #
+ # A Field class can implement the get_internal_type() method to specify
+ # which *preexisting* Django Field class it's most similar to -- i.e.,
+ # an XMLField is represented by a TEXT column type, which is the same
+ # as the TextField Django field type, which means XMLField's
+ # get_internal_type() returns 'TextField'.
+ #
+ # But the limitation of the get_internal_type() / DATA_TYPES approach
+ # is that it cannot handle database column types that aren't already
+ # mapped to one of the built-in Django field types. In this case, you
+ # can implement db_type() instead of get_internal_type() to specify
+ # exactly which wacky database column type you want to use.
+ data_types = get_creation_module().DATA_TYPES
+ internal_type = self.get_internal_type()
+ return data_types[internal_type] % self.__dict__
+
def validate_full(self, field_data, all_data):
"""
Returns a list of errors for this field. This is the main interface,
@@ -123,7 +153,7 @@ class Field(object):
Subclasses should implement validate(), not validate_full().
"""
if not self.blank and not field_data:
- return [gettext_lazy('This field is required.')]
+ return [_('This field is required.')]
try:
self.validate(field_data, all_data)
except validators.ValidationError, e:
@@ -222,8 +252,8 @@ class Field(object):
def prepare_field_objs_and_params(self, manipulator, name_prefix):
params = {'validator_list': self.validator_list[:]}
- if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
- params['maxlength'] = self.maxlength
+ if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter.
+ params['max_length'] = self.max_length
if self.choices:
if self.radio_admin:
@@ -284,7 +314,7 @@ class Field(object):
core_field_names.extend(f.get_manipulator_field_names(name_prefix))
# Now, if there are any, add the validator to this FormField.
if core_field_names:
- params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, gettext_lazy("This field is required.")))
+ params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required.")))
# Finally, add the field_names.
field_names = self.get_manipulator_field_names(name_prefix)
@@ -312,9 +342,9 @@ class Field(object):
return first_choice + list(self.choices)
rel_model = self.rel.to
if hasattr(self.rel, 'get_related_field'):
- lst = [(getattr(x, self.rel.get_related_field().attname), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
+ lst = [(getattr(x, self.rel.get_related_field().attname), smart_unicode(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
else:
- lst = [(x._get_pk_val(), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
+ lst = [(x._get_pk_val(), smart_unicode(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
return first_choice + lst
def get_choices_default(self):
@@ -354,6 +384,9 @@ class Field(object):
return self._choices
choices = property(_get_choices)
+ def save_form_data(self, instance, data):
+ setattr(instance, self.name, data)
+
def formfield(self, form_class=forms.CharField, **kwargs):
"Returns a django.newforms.Field instance for this database Field."
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
@@ -379,7 +412,7 @@ class AutoField(Field):
try:
return int(value)
except (TypeError, ValueError):
- raise validators.ValidationError, gettext("This value must be an integer.")
+ raise validators.ValidationError, _("This value must be an integer.")
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
if not rel:
@@ -414,7 +447,7 @@ class BooleanField(Field):
if value in (True, False): return value
if value in ('t', 'True', '1'): return True
if value in ('f', 'False', '0'): return False
- raise validators.ValidationError, gettext("This value must be either True or False.")
+ raise validators.ValidationError, _("This value must be either True or False.")
def get_manipulator_field_objs(self):
return [oldforms.CheckboxField]
@@ -435,11 +468,11 @@ class CharField(Field):
if self.null:
return value
else:
- raise validators.ValidationError, gettext_lazy("This field cannot be null.")
- return str(value)
+ raise validators.ValidationError, ugettext_lazy("This field cannot be null.")
+ return smart_unicode(value)
def formfield(self, **kwargs):
- defaults = {'max_length': self.maxlength}
+ defaults = {'max_length': self.max_length}
defaults.update(kwargs)
return super(CharField, self).formfield(**defaults)
@@ -469,15 +502,15 @@ class DateField(Field):
try:
return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
except ValueError:
- raise validators.ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
+ raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
def get_db_prep_lookup(self, lookup_type, value):
if lookup_type == 'range':
- value = [str(v) for v in value]
+ value = [smart_unicode(v) for v in value]
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
value = value.strftime('%Y-%m-%d')
else:
- value = str(value)
+ value = smart_unicode(value)
return Field.get_db_prep_lookup(self, lookup_type, value)
def pre_save(self, model_instance, add):
@@ -538,7 +571,7 @@ class DateTimeField(DateField):
try:
return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3])
except ValueError:
- raise validators.ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
+ raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
def get_db_prep_save(self, value):
# Casts dates into string format for entry into database.
@@ -547,14 +580,14 @@ class DateTimeField(DateField):
# doesn't support microseconds.
if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
value = value.replace(microsecond=0)
- value = str(value)
+ value = smart_unicode(value)
return Field.get_db_prep_save(self, value)
def get_db_prep_lookup(self, lookup_type, value):
if lookup_type == 'range':
- value = [str(v) for v in value]
+ value = [smart_unicode(v) for v in value]
else:
- value = str(value)
+ value = smart_unicode(value)
return Field.get_db_prep_lookup(self, lookup_type, value)
def get_manipulator_field_objs(self):
@@ -598,7 +631,8 @@ class DecimalField(Field):
try:
return decimal.Decimal(value)
except decimal.InvalidOperation:
- raise validators.ValidationError, gettext("This value must be a decimal number.")
+ raise validators.ValidationError(
+ _("This value must be a decimal number."))
def _format(self, value):
if isinstance(value, basestring):
@@ -619,7 +653,7 @@ class DecimalField(Field):
if value < 0:
num_chars += 1
- return "%.*f" % (self.decimal_places, value)
+ return u"%.*f" % (self.decimal_places, value)
def get_db_prep_save(self, value):
if value is not None:
@@ -647,7 +681,7 @@ class DecimalField(Field):
class EmailField(CharField):
def __init__(self, *args, **kwargs):
- kwargs['maxlength'] = 75
+ kwargs['max_length'] = 75
CharField.__init__(self, *args, **kwargs)
def get_internal_type(self):
@@ -669,6 +703,13 @@ class FileField(Field):
self.upload_to = upload_to
Field.__init__(self, verbose_name, name, **kwargs)
+ def get_db_prep_save(self, value):
+ "Returns field's value prepared for saving into a database."
+ # Need to convert UploadedFile objects provided via a form to unicode for database insertion
+ if value is None:
+ return None
+ return unicode(value)
+
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
if not self.blank:
@@ -681,7 +722,7 @@ class FileField(Field):
self.always_test = True
def __call__(self, field_data, all_data):
if not all_data.get(self.other_file_field_name, False):
- c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, gettext_lazy("This field is required."))
+ c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
c(field_data, all_data)
# First, get the core fields, if any.
core_field_names = []
@@ -692,7 +733,7 @@ class FileField(Field):
if core_field_names:
field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
else:
- v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, gettext_lazy("This field is required."))
+ v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
v.always_test = True
field_list[0].validator_list.append(v)
field_list[0].is_required = field_list[1].is_required = False
@@ -738,13 +779,26 @@ class FileField(Field):
func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
def get_directory_name(self):
- return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
+ return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
def get_filename(self, filename):
from django.utils.text import get_valid_filename
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
return os.path.normpath(f)
+ def save_form_data(self, instance, data):
+ if data:
+ getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
+
+ def formfield(self, **kwargs):
+ defaults = {'form_class': forms.FileField}
+ # If a file has been provided previously, then the form doesn't require
+ # that a new file is provided this time.
+ if 'initial' in kwargs:
+ defaults['required'] = False
+ defaults.update(kwargs)
+ return super(FileField, self).formfield(**defaults)
+
class FilePathField(Field):
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
self.path, self.match, self.recursive = path, match, recursive
@@ -793,6 +847,10 @@ class ImageField(FileField):
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
new_object.save()
+ def formfield(self, **kwargs):
+ defaults = {'form_class': forms.ImageField}
+ return super(ImageField, self).formfield(**defaults)
+
class IntegerField(Field):
empty_strings_allowed = False
def get_manipulator_field_objs(self):
@@ -806,7 +864,7 @@ class IntegerField(Field):
class IPAddressField(Field):
empty_strings_allowed = False
def __init__(self, *args, **kwargs):
- kwargs['maxlength'] = 15
+ kwargs['max_length'] = 15
Field.__init__(self, *args, **kwargs)
def get_manipulator_field_objs(self):
@@ -826,7 +884,7 @@ class NullBooleanField(Field):
if value in ('None'): return None
if value in ('t', 'True', '1'): return True
if value in ('f', 'False', '0'): return False
- raise validators.ValidationError, gettext("This value must be either None, True or False.")
+ raise validators.ValidationError, _("This value must be either None, True or False.")
def get_manipulator_field_objs(self):
return [oldforms.NullBooleanField]
@@ -854,7 +912,7 @@ class PositiveSmallIntegerField(IntegerField):
class SlugField(Field):
def __init__(self, *args, **kwargs):
- kwargs['maxlength'] = kwargs.get('maxlength', 50)
+ kwargs['max_length'] = kwargs.get('max_length', 50)
kwargs.setdefault('validator_list', []).append(validators.isSlug)
# Set db_index=True unless it's been set manually.
if 'db_index' not in kwargs:
@@ -891,9 +949,9 @@ class TimeField(Field):
def prep(value):
if isinstance(value, datetime.time):
value = datetime.datetime.combine(datetime.date(1900, 1, 1), value)
- return str(value)
+ return smart_unicode(value)
else:
- prep = str
+ prep = smart_unicode
if lookup_type == 'range':
value = [prep(v) for v in value]
else:
@@ -923,7 +981,7 @@ class TimeField(Field):
elif isinstance(value, basestring):
value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
else:
- value = str(value)
+ value = smart_unicode(value)
return Field.get_db_prep_save(self, value)
def get_manipulator_field_objs(self):
@@ -940,7 +998,7 @@ class TimeField(Field):
class URLField(CharField):
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
- kwargs['maxlength'] = kwargs.get('maxlength', 200)
+ kwargs['max_length'] = kwargs.get('max_length', 200)
if verify_exists:
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
self.verify_exists = verify_exists
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 60503ce14f..2ccf1e3dd0 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -1,10 +1,11 @@
-from django.db import backend, transaction
+from django.db import connection, transaction
from django.db.models import signals, get_model
-from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class
+from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
from django.db.models.related import RelatedObject
from django.utils.text import capfirst
-from django.utils.translation import gettext_lazy, string_concat, ngettext
+from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
from django.utils.functional import curry
+from django.utils.encoding import smart_unicode
from django.core import validators
from django import oldforms
from django import newforms as forms
@@ -318,7 +319,6 @@ def create_many_related_manager(superclass):
# source_col_name: the PK colname in join_table for the source object
# target_col_name: the PK colname in join_table for the target object
# *objs - objects to add. Either object instances, or primary keys of object instances.
- from django.db import connection
# If there aren't any objects, there is nothing to do.
if objs:
@@ -349,7 +349,6 @@ def create_many_related_manager(superclass):
# source_col_name: the PK colname in join_table for the source object
# target_col_name: the PK colname in join_table for the target object
# *objs - objects to remove
- from django.db import connection
# If there aren't any objects, there is nothing to do.
if objs:
@@ -370,7 +369,6 @@ def create_many_related_manager(superclass):
def _clear_items(self, source_col_name):
# source_col_name: the PK colname in join_table for the source object
- from django.db import connection
cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
(self.join_table, source_col_name),
@@ -399,7 +397,7 @@ class ManyRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__
RelatedManager = create_many_related_manager(superclass)
- qn = backend.quote_name
+ qn = connection.ops.quote_name
manager = RelatedManager(
model=rel_model,
core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
@@ -440,7 +438,7 @@ class ReverseManyRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__
RelatedManager = create_many_related_manager(superclass)
- qn = backend.quote_name
+ qn = connection.ops.quote_name
manager = RelatedManager(
model=rel_model,
core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
@@ -555,6 +553,16 @@ class ForeignKey(RelatedField, Field):
defaults.update(kwargs)
return super(ForeignKey, self).formfield(**defaults)
+ def db_type(self):
+ # The database column type of a ForeignKey is the column type
+ # of the field to which it points. An exception is if the ForeignKey
+ # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
+ # in which case the column type is simply that of an IntegerField.
+ rel_field = self.rel.get_related_field()
+ if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
+ return IntegerField().db_type()
+ return rel_field.db_type()
+
class OneToOneField(RelatedField, IntegerField):
def __init__(self, to, to_field=None, **kwargs):
try:
@@ -621,6 +629,16 @@ class OneToOneField(RelatedField, IntegerField):
defaults.update(kwargs)
return super(OneToOneField, self).formfield(**defaults)
+ def db_type(self):
+ # The database column type of a OneToOneField is the column type
+ # of the field to which it points. An exception is if the OneToOneField
+ # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
+ # in which case the column type is simply that of an IntegerField.
+ rel_field = self.rel.get_related_field()
+ if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
+ return IntegerField().db_type()
+ return rel_field.db_type()
+
class ManyToManyField(RelatedField, Field):
def __init__(self, to, **kwargs):
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
@@ -637,9 +655,9 @@ class ManyToManyField(RelatedField, Field):
Field.__init__(self, **kwargs)
if self.rel.raw_id_admin:
- msg = gettext_lazy('Separate multiple IDs with commas.')
+ msg = ugettext_lazy('Separate multiple IDs with commas.')
else:
- msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
+ msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
self.help_text = string_concat(self.help_text, ' ', msg)
def get_internal_type(self):
@@ -689,7 +707,7 @@ class ManyToManyField(RelatedField, Field):
objects = mod._default_manager.in_bulk(pks)
if len(objects) != len(pks):
badkeys = [k for k in pks if k not in objects]
- raise validators.ValidationError, ngettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
+ raise validators.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
"Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % {
'self': self.verbose_name,
'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys),
@@ -700,7 +718,7 @@ class ManyToManyField(RelatedField, Field):
if obj:
instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]
if self.rel.raw_id_admin:
- new_data[self.name] = ",".join([str(id) for id in instance_ids])
+ new_data[self.name] = u",".join([smart_unicode(id) for id in instance_ids])
else:
new_data[self.name] = instance_ids
else:
@@ -738,6 +756,9 @@ class ManyToManyField(RelatedField, Field):
"Returns the value of this field in the given model instance."
return getattr(obj, self.attname).all()
+ def save_form_data(self, instance, data):
+ setattr(instance, self.attname, data)
+
def formfield(self, **kwargs):
defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
defaults.update(kwargs)
@@ -747,6 +768,11 @@ class ManyToManyField(RelatedField, Field):
defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
return super(ManyToManyField, self).formfield(**defaults)
+ def db_type(self):
+ # A ManyToManyField is not represented by a single column,
+ # so return None.
+ return None
+
class ManyToOneRel(object):
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
diff --git a/django/db/models/loading.py b/django/db/models/loading.py
index 224f5e8451..090390aa9e 100644
--- a/django/db/models/loading.py
+++ b/django/db/models/loading.py
@@ -4,113 +4,188 @@ from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
import sys
import os
+import threading
-__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models')
+__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
+ 'load_app', 'app_cache_ready')
-_app_list = [] # Cache of installed apps.
- # Entry is not placed in app_list cache until entire app is loaded.
-_app_models = {} # Dictionary of models against app label
- # Each value is a dictionary of model name: model class
- # Applabel and Model entry exists in cache when individual model is loaded.
-_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
- # Key is the app_name of the model, value is the exception that was raised
- # during model loading.
-_loaded = False # Has the contents of settings.INSTALLED_APPS been loaded?
- # i.e., has get_apps() been called?
+class AppCache(object):
+ """
+ A cache that stores installed applications and their models. Used to
+ provide reverse-relations and for app introspection (e.g. admin).
+ """
+ # Use the Borg pattern to share state between all instances. Details at
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531.
+ __shared_state = dict(
+ # Keys of app_store are the model modules for each application.
+ app_store = {},
-def get_apps():
- "Returns a list of all installed modules that contain models."
- global _app_list
- global _loaded
- if not _loaded:
- _loaded = True
- for app_name in settings.INSTALLED_APPS:
- try:
- load_app(app_name)
- except Exception, e:
- # Problem importing the app
- _app_errors[app_name] = e
- return _app_list
+ # Mapping of app_labels to a dictionary of model names to model code.
+ app_models = {},
-def get_app(app_label, emptyOK=False):
- "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
- get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
- for app_name in settings.INSTALLED_APPS:
- if app_label == app_name.split('.')[-1]:
- mod = load_app(app_name)
- if mod is None:
- if emptyOK:
- return None
- else:
- return mod
- raise ImproperlyConfigured, "App with label %s could not be found" % app_label
+ # Mapping of app_labels to errors raised when trying to import the app.
+ app_errors = {},
-def load_app(app_name):
- "Loads the app with the provided fully qualified name, and returns the model module."
- global _app_list
- mod = __import__(app_name, {}, {}, ['models'])
- if not hasattr(mod, 'models'):
- return None
- if mod.models not in _app_list:
- _app_list.append(mod.models)
- return mod.models
+ # -- Everything below here is only used when populating the cache --
+ loaded = False,
+ handled = {},
+ postponed = [],
+ nesting_level = 0,
+ write_lock = threading.RLock(),
+ )
-def get_app_errors():
- "Returns the map of known problems with the INSTALLED_APPS"
- global _app_errors
- get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
- return _app_errors
+ def __init__(self):
+ self.__dict__ = self.__shared_state
-def get_models(app_mod=None):
- """
- Given a module containing models, returns a list of the models. Otherwise
- returns a list of all installed models.
- """
- app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
- if app_mod:
- return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
- else:
- model_list = []
- for app_mod in app_list:
- model_list.extend(get_models(app_mod))
- return model_list
+ def _populate(self):
+ """
+ Fill in all the cache information. This method is threadsafe, in the
+ sense that every caller will see the same state upon return, and if the
+ cache is already initialised, it does no work.
+ """
+ if self.loaded:
+ return
+ self.write_lock.acquire()
+ try:
+ if self.loaded:
+ return
+ for app_name in settings.INSTALLED_APPS:
+ if app_name in self.handled:
+ continue
+ try:
+ self.load_app(app_name, True)
+ except Exception, e:
+ # Problem importing the app
+ self.app_errors[app_name] = e
+ if not self.nesting_level:
+ for app_name in self.postponed:
+ self.load_app(app_name)
+ self.loaded = True
+ finally:
+ self.write_lock.release()
-def get_model(app_label, model_name, seed_cache=True):
- """
- Returns the model matching the given app_label and case-insensitive
- model_name.
+ def load_app(self, app_name, can_postpone=False):
+ """
+ Loads the app with the provided fully qualified name, and returns the
+ model module.
+ """
+ self.handled[app_name] = None
+ self.nesting_level += 1
+ mod = __import__(app_name, {}, {}, ['models'])
+ self.nesting_level -= 1
+ if not hasattr(mod, 'models'):
+ if can_postpone:
+ # Either the app has no models, or the package is still being
+ # imported by Python and the model module isn't available yet.
+ # We will check again once all the recursion has finished (in
+ # populate).
+ self.postponed.append(app_name)
+ return None
+ if mod.models not in self.app_store:
+ self.app_store[mod.models] = len(self.app_store)
+ return mod.models
- Returns None if no model is found.
- """
- if seed_cache:
- get_apps()
- try:
- model_dict = _app_models[app_label]
- except KeyError:
- return None
+ def app_cache_ready(self):
+ """
+ Returns true if the model cache is fully populated.
- try:
- return model_dict[model_name.lower()]
- except KeyError:
- return None
+ Useful for code that wants to cache the results of get_models() for
+ themselves once it is safe to do so.
+ """
+ return self.loaded
-def register_models(app_label, *models):
- """
- Register a set of models as belonging to an app.
- """
- for model in models:
- # Store as 'name: model' pair in a dictionary
- # in the _app_models dictionary
- model_name = model._meta.object_name.lower()
- model_dict = _app_models.setdefault(app_label, {})
- if model_name in model_dict:
- # The same model may be imported via different paths (e.g.
- # appname.models and project.appname.models). We use the source
- # filename as a means to detect identity.
- fname1 = os.path.abspath(sys.modules[model.__module__].__file__)
- fname2 = os.path.abspath(sys.modules[model_dict[model_name].__module__].__file__)
- # Since the filename extension could be .py the first time and .pyc
- # or .pyo the second time, ignore the extension when comparing.
- if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
- continue
- model_dict[model_name] = model
+ def get_apps(self):
+ "Returns a list of all installed modules that contain models."
+ self._populate()
+
+ # Ensure the returned list is always in the same order (with new apps
+ # added at the end). This avoids unstable ordering on the admin app
+ # list page, for example.
+ apps = [(v, k) for k, v in self.app_store.items()]
+ apps.sort()
+ return [elt[1] for elt in apps]
+
+ def get_app(self, app_label, emptyOK=False):
+ """
+ Returns the module containing the models for the given app_label. If
+ the app has no models in it and 'emptyOK' is True, returns None.
+ """
+ self._populate()
+ self.write_lock.acquire()
+ try:
+ for app_name in settings.INSTALLED_APPS:
+ if app_label == app_name.split('.')[-1]:
+ mod = self.load_app(app_name, False)
+ if mod is None:
+ if emptyOK:
+ return None
+ else:
+ return mod
+ raise ImproperlyConfigured, "App with label %s could not be found" % app_label
+ finally:
+ self.write_lock.release()
+
+ def get_app_errors(self):
+ "Returns the map of known problems with the INSTALLED_APPS."
+ self._populate()
+ return self.app_errors
+
+ def get_models(self, app_mod=None):
+ """
+ Given a module containing models, returns a list of the models.
+ Otherwise returns a list of all installed models.
+ """
+ self._populate()
+ if app_mod:
+ return self.app_models.get(app_mod.__name__.split('.')[-2], {}).values()
+ else:
+ model_list = []
+ for app_entry in self.app_models.itervalues():
+ model_list.extend(app_entry.values())
+ return model_list
+
+ def get_model(self, app_label, model_name, seed_cache=True):
+ """
+ Returns the model matching the given app_label and case-insensitive
+ model_name.
+
+ Returns None if no model is found.
+ """
+ if seed_cache:
+ self._populate()
+ return self.app_models.get(app_label, {}).get(model_name.lower())
+
+ def register_models(self, app_label, *models):
+ """
+ Register a set of models as belonging to an app.
+ """
+ for model in models:
+ # Store as 'name: model' pair in a dictionary
+ # in the _app_models dictionary
+ model_name = model._meta.object_name.lower()
+ model_dict = self.app_models.setdefault(app_label, {})
+ if model_name in model_dict:
+ # The same model may be imported via different paths (e.g.
+ # appname.models and project.appname.models). We use the source
+ # filename as a means to detect identity.
+ fname1 = os.path.abspath(sys.modules[model.__module__].__file__)
+ fname2 = os.path.abspath(sys.modules[model_dict[model_name].__module__].__file__)
+ # Since the filename extension could be .py the first time and
+ # .pyc or .pyo the second time, ignore the extension when
+ # comparing.
+ if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
+ continue
+ model_dict[model_name] = model
+
+cache = AppCache()
+
+# These methods were always module level, so are kept that way for backwards
+# compatibility.
+get_apps = cache.get_apps
+get_app = cache.get_app
+get_app_errors = cache.get_app_errors
+get_models = cache.get_models
+get_model = cache.get_model
+register_models = cache.register_models
+load_app = cache.load_app
+app_cache_ready = cache.app_cache_ready
diff --git a/django/db/models/manager.py b/django/db/models/manager.py
index b60eed262a..040b86656a 100644
--- a/django/db/models/manager.py
+++ b/django/db/models/manager.py
@@ -3,10 +3,6 @@ from django.dispatch import dispatcher
from django.db.models import signals
from django.db.models.fields import FieldDoesNotExist
-# Size of each "chunk" for get_iterator calls.
-# Larger values are slightly faster at the expense of more storage space.
-GET_ITERATOR_CHUNK_SIZE = 100
-
def ensure_default_manager(sender):
cls = sender
if not hasattr(cls, '_default_manager'):
@@ -47,7 +43,7 @@ class Manager(object):
def get_query_set(self):
"""Returns a new QuerySet object. Subclasses can override this method
- to easily customise the behaviour of the Manager.
+ to easily customize the behavior of the Manager.
"""
return QuerySet(self.model)
diff --git a/django/db/models/manipulators.py b/django/db/models/manipulators.py
index c624cb698b..c3e5292198 100644
--- a/django/db/models/manipulators.py
+++ b/django/db/models/manipulators.py
@@ -7,6 +7,8 @@ from django.db.models import signals
from django.utils.functional import curry
from django.utils.datastructures import DotExpandedDict
from django.utils.text import capfirst
+from django.utils.encoding import smart_str
+from django.utils.translation import ugettext as _
import types
def add_manipulators(sender):
@@ -111,7 +113,7 @@ class AutomaticManipulator(oldforms.Manipulator):
if self.change:
self.fields_added, self.fields_changed, self.fields_deleted = [], [], []
for f in self.opts.fields:
- if not f.primary_key and str(getattr(self.original_object, f.attname)) != str(getattr(new_object, f.attname)):
+ if not f.primary_key and smart_str(getattr(self.original_object, f.attname)) != smart_str(getattr(new_object, f.attname)):
self.fields_changed.append(f.verbose_name)
# Save many-to-many objects. Example: Set sites for a poll.
@@ -211,7 +213,7 @@ class AutomaticManipulator(oldforms.Manipulator):
self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj))
else:
for f in related.opts.fields:
- if not f.primary_key and f != related.field and str(getattr(old_rel_obj, f.attname)) != str(getattr(new_rel_obj, f.attname)):
+ if not f.primary_key and f != related.field and smart_str(getattr(old_rel_obj, f.attname)) != smart_str(getattr(new_rel_obj, f.attname)):
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
# Save many-to-many objects.
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 93627f7b72..ad813ae0f7 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -2,9 +2,11 @@ from django.conf import settings
from django.db.models.related import RelatedObject
from django.db.models.fields.related import ManyToManyRel
from django.db.models.fields import AutoField, FieldDoesNotExist
-from django.db.models.loading import get_models
+from django.db.models.loading import get_models, app_cache_ready
from django.db.models.query import orderlist2sql
from django.db.models import Manager
+from django.utils.translation import activate, deactivate_all, get_language, string_concat
+from django.utils.encoding import force_unicode, smart_str
from bisect import bisect
import re
@@ -42,6 +44,7 @@ class Options(object):
self.object_name = cls.__name__
self.module_name = self.object_name.lower()
self.verbose_name = get_verbose_name(self.object_name)
+
# Next, apply any overridden values from 'class Meta'.
if self.meta:
meta_attrs = self.meta.__dict__
@@ -51,16 +54,16 @@ class Options(object):
setattr(self, attr_name, meta_attrs.pop(attr_name, getattr(self, attr_name)))
# verbose_name_plural is a special case because it uses a 's'
# by default.
- setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', self.verbose_name + 's'))
+ setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', string_concat(self.verbose_name, 's')))
# Any leftover attributes must be invalid.
if meta_attrs != {}:
raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
else:
- self.verbose_name_plural = self.verbose_name + 's'
+ self.verbose_name_plural = string_concat(self.verbose_name, 's')
del self.meta
def _prepare(self, model):
- from django.db import backend
+ from django.db import connection
from django.db.backends.util import truncate_name
if self.order_with_respect_to:
self.order_with_respect_to = self.get_field(self.order_with_respect_to)
@@ -76,8 +79,7 @@ class Options(object):
# If the db_table wasn't provided, use the app_label + module_name.
if not self.db_table:
self.db_table = "%s_%s" % (self.app_label, self.module_name)
- self.db_table = truncate_name(self.db_table,
- backend.get_max_name_length())
+ self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
def add_field(self, field):
# Insert the given field in the order in which it was created, using
@@ -95,7 +97,20 @@ class Options(object):
return '<Options for %s>' % self.object_name
def __str__(self):
- return "%s.%s" % (self.app_label, self.module_name)
+ return "%s.%s" % (smart_str(self.app_label), smart_str(self.module_name))
+
+ def verbose_name_raw(self):
+ """
+ There are a few places where the untranslated verbose name is needed
+ (so that we get the same value regardless of currently active
+ locale).
+ """
+ lang = get_language()
+ deactivate_all()
+ raw = force_unicode(self.verbose_name)
+ activate(lang)
+ return raw
+ verbose_name_raw = property(verbose_name_raw)
def get_field(self, name, many_to_many=True):
"Returns the requested field by name. Raises FieldDoesNotExist on error."
@@ -163,7 +178,8 @@ class Options(object):
for f in klass._meta.many_to_many:
if f.rel and self == f.rel.to._meta:
rel_objs.append(RelatedObject(f.rel.to, klass, f))
- self._all_related_many_to_many_objects = rel_objs
+ if app_cache_ready():
+ self._all_related_many_to_many_objects = rel_objs
return rel_objs
def get_ordered_objects(self):
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 92bc9d78ed..a750ef5550 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1,9 +1,10 @@
from django.conf import settings
-from django.db import backend, connection, transaction
+from django.db import connection, transaction
from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models import signals, loading
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
+from django.utils.encoding import smart_unicode
from django.contrib.contenttypes import generic
import datetime
import operator
@@ -52,7 +53,7 @@ def handle_legacy_orderlist(order_list):
return order_list
else:
import warnings
- new_order_list = [LEGACY_ORDERING_MAPPING[j.upper()].replace('_', str(i)) for i, j in order_list]
+ new_order_list = [LEGACY_ORDERING_MAPPING[j.upper()].replace('_', smart_unicode(i)) for i, j in order_list]
warnings.warn("%r ordering syntax is deprecated. Use %r instead." % (order_list, new_order_list), DeprecationWarning)
return new_order_list
@@ -63,23 +64,24 @@ def orderfield2column(f, opts):
return f
def orderlist2sql(order_list, opts, prefix=''):
+ qn = connection.ops.quote_name
if prefix.endswith('.'):
- prefix = backend.quote_name(prefix[:-1]) + '.'
+ prefix = qn(prefix[:-1]) + '.'
output = []
for f in handle_legacy_orderlist(order_list):
if f.startswith('-'):
- output.append('%s%s DESC' % (prefix, backend.quote_name(orderfield2column(f[1:], opts))))
+ output.append('%s%s DESC' % (prefix, qn(orderfield2column(f[1:], opts))))
elif f == '?':
- output.append(backend.get_random_function_sql())
+ output.append(connection.ops.random_function_sql())
else:
- output.append('%s%s ASC' % (prefix, backend.quote_name(orderfield2column(f, opts))))
+ output.append('%s%s ASC' % (prefix, qn(orderfield2column(f, opts))))
return ', '.join(output)
def quote_only_if_word(word):
if re.search('\W', word): # Don't quote if there are spaces or non-word chars.
return word
else:
- return backend.quote_name(word)
+ return connection.ops.quote_name(word)
class _QuerySet(object):
"Represents a lazy database lookup for a set of objects"
@@ -113,7 +115,7 @@ class _QuerySet(object):
def __getitem__(self, k):
"Retrieve an item or slice from the set of results."
- if not isinstance(k, (slice, int)):
+ if not isinstance(k, (slice, int, long)):
raise TypeError
assert (not isinstance(k, slice) and (k >= 0)) \
or (isinstance(k, slice) and (k.start is None or k.start >= 0) and (k.stop is None or k.stop >= 0)), \
@@ -234,8 +236,8 @@ class _QuerySet(object):
cursor = connection.cursor()
if self._distinct:
- id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
- backend.quote_name(self.model._meta.pk.column))
+ id_col = "%s.%s" % (connection.ops.quote_name(self.model._meta.db_table),
+ connection.ops.quote_name(self.model._meta.pk.column))
cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params)
else:
cursor.execute("SELECT COUNT(*)" + sql, params)
@@ -307,11 +309,12 @@ class _QuerySet(object):
assert self._limit is None and self._offset is None, \
"Cannot use 'limit' or 'offset' with in_bulk"
assert isinstance(id_list, (tuple, list)), "in_bulk() must be provided with a list of IDs."
+ qn = connection.ops.quote_name
id_list = list(id_list)
if id_list == []:
return {}
qs = self._clone()
- qs._where.append("%s.%s IN (%s)" % (backend.quote_name(self.model._meta.db_table), backend.quote_name(self.model._meta.pk.column), ",".join(['%s'] * len(id_list))))
+ qs._where.append("%s.%s IN (%s)" % (qn(self.model._meta.db_table), qn(self.model._meta.pk.column), ",".join(['%s'] * len(id_list))))
qs._params.extend(id_list)
return dict([(obj._get_pk_val(), obj) for obj in qs.iterator()])
@@ -480,10 +483,11 @@ class _QuerySet(object):
return self._result_cache
def _get_sql_clause(self):
+ qn = connection.ops.quote_name
opts = self.model._meta
# Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
- select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
+ select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
tables = [quote_only_if_word(t) for t in self._tables]
joins = SortedDict()
where = self._where[:]
@@ -504,10 +508,10 @@ class _QuerySet(object):
# Add any additional SELECTs.
if self._select:
- select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
+ select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
# Start composing the body of the SQL statement.
- sql = [" FROM", backend.quote_name(opts.db_table)]
+ sql = [" FROM", qn(opts.db_table)]
# Compose the join dictionary into SQL describing the joins.
if joins:
@@ -530,7 +534,7 @@ class _QuerySet(object):
ordering_to_use = opts.ordering
for f in handle_legacy_orderlist(ordering_to_use):
if f == '?': # Special case.
- order_by.append(backend.get_random_function_sql())
+ order_by.append(connection.ops.random_function_sql())
else:
if f.startswith('-'):
col_name = f[1:]
@@ -540,29 +544,29 @@ class _QuerySet(object):
order = "ASC"
if "." in col_name:
table_prefix, col_name = col_name.split('.', 1)
- table_prefix = backend.quote_name(table_prefix) + '.'
+ table_prefix = qn(table_prefix) + '.'
else:
# Use the database table as a column prefix if it wasn't given,
# and if the requested column isn't a custom SELECT.
if "." not in col_name and col_name not in (self._select or ()):
- table_prefix = backend.quote_name(opts.db_table) + '.'
+ table_prefix = qn(opts.db_table) + '.'
else:
table_prefix = ''
- order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
+ order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
if order_by:
sql.append("ORDER BY " + ", ".join(order_by))
# LIMIT and OFFSET clauses
if self._limit is not None:
- sql.append("%s " % backend.get_limit_offset_sql(self._limit, self._offset))
+ sql.append("%s " % connection.ops.limit_offset_sql(self._limit, self._offset))
else:
assert self._offset is None, "'offset' is not allowed without 'limit'"
return select, " ".join(sql), params
-# Use the backend's QuerySet class if it defines one, otherwise use _QuerySet.
-if hasattr(backend, 'get_query_set_class'):
- QuerySet = backend.get_query_set_class(_QuerySet)
+# Use the backend's QuerySet class if it defines one. Otherwise, use _QuerySet.
+if connection.features.uses_custom_queryset:
+ QuerySet = connection.ops.query_set_class(_QuerySet)
else:
QuerySet = _QuerySet
@@ -578,28 +582,38 @@ class ValuesQuerySet(QuerySet):
except EmptyResultSet:
raise StopIteration
- # self._fields is a list of field names to fetch.
+ qn = connection.ops.quote_name
+
+ # self._select is a dictionary, and dictionaries' key order is
+ # undefined, so we convert it to a list of tuples.
+ extra_select = self._select.items()
+
+ # Construct two objects -- fields and field_names.
+ # fields is a list of Field objects to fetch.
+ # field_names is a list of field names, which will be the keys in the
+ # resulting dictionaries.
if self._fields:
- if not self._select:
+ if not extra_select:
fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields]
+ field_names = self._fields
else:
fields = []
+ field_names = []
for f in self._fields:
if f in [field.name for field in self.model._meta.fields]:
fields.append(self.model._meta.get_field(f, many_to_many=False))
- elif not self._select.has_key( f ):
- raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f )
-
- field_names = self._fields
+ field_names.append(f)
+ elif not self._select.has_key(f):
+ raise FieldDoesNotExist('%s has no field named %r' % (self.model._meta.object_name, f))
else: # Default to all fields.
fields = self.model._meta.fields
field_names = [f.attname for f in fields]
columns = [f.column for f in fields]
- select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
- # Add any additional SELECTs.
- if self._select:
- select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
+ select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c)) for c in columns]
+ if extra_select:
+ select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select])
+ field_names.extend([f[0] for f in extra_select])
cursor = connection.cursor()
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
@@ -623,32 +637,33 @@ class DateQuerySet(QuerySet):
def iterator(self):
from django.db.backends.util import typecast_timestamp
from django.db.models.fields import DateTimeField
+
+ qn = connection.ops.quote_name
self._order_by = () # Clear this because it'll mess things up otherwise.
if self._field.null:
self._where.append('%s.%s IS NOT NULL' % \
- (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
+ (qn(self.model._meta.db_table), qn(self._field.column)))
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
- table_name = backend.quote_name(self.model._meta.db_table)
- field_name = backend.quote_name(self._field.column)
+ table_name = qn(self.model._meta.db_table)
+ field_name = qn(self._field.column)
- if backend.allows_group_by_ordinal:
+ if connection.features.allows_group_by_ordinal:
group_by = '1'
else:
- group_by = backend.get_date_trunc_sql(self._kind,
- '%s.%s' % (table_name, field_name))
+ group_by = connection.ops.date_trunc_sql(self._kind, '%s.%s' % (table_name, field_name))
sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \
- (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
- backend.quote_name(self._field.column))), sql, group_by, self._order)
+ (connection.ops.date_trunc_sql(self._kind, '%s.%s' % (qn(self.model._meta.db_table),
+ qn(self._field.column))), sql, group_by, self._order)
cursor = connection.cursor()
cursor.execute(sql, params)
has_resolve_columns = hasattr(self, 'resolve_columns')
- needs_datetime_string_cast = backend.needs_datetime_string_cast
+ needs_datetime_string_cast = connection.features.needs_datetime_string_cast
dates = []
# It would be better to use self._field here instead of DateTimeField(),
# but in Oracle that will result in a list of datetime.date instead of
@@ -768,44 +783,44 @@ class QNot(Q):
return SortedDict(), [], []
return joins, where2, params
-def get_where_clause(lookup_type, table_prefix, field_name, value):
+def get_where_clause(lookup_type, table_prefix, field_name, value, db_type):
if table_prefix.endswith('.'):
- table_prefix = backend.quote_name(table_prefix[:-1])+'.'
- field_name = backend.quote_name(field_name)
- if type(value) == datetime.datetime and backend.get_datetime_cast_sql():
- cast_sql = backend.get_datetime_cast_sql()
+ table_prefix = connection.ops.quote_name(table_prefix[:-1])+'.'
+ field_name = connection.ops.quote_name(field_name)
+ if type(value) == datetime.datetime and connection.ops.datetime_cast_sql():
+ cast_sql = connection.ops.datetime_cast_sql()
else:
cast_sql = '%s'
- if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith') and backend.needs_upper_for_iops:
- format = 'UPPER(%s%s) %s'
+ field_sql = connection.ops.field_cast_sql(db_type) % (table_prefix + field_name)
+ if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith') and connection.features.needs_upper_for_iops:
+ format = 'UPPER(%s) %s'
else:
- format = '%s%s %s'
+ format = '%s %s'
try:
- return format % (table_prefix, field_name,
- backend.OPERATOR_MAPPING[lookup_type] % cast_sql)
+ return format % (field_sql, connection.operators[lookup_type] % cast_sql)
except KeyError:
pass
if lookup_type == 'in':
in_string = ','.join(['%s' for id in value])
if in_string:
- return '%s%s IN (%s)' % (table_prefix, field_name, in_string)
+ return '%s IN (%s)' % (field_sql, in_string)
else:
raise EmptyResultSet
elif lookup_type in ('range', 'year'):
- return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name)
+ return '%s BETWEEN %%s AND %%s' % field_sql
elif lookup_type in ('month', 'day'):
- return "%s = %%s" % backend.get_date_extract_sql(lookup_type, table_prefix + field_name)
+ return "%s = %%s" % connection.ops.date_extract_sql(lookup_type, field_sql)
elif lookup_type == 'isnull':
- return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or ''))
+ return "%s IS %sNULL" % (field_sql, (not value and 'NOT ' or ''))
elif lookup_type == 'search':
- return backend.get_fulltext_search_sql(table_prefix + field_name)
+ return connection.ops.fulltext_search_sql(field_sql)
elif lookup_type in ('regex', 'iregex'):
if settings.DATABASE_ENGINE == 'oracle':
if lookup_type == 'regex':
match_option = 'c'
else:
match_option = 'i'
- return "REGEXP_LIKE(%s%s, %s, '%s')" % (table_prefix, field_name, cast_sql, match_option)
+ return "REGEXP_LIKE(%s, %s, '%s')" % (field_sql, cast_sql, match_option)
else:
raise NotImplementedError
raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
@@ -837,7 +852,7 @@ def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen,
if max_depth and cur_depth > max_depth:
return None
- qn = backend.quote_name
+ qn = connection.ops.quote_name
for f in opts.fields:
if f.rel and not f.null:
db_table = f.rel.to._meta.db_table
@@ -935,7 +950,7 @@ def field_choices(field_list, related_query):
return choices
def lookup_inner(path, lookup_type, value, opts, table, column):
- qn = backend.quote_name
+ qn = connection.ops.quote_name
joins, where, params = SortedDict(), [], []
current_opts = opts
current_table = table
@@ -1062,6 +1077,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
else:
# No elements left in path. Current element is the element on which
# the search is being performed.
+ db_type = None
if join_required:
# Last query term is a RelatedObject
@@ -1091,15 +1107,16 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
else:
# Last query term was a normal field.
column = field.column
+ db_type = field.db_type()
- where.append(get_where_clause(lookup_type, current_table + '.', column, value))
+ where.append(get_where_clause(lookup_type, current_table + '.', column, value, db_type))
params.extend(field.get_db_prep_lookup(lookup_type, value))
return joins, where, params
def delete_objects(seen_objs):
"Iterate through a list of seen classes, and remove any instances that are referred to"
- qn = backend.quote_name
+ qn = connection.ops.quote_name
ordered_classes = seen_objs.keys()
ordered_classes.reverse()
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 1b2abe5049..7cd47481dc 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -1,8 +1,9 @@
import os
from Cookie import SimpleCookie
from pprint import pformat
-from urllib import urlencode, quote
-from django.utils.datastructures import MultiValueDict
+from urllib import urlencode
+from django.utils.datastructures import MultiValueDict, FileDict
+from django.utils.encoding import smart_str, iri_to_uri, force_unicode
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
@@ -17,6 +18,10 @@ class Http404(Exception):
class HttpRequest(object):
"A basic HTTP request"
+
+ # The encoding used in GET/POST dicts. None means use default setting.
+ _encoding = None
+
def __init__(self):
self.GET, self.POST, self.COOKIES, self.META, self.FILES = {}, {}, {}, {}, {}
self.path = ''
@@ -42,14 +47,31 @@ class HttpRequest(object):
def is_secure(self):
return os.environ.get("HTTPS") == "on"
+ def _set_encoding(self, val):
+ """
+ Sets the encoding used for GET/POST accesses. If the GET or POST
+ dictionary has already been created, it is removed and recreated on the
+ next access (so that it is decoded correctly).
+ """
+ self._encoding = val
+ if hasattr(self, '_get'):
+ del self._get
+ if hasattr(self, '_post'):
+ del self._post
+
+ def _get_encoding(self):
+ return self._encoding
+
+ encoding = property(_get_encoding, _set_encoding)
+
def parse_file_upload(header_dict, post_data):
- "Returns a tuple of (POST MultiValueDict, FILES MultiValueDict)"
+ "Returns a tuple of (POST QueryDict, FILES MultiValueDict)"
import email, email.Message
from cgi import parse_header
raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()])
raw_message += '\r\n\r\n' + post_data
msg = email.message_from_string(raw_message)
- POST = MultiValueDict()
+ POST = QueryDict('', mutable=True)
FILES = MultiValueDict()
for submessage in msg.get_payload():
if submessage and isinstance(submessage, email.Message.Message):
@@ -62,25 +84,38 @@ def parse_file_upload(header_dict, post_data):
if not name_dict['filename'].strip():
continue
# IE submits the full path, so trim everything but the basename.
- # (We can't use os.path.basename because it expects Linux paths.)
+ # (We can't use os.path.basename because that uses the server's
+ # directory separator, which may not be the same as the
+ # client's one.)
filename = name_dict['filename'][name_dict['filename'].rfind("\\")+1:]
- FILES.appendlist(name_dict['name'], {
+ FILES.appendlist(name_dict['name'], FileDict({
'filename': filename,
'content-type': 'Content-Type' in submessage and submessage['Content-Type'] or None,
'content': submessage.get_payload(),
- })
+ }))
else:
POST.appendlist(name_dict['name'], submessage.get_payload())
return POST, FILES
class QueryDict(MultiValueDict):
- """A specialized MultiValueDict that takes a query string when initialized.
- This is immutable unless you create a copy of it."""
- def __init__(self, query_string, mutable=False):
+ """
+ A specialized MultiValueDict that takes a query string when initialized.
+ This is immutable unless you create a copy of it.
+
+ Values retrieved from this class are converted from the given encoding
+ (DEFAULT_CHARSET by default) to unicode.
+ """
+ def __init__(self, query_string, mutable=False, encoding=None):
MultiValueDict.__init__(self)
+ if not encoding:
+ # *Important*: do not import settings any earlier because of note
+ # in core.handlers.modpython.
+ from django.conf import settings
+ encoding = settings.DEFAULT_CHARSET
+ self.encoding = encoding
self._mutable = True
for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True
- self.appendlist(key, value)
+ self.appendlist(force_unicode(key, encoding, errors='replace'), force_unicode(value, encoding, errors='replace'))
self._mutable = mutable
def _assert_mutable(self):
@@ -89,6 +124,8 @@ class QueryDict(MultiValueDict):
def __setitem__(self, key, value):
self._assert_mutable()
+ key = str_to_unicode(key, self.encoding)
+ value = str_to_unicode(value, self.encoding)
MultiValueDict.__setitem__(self, key, value)
def __delitem__(self, key):
@@ -111,15 +148,27 @@ class QueryDict(MultiValueDict):
def setlist(self, key, list_):
self._assert_mutable()
+ key = str_to_unicode(key, self.encoding)
+ list_ = [str_to_unicode(elt, self.encoding) for elt in list_]
MultiValueDict.setlist(self, key, list_)
+ def setlistdefault(self, key, default_list=()):
+ self._assert_mutable()
+ if key not in self:
+ self.setlist(key, default_list)
+ return MultiValueDict.getlist(self, key)
+
def appendlist(self, key, value):
self._assert_mutable()
+ key = str_to_unicode(key, self.encoding)
+ value = str_to_unicode(value, self.encoding)
MultiValueDict.appendlist(self, key, value)
def update(self, other_dict):
self._assert_mutable()
- MultiValueDict.update(self, other_dict)
+ f = lambda s: str_to_unicode(s, self.encoding)
+ d = dict([(f(k), f(v)) for k, v in other_dict.items()])
+ MultiValueDict.update(self, d)
def pop(self, key, *args):
self._assert_mutable()
@@ -133,9 +182,11 @@ class QueryDict(MultiValueDict):
self._assert_mutable()
MultiValueDict.clear(self)
- def setdefault(self, *args):
+ def setdefault(self, key, default=None):
self._assert_mutable()
- return MultiValueDict.setdefault(self, *args)
+ key = str_to_unicode(key, self.encoding)
+ default = str_to_unicode(default, self.encoding)
+ return MultiValueDict.setdefault(self, key, default)
def copy(self):
"Returns a mutable copy of this object."
@@ -144,7 +195,8 @@ class QueryDict(MultiValueDict):
def urlencode(self):
output = []
for k, list_ in self.lists():
- output.extend([urlencode({k: v}) for v in list_])
+ k = smart_str(k, self.encoding)
+ output.extend([urlencode({k: smart_str(v, self.encoding)}) for v in list_])
return '&'.join(output)
def parse_cookie(cookie):
@@ -162,18 +214,22 @@ class HttpResponse(object):
status_code = 200
- def __init__(self, content='', mimetype=None, status=None):
+ def __init__(self, content='', mimetype=None, status=None,
+ content_type=None):
from django.conf import settings
self._charset = settings.DEFAULT_CHARSET
- if not mimetype:
- mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET)
+ if mimetype:
+ content_type = mimetype # For backwards compatibility
+ if not content_type:
+ content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
+ settings.DEFAULT_CHARSET)
if not isinstance(content, basestring) and hasattr(content, '__iter__'):
self._container = content
self._is_string = False
else:
self._container = [content]
self._is_string = True
- self.headers = {'Content-Type': mimetype}
+ self.headers = {'Content-Type': content_type}
self.cookies = SimpleCookie()
if status:
self.status_code = status
@@ -221,9 +277,7 @@ class HttpResponse(object):
self.cookies[key]['max-age'] = 0
def _get_content(self):
- content = ''.join(self._container)
- if isinstance(content, unicode):
- content = content.encode(self._charset)
+ content = smart_str(''.join(self._container), self._charset)
return content
def _set_content(self, value):
@@ -266,14 +320,14 @@ class HttpResponseRedirect(HttpResponse):
def __init__(self, redirect_to):
HttpResponse.__init__(self)
- self['Location'] = quote(redirect_to, safe=RESERVED_CHARS)
+ self['Location'] = iri_to_uri(redirect_to)
class HttpResponsePermanentRedirect(HttpResponse):
status_code = 301
def __init__(self, redirect_to):
HttpResponse.__init__(self)
- self['Location'] = quote(redirect_to, safe=RESERVED_CHARS)
+ self['Location'] = iri_to_uri(redirect_to)
class HttpResponseNotModified(HttpResponse):
status_code = 304
@@ -312,3 +366,20 @@ def get_host(request):
if not host:
host = request.META.get('HTTP_HOST', '')
return host
+
+# It's neither necessary nor appropriate to use
+# django.utils.encoding.smart_unicode for parsing URLs and form inputs. Thus,
+# this slightly more restricted function.
+def str_to_unicode(s, encoding):
+ """
+ Convert basestring objects to unicode, using the given encoding. Illegaly
+ encoded input characters are replaced with Unicode "unknown" codepoint
+ (\ufffd).
+
+ Returns any non-basestring objects without change.
+ """
+ if isinstance(s, str):
+ return unicode(s, encoding, 'replace')
+ else:
+ return s
+
diff --git a/django/middleware/common.py b/django/middleware/common.py
index 9610e1e952..e18ec079af 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -39,7 +39,7 @@ class CommonMiddleware(object):
new_url[0] = 'www.' + old_url[0]
# Append a slash if append_slash is set and the URL doesn't have a
# trailing slash or a file extension.
- if settings.APPEND_SLASH and (old_url[1][-1] != '/') and ('.' not in old_url[1].split('/')[-1]):
+ if settings.APPEND_SLASH and (not old_url[1].endswith('/')) and ('.' not in old_url[1].split('/')[-1]):
new_url[1] = new_url[1] + '/'
if settings.DEBUG and request.method == 'POST':
raise RuntimeError, "You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to %s%s (note the trailing slash), or set APPEND_SLASH=False in your Django settings." % (new_url[0], new_url[1])
@@ -80,7 +80,9 @@ class CommonMiddleware(object):
else:
etag = md5.new(response.content).hexdigest()
if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
+ cookies = response.cookies
response = http.HttpResponseNotModified()
+ response.cookies = cookies
else:
response['ETag'] = etag
diff --git a/django/middleware/gzip.py b/django/middleware/gzip.py
index a7c74481d0..9b2a5f3d22 100644
--- a/django/middleware/gzip.py
+++ b/django/middleware/gzip.py
@@ -11,6 +11,11 @@ class GZipMiddleware(object):
on the Accept-Encoding header.
"""
def process_response(self, request, response):
+ if response.status_code != 200 or len(response.content) < 200:
+ # Not worth compressing really short responses or 304 status
+ # responses, etc.
+ return response
+
patch_vary_headers(response, ('Accept-Encoding',))
# Avoid gzipping if we've already got a content-encoding or if the
diff --git a/django/middleware/http.py b/django/middleware/http.py
index 3ebd8ffd1a..8db3e4a524 100644
--- a/django/middleware/http.py
+++ b/django/middleware/http.py
@@ -1,4 +1,4 @@
-import datetime
+from email.Utils import formatdate
class ConditionalGetMiddleware(object):
"""
@@ -11,8 +11,7 @@ class ConditionalGetMiddleware(object):
Also sets the Date and Content-Length response-headers.
"""
def process_response(self, request, response):
- now = datetime.datetime.utcnow()
- response['Date'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
+ response['Date'] = formatdate()[:26] + "GMT"
if not response.has_header('Content-Length'):
response['Content-Length'] = str(len(response.content))
diff --git a/django/newforms/extras/widgets.py b/django/newforms/extras/widgets.py
index 724dcd9b50..60936a6bd6 100644
--- a/django/newforms/extras/widgets.py
+++ b/django/newforms/extras/widgets.py
@@ -53,8 +53,8 @@ class SelectDateWidget(Widget):
return u'\n'.join(output)
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)
if y and m and d:
return '%s-%s-%s' % (y, m, d)
- return None
+ return data.get(name, None)
diff --git a/django/newforms/fields.py b/django/newforms/fields.py
index cec2ae8317..bb8a3dc582 100644
--- a/django/newforms/fields.py
+++ b/django/newforms/fields.py
@@ -6,18 +6,23 @@ import datetime
import re
import time
-from django.utils.translation import gettext
-from django.utils.encoding import smart_unicode
+from django.utils.translation import ugettext
+from django.utils.encoding import StrAndUnicode, smart_unicode
from util import ErrorList, ValidationError
-from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
+from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
+
+try:
+ from decimal import Decimal, DecimalException
+except ImportError:
+ from django.utils._decimal import Decimal, DecimalException
__all__ = (
'Field', 'CharField', 'IntegerField',
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
- 'RegexField', 'EmailField', 'URLField', 'BooleanField',
+ 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField',
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
'SplitDateTimeField',
@@ -84,7 +89,7 @@ class Field(object):
Raises ValidationError for any errors.
"""
if self.required and value in EMPTY_VALUES:
- raise ValidationError(gettext(u'This field is required.'))
+ raise ValidationError(ugettext(u'This field is required.'))
return value
def widget_attrs(self, widget):
@@ -106,14 +111,16 @@ class CharField(Field):
if value in EMPTY_VALUES:
return u''
value = smart_unicode(value)
- if self.max_length is not None and len(value) > self.max_length:
- raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length)
- if self.min_length is not None and len(value) < self.min_length:
- raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
+ value_length = len(value)
+ if self.max_length is not None and value_length > self.max_length:
+ raise ValidationError(ugettext(u'Ensure this value has at most %(max)d characters (it has %(length)d).') % {'max': self.max_length, 'length': value_length})
+ if self.min_length is not None and value_length < self.min_length:
+ raise ValidationError(ugettext(u'Ensure this value has at least %(min)d characters (it has %(length)d).') % {'min': self.min_length, 'length': value_length})
return value
def widget_attrs(self, widget):
if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
+ # The HTML attribute is maxlength, not max_length.
return {'maxlength': str(self.max_length)}
class IntegerField(Field):
@@ -132,11 +139,11 @@ class IntegerField(Field):
try:
value = int(value)
except (ValueError, TypeError):
- raise ValidationError(gettext(u'Enter a whole number.'))
+ raise ValidationError(ugettext(u'Enter a whole number.'))
if self.max_value is not None and value > self.max_value:
- raise ValidationError(gettext(u'Ensure this value is less than or equal to %s.') % self.max_value)
+ raise ValidationError(ugettext(u'Ensure this value is less than or equal to %s.') % self.max_value)
if self.min_value is not None and value < self.min_value:
- raise ValidationError(gettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
+ raise ValidationError(ugettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
return value
class FloatField(Field):
@@ -155,15 +162,13 @@ class FloatField(Field):
try:
value = float(value)
except (ValueError, TypeError):
- raise ValidationError(gettext('Enter a number.'))
+ raise ValidationError(ugettext('Enter a number.'))
if self.max_value is not None and value > self.max_value:
- raise ValidationError(gettext('Ensure this value is less than or equal to %s.') % self.max_value)
+ raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
if self.min_value is not None and value < self.min_value:
- raise ValidationError(gettext('Ensure this value is greater than or equal to %s.') % self.min_value)
+ raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
return value
-decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
-
class DecimalField(Field):
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
self.max_value, self.min_value = max_value, min_value
@@ -181,23 +186,23 @@ class DecimalField(Field):
if not self.required and value in EMPTY_VALUES:
return None
value = value.strip()
- match = decimal_re.search(value)
- if not match:
- raise ValidationError(gettext('Enter a number.'))
- else:
+ try:
value = Decimal(value)
- digits = len(match.group('digits') or '')
- decimals = len(match.group('decimals') or '')
+ except DecimalException:
+ raise ValidationError(ugettext('Enter a number.'))
+ pieces = str(value).split('.')
+ decimals = (len(pieces) == 2) and len(pieces[1]) or 0
+ digits = len(pieces[0])
if self.max_value is not None and value > self.max_value:
- raise ValidationError(gettext('Ensure this value is less than or equal to %s.') % self.max_value)
+ raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
if self.min_value is not None and value < self.min_value:
- raise ValidationError(gettext('Ensure this value is greater than or equal to %s.') % self.min_value)
+ raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
if self.max_digits is not None and (digits + decimals) > self.max_digits:
- raise ValidationError(gettext('Ensure that there are no more than %s digits in total.') % self.max_digits)
+ raise ValidationError(ugettext('Ensure that there are no more than %s digits in total.') % self.max_digits)
if self.decimal_places is not None and decimals > self.decimal_places:
- raise ValidationError(gettext('Ensure that there are no more than %s decimal places.') % self.decimal_places)
+ raise ValidationError(ugettext('Ensure that there are no more than %s decimal places.') % self.decimal_places)
if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places):
- raise ValidationError(gettext('Ensure that there are no more than %s digits before the decimal point.') % (self.max_digits - self.decimal_places))
+ raise ValidationError(ugettext('Ensure that there are no more than %s digits before the decimal point.') % (self.max_digits - self.decimal_places))
return value
DEFAULT_DATE_INPUT_FORMATS = (
@@ -230,7 +235,7 @@ class DateField(Field):
return datetime.date(*time.strptime(value, format)[:3])
except ValueError:
continue
- raise ValidationError(gettext(u'Enter a valid date.'))
+ raise ValidationError(ugettext(u'Enter a valid date.'))
DEFAULT_TIME_INPUT_FORMATS = (
'%H:%M:%S', # '14:30:59'
@@ -257,7 +262,7 @@ class TimeField(Field):
return datetime.time(*time.strptime(value, format)[3:6])
except ValueError:
continue
- raise ValidationError(gettext(u'Enter a valid time.'))
+ raise ValidationError(ugettext(u'Enter a valid time.'))
DEFAULT_DATETIME_INPUT_FORMATS = (
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
@@ -293,37 +298,29 @@ class DateTimeField(Field):
return datetime.datetime(*time.strptime(value, format)[:6])
except ValueError:
continue
- raise ValidationError(gettext(u'Enter a valid date/time.'))
+ raise ValidationError(ugettext(u'Enter a valid date/time.'))
-class RegexField(Field):
+class RegexField(CharField):
def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
"""
regex can be either a string or a compiled regular expression object.
error_message is an optional error message to use, if
'Enter a valid value' is too generic for you.
"""
- super(RegexField, self).__init__(*args, **kwargs)
+ super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
if isinstance(regex, basestring):
regex = re.compile(regex)
self.regex = regex
- self.max_length, self.min_length = max_length, min_length
- self.error_message = error_message or gettext(u'Enter a valid value.')
+ self.error_message = error_message or ugettext(u'Enter a valid value.')
def clean(self, value):
"""
Validates that the input matches the regular expression. Returns a
Unicode object.
"""
- super(RegexField, self).clean(value)
- if value in EMPTY_VALUES:
- value = u''
- value = smart_unicode(value)
+ value = super(RegexField, self).clean(value)
if value == u'':
return value
- if self.max_length is not None and len(value) > self.max_length:
- raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length)
- if self.min_length is not None and len(value) < self.min_length:
- raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
if not self.regex.search(value):
raise ValidationError(self.error_message)
return value
@@ -336,7 +333,7 @@ email_re = re.compile(
class EmailField(RegexField):
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
RegexField.__init__(self, email_re, max_length, min_length,
- gettext(u'Enter a valid e-mail address.'), *args, **kwargs)
+ ugettext(u'Enter a valid e-mail address.'), *args, **kwargs)
url_re = re.compile(
r'^https?://' # http:// or https://
@@ -347,14 +344,63 @@ url_re = re.compile(
try:
from django.conf import settings
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
-except ImportError:
+except (ImportError, EnvironmentError):
# It's OK if Django settings aren't configured.
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
+class UploadedFile(StrAndUnicode):
+ "A wrapper for files uploaded in a FileField"
+ def __init__(self, filename, content):
+ self.filename = filename
+ self.content = content
+
+ def __unicode__(self):
+ """
+ The unicode representation is the filename, so that the pre-database-insertion
+ logic can use UploadedFile objects
+ """
+ return self.filename
+
+class FileField(Field):
+ widget = FileInput
+ def __init__(self, *args, **kwargs):
+ super(FileField, self).__init__(*args, **kwargs)
+
+ def clean(self, data):
+ super(FileField, self).clean(data)
+ if not self.required and data in EMPTY_VALUES:
+ return None
+ try:
+ f = UploadedFile(data['filename'], data['content'])
+ except TypeError:
+ raise ValidationError(ugettext(u"No file was submitted. Check the encoding type on the form."))
+ except KeyError:
+ raise ValidationError(ugettext(u"No file was submitted."))
+ if not f.content:
+ raise ValidationError(ugettext(u"The submitted file is empty."))
+ return f
+
+class ImageField(FileField):
+ def clean(self, data):
+ """
+ Checks that the file-upload field data contains a valid image (GIF, JPG,
+ PNG, possibly others -- whatever the Python Imaging Library supports).
+ """
+ f = super(ImageField, self).clean(data)
+ if f is None:
+ return None
+ from PIL import Image
+ from cStringIO import StringIO
+ try:
+ Image.open(StringIO(f.content))
+ except IOError: # Python Imaging Library doesn't recognize it as an image
+ raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))
+ return f
+
class URLField(RegexField):
def __init__(self, max_length=None, min_length=None, verify_exists=False,
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
- super(URLField, self).__init__(url_re, max_length, min_length, gettext(u'Enter a valid URL.'), *args, **kwargs)
+ super(URLField, self).__init__(url_re, max_length, min_length, ugettext(u'Enter a valid URL.'), *args, **kwargs)
self.verify_exists = verify_exists
self.user_agent = validator_user_agent
@@ -376,9 +422,9 @@ class URLField(RegexField):
req = urllib2.Request(value, None, headers)
u = urllib2.urlopen(req)
except ValueError:
- raise ValidationError(gettext(u'Enter a valid URL.'))
+ raise ValidationError(ugettext(u'Enter a valid URL.'))
except: # urllib2.URLError, httplib.InvalidURL, etc.
- raise ValidationError(gettext(u'This URL appears to be a broken link.'))
+ raise ValidationError(ugettext(u'This URL appears to be a broken link.'))
return value
class BooleanField(Field):
@@ -427,9 +473,9 @@ class ChoiceField(Field):
value = smart_unicode(value)
if value == u'':
return value
- valid_values = set([str(k) for k, v in self.choices])
+ valid_values = set([smart_unicode(k) for k, v in self.choices])
if value not in valid_values:
- raise ValidationError(gettext(u'Select a valid choice. That choice is not one of the available choices.'))
+ raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
return value
class MultipleChoiceField(ChoiceField):
@@ -441,20 +487,17 @@ class MultipleChoiceField(ChoiceField):
Validates that the input is a list or tuple.
"""
if self.required and not value:
- raise ValidationError(gettext(u'This field is required.'))
+ raise ValidationError(ugettext(u'This field is required.'))
elif not self.required and not value:
return []
if not isinstance(value, (list, tuple)):
- raise ValidationError(gettext(u'Enter a list of values.'))
- new_value = []
- for val in value:
- val = smart_unicode(val)
- new_value.append(val)
+ raise ValidationError(ugettext(u'Enter a list of values.'))
+ new_value = [smart_unicode(val) for val in value]
# Validate that each value in the value list is in self.choices.
valid_values = set([smart_unicode(k) for k, v in self.choices])
for val in new_value:
if val not in valid_values:
- raise ValidationError(gettext(u'Select a valid choice. %s is not one of the available choices.') % val)
+ raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
return new_value
class ComboField(Field):
@@ -520,18 +563,18 @@ class MultiValueField(Field):
if not value or isinstance(value, (list, tuple)):
if not value or not [v for v in value if v not in EMPTY_VALUES]:
if self.required:
- raise ValidationError(gettext(u'This field is required.'))
+ raise ValidationError(ugettext(u'This field is required.'))
else:
return self.compress([])
else:
- raise ValidationError(gettext(u'Enter a list of values.'))
+ raise ValidationError(ugettext(u'Enter a list of values.'))
for i, field in enumerate(self.fields):
try:
field_value = value[i]
except IndexError:
field_value = None
if self.required and field_value in EMPTY_VALUES:
- raise ValidationError(gettext(u'This field is required.'))
+ raise ValidationError(ugettext(u'This field is required.'))
try:
clean_data.append(field.clean(field_value))
except ValidationError, e:
@@ -564,8 +607,8 @@ class SplitDateTimeField(MultiValueField):
# Raise a validation error if time or date is empty
# (possible if SplitDateTimeField has required=False).
if data_list[0] in EMPTY_VALUES:
- raise ValidationError(gettext(u'Enter a valid date.'))
+ raise ValidationError(ugettext(u'Enter a valid date.'))
if data_list[1] in EMPTY_VALUES:
- raise ValidationError(gettext(u'Enter a valid time.'))
+ raise ValidationError(ugettext(u'Enter a valid time.'))
return datetime.datetime.combine(*data_list)
return None
diff --git a/django/newforms/forms.py b/django/newforms/forms.py
index 1ea1c73d9a..906978c86f 100644
--- a/django/newforms/forms.py
+++ b/django/newforms/forms.py
@@ -6,7 +6,7 @@ import copy
from django.utils.datastructures import SortedDict
from django.utils.html import escape
-from django.utils.encoding import StrAndUnicode
+from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
from fields import Field
from widgets import TextInput, Textarea
@@ -57,9 +57,10 @@ class BaseForm(StrAndUnicode):
# class is different than Form. See the comments by the Form class for more
# information. Any improvements to the form API should be made to *this*
# class, not to the Form class.
- def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None):
- self.is_bound = data is not None
+ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None):
+ self.is_bound = data is not None or files is not None
self.data = data or {}
+ self.files = files or {}
self.auto_id = auto_id
self.prefix = prefix
self.initial = initial or {}
@@ -88,7 +89,7 @@ class BaseForm(StrAndUnicode):
return BoundField(self, field, name)
def _get_errors(self):
- "Returns an ErrorDict for self.data"
+ "Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
@@ -119,13 +120,13 @@ class BaseForm(StrAndUnicode):
bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
if bf.is_hidden:
if bf_errors:
- top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
+ top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
hidden_fields.append(unicode(bf))
else:
if errors_on_separate_row and bf_errors:
- output.append(error_row % bf_errors)
+ output.append(error_row % force_unicode(bf_errors))
if bf.label:
- label = escape(bf.label)
+ label = escape(force_unicode(bf.label))
# Only add a colon if the label does not end in punctuation.
if label[-1] not in ':?.!':
label += ':'
@@ -133,10 +134,10 @@ class BaseForm(StrAndUnicode):
else:
label = ''
if field.help_text:
- help_text = help_text_html % field.help_text
+ help_text = help_text_html % force_unicode(field.help_text)
else:
help_text = u''
- output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
+ output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text})
if top_errors:
output.insert(0, error_row % top_errors)
if hidden_fields: # Insert any hidden fields in the last row.
@@ -179,10 +180,10 @@ class BaseForm(StrAndUnicode):
return
self.cleaned_data = {}
for name, field in self.fields.items():
- # value_from_datadict() gets the data from the dictionary.
+ # value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
- value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
+ value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
value = field.clean(value)
self.cleaned_data[name] = value
@@ -232,16 +233,8 @@ class BoundField(StrAndUnicode):
self.help_text = field.help_text or ''
def __unicode__(self):
- "Renders this field as an HTML widget."
- # Use the 'widget' attribute on the field to determine which type
- # of HTML widget to use.
- value = self.as_widget(self.field.widget)
- if not isinstance(value, basestring):
- # Some Widget render() methods -- notably RadioSelect -- return a
- # "special" object rather than a string. Call __unicode__() on that
- # object to get its rendered value.
- value = unicode(value)
- return value
+ """Renders this field as an HTML widget."""
+ return self.as_widget()
def _errors(self):
"""
@@ -251,7 +244,14 @@ class BoundField(StrAndUnicode):
return self.form.errors.get(self.name, ErrorList())
errors = property(_errors)
- def as_widget(self, widget, attrs=None):
+ def as_widget(self, widget=None, attrs=None):
+ """
+ Renders the field by rendering the passed widget, adding any HTML
+ attributes passed as attrs. If no widget is specified, then the
+ field's default widget will be used.
+ """
+ if not widget:
+ widget = self.field.widget
attrs = attrs or {}
auto_id = self.auto_id
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
@@ -284,7 +284,7 @@ class BoundField(StrAndUnicode):
"""
Returns the data for this BoundField, or None if it wasn't given.
"""
- return self.field.widget.value_from_datadict(self.form.data, self.html_name)
+ return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
data = property(_data)
def label_tag(self, contents=None, attrs=None):
@@ -314,8 +314,8 @@ class BoundField(StrAndUnicode):
associated Form has specified auto_id. Returns an empty string otherwise.
"""
auto_id = self.form.auto_id
- if auto_id and '%s' in str(auto_id):
- return str(auto_id) % self.html_name
+ if auto_id and '%s' in smart_unicode(auto_id):
+ return smart_unicode(auto_id) % self.html_name
elif auto_id:
return self.html_name
return ''
diff --git a/django/newforms/models.py b/django/newforms/models.py
index d51b06c78c..247a0eea6b 100644
--- a/django/newforms/models.py
+++ b/django/newforms/models.py
@@ -3,7 +3,9 @@ Helper functions for creating Form classes from Django models
and database field objects.
"""
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
+from django.utils.encoding import smart_unicode
+
from util import ValidationError
from forms import BaseForm, SortedDictFromList
@@ -32,18 +34,24 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
continue
if fields and f.name not in fields:
continue
- setattr(instance, f.name, cleaned_data[f.name])
- if commit:
- instance.save()
+ f.save_form_data(instance, cleaned_data[f.name])
+ # Wrap up the saving of m2m data as a function
+ def save_m2m():
+ opts = instance.__class__._meta
+ cleaned_data = form.cleaned_data
for f in opts.many_to_many:
if fields and f.name not in fields:
continue
if f.name in cleaned_data:
- setattr(instance, f.attname, cleaned_data[f.name])
- # GOTCHA: If many-to-many data is given and commit=False, the many-to-many
- # data will be lost. This happens because a many-to-many options cannot be
- # set on an object until after it's saved. Maybe we should raise an
- # exception in that case.
+ f.save_form_data(instance, cleaned_data[f.name])
+ if commit:
+ # If we are committing, save the instance and the m2m data immediately
+ instance.save()
+ save_m2m()
+ else:
+ # We're not committing. Add a method to the form to allow deferred
+ # saving of m2m data
+ form.save_m2m = save_m2m
return instance
def make_model_save(model, fields, fail_message):
@@ -122,7 +130,7 @@ class QuerySetIterator(object):
if self.empty_label is not None:
yield (u"", self.empty_label)
for obj in self.queryset:
- yield (obj._get_pk_val(), str(obj))
+ yield (obj._get_pk_val(), smart_unicode(obj))
# Clear the QuerySet cache if required.
if not self.cache_choices:
self.queryset._result_cache = None
@@ -169,7 +177,7 @@ class ModelChoiceField(ChoiceField):
try:
value = self.queryset.model._default_manager.get(pk=value)
except self.queryset.model.DoesNotExist:
- raise ValidationError(gettext(u'Select a valid choice. That choice is not one of the available choices.'))
+ raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
return value
class ModelMultipleChoiceField(ModelChoiceField):
@@ -182,17 +190,17 @@ class ModelMultipleChoiceField(ModelChoiceField):
def clean(self, value):
if self.required and not value:
- raise ValidationError(gettext(u'This field is required.'))
+ raise ValidationError(ugettext(u'This field is required.'))
elif not self.required and not value:
return []
if not isinstance(value, (list, tuple)):
- raise ValidationError(gettext(u'Enter a list of values.'))
+ raise ValidationError(ugettext(u'Enter a list of values.'))
final_values = []
for val in value:
try:
obj = self.queryset.model._default_manager.get(pk=val)
except self.queryset.model.DoesNotExist:
- raise ValidationError(gettext(u'Select a valid choice. %s is not one of the available choices.') % val)
+ raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
else:
final_values.append(obj)
return final_values
diff --git a/django/newforms/util.py b/django/newforms/util.py
index 891585cba2..2bafc8d9c7 100644
--- a/django/newforms/util.py
+++ b/django/newforms/util.py
@@ -1,5 +1,5 @@
from django.utils.html import escape
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_unicode, StrAndUnicode
def flatatt(attrs):
"""
@@ -10,36 +10,36 @@ def flatatt(attrs):
"""
return u''.join([u' %s="%s"' % (k, escape(v)) for k, v in attrs.items()])
-class ErrorDict(dict):
+class ErrorDict(dict, StrAndUnicode):
"""
A collection of errors that knows how to display itself in various formats.
The dictionary keys are the field names, and the values are the errors.
"""
- def __str__(self):
+ def __unicode__(self):
return self.as_ul()
def as_ul(self):
if not self: return u''
- return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s%s</li>' % (k, v) for k, v in self.items()])
+ return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s%s</li>' % (k, smart_unicode(v)) for k, v in self.items()])
def as_text(self):
- return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % i for i in v])) for k, v in self.items()])
+ return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % smart_unicode(i) for i in v])) for k, v in self.items()])
-class ErrorList(list):
+class ErrorList(list, StrAndUnicode):
"""
A collection of errors that knows how to display itself in various formats.
"""
- def __str__(self):
+ def __unicode__(self):
return self.as_ul()
def as_ul(self):
if not self: return u''
- return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s</li>' % e for e in self])
+ return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s</li>' % smart_unicode(e) for e in self])
def as_text(self):
if not self: return u''
- return u'\n'.join([u'* %s' % e for e in self])
+ return u'\n'.join([u'* %s' % smart_unicode(e) for e in self])
class ValidationError(Exception):
def __init__(self, message):
diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py
index ecd6dcc9d3..f985124389 100644
--- a/django/newforms/widgets.py
+++ b/django/newforms/widgets.py
@@ -10,8 +10,8 @@ except NameError:
from itertools import chain
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
-from django.utils.translation import gettext
-from django.utils.encoding import StrAndUnicode, smart_unicode
+from django.utils.translation import ugettext
+from django.utils.encoding import StrAndUnicode, force_unicode
from util import flatatt
__all__ = (
@@ -47,7 +47,7 @@ class Widget(object):
attrs.update(extra_attrs)
return attrs
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
"""
Given a dictionary of data and this widget's name, returns the value
of this widget. Returns None if it's not provided.
@@ -77,7 +77,7 @@ class Input(Widget):
def render(self, name, value, attrs=None):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
- if value != '': final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty.
+ if value != '': final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
return u'<input%s />' % flatatt(final_attrs)
class TextInput(Input):
@@ -111,9 +111,9 @@ class MultipleHiddenInput(HiddenInput):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
- return u'\n'.join([(u'<input%s />' % flatatt(dict(value=smart_unicode(v), **final_attrs))) for v in value])
+ return u'\n'.join([(u'<input%s />' % flatatt(dict(value=force_unicode(v), **final_attrs))) for v in value])
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return data.getlist(name)
return data.get(name, None)
@@ -121,6 +121,13 @@ class MultipleHiddenInput(HiddenInput):
class FileInput(Input):
input_type = 'file'
+ def render(self, name, value, attrs=None):
+ return super(FileInput, self).render(name, None, attrs=attrs)
+
+ def value_from_datadict(self, data, files, name):
+ "File widgets take data from FILES, not POST"
+ return files.get(name, None)
+
class Textarea(Widget):
def __init__(self, attrs=None):
# The 'rows' and 'cols' attributes are required for HTML correctness.
@@ -130,7 +137,7 @@ class Textarea(Widget):
def render(self, name, value, attrs=None):
if value is None: value = ''
- value = smart_unicode(value)
+ value = force_unicode(value)
final_attrs = self.build_attrs(attrs, name=name)
return u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))
@@ -150,7 +157,7 @@ class CheckboxInput(Widget):
if result:
final_attrs['checked'] = 'checked'
if value not in ('', True, False, None):
- final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty.
+ final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
return u'<input%s />' % flatatt(final_attrs)
class Select(Widget):
@@ -165,11 +172,11 @@ class Select(Widget):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<select%s>' % flatatt(final_attrs)]
- str_value = smart_unicode(value) # Normalize to string.
+ str_value = force_unicode(value) # Normalize to string.
for option_value, option_label in chain(self.choices, choices):
- option_value = smart_unicode(option_value)
+ option_value = force_unicode(option_value)
selected_html = (option_value == str_value) and u' selected="selected"' or ''
- output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(smart_unicode(option_label))))
+ output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
output.append(u'</select>')
return u'\n'.join(output)
@@ -178,7 +185,7 @@ class NullBooleanSelect(Select):
A Select Widget intended to be used with NullBooleanField.
"""
def __init__(self, attrs=None):
- choices = ((u'1', gettext('Unknown')), (u'2', gettext('Yes')), (u'3', gettext('No')))
+ choices = ((u'1', ugettext('Unknown')), (u'2', ugettext('Yes')), (u'3', ugettext('No')))
super(NullBooleanSelect, self).__init__(attrs, choices)
def render(self, name, value, attrs=None, choices=()):
@@ -188,7 +195,7 @@ class NullBooleanSelect(Select):
value = u'1'
return super(NullBooleanSelect, self).render(name, value, attrs, choices)
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
value = data.get(name, None)
return {u'2': True, u'3': False, True: True, False: False}.get(value, None)
@@ -202,26 +209,30 @@ class SelectMultiple(Widget):
if value is None: value = []
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<select multiple="multiple"%s>' % flatatt(final_attrs)]
- str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
+ str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
for option_value, option_label in chain(self.choices, choices):
- option_value = smart_unicode(option_value)
+ option_value = force_unicode(option_value)
selected_html = (option_value in str_values) and ' selected="selected"' or ''
- output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(smart_unicode(option_label))))
+ output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
output.append(u'</select>')
return u'\n'.join(output)
- def value_from_datadict(self, data, name):
+ def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return data.getlist(name)
return data.get(name, None)
class RadioInput(StrAndUnicode):
- "An object used by RadioFieldRenderer that represents a single <input type='radio'>."
+ """
+ An object used by RadioFieldRenderer that represents a single
+ <input type='radio'>.
+ """
+
def __init__(self, name, value, attrs, choice, index):
self.name, self.value = name, value
self.attrs = attrs
- self.choice_value = smart_unicode(choice[0])
- self.choice_label = smart_unicode(choice[1])
+ self.choice_value = force_unicode(choice[0])
+ self.choice_label = force_unicode(choice[1])
self.index = index
def __unicode__(self):
@@ -239,7 +250,10 @@ class RadioInput(StrAndUnicode):
return u'<input%s />' % flatatt(final_attrs)
class RadioFieldRenderer(StrAndUnicode):
- "An object used by RadioSelect to enable customization of radio widgets."
+ """
+ An object used by RadioSelect to enable customization of radio widgets.
+ """
+
def __init__(self, name, value, attrs, choices):
self.name, self.value, self.attrs = name, value, attrs
self.choices = choices
@@ -253,16 +267,30 @@ class RadioFieldRenderer(StrAndUnicode):
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
def __unicode__(self):
- "Outputs a <ul> for this set of radio fields."
- return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self])
+ return self.render()
+
+ def render(self):
+ """Outputs a <ul> for this set of radio fields."""
+ return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
class RadioSelect(Select):
- def render(self, name, value, attrs=None, choices=()):
- "Returns a RadioFieldRenderer instance rather than a Unicode string."
+
+ def __init__(self, *args, **kwargs):
+ self.renderer = kwargs.pop('renderer', None)
+ if not self.renderer:
+ self.renderer = RadioFieldRenderer
+ super(RadioSelect, self).__init__(*args, **kwargs)
+
+ def get_renderer(self, name, value, attrs=None, choices=()):
+ """Returns an instance of the renderer."""
if value is None: value = ''
- str_value = smart_unicode(value) # Normalize to string.
+ str_value = force_unicode(value) # Normalize to string.
final_attrs = self.build_attrs(attrs)
- return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
+ choices = list(chain(self.choices, choices))
+ return self.renderer(name, str_value, final_attrs, choices)
+
+ def render(self, name, value, attrs=None, choices=()):
+ return self.get_renderer(name, value, attrs, choices).render()
def id_for_label(self, id_):
# RadioSelect is represented by multiple <input type="radio"> fields,
@@ -280,16 +308,16 @@ class CheckboxSelectMultiple(SelectMultiple):
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<ul>']
- str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
+ str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
# If an ID attribute was given, add a numeric index as a suffix,
# so that the checkboxes don't all have the same ID attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
- option_value = smart_unicode(option_value)
+ option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
- output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label))))
+ output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(force_unicode(option_label))))
output.append(u'</ul>')
return u'\n'.join(output)
@@ -356,8 +384,8 @@ class MultiWidget(Widget):
return id_
id_for_label = classmethod(id_for_label)
- def value_from_datadict(self, data, name):
- return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
+ def value_from_datadict(self, data, files, name):
+ return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
def format_output(self, rendered_widgets):
"""
diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py
index 5814eef7ff..93cfa1d8fa 100644
--- a/django/oldforms/__init__.py
+++ b/django/oldforms/__init__.py
@@ -2,7 +2,9 @@ from django.core import validators
from django.core.exceptions import PermissionDenied
from django.utils.html import escape
from django.conf import settings
-from django.utils.translation import gettext, ngettext
+from django.utils.translation import ugettext, ungettext
+from django.utils.encoding import smart_unicode, force_unicode
+from django.utils.maxlength import LegacyMaxlength
FORM_FIELD_ID_PREFIX = 'id_'
@@ -66,7 +68,7 @@ class Manipulator(object):
errors.setdefault(field.field_name, []).extend(e.messages)
# if field.is_required and not new_data.get(field.field_name, False):
-# errors.setdefault(field.field_name, []).append(gettext_lazy('This field is required.'))
+# errors.setdefault(field.field_name, []).append(ugettext_lazy('This field is required.'))
# continue
# try:
# validator_list = field.validator_list
@@ -166,7 +168,11 @@ class FormFieldWrapper(object):
def __str__(self):
"Renders the field"
- return str(self.formfield.render(self.data))
+ return unicode(self).encode('utf-8')
+
+ def __unicode__(self):
+ "Renders the field"
+ return force_unicode(self.formfield.render(self.data))
def __repr__(self):
return '<FormFieldWrapper for "%s">' % self.formfield.field_name
@@ -196,7 +202,10 @@ class FormFieldCollection(FormFieldWrapper):
self.formfield_dict = formfield_dict
def __str__(self):
- return str(self.formfield_dict)
+ return unicode(self).encode('utf-8')
+
+ def __unicode__(self):
+ return unicode(self.formfield_dict)
def __getitem__(self, template_key):
"Look up field by template key; raise KeyError on failure"
@@ -294,8 +303,15 @@ class FormField(object):
Subclasses should also implement a render(data) method, which is responsible
for rending the form field in XHTML.
"""
+ # Provide backwards compatibility for the maxlength attribute and
+ # argument for this class and all subclasses.
+ __metaclass__ = LegacyMaxlength
+
def __str__(self):
- return self.render('')
+ return unicode(self).encode('utf-8')
+
+ def __unicode__(self):
+ return self.render(u'')
def __repr__(self):
return 'FormField "%s"' % self.field_name
@@ -354,7 +370,7 @@ class FormField(object):
def get_validation_errors(self, new_data):
errors = {}
if self.is_required and not new_data.get(self.field_name, False):
- errors.setdefault(self.field_name, []).append(gettext('This field is required.'))
+ errors.setdefault(self.field_name, []).append(ugettext('This field is required.'))
return errors
try:
for validator in self.validator_list:
@@ -378,35 +394,33 @@ class FormField(object):
class TextField(FormField):
input_type = "text"
- def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None):
+ def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
self.field_name = field_name
- self.length, self.maxlength = length, maxlength
+ self.length, self.max_length = length, max_length
self.is_required = is_required
self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list
if member_name != None:
self.member_name = member_name
def isValidLength(self, data, form):
- if data and self.maxlength and len(data.decode(settings.DEFAULT_CHARSET)) > self.maxlength:
- raise validators.ValidationError, ngettext("Ensure your text is less than %s character.",
- "Ensure your text is less than %s characters.", self.maxlength) % self.maxlength
+ if data and self.max_length and len(smart_unicode(data)) > self.max_length:
+ raise validators.ValidationError, ungettext("Ensure your text is less than %s character.",
+ "Ensure your text is less than %s characters.", self.max_length) % self.max_length
def hasNoNewlines(self, data, form):
if data and '\n' in data:
- raise validators.ValidationError, gettext("Line breaks are not allowed here.")
+ raise validators.ValidationError, ugettext("Line breaks are not allowed here.")
def render(self, data):
if data is None:
- data = ''
- maxlength = ''
- if self.maxlength:
- maxlength = 'maxlength="%s" ' % self.maxlength
- if isinstance(data, unicode):
- data = data.encode(settings.DEFAULT_CHARSET)
- return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
- (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
- self.field_name, self.length, escape(data), maxlength)
+ data = u''
+ max_length = u''
+ if self.max_length:
+ max_length = u'maxlength="%s" ' % self.max_length
+ return u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
+ (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and u' required' or '',
+ self.field_name, self.length, escape(data), max_length)
def html2python(data):
return data
@@ -416,22 +430,20 @@ class PasswordField(TextField):
input_type = "password"
class LargeTextField(TextField):
- def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None):
+ def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, max_length=None):
if validator_list is None: validator_list = []
self.field_name = field_name
self.rows, self.cols, self.is_required = rows, cols, is_required
self.validator_list = validator_list[:]
- if maxlength:
+ if max_length:
self.validator_list.append(self.isValidLength)
- self.maxlength = maxlength
+ self.max_length = max_length
def render(self, data):
if data is None:
data = ''
- if isinstance(data, unicode):
- data = data.encode(settings.DEFAULT_CHARSET)
- return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \
- (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
+ return u'<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \
+ (self.get_id(), self.__class__.__name__, self.is_required and u' required' or u'',
self.field_name, self.rows, self.cols, escape(data))
class HiddenField(FormField):
@@ -441,7 +453,7 @@ class HiddenField(FormField):
self.validator_list = validator_list[:]
def render(self, data):
- return '<input type="hidden" id="%s" name="%s" value="%s" />' % \
+ return u'<input type="hidden" id="%s" name="%s" value="%s" />' % \
(self.get_id(), self.field_name, escape(data))
class CheckboxField(FormField):
@@ -456,7 +468,7 @@ class CheckboxField(FormField):
checked_html = ''
if data or (data is '' and self.checked_by_default):
checked_html = ' checked="checked"'
- return '<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \
+ return u'<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \
(self.get_id(), self.__class__.__name__,
self.field_name, checked_html)
@@ -471,6 +483,7 @@ class SelectField(FormField):
def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
if choices is None: choices = []
+ choices = [(k, smart_unicode(v, strings_only=True)) for k, v in choices]
self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.size, self.is_required = choices, size, is_required
@@ -479,23 +492,23 @@ class SelectField(FormField):
self.member_name = member_name
def render(self, data):
- output = ['<select id="%s" class="v%s%s" name="%s" size="%s">' % \
+ output = [u'<select id="%s" class="v%s%s" name="%s" size="%s">' % \
(self.get_id(), self.__class__.__name__,
- self.is_required and ' required' or '', self.field_name, self.size)]
- str_data = str(data) # normalize to string
+ self.is_required and u' required' or u'', self.field_name, self.size)]
+ str_data = smart_unicode(data) # normalize to string
for value, display_name in self.choices:
- selected_html = ''
- if str(value) == str_data:
- selected_html = ' selected="selected"'
- output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name)))
- output.append(' </select>')
- return '\n'.join(output)
+ selected_html = u''
+ if smart_unicode(value) == str_data:
+ selected_html = u' selected="selected"'
+ output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name)))
+ output.append(u' </select>')
+ return u'\n'.join(output)
def isValidChoice(self, data, form):
- str_data = str(data)
- str_choices = [str(item[0]) for item in self.choices]
+ str_data = smart_unicode(data)
+ str_choices = [smart_unicode(item[0]) for item in self.choices]
if str_data not in str_choices:
- raise validators.ValidationError, gettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data': str_data, 'choices': str_choices}
+ raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data': str_data, 'choices': str_choices}
class NullSelectField(SelectField):
"This SelectField converts blank fields to None"
@@ -509,6 +522,7 @@ class RadioSelectField(FormField):
def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
if choices is None: choices = []
+ choices = [(k, smart_unicode(v)) for k, v in choices]
self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.is_required = choices, is_required
@@ -520,7 +534,7 @@ class RadioSelectField(FormField):
def render(self, data):
"""
Returns a special object, RadioFieldRenderer, that is iterable *and*
- has a default str() rendered output.
+ has a default unicode() rendered output.
This allows for flexible use in templates. You can just use the default
rendering:
@@ -537,44 +551,44 @@ class RadioSelectField(FormField):
class RadioFieldRenderer:
def __init__(self, datalist, ul_class):
self.datalist, self.ul_class = datalist, ul_class
- def __str__(self):
- "Default str() output for this radio field -- a <ul>"
- output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')]
- output.extend(['<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist])
- output.append('</ul>')
- return ''.join(output)
+ def __unicode__(self):
+ "Default unicode() output for this radio field -- a <ul>"
+ output = [u'<ul%s>' % (self.ul_class and u' class="%s"' % self.ul_class or u'')]
+ output.extend([u'<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist])
+ output.append(u'</ul>')
+ return u''.join(output)
def __iter__(self):
for d in self.datalist:
yield d
def __len__(self):
return len(self.datalist)
datalist = []
- str_data = str(data) # normalize to string
+ str_data = smart_unicode(data) # normalize to string
for i, (value, display_name) in enumerate(self.choices):
selected_html = ''
- if str(value) == str_data:
- selected_html = ' checked="checked"'
+ if smart_unicode(value) == str_data:
+ selected_html = u' checked="checked"'
datalist.append({
'value': value,
'name': display_name,
- 'field': '<input type="radio" id="%s" name="%s" value="%s"%s/>' % \
- (self.get_id() + '_' + str(i), self.field_name, value, selected_html),
- 'label': '<label for="%s">%s</label>' % \
- (self.get_id() + '_' + str(i), display_name),
+ 'field': u'<input type="radio" id="%s" name="%s" value="%s"%s/>' % \
+ (self.get_id() + u'_' + unicode(i), self.field_name, value, selected_html),
+ 'label': u'<label for="%s">%s</label>' % \
+ (self.get_id() + u'_' + unicode(i), display_name),
})
return RadioFieldRenderer(datalist, self.ul_class)
def isValidChoice(self, data, form):
- str_data = str(data)
- str_choices = [str(item[0]) for item in self.choices]
+ str_data = smart_unicode(data)
+ str_choices = [smart_unicode(item[0]) for item in self.choices]
if str_data not in str_choices:
- raise validators.ValidationError, gettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':str_data, 'choices':str_choices}
+ raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':str_data, 'choices':str_choices}
class NullBooleanField(SelectField):
"This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None"
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
- SelectField.__init__(self, field_name, choices=[('1', _('Unknown')), ('2', _('Yes')), ('3', _('No'))],
+ SelectField.__init__(self, field_name, choices=[('1', ugettext('Unknown')), ('2', ugettext('Yes')), ('3', ugettext('No'))],
is_required=is_required, validator_list=validator_list)
def render(self, data):
@@ -590,24 +604,24 @@ class NullBooleanField(SelectField):
class SelectMultipleField(SelectField):
requires_data_list = True
def render(self, data):
- output = ['<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple">' % \
- (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
+ output = [u'<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple">' % \
+ (self.get_id(), self.__class__.__name__, self.is_required and u' required' or u'',
self.field_name, self.size)]
- str_data_list = map(str, data) # normalize to strings
+ str_data_list = map(smart_unicode, data) # normalize to strings
for value, choice in self.choices:
- selected_html = ''
- if str(value) in str_data_list:
- selected_html = ' selected="selected"'
- output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice)))
- output.append(' </select>')
- return '\n'.join(output)
+ selected_html = u''
+ if smart_unicode(value) in str_data_list:
+ selected_html = u' selected="selected"'
+ output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice)))
+ output.append(u' </select>')
+ return u'\n'.join(output)
def isValidChoice(self, field_data, all_data):
# data is something like ['1', '2', '3']
- str_choices = [str(item[0]) for item in self.choices]
- for val in map(str, field_data):
+ str_choices = [smart_unicode(item[0]) for item in self.choices]
+ for val in map(smart_unicode, field_data):
if val not in str_choices:
- raise validators.ValidationError, gettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':val, 'choices':str_choices}
+ raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':val, 'choices':str_choices}
def html2python(data):
if data is None:
@@ -642,18 +656,18 @@ class CheckboxSelectMultipleField(SelectMultipleField):
new_data.setlist(self.field_name, data_list)
def render(self, data):
- output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')]
- str_data_list = map(str, data) # normalize to strings
+ output = [u'<ul%s>' % (self.ul_class and u' class="%s"' % self.ul_class or u'')]
+ str_data_list = map(smart_unicode, data) # normalize to strings
for value, choice in self.choices:
- checked_html = ''
- if str(value) in str_data_list:
- checked_html = ' checked="checked"'
- field_name = '%s%s' % (self.field_name, value)
- output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \
+ checked_html = u''
+ if smart_unicode(value) in str_data_list:
+ checked_html = u' checked="checked"'
+ field_name = u'%s%s' % (self.field_name, value)
+ output.append(u'<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \
(self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
self.get_id() + escape(value), choice))
- output.append('</ul>')
- return '\n'.join(output)
+ output.append(u'</ul>')
+ return u'\n'.join(output)
####################
# FILE UPLOADS #
@@ -669,12 +683,12 @@ class FileUploadField(FormField):
try:
content = field_data['content']
except TypeError:
- raise validators.CriticalValidationError, gettext("No file was submitted. Check the encoding type on the form.")
+ raise validators.CriticalValidationError, ugettext("No file was submitted. Check the encoding type on the form.")
if not content:
- raise validators.CriticalValidationError, gettext("The submitted file is empty.")
+ raise validators.CriticalValidationError, ugettext("The submitted file is empty.")
def render(self, data):
- return '<input type="file" id="%s" class="v%s" name="%s" />' % \
+ return u'<input type="file" id="%s" class="v%s" name="%s" />' % \
(self.get_id(), self.__class__.__name__, self.field_name)
def html2python(data):
@@ -700,12 +714,12 @@ class ImageUploadField(FileUploadField):
####################
class IntegerField(TextField):
- def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None):
+ def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
validator_list = [self.isInteger] + validator_list
if member_name is not None:
self.member_name = member_name
- TextField.__init__(self, field_name, length, maxlength, is_required, validator_list)
+ TextField.__init__(self, field_name, length, max_length, is_required, validator_list)
def isInteger(self, field_data, all_data):
try:
@@ -720,57 +734,57 @@ class IntegerField(TextField):
html2python = staticmethod(html2python)
class SmallIntegerField(IntegerField):
- def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=5, max_length=5, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isSmallInteger] + validator_list
- IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
+ IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
def isSmallInteger(self, field_data, all_data):
if not -32768 <= int(field_data) <= 32767:
- raise validators.CriticalValidationError, gettext("Enter a whole number between -32,768 and 32,767.")
+ raise validators.CriticalValidationError, ugettext("Enter a whole number between -32,768 and 32,767.")
class PositiveIntegerField(IntegerField):
- def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isPositive] + validator_list
- IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
+ IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
def isPositive(self, field_data, all_data):
if int(field_data) < 0:
- raise validators.CriticalValidationError, gettext("Enter a positive number.")
+ raise validators.CriticalValidationError, ugettext("Enter a positive number.")
class PositiveSmallIntegerField(IntegerField):
- def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=5, max_length=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isPositiveSmall] + validator_list
- IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
+ IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
def isPositiveSmall(self, field_data, all_data):
if not 0 <= int(field_data) <= 32767:
- raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.")
+ raise validators.CriticalValidationError, ugettext("Enter a whole number between 0 and 32,767.")
class FloatField(TextField):
- def __init__(self, field_name, is_required=False, validator_list=None):
- if validator_list is None: validator_list = []
- validator_list = [validators.isValidFloat] + validator_list
- TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
-
- def html2python(data):
- if data == '' or data is None:
- return None
- return float(data)
- html2python = staticmethod(html2python)
-
-class DecimalField(TextField):
+ def __init__(self, field_name, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
+ validator_list = [validators.isValidFloat] + validator_list
+ TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
+
+ def html2python(data):
+ if data == '' or data is None:
+ return None
+ return float(data)
+ html2python = staticmethod(html2python)
+
+class DecimalField(TextField):
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.max_digits, self.decimal_places = max_digits, decimal_places
- validator_list = [self.isValidDecimal] + validator_list
- # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
- super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
+ validator_list = [self.isValidDecimal] + validator_list
+ # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
+ super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
- def isValidDecimal(self, field_data, all_data):
- v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
+ def isValidDecimal(self, field_data, all_data):
+ v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
try:
v(field_data, all_data)
except validators.ValidationError, e:
@@ -779,14 +793,14 @@ class DecimalField(TextField):
def html2python(data):
if data == '' or data is None:
return None
- try:
- import decimal
+ try:
+ import decimal
except ImportError:
from django.utils import _decimal as decimal
- try:
- return decimal.Decimal(data)
- except decimal.InvalidOperation, e:
- raise ValueError, e
+ try:
+ return decimal.Decimal(data)
+ except decimal.InvalidOperation, e:
+ raise ValueError, e
html2python = staticmethod(html2python)
####################
@@ -796,10 +810,10 @@ class DecimalField(TextField):
class DatetimeField(TextField):
"""A FormField that automatically converts its data to a datetime.datetime object.
The data should be in the format YYYY-MM-DD HH:MM:SS."""
- def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.field_name = field_name
- self.length, self.maxlength = length, maxlength
+ self.length, self.max_length = length, max_length
self.is_required = is_required
self.validator_list = [validators.isValidANSIDatetime] + validator_list
@@ -826,7 +840,7 @@ class DateField(TextField):
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidDate] + validator_list
- TextField.__init__(self, field_name, length=10, maxlength=10,
+ TextField.__init__(self, field_name, length=10, max_length=10,
is_required=is_required, validator_list=validator_list)
def isValidDate(self, field_data, all_data):
@@ -851,7 +865,7 @@ class TimeField(TextField):
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidTime] + validator_list
- TextField.__init__(self, field_name, length=8, maxlength=8,
+ TextField.__init__(self, field_name, length=8, max_length=8,
is_required=is_required, validator_list=validator_list)
def isValidTime(self, field_data, all_data):
@@ -883,10 +897,10 @@ class TimeField(TextField):
class EmailField(TextField):
"A convenience FormField for validating e-mail addresses"
- def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=50, max_length=75, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidEmail] + validator_list
- TextField.__init__(self, field_name, length, maxlength=maxlength,
+ TextField.__init__(self, field_name, length, max_length=max_length,
is_required=is_required, validator_list=validator_list)
def isValidEmail(self, field_data, all_data):
@@ -897,10 +911,10 @@ class EmailField(TextField):
class URLField(TextField):
"A convenience FormField for validating URLs"
- def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=50, max_length=200, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidURL] + validator_list
- TextField.__init__(self, field_name, length=length, maxlength=maxlength,
+ TextField.__init__(self, field_name, length=length, max_length=max_length,
is_required=is_required, validator_list=validator_list)
def isValidURL(self, field_data, all_data):
@@ -910,10 +924,10 @@ class URLField(TextField):
raise validators.CriticalValidationError, e.messages
class IPAddressField(TextField):
- def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None):
+ def __init__(self, field_name, length=15, max_length=15, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidIPAddress] + validator_list
- TextField.__init__(self, field_name, length=length, maxlength=maxlength,
+ TextField.__init__(self, field_name, length=length, max_length=max_length,
is_required=is_required, validator_list=validator_list)
def isValidIPAddress(self, field_data, all_data):
@@ -960,7 +974,7 @@ class PhoneNumberField(TextField):
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidPhone] + validator_list
- TextField.__init__(self, field_name, length=12, maxlength=12,
+ TextField.__init__(self, field_name, length=12, max_length=12,
is_required=is_required, validator_list=validator_list)
def isValidPhone(self, field_data, all_data):
@@ -974,7 +988,7 @@ class USStateField(TextField):
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidUSState] + validator_list
- TextField.__init__(self, field_name, length=2, maxlength=2,
+ TextField.__init__(self, field_name, length=2, max_length=2,
is_required=is_required, validator_list=validator_list)
def isValidUSState(self, field_data, all_data):
@@ -991,10 +1005,10 @@ class USStateField(TextField):
class CommaSeparatedIntegerField(TextField):
"A convenience FormField for validating comma-separated integer fields"
- def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None):
+ def __init__(self, field_name, max_length=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isCommaSeparatedIntegerList] + validator_list
- TextField.__init__(self, field_name, length=20, maxlength=maxlength,
+ TextField.__init__(self, field_name, length=20, max_length=max_length,
is_required=is_required, validator_list=validator_list)
def isCommaSeparatedIntegerList(self, field_data, all_data):
@@ -1005,9 +1019,9 @@ class CommaSeparatedIntegerField(TextField):
def render(self, data):
if data is None:
- data = ''
+ data = u''
elif isinstance(data, (list, tuple)):
- data = ','.join(data)
+ data = u','.join(data)
return super(CommaSeparatedIntegerField, self).render(data)
class RawIdAdminField(CommaSeparatedIntegerField):
diff --git a/django/shortcuts/__init__.py b/django/shortcuts/__init__.py
index 81381d08c1..dfb0c28abd 100644
--- a/django/shortcuts/__init__.py
+++ b/django/shortcuts/__init__.py
@@ -1,32 +1,62 @@
-# This module collects helper functions and classes that "span" multiple levels
-# of MVC. In other words, these functions/classes introduce controlled coupling
-# for convenience's sake.
+"""
+This module collects helper functions and classes that "span" multiple levels
+of MVC. In other words, these functions/classes introduce controlled coupling
+for convenience's sake.
+"""
from django.template import loader
from django.http import HttpResponse, Http404
from django.db.models.manager import Manager
+from django.db.models.query import QuerySet
def render_to_response(*args, **kwargs):
+ """
+ Returns a HttpResponse whose content is filled with the result of calling
+ django.template.loader.render_to_string() with the passed arguments.
+ """
return HttpResponse(loader.render_to_string(*args, **kwargs))
load_and_render = render_to_response # For backwards compatibility.
-def get_object_or_404(klass, *args, **kwargs):
- if isinstance(klass, Manager):
+def _get_queryset(klass):
+ """
+ Returns a QuerySet from a Model, Manager, or QuerySet. Created to make
+ get_object_or_404 and get_list_or_404 more DRY.
+ """
+ if isinstance(klass, QuerySet):
+ return klass
+ elif isinstance(klass, Manager):
manager = klass
- klass = manager.model
else:
manager = klass._default_manager
+ return manager.all()
+
+def get_object_or_404(klass, *args, **kwargs):
+ """
+ Uses get() to return an object, or raises a Http404 exception if the object
+ does not exist.
+
+ klass may be a Model, Manager, or QuerySet object. All other passed
+ arguments and keyword arguments are used in the get() query.
+
+ Note: Like with get(), an AssertionError will be raised if more than one
+ object is found.
+ """
+ queryset = _get_queryset(klass)
try:
- return manager.get(*args, **kwargs)
- except klass.DoesNotExist:
- raise Http404('No %s matches the given query.' % klass._meta.object_name)
+ return queryset.get(*args, **kwargs)
+ except queryset.model.DoesNotExist:
+ raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
def get_list_or_404(klass, *args, **kwargs):
- if isinstance(klass, Manager):
- manager = klass
- else:
- manager = klass._default_manager
- obj_list = list(manager.filter(*args, **kwargs))
+ """
+ Uses filter() to return a list of objects, or raise a Http404 exception if
+ the list is empty.
+
+ klass may be a Model, Manager, or QuerySet object. All other passed
+ arguments and keyword arguments are used in the filter() query.
+ """
+ queryset = _get_queryset(klass)
+ obj_list = list(queryset.filter(*args, **kwargs))
if not obj_list:
- raise Http404('No %s matches the given query.' % manager.model._meta.object_name)
+ raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
return obj_list
diff --git a/django/template/__init__.py b/django/template/__init__.py
index 4cda9bc8d0..6880fd5997 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -58,8 +58,10 @@ import re
from inspect import getargspec
from django.conf import settings
from django.template.context import Context, RequestContext, ContextPopException
-from django.utils.functional import curry
+from django.utils.functional import curry, Promise
from django.utils.text import smart_split
+from django.utils.encoding import smart_unicode, force_unicode
+from django.utils.translation import ugettext as _
__all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@@ -122,6 +124,9 @@ class TemplateSyntaxError(Exception):
class TemplateDoesNotExist(Exception):
pass
+class TemplateEncodingError(Exception):
+ pass
+
class VariableDoesNotExist(Exception):
def __init__(self, msg, params=()):
@@ -155,6 +160,10 @@ class StringOrigin(Origin):
class Template(object):
def __init__(self, template_string, origin=None, name='<Unknown Template>'):
"Compilation stage"
+ try:
+ template_string = smart_unicode(template_string)
+ except UnicodeDecodeError:
+ raise TemplateEncodingError("Templates can only be constructed from unicode or UTF-8 strings.")
if settings.TEMPLATE_DEBUG and origin == None:
origin = StringOrigin(template_string)
# Could do some crazy stack-frame stuff to record where this string
@@ -503,7 +512,7 @@ filter_raw_string = r"""
)?
)""" % {
'str': r"""[^"\\]*(?:\\.[^"\\]*)*""",
- 'var_chars': "A-Za-z0-9\_\." ,
+ 'var_chars': "\w\." ,
'filter_sep': re.escape(FILTER_SEPARATOR),
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
'i18n_open' : re.escape("_("),
@@ -511,7 +520,7 @@ filter_raw_string = r"""
}
filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "")
-filter_re = re.compile(filter_raw_string)
+filter_re = re.compile(filter_raw_string, re.UNICODE)
class FilterExpression(object):
"""
@@ -693,6 +702,13 @@ def resolve_variable(path, context):
else:
raise
del bits[0]
+ if isinstance(current, (basestring, Promise)):
+ try:
+ current = force_unicode(current)
+ except UnicodeDecodeError:
+ # Failing to convert to unicode can happen sometimes (e.g. debug
+ # tracebacks). So we allow it in this particular instance.
+ pass
return current
class Node(object):
@@ -720,7 +736,7 @@ class NodeList(list):
bits.append(self.render_node(node, context))
else:
bits.append(node)
- return ''.join(bits)
+ return ''.join([force_unicode(b) for b in bits])
def get_nodes_by_type(self, nodetype):
"Return a list of all nodes of the given type"
@@ -730,7 +746,7 @@ class NodeList(list):
return nodes
def render_node(self, node, context):
- return(node.render(context))
+ return node.render(context)
class DebugNodeList(NodeList):
def render_node(self, node, context):
@@ -765,32 +781,17 @@ class VariableNode(Node):
def __repr__(self):
return "<Variable Node: %s>" % self.filter_expression
- def encode_output(self, output):
- # Check type so that we don't run str() on a Unicode object
- if not isinstance(output, basestring):
- try:
- return str(output)
- except UnicodeEncodeError:
- # If __str__() returns a Unicode object, convert it to bytestring.
- return unicode(output).encode(settings.DEFAULT_CHARSET)
- elif isinstance(output, unicode):
- return output.encode(settings.DEFAULT_CHARSET)
- else:
- return output
-
def render(self, context):
- output = self.filter_expression.resolve(context)
- return self.encode_output(output)
+ return self.filter_expression.resolve(context)
class DebugVariableNode(VariableNode):
def render(self, context):
try:
- output = self.filter_expression.resolve(context)
+ return self.filter_expression.resolve(context)
except TemplateSyntaxError, e:
if not hasattr(e, 'source'):
e.source = self.source
raise
- return self.encode_output(output)
def generic_tag_compiler(params, defaults, name, node_class, parser, token):
"Returns a template.Node subclass."
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index bbaceba24a..6779b9b5f2 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -2,7 +2,8 @@
from django.template import resolve_variable, Library
from django.conf import settings
-from django.utils.translation import gettext, ngettext
+from django.utils.translation import ugettext, ungettext
+from django.utils.encoding import force_unicode, smart_str, iri_to_uri
import re
import random as random_module
@@ -12,29 +13,18 @@ register = Library()
# STRING DECORATOR #
#######################
-def smart_string(obj):
- # FUTURE: Unicode strings should probably be normalized to a specific
- # encoding and non-unicode strings should be converted to unicode too.
-# if isinstance(obj, unicode):
-# obj = obj.encode(settings.DEFAULT_CHARSET)
-# else:
-# obj = unicode(obj, settings.DEFAULT_CHARSET)
- # FUTURE: Replace dumb string logic below with cool unicode logic above.
- if not isinstance(obj, basestring):
- obj = str(obj)
- return obj
-
def stringfilter(func):
"""
- Decorator for filters which should only receive strings. The object passed
- as the first positional argument will be converted to a string.
+ Decorator for filters which should only receive unicode objects. The object
+ passed as the first positional argument will be converted to a unicode
+ object.
"""
def _dec(*args, **kwargs):
if args:
args = list(args)
- args[0] = smart_string(args[0])
+ args[0] = force_unicode(args[0])
return func(*args, **kwargs)
-
+
# Include a reference to the real function (used to check original
# arguments by the template parser).
_dec._decorated_function = getattr(func, '_decorated_function', func)
@@ -54,7 +44,7 @@ def capfirst(value):
"Capitalizes the first character of the value"
return value and value[0].upper() + value[1:]
capfirst = stringfilter(capfirst)
-
+
def fix_ampersands(value):
"Replaces ampersands with ``&amp;`` entities"
from django.utils.html import fix_ampersands
@@ -83,27 +73,32 @@ def floatformat(text, arg=-1):
try:
f = float(text)
except ValueError:
- return ''
+ return u''
try:
d = int(arg)
except ValueError:
- return smart_string(f)
+ return force_unicode(f)
m = f - int(f)
if not m and d < 0:
- return '%d' % int(f)
+ return u'%d' % int(f)
else:
- formatstr = '%%.%df' % abs(d)
+ formatstr = u'%%.%df' % abs(d)
return formatstr % f
+def iriencode(value):
+ "Escapes an IRI value for use in a URL"
+ return force_unicode(iri_to_uri(value))
+iriencode = stringfilter(iriencode)
+
def linenumbers(value):
"Displays text with line numbers"
from django.utils.html import escape
- lines = value.split('\n')
+ lines = value.split(u'\n')
# Find the maximum width of the line count, for use with zero padding string format command
- width = str(len(str(len(lines))))
+ width = unicode(len(unicode(len(lines))))
for i, line in enumerate(lines):
- lines[i] = ("%0" + width + "d. %s") % (i + 1, escape(line))
- return '\n'.join(lines)
+ lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line))
+ return u'\n'.join(lines)
linenumbers = stringfilter(linenumbers)
def lower(value):
@@ -120,8 +115,13 @@ def make_list(value):
make_list = stringfilter(make_list)
def slugify(value):
- "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
- value = re.sub('[^\w\s-]', '', value).strip().lower()
+ """
+ Normalizes string, converts to lowercase, removes non-alpha chars and
+ converts spaces to hyphens.
+ """
+ import unicodedata
+ value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
+ value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
return re.sub('[-\s]+', '-', value)
slugify = stringfilter(slugify)
@@ -135,9 +135,9 @@ def stringformat(value, arg):
of Python string formatting
"""
try:
- return ("%" + str(arg)) % value
+ return (u"%" + unicode(arg)) % value
except (ValueError, TypeError):
- return ""
+ return u""
def title(value):
"Converts a string into titlecase"
@@ -155,8 +155,6 @@ def truncatewords(value, arg):
length = int(arg)
except ValueError: # invalid literal for int()
return value # Fail silently.
- if not isinstance(value, basestring):
- value = str(value)
return truncate_words(value, length)
truncatewords = stringfilter(truncatewords)
@@ -171,8 +169,6 @@ def truncatewords_html(value, arg):
length = int(arg)
except ValueError: # invalid literal for int()
return value # Fail silently.
- if not isinstance(value, basestring):
- value = str(value)
return truncate_html_words(value, length)
truncatewords_html = stringfilter(truncatewords_html)
@@ -183,10 +179,8 @@ upper = stringfilter(upper)
def urlencode(value):
"Escapes a value for use in a URL"
- import urllib
- if not isinstance(value, basestring):
- value = str(value)
- return urllib.quote(value)
+ from django.utils.http import urlquote
+ return urlquote(value)
urlencode = stringfilter(urlencode)
def urlize(value):
@@ -246,7 +240,7 @@ center = stringfilter(center)
def cut(value, arg):
"Removes all values of arg from the given string"
- return value.replace(arg, '')
+ return value.replace(arg, u'')
cut = stringfilter(cut)
###################
@@ -273,11 +267,11 @@ linebreaksbr = stringfilter(linebreaksbr)
def removetags(value, tags):
"Removes a space separated list of [X]HTML tags from the output"
tags = [re.escape(tag) for tag in tags.split()]
- tags_re = '(%s)' % '|'.join(tags)
- starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re)
- endtag_re = re.compile('</%s>' % tags_re)
- value = starttag_re.sub('', value)
- value = endtag_re.sub('', value)
+ tags_re = u'(%s)' % u'|'.join(tags)
+ starttag_re = re.compile(ur'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U)
+ endtag_re = re.compile(u'</%s>' % tags_re)
+ value = starttag_re.sub(u'', value)
+ value = endtag_re.sub(u'', value)
return value
removetags = stringfilter(removetags)
@@ -296,7 +290,7 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in
the argument.
"""
- decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
+ decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
decorated.sort()
return [item[1] for item in decorated]
@@ -305,7 +299,7 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument.
"""
- decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
+ decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
decorated.sort()
decorated.reverse()
return [item[1] for item in decorated]
@@ -315,12 +309,12 @@ def first(value):
try:
return value[0]
except IndexError:
- return ''
+ return u''
def join(value, arg):
"Joins a list with a string, like Python's ``str.join(list)``"
try:
- return arg.join(map(smart_string, value))
+ return arg.join(map(force_unicode, value))
except AttributeError: # fail silently but nicely
return value
@@ -346,7 +340,7 @@ def slice_(value, arg):
"""
try:
bits = []
- for x in arg.split(':'):
+ for x in arg.split(u':'):
if len(x) == 0:
bits.append(None)
else:
@@ -378,12 +372,12 @@ def unordered_list(value):
</li>
"""
def _helper(value, tabs):
- indent = '\t' * tabs
+ indent = u'\t' * tabs
if value[1]:
- return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
- '\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
+ return u'%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, force_unicode(value[0]), indent,
+ u'\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
else:
- return '%s<li>%s</li>' % (indent, value[0])
+ return u'%s<li>%s</li>' % (indent, force_unicode(value[0]))
return _helper(value, 1)
###################
@@ -421,7 +415,7 @@ def date(value, arg=None):
"Formats a date according to the given format"
from django.utils.dateformat import format
if not value:
- return ''
+ return u''
if arg is None:
arg = settings.DATE_FORMAT
return format(value, arg)
@@ -429,8 +423,8 @@ def date(value, arg=None):
def time(value, arg=None):
"Formats a time according to the given format"
from django.utils.dateformat import time_format
- if value in (None, ''):
- return ''
+ if value in (None, u''):
+ return u''
if arg is None:
arg = settings.TIME_FORMAT
return time_format(value, arg)
@@ -439,7 +433,7 @@ def timesince(value, arg=None):
'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
from django.utils.timesince import timesince
if not value:
- return ''
+ return u''
if arg:
return timesince(arg, value)
return timesince(value)
@@ -449,7 +443,7 @@ def timeuntil(value, arg=None):
from django.utils.timesince import timesince
from datetime import datetime
if not value:
- return ''
+ return u''
if arg:
return timesince(arg, value)
return timesince(datetime.now(), value)
@@ -488,8 +482,8 @@ def yesno(value, arg=None):
========== ====================== ==================================
"""
if arg is None:
- arg = gettext('yes,no,maybe')
- bits = arg.split(',')
+ arg = ugettext('yes,no,maybe')
+ bits = arg.split(u',')
if len(bits) < 2:
return value # Invalid arg.
try:
@@ -514,28 +508,28 @@ def filesizeformat(bytes):
try:
bytes = float(bytes)
except TypeError:
- return "0 bytes"
-
+ return u"0 bytes"
+
if bytes < 1024:
- return ngettext("%(size)d byte", "%(size)d bytes", bytes) % {'size': bytes}
+ return ungettext("%(size)d byte", "%(size)d bytes", bytes) % {'size': bytes}
if bytes < 1024 * 1024:
- return gettext("%.1f KB") % (bytes / 1024)
+ return ugettext("%.1f KB") % (bytes / 1024)
if bytes < 1024 * 1024 * 1024:
- return gettext("%.1f MB") % (bytes / (1024 * 1024))
- return gettext("%.1f GB") % (bytes / (1024 * 1024 * 1024))
+ return ugettext("%.1f MB") % (bytes / (1024 * 1024))
+ return ugettext("%.1f GB") % (bytes / (1024 * 1024 * 1024))
-def pluralize(value, arg='s'):
+def pluralize(value, arg=u's'):
"""
Returns a plural suffix if the value is not 1, for '1 vote' vs. '2 votes'
By default, 's' is used as a suffix; if an argument is provided, that string
is used instead. If the provided argument contains a comma, the text before
the comma is used for the singular case.
"""
- if not ',' in arg:
- arg = ',' + arg
- bits = arg.split(',')
+ if not u',' in arg:
+ arg = u',' + arg
+ bits = arg.split(u',')
if len(bits) > 2:
- return ''
+ return u''
singular_suffix, plural_suffix = bits[:2]
try:
@@ -562,7 +556,7 @@ def pprint(value):
try:
return pformat(value)
except Exception, e:
- return "Error in formatting:%s" % e
+ return u"Error in formatting: %s" % force_unicode(e, errors="replace")
# Syntax: register.filter(name of filter, callback)
register.filter(add)
@@ -582,6 +576,7 @@ register.filter(first)
register.filter(fix_ampersands)
register.filter(floatformat)
register.filter(get_digit)
+register.filter(iriencode)
register.filter(join)
register.filter(length)
register.filter(length_is)
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 19beb29141..11cd04653f 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -4,6 +4,7 @@ from django.template import Node, NodeList, Template, Context, resolve_variable
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
from django.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings
+from django.utils.encoding import smart_str, smart_unicode
from django.utils.itercompat import groupby
import sys
import re
@@ -64,8 +65,8 @@ class FirstOfNode(Node):
except VariableDoesNotExist:
continue
if value:
- return str(value)
- return ''
+ return smart_unicode(value)
+ return u''
class ForNode(Node):
def __init__(self, loopvars, sequence, reversed, nodelist_loop):
@@ -337,7 +338,7 @@ class URLNode(Node):
def render(self, context):
from django.core.urlresolvers import reverse, NoReverseMatch
args = [arg.resolve(context) for arg in self.args]
- kwargs = dict([(k, v.resolve(context)) for k, v in self.kwargs.items()])
+ kwargs = dict([(smart_str(k,'ascii'), v.resolve(context)) for k, v in self.kwargs.items()])
try:
return reverse(self.view_name, args=args, kwargs=kwargs)
except NoReverseMatch:
@@ -648,8 +649,8 @@ def do_if(parser, token):
As you can see, the ``if`` tag can take an option ``{% else %}`` clause that
will be displayed if the test fails.
- ``if`` tags may use ``or`` or ``not`` to test a number of variables or to
- negate a given variable::
+ ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
+ variables or to negate a given variable::
{% if not athlete_list %}
There are no athletes.
@@ -659,17 +660,30 @@ def do_if(parser, token):
There are some athletes or some coaches.
{% endif %}
+ {% if athlete_list and coach_list %}
+ Both atheletes and coaches are available.
+ {% endif %}
+
{% if not athlete_list or coach_list %}
There are no athletes, or there are some coaches.
{% endif %}
- For simplicity, ``if`` tags do not allow ``and`` clauses. Use nested ``if``
- tags instead::
+ {% if athlete_list and not coach_list %}
+ There are some athletes and absolutely no coaches.
+ {% endif %}
+
+ ``if`` tags do not allow ``and`` and ``or`` clauses with the same
+ tag, because the order of logic would be ambigous. For example,
+ this is invalid::
+
+ {% if athlete_list and coach_list or cheerleader_list %}
+
+ If you need to combine ``and`` and ``or`` to do advanced logic, just use
+ nested if tags. For example:
{% if athlete_list %}
- {% if coach_list %}
- Number of athletes: {{ athlete_list|count }}.
- Number of coaches: {{ coach_list|count }}.
+ {% if coach_list or cheerleader_list %}
+ We have athletes, and either coaches or cheerleaders!
{% endif %}
{% endif %}
"""
diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py
index 4439e0b010..19f368711c 100644
--- a/django/template/loader_tags.py
+++ b/django/template/loader_tags.py
@@ -140,7 +140,7 @@ def do_extends(parser, token):
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend,
or ``{% extends variable %}`` uses the value of ``variable`` as either the
- name of the parent template to extend (if it evaluates to a string,) or as
+ name of the parent template to extend (if it evaluates to a string) or as
the parent tempate itelf (if it evaluates to a Template object).
"""
bits = token.contents.split()
diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py
index c4e91df929..f0f4b1a70e 100644
--- a/django/template/loaders/app_directories.py
+++ b/django/template/loaders/app_directories.py
@@ -1,9 +1,14 @@
-# Wrapper for loading templates from "template" directories in installed app packages.
+"""
+Wrapper for loading templates from "template" directories in INSTALLED_APPS
+packages.
+"""
+
+import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.template import TemplateDoesNotExist
-import os
+from django.utils._os import safe_join
# At compile time, cache the directories to search.
app_template_dirs = []
@@ -28,13 +33,19 @@ for app in settings.INSTALLED_APPS:
app_template_dirs = tuple(app_template_dirs)
def get_template_sources(template_name, template_dirs=None):
- for template_dir in app_template_dirs:
- yield os.path.join(template_dir, template_name)
+ if not template_dirs:
+ template_dirs = app_template_dirs
+ for template_dir in template_dirs:
+ try:
+ yield safe_join(template_dir, template_name)
+ except ValueError:
+ # The joined path was located outside of template_dir.
+ pass
def load_template_source(template_name, template_dirs=None):
for filepath in get_template_sources(template_name, template_dirs):
try:
- return (open(filepath).read(), filepath)
+ return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
except IOError:
pass
raise TemplateDoesNotExist, template_name
diff --git a/django/template/loaders/eggs.py b/django/template/loaders/eggs.py
index 6184aeaccf..0c68153917 100644
--- a/django/template/loaders/eggs.py
+++ b/django/template/loaders/eggs.py
@@ -18,7 +18,7 @@ def load_template_source(template_name, template_dirs=None):
pkg_name = 'templates/' + template_name
for app in settings.INSTALLED_APPS:
try:
- return (resource_string(app, pkg_name), 'egg:%s:%s ' % (app, pkg_name))
+ return (resource_string(app, pkg_name), 'egg:%s:%s ' % (app, pkg_name)).decode(settings.FILE_CHARSET)
except:
pass
raise TemplateDoesNotExist, template_name
diff --git a/django/template/loaders/filesystem.py b/django/template/loaders/filesystem.py
index d01f54c5fe..9997eb9a54 100644
--- a/django/template/loaders/filesystem.py
+++ b/django/template/loaders/filesystem.py
@@ -1,20 +1,26 @@
-# Wrapper for loading templates from the filesystem.
+"""
+Wrapper for loading templates from the filesystem.
+"""
from django.conf import settings
from django.template import TemplateDoesNotExist
-import os
+from django.utils._os import safe_join
def get_template_sources(template_name, template_dirs=None):
if not template_dirs:
template_dirs = settings.TEMPLATE_DIRS
for template_dir in template_dirs:
- yield os.path.join(template_dir, template_name)
+ try:
+ yield safe_join(template_dir, template_name)
+ except ValueError:
+ # The joined path was located outside of template_dir.
+ pass
def load_template_source(template_name, template_dirs=None):
tried = []
for filepath in get_template_sources(template_name, template_dirs):
try:
- return (open(filepath).read(), filepath)
+ return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
except IOError:
tried.append(filepath)
if tried:
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py
index bf6497f9aa..1e85c6b5d1 100644
--- a/django/templatetags/i18n.py
+++ b/django/templatetags/i18n.py
@@ -11,7 +11,7 @@ class GetAvailableLanguagesNode(Node):
def render(self, context):
from django.conf import settings
- context[self.variable] = [(k, translation.gettext(v)) for k, v in settings.LANGUAGES]
+ context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES]
return ''
class GetCurrentLanguageNode(Node):
@@ -40,7 +40,7 @@ class TranslateNode(Node):
if self.noop:
return value
else:
- return translation.gettext(value)
+ return translation.ugettext(value)
class BlockTranslateNode(Node):
def __init__(self, extra_context, singular, plural=None, countervar=None, counter=None):
@@ -68,9 +68,9 @@ class BlockTranslateNode(Node):
count = self.counter.resolve(context)
context[self.countervar] = count
plural = self.render_token_list(self.plural)
- result = translation.ngettext(singular, plural, count) % context
+ result = translation.ungettext(singular, plural, count) % context
else:
- result = translation.gettext(singular) % context
+ result = translation.ugettext(singular) % context
context.pop()
return result
diff --git a/django/test/client.py b/django/test/client.py
index e4fd54c23b..9ec3615973 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -10,9 +10,11 @@ from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.core.signals import got_request_exception
from django.dispatch import dispatcher
-from django.http import urlencode, SimpleCookie, HttpRequest
+from django.http import SimpleCookie, HttpRequest
from django.test import signals
from django.utils.functional import curry
+from django.utils.encoding import smart_str
+from django.utils.http import urlencode
BOUNDARY = 'BoUnDaRyStRiNg'
MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
@@ -61,29 +63,30 @@ def encode_multipart(boundary, data):
as an application/octet-stream; otherwise, str(value) will be sent.
"""
lines = []
+ to_str = lambda s: smart_str(s, settings.DEFAULT_CHARSET)
for (key, value) in data.items():
if isinstance(value, file):
lines.extend([
'--' + boundary,
- 'Content-Disposition: form-data; name="%s"; filename="%s"' % (key, value.name),
+ 'Content-Disposition: form-data; name="%s"; filename="%s"' % (to_str(key), to_str(value.name)),
'Content-Type: application/octet-stream',
'',
value.read()
])
- elif hasattr(value, '__iter__'):
+ elif hasattr(value, '__iter__'):
for item in value:
- lines.extend([
- '--' + boundary,
- 'Content-Disposition: form-data; name="%s"' % key,
- '',
- str(item)
+ lines.extend([
+ '--' + boundary,
+ 'Content-Disposition: form-data; name="%s"' % to_str(key),
+ '',
+ to_str(item)
])
else:
lines.extend([
'--' + boundary,
- 'Content-Disposition: form-data; name="%s"' % key,
+ 'Content-Disposition: form-data; name="%s"' % to_str(key),
'',
- str(value)
+ to_str(value)
])
lines.extend([
@@ -115,7 +118,7 @@ class Client:
self.defaults = defaults
self.cookies = SimpleCookie()
self.exc_info = None
-
+
def store_exc_info(self, *args, **kwargs):
"""
Utility method that can be used to store exceptions when they are
@@ -131,7 +134,7 @@ class Client:
return SessionWrapper(cookie.value)
return {}
session = property(_session)
-
+
def request(self, **request):
"""
The master request method. Composes the environment dictionary
@@ -179,7 +182,7 @@ class Client:
# Look for a signalled exception and reraise it
if self.exc_info:
raise self.exc_info[1], None, self.exc_info[2]
-
+
# Update persistent cookie data
if response.cookies:
self.cookies.update(response.cookies)
@@ -192,7 +195,7 @@ class Client:
'CONTENT_LENGTH': None,
'CONTENT_TYPE': 'text/html; charset=utf-8',
'PATH_INFO': path,
- 'QUERY_STRING': urlencode(data),
+ 'QUERY_STRING': urlencode(data, doseq=True),
'REQUEST_METHOD': 'GET',
}
r.update(extra)
@@ -222,10 +225,11 @@ class Client:
"""Set the Client to appear as if it has sucessfully logged into a site.
Returns True if login is possible; False if the provided credentials
- are incorrect, or if the Sessions framework is not available.
+ are incorrect, or the user is inactive, or if the sessions framework is
+ not available.
"""
user = authenticate(**credentials)
- if user and 'django.contrib.sessions' in settings.INSTALLED_APPS:
+ if user and user.is_active and 'django.contrib.sessions' in settings.INSTALLED_APPS:
obj = Session.objects.get_new_session_object()
# Create a fake request to store login details
@@ -243,9 +247,20 @@ class Client:
# Set the session values
Session.objects.save(obj.session_key, request.session._session,
- datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
+ datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
return True
else:
return False
-
+
+ def logout(self):
+ """Removes the authenticated user's cookies.
+
+ Causes the authenticated user to be logged out.
+ """
+ try:
+ Session.objects.get(session_key=self.cookies['sessionid'].value).delete()
+ except KeyError:
+ pass
+
+ self.cookies = SimpleCookie()
diff --git a/django/test/simple.py b/django/test/simple.py
index 5f7f86f220..6fa381ac4d 100644
--- a/django/test/simple.py
+++ b/django/test/simple.py
@@ -1,5 +1,6 @@
import unittest
from django.conf import settings
+from django.db.models import get_app, get_apps
from django.test import _doctest as doctest
from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.utils import create_test_db, destroy_test_db
@@ -10,34 +11,10 @@ TEST_MODULE = 'tests'
doctestOutputChecker = OutputChecker()
-def build_suite(app_module):
- "Create a complete Django test suite for the provided application module"
- suite = unittest.TestSuite()
-
- # Load unit and doctests in the models.py file
- suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
- try:
- suite.addTest(doctest.DocTestSuite(app_module,
- checker=doctestOutputChecker,
- runner=DocTestRunner))
- except ValueError:
- # No doc tests in models.py
- pass
-
- # Check to see if a separate 'tests' module exists parallel to the
- # models module
+def get_tests(app_module):
try:
app_path = app_module.__name__.split('.')[:-1]
test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
-
- suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
- try:
- suite.addTest(doctest.DocTestSuite(test_module,
- checker=doctestOutputChecker,
- runner=DocTestRunner))
- except ValueError:
- # No doc tests in tests.py
- pass
except ImportError, e:
# Couldn't import tests.py. Was it due to a missing file, or
# due to an import error in a tests.py that actually exists?
@@ -47,7 +24,7 @@ def build_suite(app_module):
mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
except ImportError:
# 'tests' module doesn't exist. Move on.
- pass
+ test_module = None
else:
# The module exists, so there must be an import error in the
# test module itself. We don't need the module; so if the
@@ -57,15 +34,87 @@ def build_suite(app_module):
if mod[0]:
mod[0].close()
raise
-
+ return test_module
+
+def build_suite(app_module):
+ "Create a complete Django test suite for the provided application module"
+ suite = unittest.TestSuite()
+
+ # Load unit and doctests in the models.py module. If module has
+ # a suite() method, use it. Otherwise build the test suite ourselves.
+ if hasattr(app_module, 'suite'):
+ suite.addTest(app_module.suite())
+ else:
+ suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
+ try:
+ suite.addTest(doctest.DocTestSuite(app_module,
+ checker=doctestOutputChecker,
+ runner=DocTestRunner))
+ except ValueError:
+ # No doc tests in models.py
+ pass
+
+ # Check to see if a separate 'tests' module exists parallel to the
+ # models module
+ test_module = get_tests(app_module)
+ if test_module:
+ # Load unit and doctests in the tests.py module. If module has
+ # a suite() method, use it. Otherwise build the test suite ourselves.
+ if hasattr(test_module, 'suite'):
+ suite.addTest(test_module.suite())
+ else:
+ suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
+ try:
+ suite.addTest(doctest.DocTestSuite(test_module,
+ checker=doctestOutputChecker,
+ runner=DocTestRunner))
+ except ValueError:
+ # No doc tests in tests.py
+ pass
return suite
-def run_tests(module_list, verbosity=1, extra_tests=[]):
+def build_test(label):
+ """Construct a test case a test with the specified label. Label should
+ be of the form model.TestClass or model.TestClass.test_method. Returns
+ an instantiated test or test suite corresponding to the label provided.
+
"""
- Run the unit tests for all the modules in the provided list.
- This testrunner will search each of the modules in the provided list,
- looking for doctests and unittests in models.py or tests.py within
- the module. A list of 'extra' tests may also be provided; these tests
+ parts = label.split('.')
+ if len(parts) < 2 or len(parts) > 3:
+ raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)
+
+ app_module = get_app(parts[0])
+ TestClass = getattr(app_module, parts[1], None)
+
+ # Couldn't find the test class in models.py; look in tests.py
+ if TestClass is None:
+ test_module = get_tests(app_module)
+ if test_module:
+ TestClass = getattr(test_module, parts[1], None)
+
+ if len(parts) == 2: # label is app.TestClass
+ try:
+ return unittest.TestLoader().loadTestsFromTestCase(TestClass)
+ except TypeError:
+ raise ValueError("Test label '%s' does not refer to a test class" % label)
+ else: # label is app.TestClass.test_method
+ return TestClass(parts[2])
+
+def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
+ """
+ Run the unit tests for all the test labels in the provided list.
+ Labels must be of the form:
+ - app.TestClass.test_method
+ Run a single specific test method
+ - app.TestClass
+ Run all the test methods in a given class
+ - app
+ Search for doctests and unittests in the named application.
+
+ When looking for tests, the test runner will look in the models and
+ tests modules for the application.
+
+ A list of 'extra' tests may also be provided; these tests
will be added to the test suite.
Returns the number of tests that failed.
@@ -74,15 +123,23 @@ def run_tests(module_list, verbosity=1, extra_tests=[]):
settings.DEBUG = False
suite = unittest.TestSuite()
-
- for module in module_list:
- suite.addTest(build_suite(module))
+
+ if test_labels:
+ for label in test_labels:
+ if '.' in label:
+ suite.addTest(build_test(label))
+ else:
+ app = get_app(label)
+ suite.addTest(build_suite(app))
+ else:
+ for app in get_apps():
+ suite.addTest(build_suite(app))
for test in extra_tests:
suite.addTest(test)
old_name = settings.DATABASE_NAME
- create_test_db(verbosity)
+ create_test_db(verbosity, autoclobber=not interactive)
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
destroy_test_db(old_name, verbosity)
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 2bc1b5a5f8..21c429271c 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -1,7 +1,8 @@
import re, unittest
from urlparse import urlparse
from django.db import transaction
-from django.core import management, mail
+from django.core import mail
+from django.core.management import call_command
from django.db.models import get_apps
from django.test import _doctest as doctest
from django.test.client import Client
@@ -42,9 +43,11 @@ class TestCase(unittest.TestCase):
* Clearing the mail test outbox.
"""
- management.flush(verbosity=0, interactive=False)
+ call_command('flush', verbosity=0, interactive=False)
if hasattr(self, 'fixtures'):
- management.load_data(self.fixtures, verbosity=0)
+ # We have to use this slightly awkward syntax due to the fact
+ # that we're using *args and **kwargs together.
+ call_command('loaddata', *self.fixtures, **{'verbosity': 0})
mail.outbox = []
def __call__(self, result=None):
@@ -63,7 +66,7 @@ class TestCase(unittest.TestCase):
"""
self.assertEqual(response.status_code, status_code,
- "Response didn't redirect as expected: Reponse code was %d (expected %d)" %
+ "Response didn't redirect as expected: Response code was %d (expected %d)" %
(response.status_code, status_code))
scheme, netloc, path, params, query, fragment = urlparse(response['Location'])
self.assertEqual(path, expected_path,
@@ -73,19 +76,23 @@ class TestCase(unittest.TestCase):
"Couldn't retrieve redirection page '%s': response code was %d (expected %d)" %
(path, redirect_response.status_code, target_status_code))
- def assertContains(self, response, text, count=1, status_code=200):
+ def assertContains(self, response, text, count=None, status_code=200):
"""Assert that a response indicates that a page was retreived successfully,
(i.e., the HTTP status code was as expected), and that ``text`` occurs ``count``
- times in the content of the response.
+ times in the content of the response. If ``count`` is None, the count doesn't
+ matter - the assertion is true if the text occurs at least once in the response.
"""
self.assertEqual(response.status_code, status_code,
"Couldn't retrieve page: Response code was %d (expected %d)'" %
(response.status_code, status_code))
real_count = response.content.count(text)
- self.assertEqual(real_count, count,
- "Found %d instances of '%s' in response (expected %d)" % (real_count, text, count))
-
+ if count is not None:
+ self.assertEqual(real_count, count,
+ "Found %d instances of '%s' in response (expected %d)" % (real_count, text, count))
+ else:
+ self.failUnless(real_count != 0, "Couldn't find '%s' in response" % text)
+
def assertFormError(self, response, form, field, errors):
"Assert that a form used to render the response has a specific field error"
if not response.context:
@@ -129,11 +136,11 @@ class TestCase(unittest.TestCase):
if isinstance(response.template, list):
template_names = [t.name for t in response.template]
self.failUnless(template_name in template_names,
- "Template '%s' was not one of the templates used to render the response. Templates used: %s" %
- (template_name, template_names))
+ u"Template '%s' was not one of the templates used to render the response. Templates used: %s" %
+ (template_name, u', '.join(template_names)))
elif response.template:
self.assertEqual(template_name, response.template.name,
- "Template '%s' was not used to render the response. Actual template was '%s'" %
+ u"Template '%s' was not used to render the response. Actual template was '%s'" %
(template_name, response.template.name))
else:
self.fail('No templates used to render the response')
@@ -142,8 +149,8 @@ class TestCase(unittest.TestCase):
"Assert that the template with the provided name was NOT used in rendering the response"
if isinstance(response.template, list):
self.failIf(template_name in [t.name for t in response.template],
- "Template '%s' was used unexpectedly in rendering the response" % template_name)
+ u"Template '%s' was used unexpectedly in rendering the response" % template_name)
elif response.template:
self.assertNotEqual(template_name, response.template.name,
- "Template '%s' was used unexpectedly in rendering the response" % template_name)
-
+ u"Template '%s' was used unexpectedly in rendering the response" % template_name)
+
diff --git a/django/test/utils.py b/django/test/utils.py
index 4a858a6ec7..6edd186b54 100644
--- a/django/test/utils.py
+++ b/django/test/utils.py
@@ -1,8 +1,8 @@
import sys, time
from django.conf import settings
-from django.db import connection, backend, get_creation_module
-from django.core import management, mail
-from django.core import management, mail
+from django.db import connection, get_creation_module
+from django.core import mail
+from django.core.management import call_command
from django.dispatch import dispatcher
from django.test import signals
from django.template import Template
@@ -12,18 +12,18 @@ from django.template import Template
TEST_DATABASE_PREFIX = 'test_'
def instrumented_test_render(self, context):
- """An instrumented Template render method, providing a signal
+ """
+ An instrumented Template render method, providing a signal
that can be intercepted by the test system Client
-
"""
dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
return self.nodelist.render(context)
-
+
class TestSMTPConnection(object):
"""A substitute SMTP connection for use during test sessions.
The test connection stores email messages in a dummy outbox,
rather than sending them out on the wire.
-
+
"""
def __init__(*args, **kwargs):
pass
@@ -36,37 +36,38 @@ class TestSMTPConnection(object):
def send_messages(self, messages):
"Redirect messages to the dummy outbox"
mail.outbox.extend(messages)
+ return len(messages)
def setup_test_environment():
"""Perform any global pre-test setup. This involves:
-
+
- Installing the instrumented test renderer
- Diverting the email sending functions to a test buffer
-
+
"""
Template.original_render = Template.render
Template.render = instrumented_test_render
-
+
mail.original_SMTPConnection = mail.SMTPConnection
mail.SMTPConnection = TestSMTPConnection
mail.outbox = []
-
+
def teardown_test_environment():
"""Perform any global post-test teardown. This involves:
- Restoring the original test renderer
- Restoring the email sending functions
-
+
"""
Template.render = Template.original_render
del Template.original_render
-
+
mail.SMTPConnection = mail.original_SMTPConnection
del mail.original_SMTPConnection
-
+
del mail.outbox
-
+
def _set_autocommit(connection):
"Make sure a connection is in autocommit mode."
if hasattr(connection.connection, "autocommit"):
@@ -89,12 +90,16 @@ def get_postgresql_create_suffix():
return ''
def create_test_db(verbosity=1, autoclobber=False):
+ """
+ Creates a test database, prompting the user for confirmation if the
+ database already exists. Returns the name of the test database created.
+ """
# If the database backend wants to create the test DB itself, let it
creation_module = get_creation_module()
if hasattr(creation_module, "create_test_db"):
- creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber)
+ creation_module.create_test_db(settings, connection, verbosity, autoclobber)
return
-
+
if verbosity >= 1:
print "Creating test database..."
# If we're using SQLite, it's more convenient to test against an
@@ -112,49 +117,57 @@ def create_test_db(verbosity=1, autoclobber=False):
TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
else:
TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
-
+
+ qn = connection.ops.quote_name
+
# Create the test database and connect to it. We need to autocommit
- # if the database supports it because PostgreSQL doesn't allow
+ # if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions.
cursor = connection.cursor()
_set_autocommit(connection)
try:
- cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
- except Exception, e:
+ cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
+ except Exception, e:
sys.stderr.write("Got an error creating the test database: %s\n" % e)
if not autoclobber:
- confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
+ confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
- print "Destroying old test database..."
- cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME))
+ print "Destroying old test database..."
+ cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))
if verbosity >= 1:
print "Creating test database..."
- cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
+ cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
except Exception, e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e)
sys.exit(2)
else:
print "Tests cancelled."
sys.exit(1)
-
+
connection.close()
settings.DATABASE_NAME = TEST_DATABASE_NAME
- management.syncdb(verbosity, interactive=False)
+ call_command('syncdb', verbosity=verbosity, interactive=False)
+
+ if settings.CACHE_BACKEND.startswith('db://'):
+ cache_name = settings.CACHE_BACKEND[len('db://'):]
+ call_command('createcachetable', cache_name)
# Get a cursor (even though we don't need one yet). This has
# the side effect of initializing the test database.
cursor = connection.cursor()
+ return TEST_DATABASE_NAME
+
def destroy_test_db(old_database_name, verbosity=1):
# If the database wants to drop the test DB itself, let it
creation_module = get_creation_module()
if hasattr(creation_module, "destroy_test_db"):
- creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
+ creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)
return
-
+
# Unless we're using SQLite, remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
@@ -169,5 +182,5 @@ def destroy_test_db(old_database_name, verbosity=1):
cursor = connection.cursor()
_set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.
- cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME))
+ cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))
connection.close()
diff --git a/django/utils/_os.py b/django/utils/_os.py
new file mode 100644
index 0000000000..30d7cbd444
--- /dev/null
+++ b/django/utils/_os.py
@@ -0,0 +1,23 @@
+from os.path import join, normcase, abspath, sep
+
+def safe_join(base, *paths):
+ """
+ Joins one or more path components to the base path component intelligently.
+ Returns a normalized, absolute version of the final path.
+
+ The final path must be located inside of the base path component (otherwise
+ a ValueError is raised).
+ """
+ # We need to use normcase to ensure we don't false-negative on case
+ # insensitive operating systems (like Windows).
+ final_path = normcase(abspath(join(base, *paths)))
+ base_path = normcase(abspath(base))
+ base_path_len = len(base_path)
+ # Ensure final_path starts with base_path and that the next character after
+ # the final path is os.sep (or nothing, in which case final_path must be
+ # equal to base_path).
+ if not final_path.startswith(base_path) \
+ or final_path[base_path_len:base_path_len+1] not in ('', sep):
+ raise ValueError('the joined path is located outside of the base path'
+ ' component')
+ return final_path
diff --git a/django/utils/cache.py b/django/utils/cache.py
index c8031a409a..2753d86949 100644
--- a/django/utils/cache.py
+++ b/django/utils/cache.py
@@ -17,9 +17,13 @@ A example: i18n middleware would need to distinguish caches by the
"Accept-language" header.
"""
-import datetime, md5, re
+import md5
+import re
+import time
+from email.Utils import formatdate
from django.conf import settings
from django.core.cache import cache
+from django.utils.encoding import smart_str
cc_delim_re = re.compile(r'\s*,\s*')
@@ -43,10 +47,10 @@ def patch_cache_control(response, **kwargs):
return (t[0].lower().replace('-', '_'), True)
def dictvalue(t):
- if t[1] == True:
+ if t[1] is True:
return t[0]
else:
- return t[0] + '=' + str(t[1])
+ return t[0] + '=' + smart_str(t[1])
if response.has_header('Cache-Control'):
cc = cc_delim_re.split(response['Cache-Control'])
@@ -72,16 +76,14 @@ def patch_response_headers(response, cache_timeout=None):
"""
if cache_timeout is None:
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
- now = datetime.datetime.utcnow()
+ if cache_timeout < 0:
+ cache_timeout = 0 # Can't have max-age negative
if not response.has_header('ETag'):
response['ETag'] = md5.new(response.content).hexdigest()
if not response.has_header('Last-Modified'):
- response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
+ response['Last-Modified'] = formatdate()[:26] + "GMT"
if not response.has_header('Expires'):
- expires = now + datetime.timedelta(0, cache_timeout)
- response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT')
- if cache_timeout < 0:
- cache_timeout = 0 # Can't have max-age negative
+ response['Expires'] = formatdate(time.time() + cache_timeout)[:26] + "GMT"
patch_cache_control(response, max_age=cache_timeout)
def add_never_cache_headers(response):
diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py
index 60bc0051a2..4b60d1d194 100644
--- a/django/utils/datastructures.py
+++ b/django/utils/datastructures.py
@@ -267,3 +267,16 @@ class DotExpandedDict(dict):
current[bits[-1]] = v
except TypeError: # Special-case if current isn't a dict.
current = {bits[-1] : v}
+
+class FileDict(dict):
+ """
+ A dictionary used to hold uploaded file contents. The only special feature
+ here is that repr() of this object won't dump the entire contents of the
+ file to the output. A handy safeguard for a large file upload.
+ """
+ def __repr__(self):
+ if 'content' in self:
+ d = dict(self, content='<omitted>')
+ return dict.__repr__(d)
+ return dict.__repr__(self)
+
diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py
index a558e3a69f..d5f3499d82 100644
--- a/django/utils/dateformat.py
+++ b/django/utils/dateformat.py
@@ -11,9 +11,10 @@ Usage:
>>>
"""
-from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS
+from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS, WEEKDAYS_ABBR
from django.utils.tzinfo import LocalTimezone
-from django.utils.translation import gettext as _
+from django.utils.translation import string_concat, ugettext as _
+from django.utils.encoding import force_unicode
from calendar import isleap, monthrange
import re, time
@@ -23,12 +24,12 @@ re_escaped = re.compile(r'\\(.)')
class Formatter(object):
def format(self, formatstr):
pieces = []
- for i, piece in enumerate(re_formatchars.split(formatstr)):
+ for i, piece in enumerate(re_formatchars.split(force_unicode(formatstr))):
if i % 2:
- pieces.append(str(getattr(self, piece)()))
+ pieces.append(force_unicode(getattr(self, piece)()))
elif piece:
pieces.append(re_escaped.sub(r'\1', piece))
- return ''.join(pieces)
+ return u''.join(pieces)
class TimeFormat(Formatter):
def __init__(self, t):
@@ -52,13 +53,14 @@ class TimeFormat(Formatter):
def f(self):
"""
- Time, in 12-hour hours and minutes, with minutes left off if they're zero.
+ Time, in 12-hour hours and minutes, with minutes left off if they're
+ zero.
Examples: '1', '1:30', '2:05', '2'
Proprietary extension.
"""
if self.data.minute == 0:
return self.g()
- return '%s:%s' % (self.g(), self.i())
+ return u'%s:%s' % (self.g(), self.i())
def g(self):
"Hour, 12-hour format without leading zeros; i.e. '1' to '12'"
@@ -74,15 +76,15 @@ class TimeFormat(Formatter):
def h(self):
"Hour, 12-hour format; i.e. '01' to '12'"
- return '%02d' % self.g()
+ return u'%02d' % self.g()
def H(self):
"Hour, 24-hour format; i.e. '00' to '23'"
- return '%02d' % self.G()
+ return u'%02d' % self.G()
def i(self):
"Minutes; i.e. '00' to '59'"
- return '%02d' % self.data.minute
+ return u'%02d' % self.data.minute
def P(self):
"""
@@ -95,11 +97,11 @@ class TimeFormat(Formatter):
return _('midnight')
if self.data.minute == 0 and self.data.hour == 12:
return _('noon')
- return '%s %s' % (self.f(), self.a())
+ return u'%s %s' % (self.f(), self.a())
def s(self):
"Seconds; i.e. '00' to '59'"
- return '%02d' % self.data.second
+ return u'%02d' % self.data.second
class DateFormat(TimeFormat):
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
@@ -117,11 +119,11 @@ class DateFormat(TimeFormat):
def d(self):
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
- return '%02d' % self.data.day
+ return u'%02d' % self.data.day
def D(self):
"Day of the week, textual, 3 letters; e.g. 'Fri'"
- return WEEKDAYS[self.data.weekday()][0:3]
+ return WEEKDAYS_ABBR[self.data.weekday()]
def F(self):
"Month, textual, long; e.g. 'January'"
@@ -130,9 +132,9 @@ class DateFormat(TimeFormat):
def I(self):
"'1' if Daylight Savings Time, '0' otherwise."
if self.timezone.dst(self.data):
- return '1'
+ return u'1'
else:
- return '0'
+ return u'0'
def j(self):
"Day of the month without leading zeros; i.e. '1' to '31'"
@@ -148,7 +150,7 @@ class DateFormat(TimeFormat):
def m(self):
"Month; i.e. '01' to '12'"
- return '%02d' % self.data.month
+ return u'%02d' % self.data.month
def M(self):
"Month, textual, 3 letters; e.g. 'Jan'"
@@ -165,7 +167,7 @@ class DateFormat(TimeFormat):
def O(self):
"Difference to Greenwich time in hours; e.g. '+0200'"
tz = self.timezone.utcoffset(self.data)
- return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
+ return u"%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
def r(self):
"RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
@@ -174,26 +176,26 @@ class DateFormat(TimeFormat):
def S(self):
"English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'"
if self.data.day in (11, 12, 13): # Special case
- return 'th'
+ return u'th'
last = self.data.day % 10
if last == 1:
- return 'st'
+ return u'st'
if last == 2:
- return 'nd'
+ return u'nd'
if last == 3:
- return 'rd'
- return 'th'
+ return u'rd'
+ return u'th'
def t(self):
"Number of days in the given month; i.e. '28' to '31'"
- return '%02d' % monthrange(self.data.year, self.data.month)[1]
+ return u'%02d' % monthrange(self.data.year, self.data.month)[1]
def T(self):
"Time zone of this machine; e.g. 'EST' or 'MDT'"
name = self.timezone.tzname(self.data)
if name is None:
name = self.format('O')
- return name
+ return unicode(name)
def U(self):
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
@@ -225,14 +227,14 @@ class DateFormat(TimeFormat):
week_number = 1
else:
j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
- week_number = j / 7
+ week_number = j // 7
if jan1_weekday > 4:
week_number -= 1
return week_number
def y(self):
"Year, 2 digits; e.g. '99'"
- return str(self.data.year)[2:]
+ return unicode(self.data.year)[2:]
def Y(self):
"Year, 4 digits; e.g. '1999'"
diff --git a/django/utils/dates.py b/django/utils/dates.py
index 111f32e4fc..4427af8ca9 100644
--- a/django/utils/dates.py
+++ b/django/utils/dates.py
@@ -1,11 +1,15 @@
"Commonly-used date structures"
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
WEEKDAYS = {
0:_('Monday'), 1:_('Tuesday'), 2:_('Wednesday'), 3:_('Thursday'), 4:_('Friday'),
5:_('Saturday'), 6:_('Sunday')
}
+WEEKDAYS_ABBR = {
+ 0:_('Mon'), 1:_('Tue'), 2:_('Wed'), 3:_('Thu'), 4:_('Fri'),
+ 5:_('Sat'), 6:_('Sun')
+}
WEEKDAYS_REV = {
'monday':0, 'tuesday':1, 'wednesday':2, 'thursday':3, 'friday':4,
'saturday':5, 'sunday':6
diff --git a/django/utils/decorators.py b/django/utils/decorators.py
index 1c6cc8c7de..57ce29fca4 100644
--- a/django/utils/decorators.py
+++ b/django/utils/decorators.py
@@ -1,12 +1,36 @@
"Functions that help with dynamically creating decorators for views."
+import types
+
def decorator_from_middleware(middleware_class):
"""
Given a middleware class (not an instance), returns a view decorator. This
lets you use middleware functionality on a per-view basis.
"""
- def _decorator_from_middleware(view_func, *args, **kwargs):
+ def _decorator_from_middleware(*args, **kwargs):
+ # For historical reasons, these "decorators" are also called as
+ # dec(func, *args) instead of dec(*args)(func). We handle both forms
+ # for backwards compatibility.
+ has_func = True
+ try:
+ view_func = kwargs.pop('view_func')
+ except KeyError:
+ if len(args):
+ view_func, args = args[0], args[1:]
+ else:
+ has_func = False
+ if not (has_func and isinstance(view_func, types.FunctionType)):
+ # We are being called as a decorator.
+ if has_func:
+ args = (view_func,) + args
+ middleware = middleware_class(*args, **kwargs)
+
+ def decorator_func(fn):
+ return _decorator_from_middleware(fn, *args, **kwargs)
+ return decorator_func
+
middleware = middleware_class(*args, **kwargs)
+
def _wrapped_view(request, *args, **kwargs):
if hasattr(middleware, 'process_request'):
result = middleware.process_request(request)
diff --git a/django/utils/encoding.py b/django/utils/encoding.py
index 4774fb0d26..2319496538 100644
--- a/django/utils/encoding.py
+++ b/django/utils/encoding.py
@@ -1,32 +1,83 @@
-from django.conf import settings
+import types
+import urllib
from django.utils.functional import Promise
-def smart_unicode(s):
+class StrAndUnicode(object):
+ """
+ A class whose __str__ returns its __unicode__ as a UTF-8 bytestring.
+
+ Useful as a mix-in.
+ """
+ def __str__(self):
+ return self.__unicode__().encode('utf-8')
+
+def smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
+ """
+ Returns a unicode object representing 's'. Treats bytestrings using the
+ 'encoding' codec.
+
+ If strings_only is True, don't convert (some) non-string-like objects.
+ """
if isinstance(s, Promise):
- # The input is the result of a gettext_lazy() call, or similar. It will
- # already be encoded in DEFAULT_CHARSET on evaluation and we don't want
- # to evaluate it until render time.
- # FIXME: This isn't totally consistent, because it eventually returns a
- # bytestring rather than a unicode object. It works wherever we use
- # smart_unicode() at the moment. Fixing this requires work in the
- # i18n internals.
+ # The input is the result of a gettext_lazy() call.
+ return s
+ return force_unicode(s, encoding, strings_only, errors)
+
+def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
+ """
+ Similar to smart_unicode, except that lazy instances are resolved to
+ strings, rather than kept as lazy objects.
+
+ If strings_only is True, don't convert (some) non-string-like objects.
+ """
+ if strings_only and isinstance(s, (types.NoneType, int)):
return s
if not isinstance(s, basestring,):
if hasattr(s, '__unicode__'):
s = unicode(s)
else:
- s = unicode(str(s), settings.DEFAULT_CHARSET)
+ s = unicode(str(s), encoding, errors)
elif not isinstance(s, unicode):
- s = unicode(s, settings.DEFAULT_CHARSET)
+ s = unicode(s, encoding, errors)
return s
-class StrAndUnicode(object):
+def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
"""
- A class whose __str__ returns its __unicode__ as a bytestring
- according to settings.DEFAULT_CHARSET.
+ Returns a bytestring version of 's', encoded as specified in 'encoding'.
- Useful as a mix-in.
+ If strings_only is True, don't convert (some) non-string-like objects.
"""
- def __str__(self):
- return self.__unicode__().encode(settings.DEFAULT_CHARSET)
+ if strings_only and isinstance(s, (types.NoneType, int)):
+ return s
+ if isinstance(s, Promise):
+ return unicode(s).encode(encoding, errors)
+ elif not isinstance(s, basestring):
+ try:
+ return str(s)
+ except UnicodeEncodeError:
+ return unicode(s).encode(encoding, errors)
+ elif isinstance(s, unicode):
+ return s.encode(encoding, errors)
+ elif s and encoding != 'utf-8':
+ return s.decode('utf-8', errors).encode(encoding, errors)
+ else:
+ return s
+
+def iri_to_uri(iri):
+ """
+ Convert an Internationalized Resource Identifier (IRI) portion to a URI
+ portion that is suitable for inclusion in a URL.
+
+ This is the algorithm from section 3.1 of RFC 3987. However, since we are
+ assuming input is either UTF-8 or unicode already, we can simplify things a
+ little from the full method.
+
+ Returns an ASCII string containing the encoded result.
+ """
+ # The list of safe characters here is constructed from the printable ASCII
+ # characters that are not explicitly excluded by the list at the end of
+ # section 3.1 of RFC 3987.
+ if iri is None:
+ return iri
+ return urllib.quote(smart_str(iri), safe='/#%[]=:;$&()+,!?')
diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py
index 2c82e9a37a..6b6dedfbe9 100644
--- a/django/utils/feedgenerator.py
+++ b/django/utils/feedgenerator.py
@@ -19,6 +19,7 @@ http://diveintomark.org/archives/2004/02/04/incompatible-rss
"""
from django.utils.xmlutils import SimplerXMLGenerator
+from django.utils.encoding import force_unicode, iri_to_uri
import datetime, re, time
import email.Utils
@@ -34,25 +35,29 @@ def get_tag_uri(url, date):
if date is not None:
tag = re.sub('/', ',%s:/' % date.strftime('%Y-%m-%d'), tag, 1)
tag = re.sub('#', '/', tag)
- return 'tag:' + tag
+ return u'tag:' + tag
class SyndicationFeed(object):
"Base class for all syndication feeds. Subclasses should provide write()"
def __init__(self, title, link, description, language=None, author_email=None,
author_name=None, author_link=None, subtitle=None, categories=None,
- feed_url=None, feed_copyright=None):
+ feed_url=None, feed_copyright=None, feed_guid=None):
+ to_unicode = lambda s: force_unicode(s, strings_only=True)
+ if categories:
+ categories = [force_unicode(c) for c in categories]
self.feed = {
- 'title': title,
- 'link': link,
- 'description': description,
- 'language': language,
- 'author_email': author_email,
- 'author_name': author_name,
- 'author_link': author_link,
- 'subtitle': subtitle,
+ 'title': to_unicode(title),
+ 'link': iri_to_uri(link),
+ 'description': to_unicode(description),
+ 'language': force_unicode(language),
+ 'author_email': to_unicode(author_email),
+ 'author_name': to_unicode(author_name),
+ 'author_link': iri_to_uri(author_link),
+ 'subtitle': to_unicode(subtitle),
'categories': categories or (),
- 'feed_url': feed_url,
- 'feed_copyright': feed_copyright,
+ 'feed_url': iri_to_uri(feed_url),
+ 'feed_copyright': to_unicode(feed_copyright),
+ 'id': feed_guid or link,
}
self.items = []
@@ -64,19 +69,22 @@ class SyndicationFeed(object):
objects except pubdate, which is a datetime.datetime object, and
enclosure, which is an instance of the Enclosure class.
"""
+ to_unicode = lambda s: force_unicode(s, strings_only=True)
+ if categories:
+ categories = [to_unicode(c) for c in categories]
self.items.append({
- 'title': title,
- 'link': link,
- 'description': description,
- 'author_email': author_email,
- 'author_name': author_name,
- 'author_link': author_link,
+ 'title': to_unicode(title),
+ 'link': iri_to_uri(link),
+ 'description': to_unicode(description),
+ 'author_email': to_unicode(author_email),
+ 'author_name': to_unicode(author_name),
+ 'author_link': iri_to_uri(author_link),
'pubdate': pubdate,
- 'comments': comments,
- 'unique_id': unique_id,
+ 'comments': to_unicode(comments),
+ 'unique_id': to_unicode(unique_id),
'enclosure': enclosure,
'categories': categories or (),
- 'item_copyright': item_copyright,
+ 'item_copyright': to_unicode(item_copyright),
})
def num_items(self):
@@ -114,7 +122,8 @@ class Enclosure(object):
"Represents an RSS enclosure"
def __init__(self, url, length, mime_type):
"All args are expected to be Python Unicode objects"
- self.url, self.length, self.mime_type = url, length, mime_type
+ self.length, self.mime_type = length, mime_type
+ self.url = iri_to_uri(url)
class RssFeed(SyndicationFeed):
mime_type = 'application/rss+xml'
@@ -205,7 +214,7 @@ class Atom1Feed(SyndicationFeed):
handler.addQuickElement(u"link", "", {u"rel": u"alternate", u"href": self.feed['link']})
if self.feed['feed_url'] is not None:
handler.addQuickElement(u"link", "", {u"rel": u"self", u"href": self.feed['feed_url']})
- handler.addQuickElement(u"id", self.feed['link'])
+ handler.addQuickElement(u"id", self.feed['id'])
handler.addQuickElement(u"updated", rfc3339_date(self.latest_post_date()).decode('ascii'))
if self.feed['author_name'] is not None:
handler.startElement(u"author", {})
diff --git a/django/utils/functional.py b/django/utils/functional.py
index a57546ad2d..734704f6f3 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -3,22 +3,24 @@ def curry(_curried_func, *args, **kwargs):
return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
return _curried
-def memoize(func, cache):
+def memoize(func, cache, num_args):
"""
Wrap a function so that results for any argument tuple are stored in
'cache'. Note that the args to the function must be usable as dictionary
keys.
+
+ Only the first num_args are considered when creating the key.
"""
def wrapper(*args):
- if args in cache:
- return cache[args]
-
+ mem_args = args[:num_args]
+ if mem_args in cache:
+ return cache[mem_args]
result = func(*args)
- cache[args] = result
+ cache[mem_args] = result
return result
return wrapper
-class Promise:
+class Promise(object):
"""
This is just a base class for the proxy class created in
the closure of the lazy function. It can be used to recognize
@@ -47,6 +49,11 @@ def lazy(func, *resultclasses):
self.__dispatch[resultclass] = {}
for (k, v) in resultclass.__dict__.items():
setattr(self, k, self.__promise__(resultclass, k, v))
+ self._delegate_str = str in resultclasses
+ self._delegate_unicode = unicode in resultclasses
+ assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
+ if self._delegate_unicode:
+ self.__unicode__ = self.__unicode_cast
def __promise__(self, klass, funcname, func):
# Builds a wrapper around some magic method and registers that magic
@@ -62,8 +69,56 @@ def lazy(func, *resultclasses):
self.__dispatch[klass][funcname] = func
return __wrapper__
+ def __unicode_cast(self):
+ return self.__func(*self.__args, **self.__kw)
+
+ def __str__(self):
+ # As __str__ is always a method on the type (class), it is looked
+ # up (and found) there first. So we can't just assign to it on a
+ # per-instance basis in __init__.
+ if self._delegate_str:
+ return str(self.__func(*self.__args, **self.__kw))
+ else:
+ return Promise.__str__(self)
+
+ def __cmp__(self, rhs):
+ if self._delegate_str:
+ s = str(self.__func(*self.__args, **self.__kw))
+ elif self._delegate_unicode:
+ s = unicode(self.__func(*self.__args, **self.__kw))
+ else:
+ s = self.__func(*self.__args, **self.__kw)
+ if isinstance(rhs, Promise):
+ return -cmp(rhs, s)
+ else:
+ return cmp(s, rhs)
+
+ def __mod__(self, rhs):
+ if self._delegate_str:
+ return str(self) % rhs
+ elif self._delegate_unicode:
+ return unicode(self) % rhs
+ else:
+ raise AssertionError('__mod__ not supported for non-string types')
+
def __wrapper__(*args, **kw):
# Creates the proxy object, instead of the actual value.
return __proxy__(args, kw)
return __wrapper__
+
+def allow_lazy(func, *resultclasses):
+ """
+ A decorator that allows a function to be called with one or more lazy
+ arguments. If none of the args are lazy, the function is evaluated
+ immediately, otherwise a __proxy__ is returned that will evaluate the
+ function when needed.
+ """
+ def wrapper(*args, **kwargs):
+ for arg in list(args) + kwargs.values():
+ if isinstance(arg, Promise):
+ break
+ else:
+ return func(*args, **kwargs)
+ return lazy(func, *resultclasses)(*args, **kwargs)
+ return wrapper
diff --git a/django/utils/html.py b/django/utils/html.py
index e1860627ce..ebd04d1b3c 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -1,7 +1,10 @@
"HTML utilities suitable for global use."
-import re, string
-from django.utils.encoding import smart_unicode
+import re
+import string
+
+from django.utils.encoding import force_unicode
+from django.utils.functional import allow_lazy
# Configuration for urlize() function
LEADING_PUNCTUATION = ['(', '<', '&lt;']
@@ -23,40 +26,45 @@ trailing_empty_content_re = re.compile(r'(?:<p>(?:&nbsp;|\s|<br \/>)*?</p>\s*)+\
del x # Temporary variable
def escape(html):
- "Returns the given HTML with ampersands, quotes and carets encoded"
- if not isinstance(html, basestring):
- html = str(html)
- return html.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
+ "Return the given HTML with ampersands, quotes and carets encoded."
+ return force_unicode(html).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
+escape = allow_lazy(escape, unicode)
def linebreaks(value):
- "Converts newlines into <p> and <br />s"
- value = re.sub(r'\r\n|\r|\n', '\n', value) # normalize newlines
+ "Convert newlines into <p> and <br />s."
+ value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines
paras = re.split('\n{2,}', value)
- paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
- return '\n\n'.join(paras)
+ paras = [u'<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
+ return u'\n\n'.join(paras)
+linebreaks = allow_lazy(linebreaks, unicode)
def strip_tags(value):
- "Returns the given HTML with all tags stripped"
- return re.sub(r'<[^>]*?>', '', value)
+ "Return the given HTML with all tags stripped."
+ return re.sub(r'<[^>]*?>', '', force_unicode(value))
+strip_tags = allow_lazy(strip_tags)
def strip_spaces_between_tags(value):
- "Returns the given HTML with spaces between tags removed"
- return re.sub(r'>\s+<', '><', value)
+ "Return the given HTML with spaces between tags removed."
+ return re.sub(r'>\s+<', '><', force_unicode(value))
+strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, unicode)
def strip_entities(value):
- "Returns the given HTML with all entities (&something;) stripped"
- return re.sub(r'&(?:\w+|#\d);', '', value)
+ "Return the given HTML with all entities (&something;) stripped."
+ return re.sub(r'&(?:\w+|#\d+);', '', force_unicode(value))
+strip_entities = allow_lazy(strip_entities, unicode)
def fix_ampersands(value):
- "Returns the given HTML with all unencoded ampersands encoded correctly"
- return unencoded_ampersands_re.sub('&amp;', value)
+ "Return the given HTML with all unencoded ampersands encoded correctly."
+ return unencoded_ampersands_re.sub('&amp;', force_unicode(value))
+fix_ampersands = allow_lazy(fix_ampersands, unicode)
def urlize(text, trim_url_limit=None, nofollow=False):
"""
- Converts any URLs in text into clickable links. Works on http://, https://
- and www. links. Links can have trailing punctuation (periods, commas,
- close-parens) and leading punctuation (opening parens) and it'll still do
- the right thing.
+ Convert any URLs in text into clickable links.
+
+ Works on http://, https://, and www. links. Links can have trailing
+ punctuation (periods, commas, close-parens) and leading punctuation
+ (opening parens) and it'll still do the right thing.
If trim_url_limit is not None, the URLs in link text longer than this limit
will truncated to trim_url_limit-3 characters and appended with an elipsis.
@@ -65,7 +73,7 @@ def urlize(text, trim_url_limit=None, nofollow=False):
attribute.
"""
trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x
- words = word_split_re.split(text)
+ words = word_split_re.split(force_unicode(text))
nofollow_attr = nofollow and ' rel="nofollow"' or ''
for i, word in enumerate(words):
match = punctuation_re.match(word)
@@ -82,22 +90,23 @@ def urlize(text, trim_url_limit=None, nofollow=False):
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
if lead + middle + trail != word:
words[i] = lead + middle + trail
- return ''.join(words)
+ return u''.join(words)
+urlize = allow_lazy(urlize, unicode)
def clean_html(text):
"""
- Cleans the given HTML. Specifically, it does the following:
- * Converts <b> and <i> to <strong> and <em>.
- * Encodes all ampersands correctly.
- * Removes all "target" attributes from <a> tags.
- * Removes extraneous HTML, such as presentational tags that open and
+ Clean the given HTML. Specifically, do the following:
+ * Convert <b> and <i> to <strong> and <em>.
+ * Encode all ampersands correctly.
+ * Remove all "target" attributes from <a> tags.
+ * Remove extraneous HTML, such as presentational tags that open and
immediately close and <br clear="all">.
- * Converts hard-coded bullets into HTML unordered lists.
- * Removes stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the
+ * Convert hard-coded bullets into HTML unordered lists.
+ * Remove stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the
bottom of the text.
"""
from django.utils.text import normalize_newlines
- text = normalize_newlines(text)
+ text = normalize_newlines(force_unicode(text))
text = re.sub(r'<(/?)\s*b\s*>', '<\\1strong>', text)
text = re.sub(r'<(/?)\s*i\s*>', '<\\1em>', text)
text = fix_ampersands(text)
@@ -110,9 +119,10 @@ def clean_html(text):
s = match.group().replace('</p>', '</li>')
for d in DOTS:
s = s.replace('<p>%s' % d, '<li>')
- return '<ul>\n%s\n</ul>' % s
+ return u'<ul>\n%s\n</ul>' % s
text = hard_coded_bullets_re.sub(replace_p_tags, text)
- # Remove stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the bottom of the text.
+ # Remove stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the bottom
+ # of the text.
text = trailing_empty_content_re.sub('', text)
return text
-
+clean_html = allow_lazy(clean_html, unicode)
diff --git a/django/utils/http.py b/django/utils/http.py
new file mode 100644
index 0000000000..4c3b6af868
--- /dev/null
+++ b/django/utils/http.py
@@ -0,0 +1,38 @@
+import urllib
+from django.utils.encoding import smart_str, force_unicode
+from django.utils.functional import allow_lazy
+
+def urlquote(url, safe='/'):
+ """
+ A version of Python's urllib.quote() function that can operate on unicode
+ strings. The url is first UTF-8 encoded before quoting. The returned string
+ can safely be used as part of an argument to a subsequent iri_to_uri() call
+ without double-quoting occurring.
+ """
+ return force_unicode(urllib.quote(smart_str(url)))
+urlquote = allow_lazy(urlquote, unicode)
+
+def urlquote_plus(url, safe=''):
+ """
+ A version of Python's urllib.quote_plus() function that can operate on
+ unicode strings. The url is first UTF-8 encoded before quoting. The
+ returned string can safely be used as part of an argument to a subsequent
+ iri_to_uri() call without double-quoting occurring.
+ """
+ return force_unicode(urllib.quote_plus(smart_str(url), safe))
+urlquote_plus = allow_lazy(urlquote_plus, unicode)
+
+def urlencode(query, doseq=0):
+ """
+ A version of Python's urllib.urlencode() function that can operate on
+ unicode strings. The parameters are first case to UTF-8 encoded strings and
+ then encoded as per normal.
+ """
+ if hasattr(query, 'items'):
+ query = query.items()
+ return urllib.urlencode(
+ [(smart_str(k),
+ isinstance(v, (list,tuple)) and [smart_str(i) for i in v] or smart_str(v))
+ for k, v in query],
+ doseq)
+
diff --git a/django/utils/maxlength.py b/django/utils/maxlength.py
new file mode 100644
index 0000000000..9216fe1c3a
--- /dev/null
+++ b/django/utils/maxlength.py
@@ -0,0 +1,67 @@
+"""
+Utilities for providing backwards compatibility for the maxlength argument,
+which has been replaced by max_length, see ticket #2101.
+"""
+
+from warnings import warn
+
+def get_maxlength(self):
+ return self.max_length
+
+def set_maxlength(self, value):
+ self.max_length = value
+
+def legacy_maxlength(max_length, maxlength):
+ """
+ Consolidates max_length and maxlength, providing backwards compatibilty
+ for the legacy "maxlength" argument.
+ If one of max_length or maxlength is given, then that value is returned.
+ If both are given, a TypeError is raised.
+ If maxlength is used at all, a deprecation warning is issued.
+ """
+ if maxlength is not None:
+ warn("maxlength is deprecated, use max_length instead.",
+ PendingDeprecationWarning,
+ stacklevel=3)
+ if max_length is not None:
+ raise TypeError("field can not take both the max_length"
+ " argument and the legacy maxlength argument.")
+ max_length = maxlength
+ return max_length
+
+def remove_maxlength(func):
+ """
+ A decorator to be used on a class's __init__ that provides backwards
+ compatibilty for the legacy "maxlength" keyword argument, i.e.
+ name = models.CharField(maxlength=20)
+ It does this by changing the passed "maxlength" keyword argument
+ (if it exists) into a "max_length" keyword argument.
+ """
+ def inner(self, *args, **kwargs):
+ max_length = kwargs.get('max_length', None)
+ # pop maxlength because we don't want this going to __init__.
+ maxlength = kwargs.pop('maxlength', None)
+ max_length = legacy_maxlength(max_length, maxlength)
+ # Only set the max_length keyword argument if we got a value back.
+ if max_length is not None:
+ kwargs['max_length'] = max_length
+ func(self, *args, **kwargs)
+ return inner
+
+# This metaclass is used in two places, and should be removed when legacy
+# support for maxlength is dropped.
+# * oldforms.FormField
+# * db.models.fields.Field
+
+class LegacyMaxlength(type):
+ """
+ Metaclass for providing backwards compatibility support for the
+ "maxlength" keyword argument.
+ """
+
+ def __init__(cls, name, bases, attrs):
+ super(LegacyMaxlength, cls).__init__(name, bases, attrs)
+ # Decorate the class's __init__ to remove any maxlength keyword.
+ cls.__init__ = remove_maxlength(cls.__init__)
+ # Support accessing and setting to the legacy maxlength attribute.
+ cls.maxlength = property(get_maxlength, set_maxlength)
diff --git a/django/utils/stopwords.py b/django/utils/stopwords.py
index dea5660413..18aeb7f5d3 100644
--- a/django/utils/stopwords.py
+++ b/django/utils/stopwords.py
@@ -38,5 +38,5 @@ def strip_stopwords(sentence):
for word in words:
if word.lower() not in stopwords:
sentence.append(word)
- return ' '.join(sentence)
+ return u' '.join(sentence)
diff --git a/django/utils/text.py b/django/utils/text.py
index c73ab908f3..4670ab47fa 100644
--- a/django/utils/text.py
+++ b/django/utils/text.py
@@ -1,15 +1,19 @@
import re
-
from django.conf import settings
+from django.utils.encoding import force_unicode
+from django.utils.functional import allow_lazy
+from django.utils.translation import ugettext_lazy
# Capitalizes the first letter of a string.
-capfirst = lambda x: x and x[0].upper() + x[1:]
+capfirst = lambda x: x and force_unicode(x)[0].upper() + force_unicode(x)[1:]
+capfirst = allow_lazy(capfirst, unicode)
def wrap(text, width):
"""
A word-wrap function that preserves existing line breaks and most spaces in
the text. Expects that existing line breaks are posix newlines.
"""
+ text = force_unicode(text)
def _generator():
it = iter(text.split(' '))
word = it.next()
@@ -29,29 +33,34 @@ def wrap(text, width):
if len(lines) > 1:
pos = len(lines[-1])
yield word
- return "".join(_generator())
+ return u''.join(_generator())
+wrap = allow_lazy(wrap, unicode)
def truncate_words(s, num):
"Truncates a string after a certain number of words."
+ s = force_unicode(s)
length = int(num)
words = s.split()
if len(words) > length:
words = words[:length]
if not words[-1].endswith('...'):
words.append('...')
- return ' '.join(words)
+ return u' '.join(words)
+truncate_words = allow_lazy(truncate_words, unicode)
def truncate_html_words(s, num):
"""
- Truncates html to a certain number of words (not counting tags and comments).
- Closes opened tags if they were correctly closed in the given html.
+ Truncates html to a certain number of words (not counting tags and
+ comments). Closes opened tags if they were correctly closed in the given
+ html.
"""
+ s = force_unicode(s)
length = int(num)
if length <= 0:
- return ''
+ return u''
html4_singlets = ('br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input')
# Set up regular expressions
- re_words = re.compile(r'&.*?;|<.*?>|([A-Za-z0-9][\w-]*)')
+ re_words = re.compile(r'&.*?;|<.*?>|(\w[\w-]*)', re.U)
re_tag = re.compile(r'<(/)?([^ ]+?)(?: (/)| .*?)?>')
# Count non-HTML words and keep note of open tags
pos = 0
@@ -100,6 +109,7 @@ def truncate_html_words(s, num):
out += '</%s>' % tag
# Return string
return out
+truncate_html_words = allow_lazy(truncate_html_words, unicode)
def get_valid_filename(s):
"""
@@ -110,10 +120,11 @@ def get_valid_filename(s):
>>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg'
"""
- s = s.strip().replace(' ', '_')
+ s = force_unicode(s).strip().replace(' ', '_')
return re.sub(r'[^-A-Za-z0-9_.]', '', s)
+get_valid_filename = allow_lazy(get_valid_filename, unicode)
-def get_text_list(list_, last_word='or'):
+def get_text_list(list_, last_word=ugettext_lazy(u'or')):
"""
>>> get_text_list(['a', 'b', 'c', 'd'])
'a, b, c or d'
@@ -126,23 +137,22 @@ def get_text_list(list_, last_word='or'):
>>> get_text_list([])
''
"""
- if len(list_) == 0: return ''
- if len(list_) == 1: return list_[0]
- return '%s %s %s' % (', '.join([str(i) for i in list_][:-1]), last_word, list_[-1])
+ if len(list_) == 0: return u''
+ if len(list_) == 1: return force_unicode(list_[0])
+ return u'%s %s %s' % (', '.join([force_unicode(i) for i in list_][:-1]), force_unicode(last_word), force_unicode(list_[-1]))
+get_text_list = allow_lazy(get_text_list, unicode)
def normalize_newlines(text):
- return re.sub(r'\r\n|\r|\n', '\n', text)
+ return force_unicode(re.sub(r'\r\n|\r|\n', '\n', text))
+normalize_newlines = allow_lazy(normalize_newlines, unicode)
def recapitalize(text):
"Recapitalizes text, placing caps after end-of-sentence punctuation."
-# capwords = ()
- text = text.lower()
+ text = force_unicode(text).lower()
capsRE = re.compile(r'(?:^|(?<=[\.\?\!] ))([a-z])')
text = capsRE.sub(lambda x: x.group(1).upper(), text)
-# for capword in capwords:
-# capwordRE = re.compile(r'\b%s\b' % capword, re.I)
-# text = capwordRE.sub(capword, text)
return text
+recapitalize = allow_lazy(recapitalize)
def phone2numeric(phone):
"Converts a phone number with letters into its numeric equivalent."
@@ -153,6 +163,7 @@ def phone2numeric(phone):
's': '7', 'r': '7', 'u': '8', 't': '8', 'w': '9', 'v': '8',
'y': '9', 'x': '9'}.get(m.group(0).lower())
return letters.sub(char2number, phone)
+phone2numeric = allow_lazy(phone2numeric)
# From http://www.xhaus.com/alan/python/httpcomp.html#gzip
# Used with permission.
@@ -172,7 +183,7 @@ def javascript_quote(s, quote_double_quotes=False):
return r"\u%04x" % ord(match.group(1))
if type(s) == str:
- s = s.decode(settings.DEFAULT_CHARSET)
+ s = s.decode('utf-8')
elif type(s) != unicode:
raise TypeError, s
s = s.replace('\\', '\\\\')
@@ -183,6 +194,7 @@ def javascript_quote(s, quote_double_quotes=False):
if quote_double_quotes:
s = s.replace('"', '&quot;')
return str(ustring_re.sub(fix, s))
+javascript_quote = allow_lazy(javascript_quote, unicode)
smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)')
def smart_split(text):
@@ -195,6 +207,7 @@ def smart_split(text):
>>> list(smart_split('This is "a person\'s" test.'))
['This', 'is', '"a person\'s"', 'test.']
"""
+ text = force_unicode(text)
for bit in smart_split_re.finditer(text):
bit = bit.group(0)
if bit[0] == '"' and bit[-1] == '"':
@@ -203,3 +216,5 @@ def smart_split(text):
yield "'" + bit[1:-1].replace("\\'", "'").replace("\\\\", "\\") + "'"
else:
yield bit
+smart_split = allow_lazy(smart_split, unicode)
+
diff --git a/django/utils/timesince.py b/django/utils/timesince.py
index 394f818395..455788e7d7 100644
--- a/django/utils/timesince.py
+++ b/django/utils/timesince.py
@@ -1,6 +1,6 @@
import datetime, math, time
from django.utils.tzinfo import LocalTimezone
-from django.utils.translation import ngettext, gettext
+from django.utils.translation import ungettext, ugettext
def timesince(d, now=None):
"""
@@ -9,12 +9,12 @@ def timesince(d, now=None):
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
"""
chunks = (
- (60 * 60 * 24 * 365, lambda n: ngettext('year', 'years', n)),
- (60 * 60 * 24 * 30, lambda n: ngettext('month', 'months', n)),
- (60 * 60 * 24 * 7, lambda n : ngettext('week', 'weeks', n)),
- (60 * 60 * 24, lambda n : ngettext('day', 'days', n)),
- (60 * 60, lambda n: ngettext('hour', 'hours', n)),
- (60, lambda n: ngettext('minute', 'minutes', n))
+ (60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)),
+ (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)),
+ (60 * 60 * 24 * 7, lambda n : ungettext('week', 'weeks', n)),
+ (60 * 60 * 24, lambda n : ungettext('day', 'days', n)),
+ (60 * 60, lambda n: ungettext('hour', 'hours', n)),
+ (60, lambda n: ungettext('minute', 'minutes', n))
)
# Convert datetime.date to datetime.datetime for comparison
if d.__class__ is not datetime.datetime:
@@ -33,18 +33,16 @@ def timesince(d, now=None):
delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
since = delta.days * 24 * 60 * 60 + delta.seconds
for i, (seconds, name) in enumerate(chunks):
- count = since / seconds
+ count = since // seconds
if count != 0:
break
- if count < 0:
- return gettext('%d milliseconds') % math.floor((now - d).microseconds / 1000)
- s = gettext('%(number)d %(type)s') % {'number': count, 'type': name(count)}
+ s = ugettext('%(number)d %(type)s') % {'number': count, 'type': name(count)}
if i + 1 < len(chunks):
# Now get the second item
seconds2, name2 = chunks[i + 1]
- count2 = (since - (seconds * count)) / seconds2
+ count2 = (since - (seconds * count)) // seconds2
if count2 != 0:
- s += gettext(', %(number)d %(type)s') % {'number': count2, 'type': name2(count2)}
+ s += ugettext(', %(number)d %(type)s') % {'number': count2, 'type': name2(count2)}
return s
def timeuntil(d, now=None):
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index dbb97af76c..13fc8a847a 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -7,7 +7,8 @@ __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
'ngettext_lazy', 'string_concat', 'activate', 'deactivate',
'get_language', 'get_language_bidi', 'get_date_formats',
'get_partial_date_formats', 'check_for_language', 'to_locale',
- 'get_language_from_request', 'install', 'templatize']
+ 'get_language_from_request', 'install', 'templatize', 'ugettext',
+ 'ungettext', 'deactivate_all']
# Here be dragons, so a short explanation of the logic won't hurt:
# We are trying to solve two problems: (1) access settings, in particular
@@ -48,19 +49,28 @@ del g, delayed_loader
def gettext_noop(message):
return real_gettext_noop(message)
+ugettext_noop = gettext_noop
+
def gettext(message):
return real_gettext(message)
-
def ngettext(singular, plural, number):
return real_ngettext(singular, plural, number)
+def ugettext(message):
+ return real_ugettext(message)
+
+def ungettext(singular, plural, number):
+ return real_ungettext(singular, plural, number)
+
def string_concat(*strings):
return real_string_concat(*strings)
-ngettext_lazy = lazy(ngettext, str, unicode)
-gettext_lazy = lazy(gettext, str, unicode)
-string_concat = lazy(string_concat, str, unicode)
+ngettext_lazy = lazy(ngettext, str)
+gettext_lazy = lazy(gettext, str)
+ungettext_lazy = lazy(ungettext, unicode)
+ugettext_lazy = lazy(ugettext, unicode)
+string_concat = lazy(string_concat, unicode)
def activate(language):
return real_activate(language)
@@ -95,3 +105,6 @@ def install():
def templatize(src):
return real_templatize(src)
+def deactivate_all():
+ return real_deactivate_all()
+
diff --git a/django/utils/translation/trans_null.py b/django/utils/translation/trans_null.py
index 10b07529e3..e3f89567a5 100644
--- a/django/utils/translation/trans_null.py
+++ b/django/utils/translation/trans_null.py
@@ -3,15 +3,19 @@
# settings.USE_I18N = False can use this module rather than trans_real.py.
from django.conf import settings
+from django.utils.encoding import force_unicode
def ngettext(singular, plural, number):
if number == 1: return singular
return plural
ngettext_lazy = ngettext
-string_concat = lambda *strings: ''.join([str(el) for el in strings])
+def ungettext(singular, plural, number):
+ return force_unicode(ngettext(singular, plural, number))
+
+string_concat = lambda *strings: u''.join([force_unicode(el) for el in strings])
activate = lambda x: None
-deactivate = install = lambda: None
+deactivate = deactivate_all = install = lambda: None
get_language = lambda: settings.LANGUAGE_CODE
get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
@@ -30,6 +34,9 @@ TECHNICAL_ID_MAP = {
def gettext(message):
return TECHNICAL_ID_MAP.get(message, message)
+def ugettext(message):
+ return force_unicode(gettext(message))
+
gettext_noop = gettext_lazy = _ = gettext
def to_locale(language):
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 293b4ef9cd..765152afce 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -3,6 +3,7 @@
import os, re, sys
import gettext as gettext_module
from cStringIO import StringIO
+from django.utils.encoding import force_unicode
try:
import threading
@@ -57,10 +58,10 @@ class DjangoTranslation(gettext_module.GNUTranslations):
# the output charset. Before 2.4, the output charset is
# identical with the translation file charset.
try:
- self.set_output_charset(settings.DEFAULT_CHARSET)
+ self.set_output_charset('utf-8')
except AttributeError:
pass
- self.django_output_charset = settings.DEFAULT_CHARSET
+ self.django_output_charset = 'utf-8'
self.__language = '??'
def merge(self, other):
@@ -202,6 +203,14 @@ def deactivate():
if currentThread() in _active:
del _active[currentThread()]
+def deactivate_all():
+ """
+ Makes the active translation object a NullTranslations() instance. This is
+ useful when we want delayed translations to appear as the original string
+ for some reason.
+ """
+ _active[currentThread()] = gettext_module.NullTranslations()
+
def get_language():
"Returns the currently selected language."
t = _active.get(currentThread(), None)
@@ -238,49 +247,72 @@ def catalog():
_default = translation(settings.LANGUAGE_CODE)
return _default
-def gettext(message):
+def do_translate(message, translation_function):
"""
- This function will be patched into the builtins module to provide the _
- helper function. It will use the current thread as a discriminator to find
- the translation object to use. If no current translation is activated, the
- message will be run through the default translation object.
+ Translate 'message' using the given 'translation_function' name -- which
+ will be either gettext or ugettext.
"""
global _default, _active
t = _active.get(currentThread(), None)
if t is not None:
- return t.gettext(message)
+ return getattr(t, translation_function)(message)
if _default is None:
from django.conf import settings
_default = translation(settings.LANGUAGE_CODE)
- return _default.gettext(message)
+ return getattr(_default, translation_function)(message)
+
+def gettext(message):
+ """
+ This function will be patched into the builtins module to provide the _
+ helper function. It will use the current thread as a discriminator to find
+ the translation object to use. If no current translation is activated, the
+ message will be run through the default translation object.
+ """
+ return do_translate(message, 'gettext')
+
+def ugettext(message):
+ return do_translate(message, 'ugettext')
def gettext_noop(message):
"""
Marks strings for translation but doesn't translate them now. This can be
used to store strings in global variables that should stay in the base
- language (because they might be used externally) and will be translated later.
+ language (because they might be used externally) and will be translated
+ later.
"""
return message
-def ngettext(singular, plural, number):
- """
- Returns the translation of either the singular or plural, based on the number.
- """
+def do_ntranslate(singular, plural, number, translation_function):
global _default, _active
t = _active.get(currentThread(), None)
if t is not None:
- return t.ngettext(singular, plural, number)
+ return getattr(t, translation_function)(singular, plural, number)
if _default is None:
from django.conf import settings
_default = translation(settings.LANGUAGE_CODE)
- return _default.ngettext(singular, plural, number)
+ return getattr(_default, translation_function)(singular, plural, number)
+
+def ngettext(singular, plural, number):
+ """
+ Returns a UTF-8 bytestring of the translation of either the singular or
+ plural, based on the number.
+ """
+ return do_ntranslate(singular, plural, number, 'ngettext')
+
+def ungettext(singular, plural, number):
+ """
+ Returns a unicode strings of the translation of either the singular or
+ plural, based on the number.
+ """
+ return do_ntranslate(singular, plural, number, 'ungettext')
def check_for_language(lang_code):
"""
- Checks whether there is a global language file for the given language code.
- This is used to decide whether a user-provided language is available. This is
- only used for language codes from either the cookies or session.
+ Checks whether there is a global language file for the given language
+ code. This is used to decide whether a user-provided language is
+ available. This is only used for language codes from either the cookies or
+ session.
"""
from django.conf import settings
globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
@@ -291,9 +323,10 @@ def check_for_language(lang_code):
def get_language_from_request(request):
"""
- Analyzes the request to find what language the user wants the system to show.
- Only languages listed in settings.LANGUAGES are taken into account. If the user
- requests a sublanguage where we have a main language, we send out the main language.
+ Analyzes the request to find what language the user wants the system to
+ show. Only languages listed in settings.LANGUAGES are taken into account.
+ If the user requests a sublanguage where we have a main language, we send
+ out the main language.
"""
global _accepted
from django.conf import settings
@@ -355,9 +388,9 @@ def get_date_formats():
one, the formats provided in the settings will be used.
"""
from django.conf import settings
- date_format = _('DATE_FORMAT')
- datetime_format = _('DATETIME_FORMAT')
- time_format = _('TIME_FORMAT')
+ date_format = ugettext('DATE_FORMAT')
+ datetime_format = ugettext('DATETIME_FORMAT')
+ time_format = ugettext('TIME_FORMAT')
if date_format == 'DATE_FORMAT':
date_format = settings.DATE_FORMAT
if datetime_format == 'DATETIME_FORMAT':
@@ -373,8 +406,8 @@ def get_partial_date_formats():
one, the formats provided in the settings will be used.
"""
from django.conf import settings
- year_month_format = _('YEAR_MONTH_FORMAT')
- month_day_format = _('MONTH_DAY_FORMAT')
+ year_month_format = ugettext('YEAR_MONTH_FORMAT')
+ month_day_format = ugettext('MONTH_DAY_FORMAT')
if year_month_format == 'YEAR_MONTH_FORMAT':
year_month_format = settings.YEAR_MONTH_FORMAT
if month_day_format == 'MONTH_DAY_FORMAT':
@@ -483,9 +516,7 @@ def templatize(src):
def string_concat(*strings):
""""
- lazy variant of string concatenation, needed for translations that are
- constructed from multiple parts. Handles lazy strings and non-strings by
- first turning all arguments to strings, before joining them.
+ Lazy variant of string concatenation, needed for translations that are
+ constructed from multiple parts.
"""
- return ''.join([str(el) for el in strings])
-
+ return u''.join([force_unicode(s) for s in strings])
diff --git a/django/utils/tzinfo.py b/django/utils/tzinfo.py
index cc9f028e91..e2e1d10fc1 100644
--- a/django/utils/tzinfo.py
+++ b/django/utils/tzinfo.py
@@ -1,13 +1,17 @@
"Implementation of tzinfo classes for use with datetime.datetime."
+import locale
import time
from datetime import timedelta, tzinfo
+from django.utils.encoding import smart_unicode
+
+DEFAULT_ENCODING = locale.getdefaultlocale()[1] or 'ascii'
class FixedOffset(tzinfo):
"Fixed offset in minutes east from UTC."
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
- self.__name = "%+03d%02d" % (offset // 60, offset % 60)
+ self.__name = u"%+03d%02d" % (offset // 60, offset % 60)
def __repr__(self):
return self.__name
@@ -25,7 +29,7 @@ class LocalTimezone(tzinfo):
"Proxy timezone information from time module."
def __init__(self, dt):
tzinfo.__init__(self, dt)
- self._tzname = time.tzname[self._isdst(dt)]
+ self._tzname = self.tzname(dt)
def __repr__(self):
return self._tzname
@@ -43,7 +47,10 @@ class LocalTimezone(tzinfo):
return timedelta(0)
def tzname(self, dt):
- return time.tzname[self._isdst(dt)]
+ try:
+ return smart_unicode(time.tzname[self._isdst(dt)], DEFAULT_ENCODING)
+ except UnicodeDecodeError:
+ return None
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
diff --git a/django/utils/version.py b/django/utils/version.py
new file mode 100644
index 0000000000..cf8085653f
--- /dev/null
+++ b/django/utils/version.py
@@ -0,0 +1,39 @@
+import django
+import os.path
+import re
+
+def get_svn_revision(path=None):
+ """
+ Returns the SVN revision in the form SVN-XXXX,
+ where XXXX is the revision number.
+
+ Returns SVN-unknown if anything goes wrong, such as an unexpected
+ format of internal SVN files.
+
+ If path is provided, it should be a directory whose SVN info you want to
+ inspect. If it's not provided, this will use the root django/ package
+ directory.
+ """
+ rev = None
+ if path is None:
+ path = django.__path__[0]
+ entries_path = '%s/.svn/entries' % path
+
+ if os.path.exists(entries_path):
+ entries = open(entries_path, 'r').read()
+ # Versions >= 7 of the entries file are flat text. The first line is
+ # the version number. The next set of digits after 'dir' is the revision.
+ if re.match('(\d+)', entries):
+ rev_match = re.search('\d+\s+dir\s+(\d+)', entries)
+ if rev_match:
+ rev = rev_match.groups()[0]
+ # Older XML versions of the file specify revision as an attribute of
+ # the first entries node.
+ else:
+ from xml.dom import minidom
+ dom = minidom.parse(entries_path)
+ rev = dom.getElementsByTagName('entry')[0].getAttribute('revision')
+
+ if rev:
+ return u'SVN-%s' % rev
+ return u'SVN-unknown'
diff --git a/django/views/debug.py b/django/views/debug.py
index a534f17b33..cf0b6b5a0b 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -2,6 +2,7 @@ from django.conf import settings
from django.template import Template, Context, TemplateDoesNotExist
from django.utils.html import escape
from django.http import HttpResponseServerError, HttpResponseNotFound
+from django.utils.encoding import smart_unicode
import os, re, sys
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
@@ -122,10 +123,20 @@ def technical_500_response(request, exc_type, exc_value, tb):
'function': '?',
'lineno': '?',
}]
+
+ unicode_hint = ''
+ if issubclass(exc_type, UnicodeError):
+ start = getattr(exc_value, 'start', None)
+ end = getattr(exc_value, 'end', None)
+ if start is not None and end is not None:
+ unicode_str = exc_value.args[1]
+ unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace')
+
t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template')
c = Context({
'exception_type': exc_type.__name__,
- 'exception_value': exc_value,
+ 'exception_value': smart_unicode(exc_value, errors='replace'),
+ 'unicode_hint': unicode_hint,
'frames': frames,
'lastframe': frames[-1],
'request': request,
@@ -190,6 +201,17 @@ def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_na
if source is None:
return None, [], None, []
+ encoding=None
+ for line in source[:2]:
+ # File coding may be specified (and may not be UTF-8). Match
+ # pattern from PEP-263 (http://www.python.org/dev/peps/pep-0263/)
+ match = re.search(r'coding[:=]\s*([-\w.]+)', line)
+ if match:
+ encoding = match.group(1)
+ break
+ if encoding:
+ source = [unicode(sline, encoding) for sline in source]
+
lower_bound = max(0, lineno - context_lines)
upper_bound = lineno + context_lines
@@ -246,6 +268,7 @@ TECHNICAL_500_TEMPLATE = """
#explanation { background:#eee; }
#template, #template-not-exist { background:#f6f6f6; }
#template-not-exist ul { margin: 0 0 0 20px; }
+ #unicode-hint { background:#eee; }
#traceback { background:#eee; }
#requestinfo { background:#f6f6f6; padding-left:120px; }
#summary table { border:none; background:transparent; }
@@ -346,6 +369,12 @@ TECHNICAL_500_TEMPLATE = """
</tr>
</table>
</div>
+{% if unicode_hint %}
+<div id="unicode-hint">
+ <h2>Unicode error hint</h2>
+ <p>The string that could not be encoded/decoded was: <strong>{{ unicode_hint|escape }}</strong></p>
+</div>
+{% endif %}
{% if template_does_not_exist %}
<div id="template-not-exist">
<h2>Template-loader postmortem</h2>
diff --git a/django/views/defaults.py b/django/views/defaults.py
index 701aebabd6..b4dfc1e1eb 100644
--- a/django/views/defaults.py
+++ b/django/views/defaults.py
@@ -21,7 +21,7 @@ def shortcut(request, content_type_id, object_id):
# if necessary.
# If the object actually defines a domain, we're done.
- if absurl.startswith('http://'):
+ if absurl.startswith('http://') or absurl.startswith('https://'):
return http.HttpResponseRedirect(absurl)
object_domain = None
@@ -61,7 +61,8 @@ def shortcut(request, content_type_id, object_id):
# If all that malarkey found an object domain, use it; otherwise fall back
# to whatever get_absolute_url() returned.
if object_domain is not None:
- return http.HttpResponseRedirect('http://%s%s' % (object_domain, absurl))
+ protocol = request.is_secure() and 'https' or 'http'
+ return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl))
else:
return http.HttpResponseRedirect(absurl)
diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py
index 28987f7544..46e92fe26e 100644
--- a/django/views/generic/create_update.py
+++ b/django/views/generic/create_update.py
@@ -6,7 +6,7 @@ from django.contrib.auth.views import redirect_to_login
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
-from django.utils.translation import gettext
+from django.utils.translation import ugettext
def create_object(request, model, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None,
@@ -40,7 +40,7 @@ def create_object(request, model, template_name=None,
new_object = manipulator.save(new_data)
if request.user.is_authenticated():
- request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
+ request.user.message_set.create(message=ugettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
# Redirect to the new object: first by trying post_save_redirect,
# then by obj.get_absolute_url; fail if neither works.
@@ -71,7 +71,7 @@ def create_object(request, model, template_name=None,
return HttpResponse(t.render(c))
def update_object(request, model, object_id=None, slug=None,
- slug_field=None, template_name=None, template_loader=loader,
+ slug_field='slug', template_name=None, template_loader=loader,
extra_context=None, post_save_redirect=None,
login_required=False, follow=None, context_processors=None,
template_object_name='object'):
@@ -114,7 +114,7 @@ def update_object(request, model, object_id=None, slug=None,
object = manipulator.save(new_data)
if request.user.is_authenticated():
- request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
+ request.user.message_set.create(message=ugettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
# Do a post-after-redirect so that reload works, etc.
if post_save_redirect:
@@ -146,7 +146,7 @@ def update_object(request, model, object_id=None, slug=None,
return response
def delete_object(request, model, post_delete_redirect,
- object_id=None, slug=None, slug_field=None, template_name=None,
+ object_id=None, slug=None, slug_field='slug', template_name=None,
template_loader=loader, extra_context=None,
login_required=False, context_processors=None, template_object_name='object'):
"""
@@ -181,7 +181,7 @@ def delete_object(request, model, post_delete_redirect,
if request.method == 'POST':
object.delete()
if request.user.is_authenticated():
- request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
+ request.user.message_set.create(message=ugettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
return HttpResponseRedirect(post_delete_redirect)
else:
if not template_name:
diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py
index d13c0293be..c0f219f280 100644
--- a/django/views/generic/date_based.py
+++ b/django/views/generic/date_based.py
@@ -286,7 +286,7 @@ def archive_today(request, **kwargs):
def object_detail(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', object_id=None, slug=None,
- slug_field=None, template_name=None, template_name_field=None,
+ slug_field='slug', template_name=None, template_name_field=None,
template_loader=loader, extra_context=None, context_processors=None,
template_object_name='object', mimetype=None, allow_future=False):
"""
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
index 16d55202da..f5616b9745 100644
--- a/django/views/generic/list_detail.py
+++ b/django/views/generic/list_detail.py
@@ -87,7 +87,7 @@ def object_list(request, queryset, paginate_by=None, page=None,
return HttpResponse(t.render(c), mimetype=mimetype)
def object_detail(request, queryset, object_id=None, slug=None,
- slug_field=None, template_name=None, template_name_field=None,
+ slug_field='slug', template_name=None, template_name_field=None,
template_loader=loader, extra_context=None,
context_processors=None, template_object_name='object',
mimetype=None):
diff --git a/django/views/i18n.py b/django/views/i18n.py
index 0fec6b6c6f..320caf37d7 100644
--- a/django/views/i18n.py
+++ b/django/views/i18n.py
@@ -69,9 +69,9 @@ function pluralidx(count) { return (count == 1) ? 0 : 1; }
InterPolate = r"""
function interpolate(fmt, obj, named) {
if (named) {
- return fmt.replace(/%\(\w+\)s/, function(match){return String(obj[match.slice(2,-2)])});
+ return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
- return fmt.replace(/%s/, function(match){return String(obj.shift())});
+ return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
}
"""
diff --git a/docs/add_ons.txt b/docs/add_ons.txt
index ffc4f7420f..a1d78b8685 100644
--- a/docs/add_ons.txt
+++ b/docs/add_ons.txt
@@ -138,6 +138,29 @@ Examples:
You can pass in either an integer or a string representation of an integer.
+naturalday
+----------
+
+**New in Django development version**
+
+For dates that are the current day or within one day, return "today",
+"tomorrow" or "yesterday", as appropriate. Otherwise, format the date using
+the passed in format string.
+
+**Argument:** Date formatting string as described in default tag now_.
+
+.. _now: ../templates/#now
+
+Examples (when 'today' is 17 Feb 2007):
+
+ * ``16 Feb 2007`` becomes ``yesterday``.
+ * ``17 Feb 2007`` becomes ``today``.
+ * ``18 Feb 2007`` becomes ``tomorrow``.
+ * Any other day is formatted according to given argument or the
+ `DATE_FORMAT`_ setting if no argument is given.
+
+.. _DATE_FORMAT: ../settings/#date_format
+
flatpages
=========
@@ -214,7 +237,7 @@ A framework for generating syndication feeds, in RSS and Atom, quite easily.
See the `syndication documentation`_.
-.. _syndication documentation: ../syndication/
+.. _syndication documentation: ../syndication_feeds/
Other add-ons
=============
diff --git a/docs/api_stability.txt b/docs/api_stability.txt
index cfaffeac6b..5ccf104327 100644
--- a/docs/api_stability.txt
+++ b/docs/api_stability.txt
@@ -82,9 +82,6 @@ that 90% of Django can be considered forwards-compatible at this point.
That said, these APIs should *not* be considered stable, and are likely to
change:
- - `Forms and validation`_ will most likely be completely rewritten to
- deemphasize Manipulators in favor of validation-aware models.
-
- `Serialization`_ is under heavy development; changes are likely.
- The `authentication`_ framework is changing to be far more flexible, and
@@ -114,7 +111,7 @@ change:
.. _sending email: ../email/
.. _sessions: ../sessions/
.. _settings: ../settings/
-.. _syndication: ../syndication/
+.. _syndication: ../syndication_feeds/
.. _template language: ../templates/
.. _transactions: ../transactions/
.. _url dispatch: ../url_dispatch/
diff --git a/docs/authentication.txt b/docs/authentication.txt
index efe4d47513..7860b59d7d 100644
--- a/docs/authentication.txt
+++ b/docs/authentication.txt
@@ -99,7 +99,7 @@ custom methods:
should prefer using ``is_authenticated()`` to this method.
* ``is_authenticated()`` -- Always returns ``True``. This is a way to
- tell if the user has been authenticated. This does not imply any
+ tell if the user has been authenticated. This does not imply any
permissions, and doesn't check if the user is active - it only indicates
that the user has provided a valid username and password.
@@ -114,6 +114,18 @@ custom methods:
string is the correct password for the user. (This takes care of the
password hashing in making the comparison.)
+ * ``set_unusable_password()`` -- **New in Django development version.**
+ Marks the user as having no password set. This isn't the same as having
+ a blank string for a password. ``check_password()`` for this user will
+ never return ``True``. Doesn't save the ``User`` object.
+
+ You may need this if authentication for your application takes place
+ against an existing external source such as an LDAP directory.
+
+ * ``has_usable_password()`` -- **New in Django development version.**
+ Returns ``False`` if ``set_unusable_password()`` has been called for this
+ user.
+
* ``get_group_permissions()`` -- Returns a list of permission strings that
the user has, through his/her groups.
@@ -126,7 +138,7 @@ custom methods:
* ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the
specified permissions, where each perm is in the format
- ``"package.codename"``. If the user is inactive, this method will
+ ``"package.codename"``. If the user is inactive, this method will
always return ``False``.
* ``has_module_perms(package_name)`` -- Returns ``True`` if the user has
@@ -152,9 +164,11 @@ Manager functions
The ``User`` model has a custom manager that has the following helper functions:
- * ``create_user(username, email, password)`` -- Creates, saves and returns
- a ``User``. The ``username``, ``email`` and ``password`` are set as
- given, and the ``User`` gets ``is_active=True``.
+ * ``create_user(username, email, password=None)`` -- Creates, saves and
+ returns a ``User``. The ``username``, ``email`` and ``password`` are set
+ as given, and the ``User`` gets ``is_active=True``.
+
+ If no password is provided, ``set_unusable_password()`` will be called.
See _`Creating users` for example usage.
@@ -220,7 +234,7 @@ the setting and checking of these values behind the scenes.
Previous Django versions, such as 0.90, used simple MD5 hashes without password
salts. For backwards compatibility, those are still supported; they'll be
-converted automatically to the new style the first time ``check_password()``
+converted automatically to the new style the first time ``User.check_password()``
works correctly for a given user.
Anonymous users
@@ -422,7 +436,10 @@ template context variables:
* ``next``: The URL to redirect to after successful login. This may contain
a query string, too.
* ``site_name``: The name of the current ``Site``, according to the
- ``SITE_ID`` setting. See the `site framework docs`_.
+ ``SITE_ID`` setting. If you're using the Django development version and
+ you don't have the site framework installed, this will be set to the
+ value of ``request.META['SERVER_NAME']``. For more on sites, see the
+ `site framework docs`_.
If you'd prefer not to call the template ``registration/login.html``, you can
pass the ``template_name`` parameter via the extra arguments to the view in
@@ -661,8 +678,6 @@ Example in Python 2.4 syntax::
The permission_required decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**New in Django development version**
-
It's a relatively common task to check whether a user has a particular
permission. For that reason, Django provides a shortcut for that case: the
``permission_required()`` decorator. Using this decorator, the earlier example
diff --git a/docs/cache.txt b/docs/cache.txt
index e245e100e7..d13352b025 100644
--- a/docs/cache.txt
+++ b/docs/cache.txt
@@ -543,7 +543,7 @@ Order of MIDDLEWARE_CLASSES
If you use ``CacheMiddleware``, it's important to put it in the right place
within the ``MIDDLEWARE_CLASSES`` setting, because the cache middleware needs
to know which headers by which to vary the cache storage. Middleware always
-adds something the ``Vary`` response header when it can.
+adds something to the ``Vary`` response header when it can.
Put the ``CacheMiddleware`` after any middlewares that might add something to
the ``Vary`` header. The following middlewares do so:
diff --git a/docs/contributing.txt b/docs/contributing.txt
index b3c7efa2f7..b0df62fe99 100644
--- a/docs/contributing.txt
+++ b/docs/contributing.txt
@@ -67,6 +67,13 @@ particular:
likely to get lost. If a particular ticket is controversial, please move
discussion to `django-developers`_.
+ * **Don't** post to django-developers just to announce that you have filed
+ a bug report. All the tickets are mailed to another list
+ (`django-updates`_), which is tracked by developers and triagers, so we
+ see them as they are filed.
+
+.. _django-updates: http://groups.google.com/group/django-updates
+
Reporting security issues
=========================
@@ -279,6 +286,22 @@ Please follow these coding standards when writing code for inclusion in Django:
* Mark all strings for internationalization; see the `i18n documentation`_
for details.
+ * In docstrings, use "action words" such as::
+
+ def foo():
+ """
+ Calculates something and returns the result.
+ """
+ pass
+
+ Here's an example of what not to do::
+
+ def foo():
+ """
+ Calculate something and return the result.
+ """
+ pass
+
* Please don't put your name in the code you contribute. Our policy is to
keep contributors' names in the ``AUTHORS`` file distributed with Django
-- not scattered throughout the codebase itself. Feel free to include a
@@ -324,14 +347,14 @@ Model style
Do this::
class Person(models.Model):
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=40)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=40)
Don't do this::
class Person(models.Model):
- FirstName = models.CharField(maxlength=20)
- Last_Name = models.CharField(maxlength=40)
+ FirstName = models.CharField(max_length=20)
+ Last_Name = models.CharField(max_length=40)
* The ``class Meta`` should appear *after* the fields are defined, with
a single blank line separating the fields and the class definition.
@@ -339,8 +362,8 @@ Model style
Do this::
class Person(models.Model):
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=40)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
@@ -348,8 +371,8 @@ Model style
Don't do this::
class Person(models.Model):
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=40)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
@@ -359,8 +382,8 @@ Model style
class Meta:
verbose_name_plural = 'people'
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=40)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=40)
* The order of model inner classes and standard methods should be as
follows (noting that these are not all required):
@@ -368,6 +391,7 @@ Model style
* All database fields
* ``class Meta``
* ``class Admin``
+ * ``def __unicode__()``
* ``def __str__()``
* ``def save()``
* ``def get_absolute_url()``
@@ -393,11 +417,11 @@ Guidelines for ReST files
These guidelines regulate the format of our ReST documentation:
- * In section titles, capitalize only initial words and proper nouns.
+ * In section titles, capitalize only initial words and proper nouns.
- * Wrap the documentation at 80 characters wide, unless a code example
- is significantly less readable when split over two lines, or for another
- good reason.
+ * Wrap the documentation at 80 characters wide, unless a code example
+ is significantly less readable when split over two lines, or for another
+ good reason.
Commonly used terms
-------------------
@@ -405,41 +429,41 @@ Commonly used terms
Here are some style guidelines on commonly used terms throughout the
documentation:
- * **Django** -- when referring to the framework, capitalize Django. It is
- lowercase only in Python code and in the djangoproject.com logo.
+ * **Django** -- when referring to the framework, capitalize Django. It is
+ lowercase only in Python code and in the djangoproject.com logo.
- * **e-mail** -- it has a hyphen.
+ * **e-mail** -- it has a hyphen.
- * **MySQL**
+ * **MySQL**
- * **PostgreSQL**
+ * **PostgreSQL**
- * **Python** -- when referring to the language, capitalize Python.
+ * **Python** -- when referring to the language, capitalize Python.
- * **realize**, **customize**, **initialize**, etc. -- use the American
- "ize" suffix, not "ise."
+ * **realize**, **customize**, **initialize**, etc. -- use the American
+ "ize" suffix, not "ise."
- * **SQLite**
+ * **SQLite**
- * **subclass** -- it's a single word without a hyphen, both as a verb
- ("subclass that model") and as a noun ("create a subclass").
+ * **subclass** -- it's a single word without a hyphen, both as a verb
+ ("subclass that model") and as a noun ("create a subclass").
- * **Web**, **World Wide Web**, **the Web** -- note Web is always
- capitalized when referring to the World Wide Web.
+ * **Web**, **World Wide Web**, **the Web** -- note Web is always
+ capitalized when referring to the World Wide Web.
* **Web site** -- use two words, with Web capitalized.
Django-specific terminology
---------------------------
- * **model** -- it's not capitalized.
+ * **model** -- it's not capitalized.
- * **template** -- it's not capitalized.
+ * **template** -- it's not capitalized.
- * **URLconf** -- use three capitalized letters, with no space before
- "conf."
+ * **URLconf** -- use three capitalized letters, with no space before
+ "conf."
- * **view** -- it's not capitalized.
+ * **view** -- it's not capitalized.
Committing code
===============
@@ -528,11 +552,9 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
./runtests.py --settings=path.to.django.settings
Yes, the unit tests need a settings module, but only for database connection
-info -- the ``DATABASE_NAME`` (required, but will be ignored),
-``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD`` settings. You
-will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just needs
-to be present) and a ``SITE_ID`` setting (any integer value will do) in order
-for all the tests to pass.
+info, with the ``DATABASE_ENGINE`` setting. You will also need a ``ROOT_URLCONF``
+setting (its value is ignored; it just needs to be present) and a ``SITE_ID``
+setting (any non-zero integer value will do) in order for all the tests to pass.
The unit tests will not touch your existing databases; they create a new
database, called ``django_test_db``, which is deleted when the tests are
diff --git a/docs/csrf.txt b/docs/csrf.txt
index c12dd1d116..7d79e39502 100644
--- a/docs/csrf.txt
+++ b/docs/csrf.txt
@@ -41,10 +41,10 @@ CsrfMiddleware does two things:
This ensures that only forms that have originated from your web site
can be used to POST data back.
-It deliberately only targets HTTP POST requests (and the corresponding
-POST forms). GET requests ought never to have side effects (if you are
-using HTTP GET and POST correctly), and so a CSRF attack with a GET
-request will always be harmless.
+It deliberately only targets HTTP POST requests (and the corresponding POST
+forms). GET requests ought never to have any potentially dangerous side
+effects (see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a
+CSRF attack with a GET request ought to be harmless.
POST requests that are not accompanied by a session cookie are not protected,
but they do not need to be protected, since the 'attacking' web site
@@ -54,6 +54,8 @@ The Content-Type is checked before modifying the response, and only
pages that are served as 'text/html' or 'application/xml+xhtml'
are modified.
+.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+
Limitations
===========
diff --git a/docs/databases.txt b/docs/databases.txt
index b73f39843c..ed0cb61bc3 100644
--- a/docs/databases.txt
+++ b/docs/databases.txt
@@ -124,7 +124,7 @@ Several other MySQLdb connection options may be useful, such as ``ssl``,
``use_unicode``, ``init_command``, and ``sql_mode``. Consult the
`MySQLdb documentation`_ for more details.
-.. _settings documentation: http://www.djangoproject.com/documentation/settings/#database-engine
+.. _settings documentation: ../settings/#database-engine
.. _MySQL option file: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
.. _MySQLdb documentation: http://mysql-python.sourceforge.net/
diff --git a/docs/databrowse.txt b/docs/databrowse.txt
index 9c03e7e4ea..81e9e8e83b 100644
--- a/docs/databrowse.txt
+++ b/docs/databrowse.txt
@@ -35,6 +35,7 @@ How to use Databrowse
2. Register a number of models with the Databrowse site::
from django.contrib import databrowse
+ from myapp.models import SomeModel, SomeOtherModel
databrowse.site.register(SomeModel)
databrowse.site.register(SomeOtherModel)
diff --git a/docs/db-api.txt b/docs/db-api.txt
index a4b920fb33..766a6ae519 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -12,27 +12,27 @@ Throughout this reference, we'll refer to the following models, which comprise
a weblog application::
class Blog(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
tagline = models.TextField()
- def __str__(self):
+ def __unicode__(self):
return self.name
class Author(models.Model):
- name = models.CharField(maxlength=50)
- email = models.URLField()
+ name = models.CharField(max_length=50)
+ email = models.EmailField()
- def __str__(self):
+ def __unicode__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog)
- headline = models.CharField(maxlength=255)
+ headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateTimeField()
authors = models.ManyToManyField(Author)
- def __str__(self):
+ def __unicode__(self):
return self.headline
Creating objects
@@ -118,6 +118,79 @@ happens.
Explicitly specifying auto-primary-key values is mostly useful for bulk-saving
objects, when you're confident you won't have primary-key collision.
+What happens when you save?
+---------------------------
+
+When you save an object, Django performs the following steps:
+
+ 1. **Emit a ``pre_save`` signal.** This provides a notification that
+ an object is about to be saved. You can register a listener that
+ will be invoked whenever this signal is emitted. (These signals are
+ not yet documented.)
+
+ 2. **Pre-process the data.** Each field on the object is asked to
+ perform any automated data modification that the field may need
+ to perform.
+
+ Most fields do *no* pre-processing -- the field data is kept as-is.
+ Pre-processing is only used on fields that have special behavior.
+ For example, if your model has a ``DateField`` with ``auto_now=True``,
+ the pre-save phase will alter the data in the object to ensure that
+ the date field contains the current date stamp. (Our documentation
+ doesn't yet include a list of all the fields with this "special
+ behavior.")
+
+ 3. **Prepare the data for the database.** Each field is asked to provide
+ its current value in a data type that can be written to the database.
+
+ Most fields require *no* data preparation. Simple data types, such as
+ integers and strings, are 'ready to write' as a Python object. However,
+ more complex data types often require some modification.
+
+ For example, ``DateFields`` use a Python ``datetime`` object to store
+ data. Databases don't store ``datetime`` objects, so the field value
+ must be converted into an ISO-compliant date string for insertion
+ into the database.
+
+ 4. **Insert the data into the database.** The pre-processed, prepared
+ data is then composed into an SQL statement for insertion into the
+ database.
+
+ 5. **Emit a ``post_save`` signal.** As with the ``pre_save`` signal, this
+ is used to provide notification that an object has been successfully
+ saved. (These signals are not yet documented.)
+
+Raw Saves
+~~~~~~~~~
+
+**New in Django development version**
+
+The pre-processing step (#2 in the previous section) is useful, but it modifies
+the data stored in a field. This can cause problems if you're relying upon the
+data you provide being used as-is.
+
+For example, if you're setting up conditions for a test, you'll want the test
+conditions to be repeatable. If pre-processing is performed, the data used
+to specify test conditions may be modified, changing the conditions for the
+test each time the test is run.
+
+In cases such as this, you need to prevent pre-processing from being performed
+when you save an object. To do this, you can invoke a **raw save** by passing
+``raw=True`` as an argument to the ``save()`` method::
+
+ b4.save(raw=True) # Save object, but do no pre-processing
+
+A raw save skips the usual data pre-processing that is performed during the
+save. All other steps in the save (pre-save signal, data preparation, data
+insertion, and post-save signal) are performed as normal.
+
+.. admonition:: When to use a raw save
+
+ Generally speaking, you shouldn't need to use a raw save. Disabling field
+ pre-processing is an extraordinary measure that should only be required
+ in extraordinary circumstances, such as setting up reliable test
+ conditions.
+
Saving changes to objects
=========================
@@ -140,7 +213,7 @@ object of the right type to the field in question::
joe = Author.objects.create(name="Joe")
entry.author = joe
entry.save()
-
+
Django will complain if you try to assign an object of the wrong type.
How Django knows to UPDATE vs. INSERT
@@ -336,7 +409,7 @@ For example, this returns the first 5 objects (``LIMIT 5``)::
Entry.objects.all()[:5]
-This returns the fifth through tenth objects (``OFFSET 5 LIMIT 5``)::
+This returns the sixth through tenth objects (``OFFSET 5 LIMIT 5``)::
Entry.objects.all()[5:10]
@@ -1430,7 +1503,7 @@ precede the definition of any keyword arguments. For example::
See the `OR lookups examples page`_ for more examples.
-.. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/
+.. _OR lookups examples page: ../models/or_lookups/
Related objects
===============
@@ -1733,8 +1806,8 @@ following model::
('F', 'Female'),
)
class Person(models.Model):
- name = models.CharField(maxlength=20)
- gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
+ name = models.CharField(max_length=20)
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
...each ``Person`` instance will have a ``get_gender_display()`` method. Example::
@@ -1761,7 +1834,7 @@ Note that in the case of identical date values, these methods will use the ID
as a fallback check. This guarantees that no records are skipped or duplicated.
For a full example, see the `lookup API sample model`_.
-.. _lookup API sample model: http://www.djangoproject.com/documentation/models/lookup/
+.. _lookup API sample model: ../models/lookup/
get_FOO_filename()
------------------
@@ -1818,8 +1891,8 @@ get_object_or_404()
One common idiom to use ``get()`` and raise ``Http404`` if the
object doesn't exist. This idiom is captured by ``get_object_or_404()``.
This function takes a Django model as its first argument and an
-arbitrary number of keyword arguments, which it passes to the manager's
-``get()`` function. It raises ``Http404`` if the object doesn't
+arbitrary number of keyword arguments, which it passes to the default
+manager's ``get()`` function. It raises ``Http404`` if the object doesn't
exist. For example::
# Get the Entry with a primary key of 3
@@ -1828,7 +1901,7 @@ exist. For example::
When you provide a model to this shortcut function, the default manager
is used to execute the underlying ``get()`` query. If you don't want to
use the default manager, or if you want to search a list of related objects,
-you can provide ``get_object_or_404()`` with a manager object instead.
+you can provide ``get_object_or_404()`` with a ``Manager`` object instead.
For example::
# Get the author of blog instance e with a name of 'Fred'
@@ -1838,6 +1911,14 @@ For example::
# entry with a primary key of 3
e = get_object_or_404(Entry.recent_entries, pk=3)
+**New in Django development version:** The first argument to
+``get_object_or_404()`` can be a ``QuerySet`` object. This is useful in cases
+where you've defined a custom manager method. For example::
+
+ # Use a QuerySet returned from a 'published' method of a custom manager
+ # in the search for an entry with primary key of 5
+ e = get_object_or_404(Entry.objects.published(), pk=5)
+
get_list_or_404()
-----------------
diff --git a/docs/distributions.txt b/docs/distributions.txt
index 4ec265f93c..f9b9cbe9f8 100644
--- a/docs/distributions.txt
+++ b/docs/distributions.txt
@@ -21,16 +21,17 @@ Linux distributions
Debian
------
-A `packaged version of Django`_ is available for `Debian GNU/Linux`_, and can be
-installed from either the "testing" or the "unstable" repositories by typing
-``apt-get install python-django``.
+A `packaged version of Django`_ is available for `Debian GNU/Linux`_. Version
+0.95.1 is available in the "stable" repository; Version 0.96 is available in
+the "testing" and "unstable" repositories. Regardless of your chosen repository,
+you can install Django by typing ``apt-get install python-django``.
When you install this package, ``apt`` will recommend installing a database
adapter; you should select and install the adapter for whichever database you
plan to use with Django.
.. _Debian GNU/Linux: http://www.debian.org/
-.. _packaged version of Django: http://packages.debian.org/testing/python/python-django
+.. _packaged version of Django: http://packages.debian.org/stable/python/python-django
Ubuntu
------
@@ -64,11 +65,24 @@ The `current Gentoo build`_ can be installed by typing ``emerge django``.
.. _Gentoo Linux: http://www.gentoo.org/
.. _current Gentoo build: http://packages.gentoo.org/packages/?category=dev-python;name=django
+Mac OS X
+========
+
+MacPorts
+--------
+
+Django 0.96 can be installed via the `MacPorts`_ system. If you're using Python 2.4,
+type ``sudo port install py-django-devel``. For Python 2.5, type ``sudo port
+install py25-django-devel``. MacPorts can also be used to install a database,
+and the Python interface to your chosen database.
+
+.. _MacPorts: http://www.macports.org/
+
For distributors
================
If you'd like to package Django for distribution, we'd be happy to help out!
-Please join the `django-developers mailing list`_ and introduce yourself.
+Please join the `django-developers mailing list`_ and introduce yourself.
We also encourage all distributors to subscribe to the `django-announce mailing
list`_, which is a (very) low-traffic list for announcing new releases of Django
diff --git a/docs/django-admin.txt b/docs/django-admin.txt
index 75c2738543..aea990c5dc 100644
--- a/docs/django-admin.txt
+++ b/docs/django-admin.txt
@@ -235,6 +235,7 @@ The ``dumpdata`` command can be used to generate input for ``loaddata``.
reset [appname appname ...]
---------------------------
+
Executes the equivalent of ``sqlreset`` for the given appnames.
runfcgi [options]
@@ -400,6 +401,19 @@ install them in the database. This includes any apps shipped with Django that
might be in ``INSTALLED_APPS`` by default. When you start a new project, run
this command to install the default apps.
+.. admonition:: Syncdb will not alter existing tables
+
+ ``syncdb`` will only create tables for models which have not yet been
+ installed. It will *never* issue ``ALTER TABLE`` statements to match
+ changes made to a model class after installation. Changes to model classes
+ and database schemas often involve some form of ambiguity and, in those
+ cases, Django would have to guess at the correct changes to make. There is
+ a risk that critical data would be lost in the process.
+
+ If you have made changes to a model and wish to alter the database tables
+ to match, use the ``sql`` command to display the new SQL structure and
+ compare that to your existing table schema to work out the changes.
+
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
give you the option of creating a superuser immediately.
@@ -413,7 +427,46 @@ test
Discover and run tests for all installed models. See `Testing Django applications`_ for more information.
-.. _testing django applications: ../testing/
+.. _testing Django applications: ../testing/
+
+testserver [fixture fixture ...]
+--------------------------------
+
+**New in Django development version**
+
+Runs a Django development server (as in ``runserver``) using data from the
+given fixture(s).
+
+For example, this command::
+
+ django-admin.py testserver mydata.json
+
+...would perform the following steps:
+
+ 1. Create a test database, as described in `testing Django applications`_.
+ 2. Populate the test database with fixture data from the given fixtures.
+ (For more on fixtures, see the documentation for ``loaddata`` above.)
+ 3. Runs the Django development server (as in ``runserver``), pointed at
+ this newly created test database instead of your production database.
+
+This is useful in a number of ways:
+
+ * When you're writing `unit tests`_ of how your views act with certain
+ fixture data, you can use ``testserver`` to interact with the views in
+ a Web browser, manually.
+
+ * Let's say you're developing your Django application and have a "pristine"
+ copy of a database that you'd like to interact with. You can dump your
+ database to a fixture (using the ``dumpdata`` command, explained above),
+ then use ``testserver`` to run your Web application with that data. With
+ this arrangement, you have the flexibility of messing up your data
+ in any way, knowing that whatever data changes you're making are only
+ being made to a test database.
+
+Note that this server can only run on the default port on localhost; it does
+not yet accept a ``host`` or ``port`` parameter.
+
+.. _unit tests: ../testing/
validate
--------
diff --git a/docs/email.txt b/docs/email.txt
index 50dafaf8df..97bdec0037 100644
--- a/docs/email.txt
+++ b/docs/email.txt
@@ -314,7 +314,7 @@ To send a text and HTML combination, you could write::
subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
- html_content = '<p>This is an <strong>important</strong> message.'
+ html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, to)
msg.attach_alternative(html_content, "text/html")
msg.send()
diff --git a/docs/faq.txt b/docs/faq.txt
index 67ed8a49a5..844ea77809 100644
--- a/docs/faq.txt
+++ b/docs/faq.txt
@@ -42,7 +42,10 @@ Listen to his music. You'll like it.
Django is pronounced **JANG**-oh. Rhymes with FANG-oh. The "D" is silent.
+We've also recorded an `audio clip of the pronunciation`_.
+
.. _Django Reinhardt: http://en.wikipedia.org/wiki/Django_Reinhardt
+.. _audio clip of the pronunciation: http://red-bean.com/~adrian/django_pronunciation.mp3
Is Django stable?
-----------------
diff --git a/docs/fastcgi.txt b/docs/fastcgi.txt
index 81888bba76..dff1689905 100644
--- a/docs/fastcgi.txt
+++ b/docs/fastcgi.txt
@@ -93,7 +93,7 @@ protocol by using the ``protocol=<protocol_name>`` option with
``./manage.py runfcgi`` -- where ``<protocol_name>`` may be one of: ``fcgi``
(the default), ``scgi`` or ``ajp``. For example::
- ./manage.py runfcgi --protocol=scgi
+ ./manage.py runfcgi protocol=scgi
.. _flup: http://www.saddi.com/software/flup/
.. _fastcgi: http://www.fastcgi.com/
diff --git a/docs/forms.txt b/docs/forms.txt
index f6cb55a3f6..18d322a8eb 100644
--- a/docs/forms.txt
+++ b/docs/forms.txt
@@ -37,17 +37,17 @@ this document, we'll be working with the following model, a "place" object::
)
class Place(models.Model):
- name = models.CharField(maxlength=100)
- address = models.CharField(maxlength=100, blank=True)
- city = models.CharField(maxlength=50, blank=True)
+ name = models.CharField(max_length=100)
+ address = models.CharField(max_length=100, blank=True)
+ city = models.CharField(max_length=50, blank=True)
state = models.USStateField()
- zip_code = models.CharField(maxlength=5, blank=True)
+ zip_code = models.CharField(max_length=5, blank=True)
place_type = models.IntegerField(choices=PLACE_TYPES)
class Admin:
pass
- def __str__(self):
+ def __unicode__(self):
return self.name
Defining the above class is enough to create an admin interface to a ``Place``,
@@ -388,7 +388,7 @@ for a "contact" form on a website::
def __init__(self):
self.fields = (
forms.EmailField(field_name="from", is_required=True),
- forms.TextField(field_name="subject", length=30, maxlength=200, is_required=True),
+ forms.TextField(field_name="subject", length=30, max_length=200, is_required=True),
forms.SelectField(field_name="urgency", choices=urgency_choices),
forms.LargeTextField(field_name="contents", is_required=True),
)
diff --git a/docs/generic_views.txt b/docs/generic_views.txt
index 2b80348903..0601aead11 100644
--- a/docs/generic_views.txt
+++ b/docs/generic_views.txt
@@ -40,7 +40,7 @@ simple weblog app that drives the blog on djangoproject.com::
}
urlpatterns = patterns('django.views.generic.date_based',
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', dict(info_dict, slug_field='slug')),
+ (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', info_dict),
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict),
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict),
(r'^(?P<year>\d{4})/$', 'archive_year', info_dict),
@@ -603,7 +603,7 @@ future, the view will throw a 404 error by default, unless you set
Otherwise, ``slug`` should be the slug of the given object, and
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
- model.
+ model. By default, ``slug_field`` is ``'slug'``.
**Optional arguments:**
@@ -804,7 +804,7 @@ A page representing an individual object.
Otherwise, ``slug`` should be the slug of the given object, and
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
- model.
+ model. By default, ``slug_field`` is ``'slug'``.
**Optional arguments:**
@@ -948,7 +948,7 @@ object. This uses the automatic manipulators that come with Django models.
Otherwise, ``slug`` should be the slug of the given object, and
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
- model.
+ model. By default, ``slug_field`` is ``'slug'``.
**Optional arguments:**
@@ -1033,7 +1033,7 @@ contain a form that POSTs to the same URL.
Otherwise, ``slug`` should be the slug of the given object, and
``slug_field`` should be the name of the slug field in the ``QuerySet``'s
- model.
+ model. By default, ``slug_field`` is ``'slug'``.
* ``post_delete_redirect``: A URL to which the view will redirect after
deleting the object.
diff --git a/docs/i18n.txt b/docs/i18n.txt
index 27abadacc9..38252edeb1 100644
--- a/docs/i18n.txt
+++ b/docs/i18n.txt
@@ -68,23 +68,41 @@ In Python code
Standard translation
~~~~~~~~~~~~~~~~~~~~
-Specify a translation string by using the function ``_()``. (Yes, the name of
-the function is the "underscore" character.) This function is available
-globally in any Python module; you don't have to import it.
+Specify a translation string by using the function ``ugettext()``. It's
+convention to import this as a shorter alias, ``_``, to save typing.
+
+.. note::
+ Python's standard library ``gettext`` module installs ``_()`` into the
+ global namespace, as an alias for ``gettext()``. In Django, we have chosen
+ not to follow this practice, for a couple of reasons:
+
+ 1. For international character set (Unicode) support, ``ugettext()`` is
+ more useful than ``gettext()``. Sometimes, you should be using
+ ``ugettext_lazy()`` as the default translation method for a particular
+ file. Without ``_()`` in the global namespace, the developer has to
+ think about which is the most appropriate translation function.
+
+ 2. The underscore character (``_``) is used to represent "the previous
+ result" in Python's interactive shell and doctest tests. Installing a
+ global ``_()`` function causes interference. Explicitly importing
+ ``ugettext()`` as ``_()`` avoids this problem.
In this example, the text ``"Welcome to my site."`` is marked as a translation
string::
+ from django.utils.translation import ugettext as _
+
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)
-The function ``django.utils.translation.gettext()`` is identical to ``_()``.
-This example is identical to the previous one::
+Obviously, you could code this without using the alias. This example is
+identical to the previous one::
+
+ from django.utils.translation import ugettext
- from django.utils.translation import gettext
def my_view(request):
- output = gettext("Welcome to my site.")
+ output = ugettext("Welcome to my site.")
return HttpResponse(output)
Translation works on computed values. This example is identical to the previous
@@ -107,7 +125,7 @@ examples, is that Django's translation-string-detecting utility,
``make-messages.py``, won't be able to find these strings. More on
``make-messages`` later.)
-The strings you pass to ``_()`` or ``gettext()`` can take placeholders,
+The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
specified with Python's standard named-string interpolation syntax. Example::
def my_view(request, n):
@@ -120,14 +138,14 @@ while a Spanish translation may be ``"Me llamo Adrian."`` -- with the
placeholder (the name) placed after the translated text instead of before it.
For this reason, you should use named-string interpolation (e.g., ``%(name)s``)
-instead of positional interpolation (e.g., ``%s`` or ``%d``). If you used
-positional interpolation, translations wouldn't be able to reorder placeholder
-text.
+instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
+have more than a single parameter. If you used positional interpolation,
+translations wouldn't be able to reorder placeholder text.
Marking strings as no-op
~~~~~~~~~~~~~~~~~~~~~~~~
-Use the function ``django.utils.translation.gettext_noop()`` to mark a string
+Use the function ``django.utils.translation.ugettext_noop()`` to mark a string
as a translation string without translating it. The string is later translated
from a variable.
@@ -139,35 +157,35 @@ as when the string is presented to the user.
Lazy translation
~~~~~~~~~~~~~~~~
-Use the function ``django.utils.translation.gettext_lazy()`` to translate
+Use the function ``django.utils.translation.ugettext_lazy()`` to translate
strings lazily -- when the value is accessed rather than when the
-``gettext_lazy()`` function is called.
+``ugettext_lazy()`` function is called.
For example, to translate a model's ``help_text``, do the following::
- from django.utils.translation import gettext_lazy
+ from django.utils.translation import ugettext_lazy
class MyThing(models.Model):
- name = models.CharField(help_text=gettext_lazy('This is the help text'))
+ name = models.CharField(help_text=ugettext_lazy('This is the help text'))
-In this example, ``gettext_lazy()`` stores a lazy reference to the string --
+In this example, ``ugettext_lazy()`` stores a lazy reference to the string --
not the actual translation. The translation itself will be done when the string
is used in a string context, such as template rendering on the Django admin site.
-If you don't like the verbose name ``gettext_lazy``, you can just alias it as
+If you don't like the verbose name ``ugettext_lazy``, you can just alias it as
``_`` (underscore), like so::
- from django.utils.translation import gettext_lazy as _
+ from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=_('This is the help text'))
-Always use lazy translations in `Django models`_. And it's a good idea to add
+Always use lazy translations in `Django models`_. It's a good idea to add
translations for the field names and table names, too. This means writing
explicit ``verbose_name`` and ``verbose_name_plural`` options in the ``Meta``
class, though::
- from django.utils.translation import gettext_lazy as _
+ from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
name = models.CharField(_('name'), help_text=_('This is the help text'))
@@ -180,24 +198,24 @@ class, though::
Pluralization
~~~~~~~~~~~~~
-Use the function ``django.utils.translation.ngettext()`` to specify pluralized
+Use the function ``django.utils.translation.ungettext()`` to specify pluralized
messages. Example::
- from django.utils.translation import ngettext
+ from django.utils.translation import ungettext
def hello_world(request, count):
- page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % {
+ page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % {
'count': count,
}
return HttpResponse(page)
-``ngettext`` takes three arguments: the singular translation string, the plural
+``ungettext`` takes three arguments: the singular translation string, the plural
translation string and the number of objects (which is passed to the
translation languages as the ``count`` variable).
In template code
----------------
-Using translations in `Django templates`_ uses two template tags and a slightly
+Translations in `Django templates`_ uses two template tags and a slightly
different syntax than in Python code. To give your template access to these
tags, put ``{% load i18n %}`` toward the top of your template.
@@ -243,9 +261,9 @@ To pluralize, specify both the singular and plural forms with the
{% endblocktrans %}
Internally, all block and inline translations use the appropriate
-``gettext`` / ``ngettext`` call.
+``ugettext`` / ``ungettext`` call.
-Each ``RequestContext`` has access to two translation-specific variables:
+Each ``RequestContext`` has access to three translation-specific variables:
* ``LANGUAGES`` is a list of tuples in which the first element is the
language code and the second is the language name (in that language).
@@ -276,6 +294,71 @@ string, so they don't need to be aware of translations.
.. _Django templates: ../templates_python/
+Working with lazy translation objects
+=====================================
+
+Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models
+and utility functions is a common operation. When you're working with these
+objects elsewhere in your code, you should ensure that you don't accidentally
+convert them to strings, because they should be converted as late as possible
+(so that the correct locale is in effect). This necessitates the use of a
+couple of helper functions.
+
+Joining strings: string_concat()
+--------------------------------
+
+Standard Python string joins (``''.join([...])``) will not work on lists
+containing lazy translation objects. Instead, you can use
+``django.utils.translation.string_concat()``, which creates a lazy object that
+concatenates its contents *and* converts them to strings only when the result
+is included in a string. For example::
+
+ from django.utils.translation import string_concat
+ ...
+ name = ugettext_lazy(u'John Lennon')
+ instrument = ugettext_lazy(u'guitar')
+ result = string_concat([name, ': ', instrument])
+
+In this case, the lazy translations in ``result`` will only be converted to
+strings when ``result`` itself is used in a string (usually at template
+rendering time).
+
+The allow_lazy() decorator
+--------------------------
+
+Django offers many utility functions (particularly in ``django.utils``) that
+take a string as their first argument and do something to that string. These
+functions are used by template filters as well as directly in other code.
+
+If you write your own similar functions and deal with translations, you'll
+face the problem of what to do when the first argument is a lazy translation
+object. You don't want to convert it to a string immediately, because you might
+be using this function outside of a view (and hence the current thread's locale
+setting will not be correct).
+
+For cases like this, use the ``django.utils.functional.allow_lazy()``
+decorator. It modifies the function so that *if* it's called with a lazy
+translation as the first argument, the function evaluation is delayed until it
+needs to be converted to a string.
+
+For example::
+
+ from django.utils.functional import allow_lazy
+
+ def fancy_utility_function(s, ...):
+ # Do some conversion on string 's'
+ ...
+ fancy_utility_function = allow_lazy(fancy_utility_function, unicode)
+
+The ``allow_lazy()`` decorator takes, in addition to the function to decorate,
+a number of extra arguments (``*args``) specifying the type(s) that the
+original function can return. Usually, it's enough to include ``unicode`` here
+and ensure that your function returns only Unicode strings.
+
+Using this decorator means you can write your function and assume that the
+input is a proper string, then add support for lazy translation objects at the
+end.
+
How to create language files
============================
@@ -487,26 +570,26 @@ Notes:
* If you define a custom ``LANGUAGES`` setting, as explained in the
previous bullet, it's OK to mark the languages as translation strings
- -- but use a "dummy" ``gettext()`` function, not the one in
+ -- but use a "dummy" ``ugettext()`` function, not the one in
``django.utils.translation``. You should *never* import
``django.utils.translation`` from within your settings file, because that
module in itself depends on the settings, and that would cause a circular
import.
- The solution is to use a "dummy" ``gettext()`` function. Here's a sample
+ The solution is to use a "dummy" ``ugettext()`` function. Here's a sample
settings file::
- gettext = lambda s: s
+ ugettext = lambda s: s
LANGUAGES = (
- ('de', gettext('German')),
- ('en', gettext('English')),
+ ('de', ugettext('German')),
+ ('en', ugettext('English')),
)
With this arrangement, ``make-messages.py`` will still find and mark
these strings for translation, but the translation won't happen at
runtime -- so you'll have to remember to wrap the languages in the *real*
- ``gettext()`` in any code that uses ``LANGUAGES`` at runtime.
+ ``ugettext()`` in any code that uses ``LANGUAGES`` at runtime.
* The ``LocaleMiddleware`` can only select languages for which there is a
Django-provided base translation. If you want to provide translations
@@ -712,23 +795,23 @@ interface to access it::
document.write(gettext('this is to be translated'));
-There even is a ``ngettext`` interface and a string interpolation function::
+There even is a ``ungettext`` interface and a string interpolation function::
d = {
count: 10
};
- s = interpolate(ngettext('this is %(count)s object', 'this are %(count)s objects', d.count), d);
+ s = interpolate(ungettext('this is %(count)s object', 'this are %(count)s objects', d.count), d);
The ``interpolate`` function supports both positional interpolation and named
interpolation. So the above could have been written as::
- s = interpolate(ngettext('this is %s object', 'this are %s objects', 11), [11]);
+ s = interpolate(ungettext('this is %s object', 'this are %s objects', 11), [11]);
The interpolation syntax is borrowed from Python. You shouldn't go over the top
with string interpolation, though: this is still JavaScript, so the code will
have to do repeated regular-expression substitutions. This isn't as fast as
string interpolation in Python, so keep it to those cases where you really
-need it (for example, in conjunction with ``ngettext`` to produce proper
+need it (for example, in conjunction with ``ungettext`` to produce proper
pluralizations).
Creating JavaScript translation catalogs
@@ -750,16 +833,13 @@ Specialities of Django translation
If you know ``gettext``, you might note these specialities in the way Django
does translation:
- * The string domain is ``django`` or ``djangojs``. The string domain is used to
- differentiate between different programs that store their data in a
- common message-file library (usually ``/usr/share/locale/``). The ``django``
- domain is used for python and template translation strings and is loaded into
- the global translation catalogs. The ``djangojs`` domain is only used for
- JavaScript translation catalogs to make sure that those are as small as
- possible.
- * Django only uses ``gettext`` and ``gettext_noop``. That's because Django
- always uses ``DEFAULT_CHARSET`` strings internally. There isn't much use
- in using ``ugettext``, because you'll always need to produce utf-8
- anyway.
+ * The string domain is ``django`` or ``djangojs``. The string domain is
+ used to differentiate between different programs that store their data
+ in a common message-file library (usually ``/usr/share/locale/``). The
+ ``django`` domain is used for python and template translation strings
+ and is loaded into the global translation catalogs. The ``djangojs``
+ domain is only used for JavaScript translation catalogs to make sure
+ that those are as small as possible.
* Django doesn't use ``xgettext`` alone. It uses Python wrappers around
``xgettext`` and ``msgfmt``. That's mostly for convenience.
+
diff --git a/docs/install.txt b/docs/install.txt
index e850e48955..082000149f 100644
--- a/docs/install.txt
+++ b/docs/install.txt
@@ -48,8 +48,8 @@ Get your database running
If you plan to use Django's database API functionality, you'll need to
make sure a database server is running. Django works with PostgreSQL_,
-MySQL_, Oracle_ and SQLite_ (the latter doesn't require a separate server to
-be running).
+MySQL_, Oracle_ and SQLite_ (although SQLite doesn't require a separate server
+to be running).
Additionally, you'll need to make sure your Python database bindings are
installed.
@@ -109,25 +109,29 @@ Install the Django code
=======================
Installation instructions are slightly different depending on whether you're
-using the latest official version or the latest development version.
+installing a distribution-specific package, downloading the the latest official
+release, or fetching the latest development version.
-It's easy either way.
+It's easy, no matter which way you choose.
-Installing the official version
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Installing a distribution-specific package
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 1. Check the `distribution specific notes`_ to see if your
- platform/distribution provides official Django packages/installers.
- Distribution-provided packages will typically allow for automatic
- installation of dependancies and easy upgrade paths.
+Check the `distribution specific notes`_ to see if your
+platform/distribution provides official Django packages/installers.
+Distribution-provided packages will typically allow for automatic
+installation of dependancies and easy upgrade paths.
- 2. Download the latest release from our `download page`_.
+Installing an official release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 3. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``).
+ 1. Download the latest release from our `download page`_.
- 4. Change into the downloaded directory (e.g. ``cd Django-NNN``).
+ 2. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``).
- 5. Run ``sudo python setup.py install``.
+ 3. Change into the downloaded directory (e.g. ``cd Django-NNN``).
+
+ 4. Run ``sudo python setup.py install``.
The command will install Django in your Python installation's ``site-packages``
directory.
diff --git a/docs/man/compile-messages.1 b/docs/man/compile-messages.1
new file mode 100644
index 0000000000..d26a94aca7
--- /dev/null
+++ b/docs/man/compile-messages.1
@@ -0,0 +1,40 @@
+.TH "compile-messages.py" "1" "August 2007" "Django Project" ""
+.SH "NAME"
+compile-messages.py \- Internationalization utility for the Django
+web framework
+.SH "SYNOPSIS"
+.B compile-messages.py \fR[-l <locale>]
+
+.SH "DESCRIPTION"
+A Django-customised wrapper around gettext's \fBmsgfmt\fR command. Generates
+binary message catalogs (.mo files) from textual translation descriptions (.po
+files).
+.sp
+The script should be invoked after running
+.BI make-messages.py,
+in the same directory from which
+.BI make-messages.py
+was invoked.
+
+.SH "OPTIONS"
+.TP
+.I \-l <locale>
+Compile the message catalogs for a specific locale. If this option is omitted,
+all message catalogs are (re-)compiled.
+
+.SH "SEE ALSO"
+The man page for
+.BI msgfmt
+from the GNU gettext utilities, and the internationalization documentation
+for Django:
+.sp
+.I http://www.djangoproject.com/documentation/i18n/
+
+.SH "AUTHORS/CREDITS"
+Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
+AUTHORS file in the Django distribution for contributors.
+
+.SH "LICENSE"
+New BSD license. For the full license text refer to the LICENSE file in the
+Django distribution.
+
diff --git a/docs/man/daily_cleanup.1 b/docs/man/daily_cleanup.1
new file mode 100644
index 0000000000..9186dd67d6
--- /dev/null
+++ b/docs/man/daily_cleanup.1
@@ -0,0 +1,34 @@
+.TH "daily_cleanup.py" "1" "August 2007" "Django Project" ""
+.SH "NAME"
+daily_cleanup.py \- Database clean-up for the Django web framework
+.SH "SYNOPSIS"
+.B daily_cleanup.py
+
+.SH "DESCRIPTION"
+Removes stale session data from a Django database. This means, any session data
+which has an expiry date prior to the date the script is run.
+.sp
+The script can be run manually or can be scheduled to run at regular
+intervals as a
+.BI cron
+job.
+
+.SH "ENVIRONMENT"
+.TP
+.I DJANGO_SETTINGS_MODULE
+This environment variable defines the settings module to be read.
+It should be in Python-import form, e.g. "myproject.settings".
+
+.SH "SEE ALSO"
+The sessions documentation:
+.sp
+.I http://www.djangoproject.com/documentation/sessions/
+
+.SH "AUTHORS/CREDITS"
+Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
+AUTHORS file in the Django distribution for contributors.
+
+.SH "LICENSE"
+New BSD license. For the full license text refer to the LICENSE file in the
+Django distribution.
+
diff --git a/docs/man/gather_profile_stats.1 b/docs/man/gather_profile_stats.1
new file mode 100644
index 0000000000..5ff13d8e69
--- /dev/null
+++ b/docs/man/gather_profile_stats.1
@@ -0,0 +1,26 @@
+.TH "gather_profile_stats.py" "1" "August 2007" "Django Project" ""
+.SH "NAME"
+gather_profile_stats.py \- Performance analysis tool for the Django web
+framework
+.SH "SYNOPSIS"
+.B python gather_profile_stats.py
+.I <path>
+
+.SH "DESCRIPTION"
+This utility script aggregates profiling logs generated using Python's
+hotshot profiler. The sole command-line argument is the full path to the
+directory containing the profiling logfiles.
+
+.SH "SEE ALSO"
+Discussion of profiling Django applications on the Django project's wiki:
+.sp
+.I http://www.djangoproject.com/wiki/ProfilingDjango
+
+.SH "AUTHORS/CREDITS"
+Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
+AUTHORS file in the Django distribution for contributors.
+
+.SH "LICENSE"
+New BSD license. For the full license text refer to the LICENSE file in the
+Django distribution.
+
diff --git a/docs/man/make-messages.1 b/docs/man/make-messages.1
new file mode 100644
index 0000000000..b8c83dcff5
--- /dev/null
+++ b/docs/man/make-messages.1
@@ -0,0 +1,62 @@
+.TH "make-messages.py" "1" "August 2007" "Django Project" ""
+.SH "NAME"
+make-messages.py \- Internationalization utility for the Django
+web framework
+.SH "SYNOPSIS"
+.B make-messages.py\fR [\-a] [\-v] [\-l <locale>] [\-d <domain>]
+
+.SH "DESCRIPTION"
+This script creates or updates one or more message files for a Django app,
+a Django project or the Django framework itself. It should be run from one
+of three places: the root directory of a Django app; the root directory
+of a Django project; or the root django directory (the one in your PYTHONPATH,
+not the root of a Subversion checkout).
+.sp
+The script will run over the source tree of an application, project or Django
+itself (depending on where it is invoked), pulling out all strings marked for
+translation and creating or updating a standard PO-format message file for the
+specified language. Refer to Django's internationalization documentation for
+details of where this file is created.
+.sp
+The \fI\-a\fR and \fI\-l\fR options are used to control whether message
+catalogs are created for all locales, or just a single one.
+
+.SH "OPTIONS"
+.TP
+.I \-a
+Run make-messages for all locales specified in the Django settings file. Cannot
+be used in conjuntion with \fI\-l\fR.
+.TP
+.I \-d <domain>
+Specifies the translation domain to use. Valid domains are \fIdjango\fR or
+\fIdjangojs\fR, depending on whether you wish to generate translation strings
+for the Python or JavaScript components of your app, your project or the
+framework itself. The default domain is \fIdjango\fR.
+.TP
+.I \-l <locale>
+Extract messages for a particular locale.
+.TP
+.I \-v
+Run verbosely.
+
+.SH "ENVIRONMENT"
+.TP
+.I DJANGO_SETTINGS_MODULE
+This environment variable defines the settings module to be read.
+It should be in Python-import form, e.g. "myproject.settings".
+
+.SH "SEE ALSO"
+The Django internationalization documentation:
+.sp
+.I http://www.djangoproject.com/documentation/i18n/
+.sp
+The PO file format is documented in the GNU gettext documentation.
+
+.SH "AUTHORS/CREDITS"
+Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
+AUTHORS file in the Django distribution for contributors.
+
+.SH "LICENSE"
+New BSD license. For the full license text refer to the LICENSE file in the
+Django distribution.
+
diff --git a/docs/middleware.txt b/docs/middleware.txt
index 0d533443d3..63ba8c6999 100644
--- a/docs/middleware.txt
+++ b/docs/middleware.txt
@@ -91,6 +91,12 @@ django.middleware.gzip.GZipMiddleware
Compresses content for browsers that understand gzip compression (all modern
browsers).
+It is suggested to place this first in the middleware list, so that the
+compression of the response content is the last thing that happens. Will not
+compress content bodies less than 200 bytes long, when the response code is
+something other than 200, Javascript files (for IE compatibitility), or
+responses that have the ``Content-Encoding`` header already specified.
+
django.middleware.http.ConditionalGetMiddleware
-----------------------------------------------
@@ -116,6 +122,14 @@ not use this middleware. Anybody can spoof the value of
``HTTP_X_FORWARDED_FOR``, that means anybody can "fake" their IP address. Only
use this when you can absolutely trust the value of ``HTTP_X_FORWARDED_FOR``.
+django.middleware.locale.LocaleMiddleware
+-----------------------------------------
+
+Enables language selection based on data from the request. It customizes content
+for each user. See the `internationalization documentation`_.
+
+.. _`internationalization documentation`: ../i18n/
+
django.contrib.sessions.middleware.SessionMiddleware
----------------------------------------------------
diff --git a/docs/model-api.txt b/docs/model-api.txt
index 22ff7445b5..0f872c3097 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -22,7 +22,7 @@ A companion to this document is the `official repository of model examples`_.
``tests/modeltests`` directory.)
.. _Database API reference: ../db-api/
-.. _official repository of model examples: http://www.djangoproject.com/documentation/models/
+.. _official repository of model examples: ../models/
Quick example
=============
@@ -33,8 +33,8 @@ This example model defines a ``Person``, which has a ``first_name`` and
from django.db import models
class Person(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
``first_name`` and ``last_name`` are *fields* of the model. Each field is
specified as a class attribute, and each attribute maps to a database column.
@@ -69,13 +69,13 @@ attributes.
Example::
class Musician(models.Model):
- first_name = models.CharField(maxlength=50)
- last_name = models.CharField(maxlength=50)
- instrument = models.CharField(maxlength=100)
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
+ instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
@@ -142,14 +142,18 @@ For large amounts of text, use ``TextField``.
The admin represents this as an ``<input type="text">`` (a single-line input).
-``CharField`` has an extra required argument, ``maxlength``, the maximum length
-(in characters) of the field. The maxlength is enforced at the database level
+``CharField`` has an extra required argument, ``max_length``, the maximum length
+(in characters) of the field. The max_length is enforced at the database level
and in Django's validation.
+Django veterans: Note that the argument is now called ``max_length`` to
+provide consistency throughout Django. There is full legacy support for
+the old ``maxlength`` argument, but ``max_length`` is prefered.
+
``CommaSeparatedIntegerField``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A field of integers separated by commas. As in ``CharField``, the ``maxlength``
+A field of integers separated by commas. As in ``CharField``, the ``max_length``
argument is required.
``DateField``
@@ -217,7 +221,7 @@ The admin represents this as an ``<input type="text">`` (a single-line input).
~~~~~~~~~~~~~~
A ``CharField`` that checks that the value is a valid e-mail address.
-This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to
+This doesn't accept ``max_length``; its ``max_length`` is automatically set to
75.
``FileField``
@@ -400,7 +404,7 @@ Like a ``PositiveIntegerField``, but only allows values under a certain
containing only letters, numbers, underscores or hyphens. They're generally
used in URLs.
-Like a CharField, you can specify ``maxlength``. If ``maxlength`` is
+Like a CharField, you can specify ``max_length``. If ``max_length`` is
not specified, Django will use a default length of 50.
Implies ``db_index=True``.
@@ -411,7 +415,8 @@ form::
models.SlugField(prepopulate_from=("pre_name", "name"))
-``prepopulate_from`` doesn't accept DateTimeFields.
+``prepopulate_from`` doesn't accept DateTimeFields, ForeignKeys nor
+ManyToManyFields.
The admin represents ``SlugField`` as an ``<input type="text">`` (a
single-line input).
@@ -447,9 +452,9 @@ and doesn't give a 404 response).
The admin represents this as an ``<input type="text">`` (a single-line input).
-``URLField`` takes an optional argument, ``maxlength``, the maximum length (in
-characters) of the field. The maxlength is enforced at the database level and
-in Django's validation. If you don't specify ``maxlength``, a default of 200
+``URLField`` takes an optional argument, ``max_length``, the maximum length (in
+characters) of the field. The maximum length is enforced at the database level and
+in Django's validation. If you don't specify ``max_length``, a default of 200
is used.
``USStateField``
@@ -536,7 +541,7 @@ The choices list can be defined either as part of your model class::
('M', 'Male'),
('F', 'Female'),
)
- gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
or outside your model class altogether::
@@ -545,7 +550,7 @@ or outside your model class altogether::
('F', 'Female'),
)
class Foo(models.Model):
- gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
For each model field that has ``choices`` set, Django will add a method to
retrieve the human-readable name for the field's current value. See
@@ -620,6 +625,12 @@ Extra "help" text to be displayed under the field on the object's admin
form. It's useful for documentation even if your object doesn't have an
admin form.
+Note that this value is *not* HTML-escaped when it's displayed in the admin
+interface. This lets you include HTML in ``help_text`` if you so desire. For
+example::
+
+ help_text="Please use the following format: <em>YYYY-MM-DD</em>."
+
``primary_key``
~~~~~~~~~~~~~~~
@@ -698,11 +709,11 @@ it using the field's attribute name, converting underscores to spaces.
In this example, the verbose name is ``"Person's first name"``::
- first_name = models.CharField("Person's first name", maxlength=30)
+ first_name = models.CharField("Person's first name", max_length=30)
In this example, the verbose name is ``"first name"``::
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
``ForeignKey``, ``ManyToManyField`` and ``OneToOneField`` require the first
argument to be a model class, so use the ``verbose_name`` keyword argument::
@@ -727,7 +738,7 @@ Many-to-one relationships
To define a many-to-one relationship, use ``ForeignKey``. You use it just like
any other ``Field`` type: by including it as a class attribute of your model.
-``ForeignKey`` requires a positional argument: The class to which the model is
+``ForeignKey`` requires a positional argument: the class to which the model is
related.
For example, if a ``Car`` model has a ``Manufacturer`` -- that is, a
@@ -775,7 +786,7 @@ You can, of course, call the field whatever you want. For example::
See the `Many-to-one relationship model example`_ for a full example.
-.. _Many-to-one relationship model example: http://www.djangoproject.com/documentation/models/many_to_one/
+.. _Many-to-one relationship model example: ../models/many_to_one/
``ForeignKey`` fields take a number of extra arguments for defining how the
relationship should work. All are optional:
@@ -862,7 +873,7 @@ To define a many-to-many relationship, use ``ManyToManyField``. You use it just
like any other ``Field`` type: by including it as a class attribute of your
model.
-``ManyToManyField`` requires a positional argument: The class to which the
+``ManyToManyField`` requires a positional argument: the class to which the
model is related.
For example, if a ``Pizza`` has multiple ``Topping`` objects -- that is, a
@@ -902,7 +913,7 @@ set up above, the ``Pizza`` admin form would let users select the toppings.
See the `Many-to-many relationship model example`_ for a full example.
-.. _Many-to-many relationship model example: http://www.djangoproject.com/documentation/models/many_to_many/
+.. _Many-to-many relationship model example: ../models/many_to_many/
``ManyToManyField`` objects take a number of extra arguments for defining how
the relationship should work. All are optional:
@@ -959,7 +970,7 @@ model.
This is most useful on the primary key of an object when that object "extends"
another object in some way.
-``OneToOneField`` requires a positional argument: The class to which the
+``OneToOneField`` requires a positional argument: the class to which the
model is related.
For example, if you're building a database of "places", you would build pretty
@@ -979,7 +990,116 @@ as a read-only field when you edit an object in the admin interface:
See the `One-to-one relationship model example`_ for a full example.
-.. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/
+.. _One-to-one relationship model example: ../models/one_to_one/
+
+Custom field types
+------------------
+
+**New in Django development version**
+
+Django's built-in field types don't cover every possible database column type --
+only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
+column types, such as geographic polygons or even user-created types such as
+`PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
+
+.. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html
+
+.. admonition:: Experimental territory
+
+ This is an area of Django that traditionally has not been documented, but
+ we're starting to include bits of documentation, one feature at a time.
+ Please forgive the sparseness of this section.
+
+ If you like living on the edge and are comfortable with the risk of
+ unstable, undocumented APIs, see the code for the core ``Field`` class
+ in ``django/db/models/fields/__init__.py`` -- but if/when the innards
+ change, don't say we didn't warn you.
+
+To create a custom field type, simply subclass ``django.db.models.Field``.
+Here is an incomplete list of the methods you should implement:
+
+``db_type()``
+~~~~~~~~~~~~~
+
+Returns the database column data type for the ``Field``, taking into account
+the current ``DATABASE_ENGINE`` setting.
+
+Say you've created a PostgreSQL custom type called ``mytype``. You can use this
+field with Django by subclassing ``Field`` and implementing the ``db_type()``
+method, like so::
+
+ from django.db import models
+
+ class MytypeField(models.Field):
+ def db_type(self):
+ return 'mytype'
+
+Once you have ``MytypeField``, you can use it in any model, just like any other
+``Field`` type::
+
+ class Person(models.Model):
+ name = models.CharField(max_length=80)
+ gender = models.CharField(max_length=1)
+ something_else = MytypeField()
+
+If you aim to build a database-agnostic application, you should account for
+differences in database column types. For example, the date/time column type
+in PostgreSQL is called ``timestamp``, while the same column in MySQL is called
+``datetime``. The simplest way to handle this in a ``db_type()`` method is to
+import the Django settings module and check the ``DATABASE_ENGINE`` setting.
+For example::
+
+ class MyDateField(models.Field):
+ def db_type(self):
+ from django.conf import settings
+ if settings.DATABASE_ENGINE == 'mysql':
+ return 'datetime'
+ else:
+ return 'timestamp'
+
+The ``db_type()`` method is only called by Django when the framework constructs
+the ``CREATE TABLE`` statements for your application -- that is, when you first
+create your tables. It's not called at any other time, so it can afford to
+execute slightly complex code, such as the ``DATABASE_ENGINE`` check in the
+above example.
+
+Some database column types accept parameters, such as ``CHAR(25)``, where the
+parameter ``25`` represents the maximum column length. In cases like these,
+it's more flexible if the parameter is specified in the model rather than being
+hard-coded in the ``db_type()`` method. For example, it wouldn't make much
+sense to have a ``CharMaxlength25Field``, shown here::
+
+ # This is a silly example of hard-coded parameters.
+ class CharMaxlength25Field(models.Field):
+ def db_type(self):
+ return 'char(25)'
+
+ # In the model:
+ class MyModel(models.Model):
+ # ...
+ my_field = CharMaxlength25Field()
+
+The better way of doing this would be to make the parameter specifiable at run
+time -- i.e., when the class is instantiated. To do that, just implement
+``__init__()``, like so::
+
+ # This is a much more flexible example.
+ class BetterCharField(models.Field):
+ def __init__(self, max_length, *args, **kwargs):
+ self.max_length = max_length
+ super(BetterCharField, self).__init__(*args, **kwargs)
+
+ def db_type(self):
+ return 'char(%s)' % self.max_length
+
+ # In the model:
+ class MyModel(models.Model):
+ # ...
+ my_field = BetterCharField(25)
+
+Note that if you implement ``__init__()`` on a ``Field`` subclass, it's
+important to call ``Field.__init__()`` -- i.e., the parent class'
+``__init__()`` method.
Meta options
============
@@ -987,7 +1107,7 @@ Meta options
Give your model metadata by using an inner ``class Meta``, like so::
class Foo(models.Model):
- bar = models.CharField(maxlength=30)
+ bar = models.CharField(max_length=30)
class Meta:
# ...
@@ -1077,7 +1197,7 @@ See `Specifying ordering`_ for more examples.
Note that, regardless of how many fields are in ``ordering``, the admin
site uses only the first field.
-.. _Specifying ordering: http://www.djangoproject.com/documentation/models/ordering/
+.. _Specifying ordering: ../models/ordering/
``permissions``
---------------
@@ -1161,8 +1281,8 @@ If you want your model to be visible to Django's admin site, give your model an
inner ``"class Admin"``, like so::
class Person(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
# Admin options go here
@@ -1302,8 +1422,8 @@ that displays the ``__str__()`` representation of each object.
A few special cases to note about ``list_display``:
- * If the field is a ``ForeignKey``, Django will display the ``__str__()``
- of the related object.
+ * If the field is a ``ForeignKey``, Django will display the
+ ``__unicode__()`` of the related object.
* ``ManyToManyField`` fields aren't supported, because that would entail
executing a separate SQL statement for each row in the table. If you
@@ -1321,7 +1441,7 @@ A few special cases to note about ``list_display``:
Here's a full example model::
class Person(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
birthday = models.DateField()
class Admin:
@@ -1338,9 +1458,9 @@ A few special cases to note about ``list_display``:
Here's a full example model::
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
- last_name = models.CharField(maxlength=50)
- color_code = models.CharField(maxlength=6)
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
+ color_code = models.CharField(max_length=6)
class Admin:
list_display = ('first_name', 'last_name', 'colored_name')
@@ -1356,7 +1476,7 @@ A few special cases to note about ``list_display``:
Here's a full example model::
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
+ first_name = models.CharField(max_length=50)
birthday = models.DateField()
class Admin:
@@ -1367,10 +1487,11 @@ A few special cases to note about ``list_display``:
born_in_fifties.boolean = True
- * The ``__str__()`` method is just as valid in ``list_display`` as any
- other model method, so it's perfectly OK to do this::
+ * The ``__str__()`` and ``__unicode__()`` methods are just as valid in
+ ``list_display`` as any other model method, so it's perfectly OK to do
+ this::
- list_display = ('__str__', 'some_other_field')
+ list_display = ('__unicode__', 'some_other_field')
* Usually, elements of ``list_display`` that aren't actual database fields
can't be used in sorting (because Django does all the sorting at the
@@ -1383,8 +1504,8 @@ A few special cases to note about ``list_display``:
For example::
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
- color_code = models.CharField(maxlength=6)
+ first_name = models.CharField(max_length=50)
+ color_code = models.CharField(max_length=6)
class Admin:
list_display = ('first_name', 'colored_first_name')
@@ -1552,7 +1673,7 @@ with an operator:
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')
Note that the query input is split by spaces, so, following this example,
- it's not currently not possible to search for all records in which
+ it's currently not possible to search for all records in which
``first_name`` is exactly ``'john winston'`` (containing a space).
``@``
@@ -1634,13 +1755,13 @@ returns a list of all ``OpinionPoll`` objects, each with an extra
return result_list
class OpinionPoll(models.Model):
- question = models.CharField(maxlength=200)
+ question = models.CharField(max_length=200)
poll_date = models.DateField()
objects = PollManager()
class Response(models.Model):
poll = models.ForeignKey(Poll)
- person_name = models.CharField(maxlength=50)
+ person_name = models.CharField(max_length=50)
response = models.TextField()
With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return
@@ -1656,8 +1777,8 @@ A ``Manager``'s base ``QuerySet`` returns all objects in the system. For
example, using this model::
class Book(models.Model):
- title = models.CharField(maxlength=100)
- author = models.CharField(maxlength=50)
+ title = models.CharField(max_length=100)
+ author = models.CharField(max_length=50)
...the statement ``Book.objects.all()`` will return all books in the database.
@@ -1675,8 +1796,8 @@ all objects, and one that returns only the books by Roald Dahl::
# Then hook it into the Book model explicitly.
class Book(models.Model):
- title = models.CharField(maxlength=100)
- author = models.CharField(maxlength=50)
+ title = models.CharField(max_length=100)
+ author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
@@ -1709,9 +1830,9 @@ For example::
return super(FemaleManager, self).get_query_set().filter(sex='F')
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
- last_name = models.CharField(maxlength=50)
- sex = models.CharField(maxlength=1, choices=(('M', 'Male'), ('F', 'Female')))
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
+ sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
people = models.Manager()
men = MaleManager()
women = FemaleManager()
@@ -1741,11 +1862,11 @@ model.
For example, this model has a few custom methods::
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
- last_name = models.CharField(maxlength=50)
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
birth_date = models.DateField()
- address = models.CharField(maxlength=100)
- city = models.CharField(maxlength=50)
+ address = models.CharField(max_length=100)
+ city = models.CharField(max_length=50)
state = models.USStateField() # Yes, this is America-centric...
def baby_boomer_status(self):
@@ -1776,20 +1897,47 @@ A few object methods have special meaning:
-----------
``__str__()`` is a Python "magic method" that defines what should be returned
-if you call ``str()`` on the object. Django uses ``str(obj)`` in a number of
-places, most notably as the value displayed to render an object in the Django
-admin site and as the value inserted into a template when it displays an
-object. Thus, you should always return a nice, human-readable string for the
-object's ``__str__``. Although this isn't required, it's strongly encouraged.
+if you call ``str()`` on the object. Django uses ``str(obj)`` (or the related
+function, ``unicode(obj)`` -- see below) in a number of places, most notably
+as the value displayed to render an object in the Django admin site and as the
+value inserted into a template when it displays an object. Thus, you should
+always return a nice, human-readable string for the object's ``__str__``.
+Although this isn't required, it's strongly encouraged (see the description of
+``__unicode__``, below, before putting ``_str__`` methods everywhere).
For example::
class Person(models.Model):
- first_name = models.CharField(maxlength=50)
- last_name = models.CharField(maxlength=50)
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
def __str__(self):
- return '%s %s' % (self.first_name, self.last_name)
+ # Note use of django.utils.encoding.smart_str() here because
+ # first_name and last_name will be unicode strings.
+ return smart_str('%s %s' % (self.first_name, self.last_name))
+
+``__unicode__``
+---------------
+
+The ``__unicode__()`` method is called whenever you call ``unicode()`` on an
+object. Since Django's database backends will return Unicode strings in your
+model's attributes, you would normally want to write a ``__unicode__()``
+method for your model. The example in the previous section could be written
+more simply as::
+
+ class Person(models.Model):
+ first_name = models.CharField(max_length=50)
+ last_name = models.CharField(max_length=50)
+
+ def __unicode__(self):
+ return u'%s %s' % (self.first_name, self.last_name)
+
+If you define a ``__unicode__()`` method on your model and not a ``__str__()``
+method, Django will automatically provide you with a ``__str__()`` that calls
+``__unicode()__`` and then converts the result correctly to a UTF-8 encoded
+string object. This is recommended development practice: define only
+``__unicode__()`` and let Django take care of the conversion to string objects
+when required.
``get_absolute_url``
--------------------
@@ -1805,10 +1953,12 @@ Django uses this in its admin interface. If an object defines
link that will jump you directly to the object's public view, according to
``get_absolute_url()``.
-Also, a couple of other bits of Django, such as the syndication-feed framework,
+Also, a couple of other bits of Django, such as the `syndication feed framework`_,
use ``get_absolute_url()`` as a convenience to reward people who've defined the
method.
+.. _syndication feed framework: ../syndication_feeds/
+
It's good practice to use ``get_absolute_url()`` in templates, instead of
hard-coding your objects' URLs. For example, this template code is bad::
@@ -1823,7 +1973,9 @@ But this template code is good::
characters (required by the URI spec, `RFC 2396`_) that have been
URL-encoded, if necessary. Code and templates using ``get_absolute_url()``
should be able to use the result directly without needing to do any
- further processing.
+ further processing. You may wish to use the
+ ``django.utils.encoding.iri_to_uri()`` function to help with this if you
+ are using unicode strings a lot.
.. _RFC 2396: http://www.ietf.org/rfc/rfc2396.txt
@@ -1841,7 +1993,7 @@ works out the correct full URL path using the URLconf, substituting the
parameters you have given into the URL. For example, if your URLconf
contained a line such as::
- (r'^/people/(\d+)/$', 'people.views.details'),
+ (r'^people/(\d+)/$', 'people.views.details'),
...your model could have a ``get_absolute_url`` method that looked like this::
@@ -1864,8 +2016,8 @@ Similarly, if you had a URLconf entry that looked like::
'day': self.created.day})
get_absolute_url = permalink(get_absolute_url)
-Notice that we specify an empty sequence for the second argument in this case,
-because we only want to pass keyword arguments, not named arguments.
+Notice that we specify an empty sequence for the second parameter in this case,
+because we only want to pass keyword parameters, not positional ones.
In this way, you're tying the model's absolute URL to the view that is used
to display it, without repeating the URL information anywhere. You can still
@@ -1917,7 +2069,7 @@ A classic use-case for overriding the built-in methods is if you want something
to happen whenever you save an object. For example::
class Blog(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self):
@@ -1928,7 +2080,7 @@ to happen whenever you save an object. For example::
You can also prevent saving::
class Blog(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self):
diff --git a/docs/modpython.txt b/docs/modpython.txt
index 388a6168f3..c90296bd9a 100644
--- a/docs/modpython.txt
+++ b/docs/modpython.txt
@@ -50,8 +50,8 @@ directive. The latter is used for pointing at places on your filesystem,
whereas ``<Location>`` points at places in the URL structure of a Web site.
``<Directory>`` would be meaningless here.
-Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
-on it, you'll need to tell mod_python:
+Also, if your Django project is not on the default ``PYTHONPATH`` for your
+computer, you'll have to tell mod_python where your project can be found:
.. parsed-literal::
@@ -63,6 +63,30 @@ on it, you'll need to tell mod_python:
**PythonPath "['/path/to/project'] + sys.path"**
</Location>
+The value you use for ``PythonPath`` should include the parent directories of
+all the modules you are going to import in your application. It should also
+include the parent directory of the ``DJANGO_SETTINGS_MODULE`` location. This
+is exactly the same situation as setting the Python path for interactive
+usage. Whenever you try to import something, Python will run through all the
+directories in ``sys.path`` in turn, from first to last, and try to import
+from each directory until one succeeds.
+
+An example might make this clearer. Suppose
+you have some applications under ``/usr/local/django-apps/`` (for example,
+``/usr/local/django-apps/weblog/`` and so forth), your settings file is at
+``/var/www/mysite/settings.py`` and you have specified
+``DJANGO_SETTINGS_MODULE`` as in the above example. In this case, you would
+need to write your ``PythonPath`` directive as::
+
+ PythonPath "['/var/production/django-apps/', '/var/www'] + sys.path"
+
+With this path, ``import weblog`` and ``import mysite.settings`` will both
+work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
+lived under the ``weblog/`` directory, you would *also* need to add
+``/var/production/django-apps/weblog/`` to your ``PythonPath``. Remember: the
+**parent directories** of anything you import directly must be on the Python
+path.
+
.. caution::
If you're using Windows, remember that the path will contain backslashes.
diff --git a/docs/newforms.txt b/docs/newforms.txt
index 41db04a7dd..0b59a7ad65 100644
--- a/docs/newforms.txt
+++ b/docs/newforms.txt
@@ -641,7 +641,7 @@ the "Outputting forms as HTML" section above.
The simplest way to display a form's HTML is to use the variable on its own,
like this::
- <form method="post">
+ <form method="post" action="">
<table>{{ form }}</table>
<input type="submit" />
</form>
@@ -653,7 +653,7 @@ class' ``__str__()`` method calls its ``as_table()`` method.
The following is equivalent but a bit more explicit::
- <form method="post">
+ <form method="post" action="">
<table>{{ form.as_table }}</table>
<input type="submit" />
</form>
@@ -675,10 +675,10 @@ individual fields for complete template control over the form's design.
The easiest way is to iterate over the form's fields, with
``{% for field in form %}``. For example::
- <form method="post">
+ <form method="post" action="">
<dl>
{% for field in form %}
- <dt>{{ field.label }}</dt>
+ <dt>{{ field.label_tag }}</dt>
<dd>{{ field }}</dd>
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
@@ -696,13 +696,13 @@ Alternatively, you can arrange the form's fields explicitly, by name. Do that
by accessing ``{{ form.fieldname }}``, where ``fieldname`` is the field's name.
For example::
- <form method="post">
+ <form method="post" action="">
<ul class="myformclass">
- <li>{{ form.sender.label }} {{ form.sender }}</li>
+ <li>{{ form.sender.label_tag }} {{ form.sender }}</li>
<li class="helptext">{{ form.sender.help_text }}</li>
{% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %}
- <li>{{ form.subject.label }} {{ form.subject }}</li>
+ <li>{{ form.subject.label_tag }} {{ form.subject }}</li>
<li class="helptext">{{ form.subject.help_text }}</li>
{% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %}
@@ -710,6 +710,49 @@ For example::
</ul>
</form>
+Binding uploaded files to a form
+--------------------------------
+
+**New in Django development version**
+
+Dealing with forms that have ``FileField`` and ``ImageField`` fields
+is a little more complicated than a normal form.
+
+Firstly, in order to upload files, you'll need to make sure that your
+``<form>`` element correctly defines the ``enctype`` as
+``"multipart/form-data"``::
+
+ <form enctype="multipart/form-data" method="post" action="/foo/">
+
+Secondly, when you use the form, you need to bind the file data. File
+data is handled separately to normal form data, so when your form
+contains a ``FileField`` and ``ImageField``, you will need to specify
+a second argument when you bind your form. So if we extend our
+ContactForm to include an ``ImageField`` called ``mugshot``, we
+need to bind the file data containing the mugshot image::
+
+ # Bound form with an image field
+ >>> data = {'subject': 'hello',
+ ... 'message': 'Hi there',
+ ... 'sender': 'foo@example.com',
+ ... 'cc_myself': True}
+ >>> file_data = {'mugshot': {'filename':'face.jpg'
+ ... 'content': <file data>}}
+ >>> f = ContactFormWithMugshot(data, file_data)
+
+In practice, you will usually specify ``request.FILES`` as the source
+of file data (just like you use ``request.POST`` as the source of
+form data)::
+
+ # Bound form with an image field, data from the request
+ >>> f = ContactFormWithMugshot(request.POST, request.FILES)
+
+Constructing an unbound form is the same as always -- just omit both
+form data *and* file data::
+
+ # Unbound form with a image field
+ >>> f = ContactFormWithMugshot()
+
Subclassing forms
-----------------
@@ -919,7 +962,7 @@ validation if a particular field's value is not given. ``initial`` values are
~~~~~~~~~~
The ``widget`` argument lets you specify a ``Widget`` class to use when
-rendering this ``Field``. See "Widgets" below for more information.
+rendering this ``Field``. See "Widgets"_ below for more information.
``help_text``
~~~~~~~~~~~~~
@@ -1086,6 +1129,24 @@ If no ``input_formats`` argument is provided, the default input formats are::
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
+``DecimalField``
+~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+ * Default widget: ``TextInput``
+ * Empty value: ``None``
+ * Normalizes to: A Python ``decimal``.
+ * Validates that the given value is a decimal. Leading and trailing
+ whitespace is ignored.
+
+Takes four optional arguments: ``max_value``, ``min_value``, ``max_digits``,
+and ``decimal_places``. The first two define the limits for the fields value.
+``max_digits`` is the maximum number of digits (those before the decimal
+point plus those after the decimal point, with leading zeros stripped)
+permitted in the value, whilst ``decimal_places`` is the maximum number of
+decimal places permitted.
+
``EmailField``
~~~~~~~~~~~~~~
@@ -1099,6 +1160,54 @@ Has two optional arguments for validation, ``max_length`` and ``min_length``.
If provided, these arguments ensure that the string is at most or at least the
given length.
+``FileField``
+~~~~~~~~~~~~~
+
+**New in Django development version**
+
+ * Default widget: ``FileInput``
+ * Empty value: ``None``
+ * Normalizes to: An ``UploadedFile`` object that wraps the file content
+ and file name into a single object.
+ * Validates that non-empty file data has been bound to the form.
+
+An ``UploadedFile`` object has two attributes:
+
+ ====================== =====================================================
+ Argument Description
+ ====================== =====================================================
+ ``filename`` The name of the file, provided by the uploading
+ client.
+ ``content`` The array of bytes comprising the file content.
+ ====================== =====================================================
+
+The string representation of an ``UploadedFile`` is the same as the filename
+attribute.
+
+When you use a ``FileField`` on a form, you must also remember to
+`bind the file data to the form`_.
+
+.. _`bind the file data to the form`: `Binding uploaded files to a form`_
+
+``ImageField``
+~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+ * Default widget: ``FileInput``
+ * Empty value: ``None``
+ * Normalizes to: An ``UploadedFile`` object that wraps the file content
+ and file name into a single object.
+ * Validates that file data has been bound to the form, and that the
+ file is of an image format understood by PIL.
+
+Using an ImageField requires that the `Python Imaging Library`_ is installed.
+
+When you use a ``FileField`` on a form, you must also remember to
+`bind the file data to the form`_.
+
+.. _Python Imaging Library: http://www.pythonware.com/products/pil/
+
``IntegerField``
~~~~~~~~~~~~~~~~
@@ -1108,6 +1217,9 @@ given length.
* Validates that the given value is an integer. Leading and trailing
whitespace is allowed, as in Python's ``int()`` function.
+Takes two optional arguments for validation, ``max_value`` and ``min_value``.
+These control the range of values permitted in the field.
+
``MultipleChoiceField``
~~~~~~~~~~~~~~~~~~~~~~~
@@ -1222,7 +1334,7 @@ Custom form and field validation
Form validation happens when the data is cleaned. If you want to customise
this process, there are various places you can change, each one serving a
-different purpose. Thee types of cleaning methods are run during form
+different purpose. Three types of cleaning methods are run during form
processing. These are normally executed when you call the ``is_valid()``
method on a form. There are other things that can trigger cleaning and
validation (accessing the ``errors`` attribute or calling ``full_clean()``
@@ -1307,12 +1419,12 @@ keep it simple and assume e-mail validation is contained in a function called
class MultiEmailField(forms.Field):
def clean(self, value):
+ if not value:
+ raise forms.ValidationError('Enter at least one e-mail address.')
emails = value.split(',')
for email in emails:
if not is_valid_email(email):
raise forms.ValidationError('%s is not a valid e-mail address.' % email)
- if not emails:
- raise forms.ValidationError('Enter at least one e-mail address.')
return emails
Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use
@@ -1325,6 +1437,156 @@ like so::
senders = MultiEmailField()
cc_myself = forms.BooleanField()
+Widgets
+=======
+
+A widget is Django's representation of a HTML input element. The widget
+handles the rendering of the HTML, and the extraction of data from a GET/POST
+dictionary that corresponds to the widget.
+
+Django provides a representation of all the basic HTML widgets, plus some
+commonly used groups of widgets:
+
+ ============================ ===========================================
+ Widget HTML Equivalent
+ ============================ ===========================================
+ ``TextInput`` ``<input type='text' ...``
+ ``PasswordInput`` ``<input type='password' ...``
+ ``HiddenInput`` ``<input type='hidden' ...``
+ ``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
+ instances.
+ ``FileInput`` ``<input type='file' ...``
+ ``Textarea`` ``<textarea>...</textarea>``
+ ``CheckboxInput`` ``<input type='checkbox' ...``
+ ``Select`` ``<select><option ...``
+ ``NullBooleanSelect`` Select widget with options 'Unknown',
+ 'Yes' and 'No'
+ ``SelectMultiple`` ``<select multiple='multiple'><option ...``
+ ``RadioSelect`` ``<ul><li><input type='radio' ...``
+ ``CheckboxSelectMultiple`` ``<ul><li><input type='checkbox' ...``
+ ``MultiWidget`` Wrapper around multiple other widgets
+ ``SplitDateTimeWidget`` Wrapper around two ``TextInput`` widgets:
+ one for the Date, and one for the Time.
+ ============================ ===========================================
+
+Specifying widgets
+------------------
+
+Whenever you specify a field on a form, Django will use a default widget
+that is appropriate to the type of data that is to be displayed. To find
+which widget is used on which field, see the documentation for the
+built-in Field classes.
+
+However, if you want to use a different widget for a field, you can -
+just use the 'widget' argument on the field definition. For example::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField()
+ url = forms.URLField()
+ comment = forms.CharField(widget=forms.Textarea)
+
+This would specify a form with a comment that uses a larger Textarea widget,
+rather than the default TextInput widget.
+
+Customizing widget instances
+----------------------------
+
+When Django renders a widget as HTML, it only renders the bare minimum
+HTML - Django doesn't add a class definition, or any other widget-specific
+attributes. This means that all 'TextInput' widgets will appear the same
+on your web page.
+
+If you want to make one widget look different to another, you need to
+specify additional attributes for each widget. When you specify a
+widget, you can provide a list of attributes that will be added to the
+rendered HTML for the widget.
+
+For example, take the following simple form::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField()
+ url = forms.URLField()
+ comment = forms.CharField()
+
+This form will include three default TextInput widgets, with default rendering -
+no CSS class, no extra attributes. This means that the inputs boxes provided for
+each widget will be rendered exactly the same::
+
+ >>> f = CommentForm(auto_id=False)
+ >>> f.as_table()
+ <tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
+ <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
+ <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
+
+On a real web page, you probably don't want every widget to look the same. You
+might want a larger input element for the comment, and you might want the
+'name' widget to have some special CSS class. To do this, you specify a
+custom widget for your fields, and specify some attributes to use
+when rendering those widgets::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField(
+ widget=forms.TextInput(attrs={'class':'special'}))
+ url = forms.URLField()
+ comment = forms.CharField(
+ widget=forms.TextInput(attrs={'size':'40'}))
+
+Django will then include the extra attributes in the rendered output::
+
+ >>> f = CommentForm(auto_id=False)
+ >>> f.as_table()
+ <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
+ <tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
+ <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
+
+Custom Widgets
+--------------
+
+When you start to write a lot of forms, you will probably find that you will
+reuse certain sets of widget attributes over and over again. Rather than
+repeat these attribute definitions every time you need them, Django allows
+you to capture those definitions as a custom widget.
+
+For example, if you find that you are including a lot of comment fields on forms,
+you could capture the idea of a ``TextInput`` with a specific ``size`` attribute
+as a custom extension to the ``TextInput`` widget::
+
+ class CommentWidget(forms.TextInput):
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('attrs',{}).update({'size': '40'})
+ super(forms.TextInput, self).__init__(*args, **kwargs)
+
+Then you can use this widget in your forms::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField()
+ url = forms.URLField()
+ comment = forms.CharField(widget=CommentWidget)
+
+You can even customize your custom widget, in the same way as you would
+any other widget. Adding a once-off class to your ``CommentWidget`` is as
+simple as adding an attribute definition::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField(max_length=20)
+ url = forms.URLField()
+ comment = forms.CharField(
+ widget=CommentWidget(attrs={'class': 'special'}))
+
+Django also makes it easy to specify a custom field type that uses your custom
+widget. For example, you could define a customized field type for comments
+by defining::
+
+ class CommentInput(forms.CharField):
+ widget = CommentWidget
+
+You can then use this field whenever you have a form that requires a comment::
+
+ class CommentForm(forms.Form):
+ name = forms.CharField()
+ url = forms.URLField()
+ comment = CommentInput()
+
Generating forms for models
===========================
@@ -1372,17 +1634,17 @@ the full list of conversions:
``AutoField`` Not represented in the form
``BooleanField`` ``BooleanField``
``CharField`` ``CharField`` with ``max_length`` set to
- the model field's ``maxlength``
+ the model field's ``max_length``
``CommaSeparatedIntegerField`` ``CharField``
``DateField`` ``DateField``
``DateTimeField`` ``DateTimeField``
``DecimalField`` ``DecimalField``
``EmailField`` ``EmailField``
- ``FileField`` ``CharField``
+ ``FileField`` ``FileField``
``FilePathField`` ``CharField``
``FloatField`` ``FloatField``
``ForeignKey`` ``ModelChoiceField`` (see below)
- ``ImageField`` ``CharField``
+ ``ImageField`` ``ImageField``
``IntegerField`` ``IntegerField``
``IPAddressField`` ``CharField``
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
@@ -1452,15 +1714,15 @@ Consider this set of models::
)
class Author(models.Model):
- name = models.CharField(maxlength=100)
- title = models.CharField(maxlength=3, choices=TITLE_CHOICES)
+ name = models.CharField(max_length=100)
+ title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Book(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
With these models, a call to ``form_for_model(Author)`` would return a ``Form``
@@ -1495,6 +1757,51 @@ example::
Note that ``save()`` will raise a ``ValueError`` if the data in the form
doesn't validate -- i.e., ``if form.errors``.
+This ``save()`` method accepts an optional ``commit`` keyword argument, which
+accepts either ``True`` or ``False``. If you call ``save()`` with
+``commit=False``, then it will return an object that hasn't yet been saved to
+the database. In this case, it's up to you to call ``save()`` on the resulting
+model instance. This is useful if you want to do custom processing on the
+object before saving it. ``commit`` is ``True`` by default.
+
+Another side effect of using ``commit=False`` is seen when your model has
+a many-to-many relation with another model. If your model has a many-to-many
+relation and you specify ``commit=False`` when you save a form, Django cannot
+immediately save the form data for the many-to-many relation. This is because
+it isn't possible to save many-to-many data for an instance until the instance
+exists in the database.
+
+To work around this problem, every time you save a form using ``commit=False``,
+Django adds a ``save_m2m()`` method to the form created by ``form_for_model``.
+After you've manually saved the instance produced by the form, you can invoke
+``save_m2m()`` to save the many-to-many form data. For example::
+
+ # Create a form instance with POST data.
+ >>> f = AuthorForm(request.POST)
+
+ # Create, but don't save the new author instance.
+ >>> new_author = f.save(commit=False)
+
+ # Modify the author in some way.
+ >>> new_author.some_field = 'some_value'
+
+ # Save the new instance.
+ >>> new_author.save()
+
+ # Now, save the many-to-many data for the form.
+ >>> f.save_m2m()
+
+Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
+When you use a simple ``save()`` on a form, all data -- including
+many-to-many data -- is saved without the need for any additional method calls.
+For example::
+
+ # Create a form instance with POST data.
+ >>> f = AuthorForm(request.POST)
+
+ # Create and save the new author instance. There's no need to do anything else.
+ >>> new_author = f.save()
+
Using an alternate base class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1624,6 +1931,42 @@ will raise ``ValueError`` if the data doesn't validate.
``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
arguments that behave the same way as they do for ``form_for_model()``.
+Let's modify the earlier `contact form`_ view example a little bit. Suppose we
+have a ``Message`` model that holds each contact submission. Something like::
+
+ class Message(models.Model):
+ subject = models.CharField(max_length=100)
+ message = models.TextField()
+ sender = models.EmailField()
+ cc_myself = models.BooleanField()
+
+You could use this model to create a form (using ``form_for_model()``). You
+could also use existing ``Message`` instances to create a form for editing
+messages. The earlier_ view can be changed slightly to accept the ``id`` value
+of an existing ``Message`` and present it for editing::
+
+ def contact_edit(request, msg_id):
+ # Create the form from the message id.
+ message = get_object_or_404(Message, id=msg_id)
+ ContactForm = form_for_instance(message)
+
+ if request.method == 'POST':
+ form = ContactForm(request.POST)
+ if form.is_valid():
+ form.save()
+ return HttpResponseRedirect('/url/on_success/')
+ else:
+ form = ContactForm()
+ return render_to_response('contact.html', {'form': form})
+
+Aside from how we create the ``ContactForm`` class here, the main point to
+note is that the form display in the ``GET`` branch of the function
+will use the values from the ``message`` instance as initial values for the
+form field.
+
+.. _contact form: `Simple view example`_
+.. _earlier: `Simple view example`_
+
When should you use ``form_for_model()`` and ``form_for_instance()``?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/overview.txt b/docs/overview.txt
index 7b3559663a..0fd1be5c85 100644
--- a/docs/overview.txt
+++ b/docs/overview.txt
@@ -25,18 +25,18 @@ far, it's been solving two years' worth of database-schema problems. Here's a
quick example::
class Reporter(models.Model):
- full_name = models.CharField(maxlength=70)
+ full_name = models.CharField(max_length=70)
- def __str__(self):
+ def __unicode__(self):
return self.full_name
class Article(models.Model):
pub_date = models.DateTimeField()
- headline = models.CharField(maxlength=200)
+ headline = models.CharField(max_length=200)
article = models.TextField()
reporter = models.ForeignKey(Reporter)
- def __str__(self):
+ def __unicode__(self):
return self.headline
Install it
@@ -54,7 +54,7 @@ Enjoy the free API
==================
With that, you've got a free, and rich, Python API to access your data. The API
-is created on the fly: No code generation necessary::
+is created on the fly, no code generation necessary::
>>> from mysite.models import Reporter, Article
@@ -124,7 +124,7 @@ is created on the fly: No code generation necessary::
# Delete an object with delete().
>>> r.delete()
-A dynamic admin interface: It's not just scaffolding -- it's the whole house
+A dynamic admin interface: it's not just scaffolding -- it's the whole house
============================================================================
Once your models are defined, Django can automatically create a professional,
@@ -134,7 +134,7 @@ your model classes::
class Article(models.Model):
pub_date = models.DateTimeField()
- headline = models.CharField(maxlength=200)
+ headline = models.CharField(max_length=200)
article = models.TextField()
reporter = models.ForeignKey(Reporter)
class Admin: pass
@@ -165,9 +165,9 @@ example above::
from django.conf.urls.defaults import *
urlpatterns = patterns('',
- (r'^/articles/(\d{4})/$', 'mysite.views.year_archive'),
- (r'^/articles/(\d{4})/(\d{2})/$', 'mysite.views.month_archive'),
- (r'^/articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.views.article_detail'),
+ (r'^articles/(\d{4})/$', 'mysite.views.year_archive'),
+ (r'^articles/(\d{4})/(\d{2})/$', 'mysite.views.month_archive'),
+ (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.views.article_detail'),
)
The code above maps URLs, as simple regular expressions, to the location of
@@ -250,7 +250,7 @@ Finally, Django uses the concept of "template inheritance": That's what the
``{% extends "base.html" %}`` does. It means "First load the template called
'base', which has defined a bunch of blocks, and fill the blocks with the
following blocks." In short, that lets you dramatically cut down on redundancy
-in templates: Each template has to define only what's unique to that template.
+in templates: each template has to define only what's unique to that template.
Here's what the "base.html" template might look like::
@@ -288,14 +288,16 @@ This has been only a quick overview of Django's functionality. Some more useful
features:
* A caching framework that integrates with memcached or other backends.
- * A syndication framework that makes creating RSS and Atom feeds as easy as
+ * A `syndication framework`_ that makes creating RSS and Atom feeds as easy as
writing a small Python class.
* More sexy automatically-generated admin features -- this overview barely
scratched the surface.
+.. _syndication framework: ../syndication_feeds/
+
The next obvious steps are for you to `download Django`_, read `the tutorial`_
and join `the community`_. Thanks for your interest!
.. _download Django: http://www.djangoproject.com/download/
-.. _the tutorial: http://www.djangoproject.com/documentation/tutorial01/
+.. _the tutorial: ../tutorial01/
.. _the community: http://www.djangoproject.com/community/
diff --git a/docs/release_notes_0.95.txt b/docs/release_notes_0.95.txt
index 3709cacf5a..f2ecbb66e6 100644
--- a/docs/release_notes_0.95.txt
+++ b/docs/release_notes_0.95.txt
@@ -114,7 +114,7 @@ there's a #django channel on irc.freenode.net that is regularly populated by
Django users and developers from around the world. Friendly people are usually
available at any hour of the day -- to help, or just to chat.
-.. _online: http://www.djangoproject.com/documentation/
+.. _online: http://www.djangoproject.com/documentation/0.95/
.. _Django website: http://www.djangoproject.com/
.. _FAQ: http://www.djangoproject.com/documentation/faq/
.. _django-users: http://groups.google.com/group/django-users
diff --git a/docs/request_response.txt b/docs/request_response.txt
index 0b985d563b..867464226a 100644
--- a/docs/request_response.txt
+++ b/docs/request_response.txt
@@ -38,6 +38,16 @@ All attributes except ``session`` should be considered read-only.
elif request.method == 'POST':
do_something_else()
+``encoding``
+ **New in Django development version**
+
+ A string representing the current encoding used to decode form submission
+ data (or ``None``, which means the ``DEFAULT_CHARSET`` setting is used).
+ You can write to this attribute to change the encoding used when accessing
+ the form data. Any subsequent attribute accesses (such as reading from
+ ``GET`` or ``POST``) will use the new ``encoding`` value. Useful if you
+ know the form data is not in the ``DEFAULT_CHARSET`` encoding.
+
``GET``
A dictionary-like object containing all given HTTP GET parameters. See the
``QueryDict`` documentation below.
@@ -297,7 +307,7 @@ In contrast to ``HttpRequest`` objects, which are created automatically by
Django, ``HttpResponse`` objects are your responsibility. Each view you write
is responsible for instantiating, populating and returning an ``HttpResponse``.
-The ``HttpResponse`` class lives at ``django.http.HttpResponse``.
+The ``HttpResponse`` class lives in the ``django.http`` module.
Usage
-----
@@ -342,7 +352,7 @@ hard-coded strings. If you use this technique, follow these guidelines:
Methods
-------
-``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)``
+``__init__(content='', mimetype=None, status=200, content_type=DEFAULT_CONTENT_TYPE)``
Instantiates an ``HttpResponse`` object with the given page content (a
string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``.
@@ -350,6 +360,16 @@ Methods
return strings, and those strings will be joined together to form the
content of the response.
+ ``status`` is the `HTTP Status code`_ for the response.
+
+ **(New in Django development version)** ``content_type`` is an alias for
+ ``mimetype``. Historically, the parameter was only called ``mimetype``,
+ but since this is actually the value included in the HTTP ``Content-Type``
+ header, it can also include the character set encoding, which makes it
+ more than just a MIME type specification. If ``mimetype`` is specifiedi
+ (not None), that value is used. Otherwise, ``content_type`` is used. If
+ neither is given, the ``DEFAULT_CONTENT_TYPE`` setting is used.
+
``__setitem__(header, value)``
Sets the given header name to the given value. Both ``header`` and
``value`` should be strings.
@@ -396,6 +416,8 @@ Methods
``write(content)``, ``flush()`` and ``tell()``
These methods make an ``HttpResponse`` instance a file-like object.
+.. _HTTP Status code: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10
+
HttpResponse subclasses
-----------------------
diff --git a/docs/sessions.txt b/docs/sessions.txt
index c7124ba703..96a88c617a 100644
--- a/docs/sessions.txt
+++ b/docs/sessions.txt
@@ -190,6 +190,12 @@ deleted::
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'
+In the last case of the above example, we can tell the session object
+explicitly that it has been modified by setting the ``modified`` attribute on
+the session object::
+
+ request.session.modified = True
+
To change this default behavior, set the ``SESSION_SAVE_EVERY_REQUEST`` setting
to ``True``. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, Django will save
the session to the database on every single request.
diff --git a/docs/settings.txt b/docs/settings.txt
index 897cdc8099..050e377713 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -233,12 +233,21 @@ Default: ``'simple://'``
The cache backend to use. See the `cache docs`_.
CACHE_MIDDLEWARE_KEY_PREFIX
+---------------------------
Default: ``''`` (Empty string)
The cache key prefix that the cache middleware should use. See the
`cache docs`_.
+CACHE_MIDDLEWARE_SECONDS
+------------------------
+
+Default: ``600``
+
+The default number of seconds to cache a page when the caching middleware or
+``cache_page()`` decorator is used.
+
DATABASE_ENGINE
---------------
@@ -442,6 +451,16 @@ Default: ``False``
Whether to use a TLS (secure) connection when talking to the SMTP server.
+FILE_CHARSET
+------------
+
+**New in Django development version**
+
+Default: ``'utf-8'``
+
+The character encoding used to decode any files read from disk. This includes
+template files and initial SQL data files.
+
FIXTURE_DIRS
-------------
diff --git a/docs/sitemaps.txt b/docs/sitemaps.txt
index 550f448de1..1d4fba2626 100644
--- a/docs/sitemaps.txt
+++ b/docs/sitemaps.txt
@@ -21,7 +21,7 @@ you express this information in Python code.
It works much like Django's `syndication framework`_. To create a sitemap, just
write a ``Sitemap`` class and point to it in your URLconf_.
-.. _syndication framework: ../syndication/
+.. _syndication framework: ../syndication_feeds/
.. _URLconf: ../url_dispatch/
Installation
diff --git a/docs/sites.txt b/docs/sites.txt
index 12259b04c3..90a9d0f90f 100644
--- a/docs/sites.txt
+++ b/docs/sites.txt
@@ -46,7 +46,7 @@ that's represented by a ``ManyToManyField`` in the ``Article`` model::
from django.contrib.sites.models import Site
class Article(models.Model):
- headline = models.CharField(maxlength=200)
+ headline = models.CharField(max_length=200)
# ...
sites = models.ManyToManyField(Site)
@@ -87,7 +87,7 @@ like this::
from django.contrib.sites.models import Site
class Article(models.Model):
- headline = models.CharField(maxlength=200)
+ headline = models.CharField(max_length=200)
# ...
site = models.ForeignKey(Site)
@@ -229,7 +229,7 @@ Use ``CurrentSiteManager`` by adding it to your model explicitly. For example::
class Photo(models.Model):
photo = models.FileField(upload_to='/home/photos')
- photographer_name = models.CharField(maxlength=100)
+ photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
site = models.ForeignKey(Site)
objects = models.Manager()
@@ -257,7 +257,7 @@ this::
class Photo(models.Model):
photo = models.FileField(upload_to='/home/photos')
- photographer_name = models.CharField(maxlength=100)
+ photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
publish_on = models.ForeignKey(Site)
objects = models.Manager()
@@ -318,5 +318,23 @@ Here's how Django uses the sites framework:
.. _redirects framework: ../redirects/
.. _flatpages framework: ../flatpages/
-.. _syndication framework: ../syndication/
+.. _syndication framework: ../syndication_feeds/
.. _authentication framework: ../authentication/
+
+``RequestSite`` objects
+=======================
+
+**New in Django development version**
+
+Some ``django.contrib`` applications take advantage of the sites framework but
+are architected in a way that doesn't *require* the sites framework to be
+installed in your database. (Some people don't want to, or just aren't *able*
+to install the extra database table that the sites framework requires.) For
+those cases, the framework provides a ``RequestSite`` class, which can be used
+as a fallback when the database-backed sites framework is not available.
+
+A ``RequestSite`` object has a similar interface to a normal ``Site`` object,
+except its ``__init__()`` method takes an ``HttpRequest`` object. It's able to
+deduce the ``domain`` and ``name`` by looking at the request's domain. It has
+``save()`` and ``delete()`` methods to match the interface of ``Site``, but
+the methods raise ``NotImplementedError``.
diff --git a/docs/static_files.txt b/docs/static_files.txt
index b6a1d278fd..846c3eb56b 100644
--- a/docs/static_files.txt
+++ b/docs/static_files.txt
@@ -103,10 +103,10 @@ Do this by wrapping an ``if DEBUG`` statement around the
from django.conf import settings
urlpatterns = patterns('',
- (r'^/articles/2003/$', 'news.views.special_case_2003'),
- (r'^/articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
- (r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
- (r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
+ (r'^articles/2003/$', 'news.views.special_case_2003'),
+ (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
+ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
+ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
)
if settings.DEBUG:
diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt
index 2a03e6d5a6..393572f3e2 100644
--- a/docs/syndication_feeds.txt
+++ b/docs/syndication_feeds.txt
@@ -31,6 +31,12 @@ To create a feed, just write a ``Feed`` class and point to it in your URLconf_.
Initialization
--------------
+If you're not using the latest Django development version, you'll need to make
+sure Django's sites framework is installed -- including its database table.
+(See the `sites framework documentation`_ for more information.) This has
+changed in the Django development version; the syndication feed framework no
+longer requires the sites framework.
+
To activate syndication feeds on your Django site, add this line to your
URLconf_::
@@ -72,6 +78,7 @@ The above example registers two feeds:
Once that's set up, you just need to define the ``Feed`` classes themselves.
+.. _sites framework documentation: ../sites/
.. _URLconf: ../url_dispatch/
.. _settings file: ../settings/
@@ -131,9 +138,14 @@ put into those elements.
* ``{{ obj }}`` -- The current object (one of whichever objects you
returned in ``items()``).
- * ``{{ site }}`` -- A ``django.models.core.sites.Site`` object
+ * ``{{ site }}`` -- A ``django.contrib.sites.models.Site`` object
representing the current site. This is useful for
- ``{{ site.domain }}`` or ``{{ site.name }}``.
+ ``{{ site.domain }}`` or ``{{ site.name }}``. Note that if you're
+ using the latest Django development version and do *not* have the
+ Django sites framework installed, this will be set to a
+ ``django.contrib.sites.models.RequestSite`` object. See the
+ `RequestSite section of the sites framework documentation`_ for
+ more.
If you don't create a template for either the title or description, the
framework will use the template ``"{{ obj }}"`` by default -- that is,
@@ -164,6 +176,7 @@ put into those elements.
.. _chicagocrime.org: http://www.chicagocrime.org/
.. _object-relational mapper: ../db-api/
.. _Django templates: ../templates/
+.. _RequestSite section of the sites framework documentation: ../sites/#requestsite-objects
A complex example
-----------------
@@ -416,6 +429,26 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
link = '/foo/bar/' # Hard-coded link.
+ # GUID -- One of the following three is optional. The framework looks
+ # for them in this order. This property is only used for Atom feeds
+ # (where it is the feed-level ID element). If not provided, the feed
+ # link is used as the ID.
+ #
+ # (New in Django development version)
+
+ def feed_guid(self, obj):
+ """
+ Takes the object returned by get_object() and returns the globally
+ unique ID for the feed as a normal Python string.
+ """
+
+ def feed_guid(self):
+ """
+ Returns the feed's globally unique ID as a normal Python string.
+ """
+
+ feed_guid = '/foo/bar/1234' # Hard-coded guid.
+
# DESCRIPTION -- One of the following three is required. The framework
# looks for them in this order.
@@ -556,7 +589,18 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
Returns the URL for every item in the feed.
"""
- # ITEM AUTHOR NAME --One of the following three is optional. The
+ # ITEM_GUID -- The following method is optional. This property is
+ # only used for Atom feeds (it is the ID element for an item in an
+ # Atom feed). If not provided, the item's link is used by default.
+ #
+ # (New in Django development version)
+
+ def item_guid(self, obj):
+ """
+ Takes an item, as return by items(), and returns the item's ID.
+ """
+
+ # ITEM AUTHOR NAME -- One of the following three is optional. The
# framework looks for them in this order.
def item_author_name(self, item):
diff --git a/docs/templates.txt b/docs/templates.txt
index c32b1af1dd..6cebd3b7bd 100644
--- a/docs/templates.txt
+++ b/docs/templates.txt
@@ -741,8 +741,19 @@ regroup
Regroup a list of alike objects by a common attribute.
This complex tag is best illustrated by use of an example: say that ``people``
-is a list of ``Person`` objects that have ``first_name``, ``last_name``, and
-``gender`` attributes, and you'd like to display a list that looks like:
+is a list of people represented by dictionaries with ``first_name``,
+``last_name``, and ``gender`` keys::
+
+ people = [
+ {'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
+ {'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
+ {'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
+ {'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
+ {'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'},
+ ]
+
+...and you'd like to display a hierarchical list that is ordered by gender,
+like this:
* Male:
* George Bush
@@ -753,33 +764,72 @@ is a list of ``Person`` objects that have ``first_name``, ``last_name``, and
* Unknown:
* Pat Smith
-The following snippet of template code would accomplish this dubious task::
+You can use the ``{% regroup %}`` tag to group the list of people by gender.
+The following snippet of template code would accomplish this::
+
+ {% regroup people by gender as gender_list %}
- {% regroup people by gender as grouped %}
<ul>
- {% for group in grouped %}
- <li>{{ group.grouper }}
+ {% for gender in gender_list %}
+ <li>{{ gender.grouper }}
<ul>
- {% for item in group.list %}
- <li>{{ item }}</li>
+ {% for item in gender.list %}
+ <li>{{ item.first_name }} {{ item.last_name }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
-As you can see, ``{% regroup %}`` populates a variable with a list of objects
-with ``grouper`` and ``list`` attributes. ``grouper`` contains the item that
-was grouped by; ``list`` contains the list of objects that share that
-``grouper``. In this case, ``grouper`` would be ``Male``, ``Female`` and
-``Unknown``, and ``list`` is the list of people with those genders.
+Let's walk through this example. ``{% regroup %}`` takes three arguments: the
+list you want to regroup, the attribute to group by, and the name of the
+resulting list. Here, we're regrouping the ``people`` list by the ``gender``
+attribute and calling the result ``gender_list``.
+
+``{% regroup %}`` produces a list (in this case, ``gender_list``) of
+**group objects**. Each group object has two attributes:
+
+ * ``grouper`` -- the item that was grouped by (e.g., the string "Male" or
+ "Female").
+ * ``list`` -- a list of all items in this group (e.g., a list of all people
+ with gender='Male').
+
+Note that ``{% regroup %}`` does not order its input! Our example relies on
+the fact that the ``people`` list was ordered by ``gender`` in the first place.
+If the ``people`` list did *not* order its members by ``gender``, the regrouping
+would naively display more than one group for a single gender. For example,
+say the ``people`` list was set to this (note that the males are not grouped
+together)::
+
+ people = [
+ {'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
+ {'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'},
+ {'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
+ {'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
+ {'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
+ ]
+
+With this input for ``people``, the example ``{% regroup %}`` template code
+above would result in the following output:
+
+ * Male:
+ * Bill Clinton
+ * Unknown:
+ * Pat Smith
+ * Female:
+ * Margaret Thatcher
+ * Male:
+ * George Bush
+ * Female:
+ * Condoleezza Rice
+
+The easiest solution to this gotcha is to make sure in your view code that the
+data is ordered according to how you want to display it.
-Note that ``{% regroup %}`` does not work when the list to be grouped is not
-sorted by the key you are grouping by! This means that if your list of people
-was not sorted by gender, you'd need to make sure it is sorted before using it,
-i.e.::
+Another solution is to sort the data in the template using the ``dictsort``
+filter, if your data is in a list of dictionaries::
- {% regroup people|dictsort:"gender" by gender as grouped %}
+ {% regroup people|dictsort:"gender" by gender as gender_list %}
spaceless
~~~~~~~~~
@@ -887,6 +937,12 @@ such as this::
The template tag will output the string ``/clients/client/123/``.
+**New in development version:** If you're using `named URL patterns`_,
+you can refer to the name of the pattern in the ``url`` tag instead of
+using the path to the view.
+
+.. _named URL patterns: ../url_dispatch/#naming-url-patterns
+
widthratio
~~~~~~~~~~
@@ -950,7 +1006,7 @@ Removes all values of arg from the given string.
date
~~~~
-Formats a date according to the given format (same as the ``now`` tag).
+Formats a date according to the given format (same as the `now`_ tag).
default
~~~~~~~
@@ -965,14 +1021,14 @@ If value is ``None``, use given default.
dictsort
~~~~~~~~
-Takes a list of dicts, returns that list sorted by the property given in the
-argument.
+Takes a list of dictionaries, returns that list sorted by the key given in
+the argument.
dictsortreversed
~~~~~~~~~~~~~~~~
-Takes a list of dicts, returns that list sorted in reverse order by the
-property given in the argument.
+Takes a list of dictionaries, returns that list sorted in reverse order by the
+key given in the argument.
divisibleby
~~~~~~~~~~~
@@ -1040,6 +1096,16 @@ right-most digit, 2 is the second-right-most digit, etc. Returns the original
value for invalid input (if input or argument is not an integer, or if argument
is less than 1). Otherwise, output is always an integer.
+iriencode
+~~~~~~~~~
+
+Converts an IRI (Internationalized Resource Identifier) to a string that is
+suitable for including in a URL. This is necessary if you're trying to use
+strings containing non-ASCII characters in a URL.
+
+It's safe to use this filter on a string that has already gone through the
+``urlencode`` filter.
+
join
~~~~
@@ -1179,7 +1245,10 @@ Strips all [X]HTML tags.
time
~~~~
-Formats a time according to the given format (same as the ``now`` tag).
+Formats a time according to the given format (same as the `now`_ tag).
+The time filter will only accept parameters in the format string that relate
+to the time of day, not the date (for obvious reasons). If you need to
+format a date, use the `date`_ filter.
timesince
~~~~~~~~~
@@ -1263,12 +1332,17 @@ urlize
Converts URLs in plain text into clickable links.
+Note that if ``urlize`` is applied to text that already contains HTML markup,
+things won't work as expected. Apply this filter only to *plain* text.
+
urlizetrunc
~~~~~~~~~~~
Converts URLs into clickable links, truncating URLs longer than the given
character limit.
+As with urlize_, this filter should only be applied to *plain* text.
+
**Argument:** Length to truncate URLs to
wordcount
diff --git a/docs/templates_python.txt b/docs/templates_python.txt
index 7171f32612..261eaedf74 100644
--- a/docs/templates_python.txt
+++ b/docs/templates_python.txt
@@ -277,7 +277,7 @@ Subclassing Context: RequestContext
Django comes with a special ``Context`` class,
``django.template.RequestContext``, that acts slightly differently than
-the normal ``django.template.Context``. The first difference is that takes
+the normal ``django.template.Context``. The first difference is that it takes
an `HttpRequest object`_ as its first argument. For example::
c = RequestContext(request, {
@@ -311,9 +311,10 @@ optional, third positional argument, ``processors``. In this example, the
def some_view(request):
# ...
- return RequestContext(request, {
+ c = RequestContext(request, {
'foo': 'bar',
}, [ip_address_processor])
+ return t.render(c)
Note::
If you're using Django's ``render_to_response()`` shortcut to populate a
@@ -673,11 +674,11 @@ If you are writing a template filter which only expects a string as the first
argument, you should use the included decorator ``stringfilter`` which will convert
an object to it's string value before being passed to your function::
- from django import template
+ from django.template.defaultfilters import stringfilter
- @template.stringfilter
+ @stringfilter
def lower(value):
- return value.lower()
+ return value.lower()
Writing custom template tags
----------------------------
diff --git a/docs/testing.txt b/docs/testing.txt
index b326e0099d..e27479cc34 100644
--- a/docs/testing.txt
+++ b/docs/testing.txt
@@ -22,6 +22,9 @@ it should be doing.
The best part is, it's really easy.
+This document is split into two primary sections. First, we explain how to
+write tests with Django. Then, we explain how to run them.
+
.. admonition:: Note
This testing framework is currently under development. It may change
@@ -32,37 +35,83 @@ The best part is, it's really easy.
Writing tests
=============
-Tests in Django come in two forms: doctests and unit tests.
+There are two primary ways to write tests with Django, corresponding to the
+two test frameworks that ship in the Python standard library. The two
+frameworks are:
+
+ * **Doctests** -- tests that are embedded in your functions' docstrings and
+ are written in a way that emulates a session of the Python interactive
+ interpreter. For example::
+
+ def my_func(a_list, idx):
+ """
+ >>> a = ['larry', 'curly', 'moe']
+ >>> my_func(a, 0)
+ 'larry'
+ >>> my_func(a, 1)
+ 'curly'
+ """
+ return a_list[idx]
+
+ * **Unit tests** -- tests that are expressed as methods on a Python class
+ that subclasses ``unittest.TestCase``. For example::
+
+ import unittest
+
+ class MyFuncTestCase(unittest.TestCase)
+ def testBasic(self):
+ a = ['larry', 'curly', 'moe']
+ self.assertEquals(my_func(a, 0), 'larry')
+ self.assertEquals(my_func(a, 1), 'curly')
+
+You can choose the test framework you like, depending on which syntax you
+prefer, or you can mix and match, using one framework for some of your code and
+the other framework for other code. You can also use any *other* Python test
+frameworks, as we'll explain in a bit.
Writing doctests
----------------
-Doctests use Python's standard doctest_ module, which searches for tests in
-your docstrings. Django's test runner looks for doctests in your ``models.py``
-file, and executes any that it finds. Django will also search for a file
-called ``tests.py`` in the application directory (i.e., the directory that
-holds ``models.py``). If a ``tests.py`` is found, it will also be searched
-for doctests.
+Doctests use Python's standard doctest_ module, which searches your docstrings
+for statements that resemble a session of the Python interactive interpreter.
+A full explanation of how doctest works is out of the scope of this document;
+read Python's official documentation for the details.
.. admonition:: What's a **docstring**?
- A good explanation of docstrings (and some guidlines for using them
+ A good explanation of docstrings (and some guidelines for using them
effectively) can be found in :PEP:`257`:
A docstring is a string literal that occurs as the first statement in
a module, function, class, or method definition. Such a docstring
becomes the ``__doc__`` special attribute of that object.
- Since tests often make great documentation, doctest lets you put your
- tests directly in your docstrings.
+ For example, this function has a docstring that describes what it does::
-You can put doctest strings on any object in your ``models.py``, but it's
-common practice to put application-level doctests in the module docstring, and
-model-level doctests in the docstring for each model.
+ def add_two(num):
+ "Adds 2 to the given number and returns the result."
+ return num + 2
-For example::
+ Because tests often make great documentation, putting tests directly in
+ your docstrings is an effective way to document *and* test your code.
- from django.db import model
+For a given Django application, the test runner looks for doctests in two
+places:
+
+ * The ``models.py`` file. You can define module-level doctests and/or a
+ doctest for individual models. It's common practice to put
+ application-level doctests in the module docstring and model-level
+ doctests in the model docstrings.
+
+ * A file called ``tests.py`` in the application directory -- i.e., the
+ directory that holds ``models.py``. This file is a hook for any and all
+ doctests you want to write that aren't necessarily related to models.
+
+Here is an example model doctest::
+
+ # models.py
+
+ from django.db import models
class Animal(models.Model):
"""
@@ -78,38 +127,53 @@ For example::
>>> cat.speak()
'The cat says "meow"'
"""
-
- name = models.CharField(maxlength=20)
- sound = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
+ sound = models.CharField(max_length=20)
def speak(self):
return 'The %s says "%s"' % (self.name, self.sound)
-When you `run your tests`_, the test utility will find this docstring, notice
+When you `run your tests`_, the test runner will find this docstring, notice
that portions of it look like an interactive Python session, and execute those
lines while checking that the results match.
+In the case of model tests, note that the test runner takes care of creating
+its own test database. That is, any test that accesses a database -- by
+creating and saving model instances, for example -- will not affect your
+production database. Each doctest begins with a "blank slate" -- a fresh
+database containing an empty table for each model. (See the section on
+fixtures, below, for more on this.)
+
For more details about how doctest works, see the `standard library
documentation for doctest`_
.. _doctest: http://docs.python.org/lib/module-doctest.html
.. _standard library documentation for doctest: doctest_
-Writing unittests
------------------
+Writing unit tests
+------------------
Like doctests, Django's unit tests use a standard library module: unittest_.
-As with doctests, Django's test runner looks for any unit test cases defined
-in ``models.py``, or in a ``tests.py`` file stored in the application
-directory.
+This module uses a different way of defining tests, taking a class-based
+approach.
+
+As with doctests, for a given Django application, the test runner looks for
+unit tests in two places:
+
+ * The ``models.py`` file. The test runner looks for any subclass of
+ ``unittest.TestCase`` in this module.
-An equivalent unittest test case for the above example would look like::
+ * A file called ``tests.py`` in the application directory -- i.e., the
+ directory that holds ``models.py``. Again, the test runner looks for any
+ subclass of ``unittest.TestCase`` in this module.
+
+This example ``unittest.TestCase`` subclass is equivalent to the example given
+in the doctest section above::
import unittest
from myapp.models import Animal
class AnimalTestCase(unittest.TestCase):
-
def setUp(self):
self.lion = Animal.objects.create(name="lion", sound="roar")
self.cat = Animal.objects.create(name="cat", sound="meow")
@@ -118,10 +182,17 @@ An equivalent unittest test case for the above example would look like::
self.assertEquals(self.lion.speak(), 'The lion says "roar"')
self.assertEquals(self.cat.speak(), 'The cat says "meow"')
-When you `run your tests`_, the test utility will find all the test cases
-(that is, subclasses of ``unittest.TestCase``) in ``models.py`` and
-``tests.py``, automatically build a test suite out of those test cases,
-and run that suite.
+When you `run your tests`_, the default behavior of the test utility is
+to find all the test cases (that is, subclasses of ``unittest.TestCase``)
+in ``models.py`` and ``tests.py``, automatically build a test suite out of
+those test cases, and run that suite.
+
+In the Django development version, there is a second way to define the test
+suite for a module: if you define a function called ``suite()`` in either
+``models.py`` or ``tests.py``, the Django test runner will use that function
+to construct the test suite for that module. This follows the
+`suggested organization`_ for unit tests. See the Python documentation for
+more details on how to construct a complex test suite.
For more details about ``unittest``, see the `standard library unittest
documentation`_.
@@ -129,308 +200,557 @@ documentation`_.
.. _unittest: http://docs.python.org/lib/module-unittest.html
.. _standard library unittest documentation: unittest_
.. _run your tests: `Running tests`_
+.. _suggested organization: http://docs.python.org/lib/organizing-tests.html
Which should I use?
-------------------
-Choosing a test framework is often contentious, so Django simply supports
-both of the standard Python test frameworks. Choosing one is up to each
-developer's personal tastes; each is supported equally. Since each test
-system has different benefits, the best approach is probably to use both
-together, picking the test system to match the type of tests you need to
-write.
+Because Django supports both of the standard Python test frameworks, it's up to
+you and your tastes to decide which one to use. You can even decide to use
+*both*.
-For developers new to testing, however, this choice can seem
-confusing, so here are a few key differences to help you decide whether
-doctests or unit tests are right for you.
+For developers new to testing, however, this choice can seem confusing. Here,
+then, are a few key differences to help you decide which approach is right for
+you:
-If you've been using Python for a while, ``doctest`` will probably feel more
-"pythonic". It's designed to make writing tests as easy as possible, so
-there's no overhead of writing classes or methods; you simply put tests in
-docstrings. This gives the added advantage of giving your modules automatic
-documentation -- well-written doctests can kill both the documentation and the
-testing bird with a single stone.
+ * If you've been using Python for a while, ``doctest`` will probably feel
+ more "pythonic". It's designed to make writing tests as easy as possible,
+ so it requires no overhead of writing classes or methods. You simply put
+ tests in docstrings. This has the added advantage of serving as
+ documentation (and correct documentation, at that!).
-For developers just getting started with testing, using doctests will probably
-get you started faster.
+ If you're just getting started with testing, using doctests will probably
+ get you started faster.
-The ``unittest`` framework will probably feel very familiar to developers
-coming from Java. Since ``unittest`` is inspired by Java's JUnit, if
-you've used testing frameworks in other languages that similarly were
-inspired by JUnit, ``unittest`` should also feel pretty familiar.
+ * The ``unittest`` framework will probably feel very familiar to developers
+ coming from Java. ``unittest`` is inspired by Java's JUnit, so you'll
+ feel at home with this method if you've used JUnit or any test framework
+ inspired by JUnit.
-Since ``unittest`` is organized around classes and methods, if you need
-to write a bunch of tests that all share similar code, you can easily use
-subclass to abstract common tasks; this makes test code shorter and cleaner.
-There's also support for explicit setup and/or cleanup routines, which give
-you a high level of control over the environment your test cases run in.
+ * If you need to write a bunch of tests that share similar code, then
+ you'll appreciate the ``unittest`` framework's organization around
+ classes and methods. This makes it easy to abstract common tasks into
+ common methods. The framework also supports explicit setup and/or cleanup
+ routines, which give you a high level of control over the environment
+ in which your test cases are run.
Again, remember that you can use both systems side-by-side (even in the same
-app). In the end, most projects will eventually end up using both; each shines
+app). In the end, most projects will eventually end up using both. Each shines
in different circumstances.
-Testing Tools
+Running tests
=============
-To assist in testing various features of your application, Django provides
-tools that can be used to establish tests and test conditions.
+Once you've written tests, run them using your project's ``manage.py`` utility::
+
+ $ ./manage.py test
+
+By default, this will run every test in every application in ``INSTALLED_APPS``.
+If you only want to run tests for a particular application, add the
+application name to the command line. For example, if your ``INSTALLED_APPS``
+contains ``'myproject.polls'`` and ``'myproject.animals'``, you can run the
+``myproject.animals`` unit tests alone with this command::
+
+ # ./manage.py test animals
-* `Test Client`_
-* `TestCase`_
-* `E-mail services`_
+Note that we used ``animals``, not ``myproject.animals``.
-Test Client
------------
+**New in Django development version:** If you use unit tests, as opposed to
+doctests, you can be even *more* specific in choosing which tests to execute.
+To run a single test case in an application (for example, the
+``AnimalTestCase`` described in the "Writing unit tests" section), add the
+name of the test case to the label on the command line::
-The Test Client is a simple dummy browser. It allows you to simulate
-GET and POST requests on a URL, and observe the response that is received.
-This allows you to test that the correct view is executed for a given URL,
-and that the view constructs the correct response.
+ $ ./manage.py test animals.AnimalTestCase
-As the response is generated, the Test Client gathers details on the
-Template and Context objects that were used to generate the response. These
-Templates and Contexts are then provided as part of the response, and can be
-used as test conditions.
+And it gets even more granular than that! To run a *single* test method inside
+a test case, add the name of the test method to the label::
-.. admonition:: Test Client vs Browser Automation?
+ $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
- The Test Client is not intended as a replacement for Twill_, Selenium_,
- or other browser automation frameworks - it is intended to allow
- testing of the contexts and templates produced by a view,
- rather than the HTML rendered to the end-user.
+Understanding the test output
+-----------------------------
- A comprehensive test suite should use a combination of both: Test Client
- tests to establish that the correct view is being called and that
- the view is collecting the correct context data, and Browser Automation
- tests to check that user interface behaves as expected.
+When you run your tests, you'll see a number of messages as the test runner
+prepares itself::
+
+ Creating test database...
+ Creating table myapp_animal
+ Creating table myapp_mineral
+ Loading 'initial_data' fixtures...
+ No fixtures found.
+
+This tells you that the test runner is creating a test database -- a blank,
+from-scratch database that it will use for any tests that happen to require a
+database (namely, model tests).
+
+Don't worry -- the test runner will not touch your "real" (production)
+database. It creates a separate database purely for the tests. This test
+database gets its name by prepending ``test_`` to the value of the
+``DATABASE_NAME`` setting. If you want to use a different name, specify the
+``TEST_DATABASE_NAME`` setting.
+
+Aside from using a separate database, the test runner will otherwise use all of
+the same database settings you have in your settings file: ``DATABASE_ENGINE``,
+``DATABASE_USER``, ``DATABASE_HOST``, etc. The test database is created by the
+user specified by ``DATABASE_USER``, so you'll need to make sure that the given
+user account has sufficient privileges to create a new database on the system.
+
+**New in Django development version:** For fine-grained control over the
+character encoding of your test database, use the ``TEST_DATABASE_CHARSET``
+setting. If you're using MySQL, you can also use the ``TEST_DATABASE_COLLATION``
+setting to control the particular collation used by the test database. See the
+settings_ documentation for details of these advanced settings.
+
+.. _settings: ../settings/
+
+Once the test database has been created, Django will run your tests.
+If everything goes well, you'll see something like this::
+
+ ----------------------------------------------------------------------
+ Ran 22 tests in 0.221s
+
+ OK
+
+If there are test failures, however, you'll see full details about which tests
+failed::
+
+ ======================================================================
+ FAIL: Doctest: ellington.core.throttle.models
+ ----------------------------------------------------------------------
+ Traceback (most recent call last):
+ File "/dev/django/test/doctest.py", line 2153, in runTest
+ raise self.failureException(self.format_failure(new.getvalue()))
+ AssertionError: Failed doctest test for myapp.models
+ File "/dev/myapp/models.py", line 0, in models
+
+ ----------------------------------------------------------------------
+ File "/dev/myapp/models.py", line 14, in myapp.models
+ Failed example:
+ throttle.check("actor A", "action one", limit=2, hours=1)
+ Expected:
+ True
+ Got:
+ False
+
+ ----------------------------------------------------------------------
+ Ran 2 tests in 0.048s
+
+ FAILED (failures=1)
+
+A full explanation of this error output is beyond the scope of this document,
+but it's pretty intuitive. You can consult the documentation of Python's
+``unittest`` library for details.
+
+Note that the return code for the test-runner script is the total number of
+failed and erroneous tests. If all the tests pass, the return code is 0. This
+feature is useful if you're using the test-runner script in a shell script and
+need to test for success or failure at that level.
+
+Regardless of whether the tests pass or fail, the test database is destroyed when
+all the tests have been executed.
+
+Testing tools
+=============
+
+Django provides a small set of tools that come in handy when writing tests.
+
+The test client
+---------------
+
+The test client is a Python class that acts as a dummy Web browser, allowing
+you to test your views and interact with your Django-powered application
+programatically.
+
+Some of the things you can do with the test client are:
+
+ * Simulate GET and POST requests on a URL and observe the response --
+ everything from low-level HTTP (result headers and status codes) to
+ page content.
+
+ * Test that the correct view is executed for a given URL.
+
+ * Test that a given request is rendered by a given Django template, with
+ a template context that contains certain values.
+
+Note that the test client is not intended to be a replacement for Twill_,
+Selenium_, or other "in-browser" frameworks. Django's test client has
+a different focus. In short:
+
+ * Use Django's test client to establish that the correct view is being
+ called and that the view is collecting the correct context data.
+
+ * Use in-browser frameworks such as Twill and Selenium to test *rendered*
+ HTML and the *behavior* of Web pages, namely JavaScript functionality.
+
+A comprehensive test suite should use a combination of both test types.
.. _Twill: http://twill.idyll.org/
.. _Selenium: http://www.openqa.org/selenium/
+Overview and a quick example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To use the test client, instantiate ``django.test.client.Client`` and retrieve
+Web pages::
+
+ >>> from django.test.client import Client
+ >>> c = Client()
+ >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
+ >>> response.status_code
+ 200
+ >>> response = c.get('/customer/details/')
+ >>> response.content
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...'
+
+As this example suggests, you can instantiate ``Client`` from within a session
+of the Python interactive interpreter.
+
+Note a few important things about how the test client works:
+
+ * The test client does *not* require the Web server to be running. In fact,
+ it will run just fine with no Web server running at all! That's because
+ it avoids the overhead of HTTP and deals directly with the Django
+ framework. This helps make the unit tests run quickly.
+
+ * When retrieving pages, remember to specify the *path* of the URL, not the
+ whole domain. For example, this is correct::
+
+ >>> c.get('/login/')
+
+ This is incorrect::
+
+ >>> c.get('http://www.example.com/login/')
+
+ The test client is not capable of retrieving Web pages that are not
+ powered by your Django project. If you need to retrieve other Web pages,
+ use a Python standard library module such as urllib_ or urllib2_.
+
+ * To resolve URLs, the test client uses whatever URLconf is pointed-to by
+ your ``ROOT_URLCONF`` setting.
+
+ * Although the above example would work in the Python interactive
+ interpreter, some of the test client's functionality, notably the
+ template-related functionality, is only available *while tests are running*.
+
+ The reason for this is that Django's test runner performs a bit of black
+ magic in order to determine which template was loaded by a given view.
+ This black magic (essentially a patching of Django's template system in
+ memory) only happens during test running.
+
+.. _urllib: http://docs.python.org/lib/module-urllib.html
+.. _urllib2: http://docs.python.org/lib/module-urllib2.html
+
Making requests
~~~~~~~~~~~~~~~
-Creating an instance of ``Client`` (``django.test.client.Client``) requires
-no arguments at time of construction. Once constructed, the following methods
-can be invoked on the ``Client`` instance.
+Use the ``django.test.client.Client`` class to make requests. It requires no
+arguments at time of construction::
+
+ >>> c = Client()
+
+Once you have a ``Client`` instance, you can call any of the following methods:
``get(path, data={})``
- Make a GET request on the provided ``path``. The key-value pairs in the
- data dictionary will be used to create a GET data payload. For example::
+ Makes a GET request on the provided ``path`` and returns a ``Response``
+ object, which is documented below.
+
+ The key-value pairs in the ``data`` dictionary are used to create a GET
+ data payload. For example::
- c = Client()
- c.get('/customers/details/', {'name':'fred', 'age':7})
+ >>> c = Client()
+ >>> c.get('/customers/details/', {'name': 'fred', 'age': 7})
- will result in the evaluation of a GET request equivalent to::
+ ...will result in the evaluation of a GET request equivalent to::
- http://yoursite.com/customers/details/?name=fred&age=7
+ /customers/details/?name=fred&age=7
``post(path, data={}, content_type=MULTIPART_CONTENT)``
- Make a POST request on the provided ``path``. If you provide a content type
- (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be
- sent as-is in the POST request, using the content type in the HTTP
- ``Content-Type`` header.
+ Makes a POST request on the provided ``path`` and returns a ``Response``
+ object, which is documented below.
- If you do not provide a value for ``content_type``, the values in
+ The key-value pairs in the ``data`` dictionary are used to submit POST
+ data. For example::
+
+ >>> c = Client()
+ >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})
+
+ ...will result in the evaluation of a POST request to this URL::
+
+ /login/
+
+ ...with this POST data::
+
+ name=fred&passwd=secret
+
+ If you provide ``content_type`` (e.g., ``text/xml`` for an XML payload),
+ the contents of ``data`` will be sent as-is in the POST request, using
+ ``content_type`` in the HTTP ``Content-Type`` header.
+
+ If you don't provide a value for ``content_type``, the values in
``data`` will be transmitted with a content type of ``multipart/form-data``.
- The key-value pairs in the data dictionary will be encoded as a multipart
- message and used to create the POST data payload.
+ In this case, the key-value pairs in ``data`` will be encoded as a
+ multipart message and used to create the POST data payload.
- To submit multiple values for a given key (for example, to specify
- the selections for a multiple selection list), provide the values as a
- list or tuple for the required key. For example, a data dictionary of
- ``{'choices': ('a','b','d')}`` would submit three selected rows for the
- field named ``choices``.
+ To submit multiple values for a given key -- for example, to specify
+ the selections for a ``<select multiple>`` -- provide the values as a
+ list or tuple for the required key. For example, this value of ``data``
+ would submit three selected values for the field named ``choices``::
- Submitting files is a special case. To POST a file, you need only
- provide the file field name as a key, and a file handle to the file you wish to
- upload as a value. The Test Client will populate the two POST fields (i.e.,
- ``field`` and ``field_file``) required by Django's FileField. For example::
+ {'choices': ('a', 'b', 'd')}
- c = Client()
- f = open('wishlist.doc')
- c.post('/customers/wishes/', {'name':'fred', 'attachment':f})
- f.close()
+ Submitting files is a special case. To POST a file, you need only provide
+ the file field name as a key, and a file handle to the file you wish to
+ upload as a value. For example::
- will result in the evaluation of a POST request on ``/customers/wishes/``,
- with a POST dictionary that contains ``name``, ``attachment`` (containing the
- file name), and ``attachment_file`` (containing the file data). Note that you
- need to manually close the file after it has been provided to the POST.
+ >>> c = Client()
+ >>> f = open('wishlist.doc')
+ >>> c.post('/customers/wishes/', {'name': 'fred', 'attachment': f})
+ >>> f.close()
+
+ (The name ``attachment`` here is not relevant; use whatever name your
+ file-processing code expects.)
+
+ Note that you should manually close the file after it has been provided to
+ ``post()``.
``login(**credentials)``
**New in Django development version**
- On a production site, it is likely that some views will be protected from
- anonymous access through the use of the @login_required decorator, or some
- other login checking mechanism. The ``login()`` method can be used to
- simulate the effect of a user logging into the site. As a result of calling
- this method, the Client will have all the cookies and session data required
- to pass any login-based tests that may form part of a view.
+ If your site uses Django's `authentication system`_ and you deal with
+ logging in users, you can use the test client's ``login()`` method to
+ simulate the effect of a user logging into the site.
+
+ After you call this method, the test client will have all the cookies and
+ session data required to pass any login-based tests that may form part of
+ a view.
- In most cases, the ``credentials`` required by this method are the username
- and password of the user that wants to log in, provided as keyword
- arguments::
+ The format of the ``credentials`` argument depends on which
+ `authentication backend`_ you're using (which is configured by your
+ ``AUTHENTICATION_BACKENDS`` setting). If you're using the standard
+ authentication backend provided by Django (``ModelBackend``),
+ ``credentials`` should be the user's username and password, provided as
+ keyword arguments::
- c = Client()
- c.login(username='fred', password='secret')
- # Now you can access a login protected view
+ >>> c = Client()
+ >>> c.login(username='fred', password='secret')
+ >>> # Now you can access a view that's only available to logged-in users.
- If you are using a different authentication backend, this method may
- require different credentials.
+ If you're using a different authentication backend, this method may require
+ different credentials. It requires whichever credentials are required by
+ your backend's ``authenticate()`` method.
``login()`` returns ``True`` if it the credentials were accepted and login
was successful.
- Note that since the test suite will be executed using the test database,
- which contains no users by default. As a result, logins that are valid
- on your production site will not work under test conditions. You will
- need to create users as part of the test suite (either manually, or
- using a test fixture).
+ Finally, you'll need to remember to create user accounts before you can use
+ this method. As we explained above, the test runner is executed using a
+ test database, which contains no users by default. As a result, user
+ accounts that are valid on your production site will not work under test
+ conditions. You'll need to create users as part of the test suite -- either
+ manually (using the Django model API) or with a test fixture.
+
+``logout()``
+ **New in Django development version**
+
+ If your site uses Django's `authentication system`_, the ``logout()``
+ method can be used to simulate the effect of a user logging out of
+ your site.
-Testing Responses
+ After you call this method, the test client will have all the cookies and
+ session data cleared to defaults. Subsequent requests will appear to
+ come from an AnonymousUser.
+
+.. _authentication system: ../authentication/
+.. _authentication backend: ../authentication/#other-authentication-sources
+
+Testing responses
~~~~~~~~~~~~~~~~~
-The ``get()`` and ``post()`` methods both return a Response object. This
-Response object has the following properties that can be used for testing
-purposes:
+The ``get()`` and ``post()`` methods both return a ``Response`` object. This
+``Response`` object is *not* the same as the ``HttpResponse`` object returned
+Django views; this object is simpler and has some additional data useful for
+tests.
+
+Specifically, a ``Response`` object has the following attributes:
=============== ==========================================================
- Property Description
+ Attribute Description
=============== ==========================================================
- ``status_code`` The HTTP status of the response. See RFC2616_ for a
- full list of HTTP status codes.
+ ``status_code`` The HTTP status of the response, as an integer. See
+ RFC2616_ for a full list of HTTP status codes.
- ``content`` The body of the response. This is the final page
- content as rendered by the view, or any error message
- (such as the URL for a 302 redirect).
+ ``content`` The body of the response, as a string. This is the final
+ page content as rendered by the view, or any error
+ message (such as the URL for a 302 redirect).
- ``template`` The Template instance that was used to render the final
- content. Testing ``template.name`` can be particularly
- useful; if the template was loaded from a file,
- ``template.name`` will be the file name that was loaded.
+ ``template`` The ``Template`` instance that was used to render the
+ final content. Use ``template.name`` to get the
+ template's file name, if the template was loaded from a
+ file. (The name is a string such as
+ ``'admin/index.html'``.)
- If multiple templates were rendered, (e.g., if one
- template includes another template),``template`` will
- be a list of Template objects, in the order in which
- they were rendered.
+ If the rendered page used multiple templates -- e.g.,
+ using `template inheritance`_ -- then ``template`` will
+ be a list of ``Template`` instances, in the order in
+ which they were rendered.
- ``context`` The Context that was used to render the template that
- produced the response content.
+ ``context`` The template ``Context`` instance that was used to render
+ the template that produced the response content.
- As with ``template``, if multiple templates were rendered
- ``context`` will be a list of Context objects, stored in
- the order in which they were rendered.
+ As with ``template``, if the rendered page used multiple
+ templates, then ``context`` will be a list of ``Context``
+ objects, in the order in which they were rendered.
=============== ==========================================================
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+.. _template inheritance: ../templates/#template-inheritance
Exceptions
~~~~~~~~~~
-If you point the Test Client at a view that raises an exception, that exception
+If you point the test client at a view that raises an exception, that exception
will be visible in the test case. You can then use a standard ``try...catch``
-block, or ``unittest.TestCase.assertRaises()`` to test for exceptions.
+block or ``unittest.TestCase.assertRaises()`` to test for exceptions.
-The only exceptions that are not visible in a Test Case are ``Http404``,
+The only exceptions that are not visible to the test client are ``Http404``,
``PermissionDenied`` and ``SystemExit``. Django catches these exceptions
-internally and converts them into the appropriate HTTP responses codes.
+internally and converts them into the appropriate HTTP response codes. In these
+cases, you can check ``response.status_code`` in your test.
Persistent state
~~~~~~~~~~~~~~~~
-The Test Client is stateful; if a cookie is returned as part of a response,
-that cookie is provided as part of the next request issued by that Client
-instance. Expiry policies for these cookies are not followed; if you want
-a cookie to expire, either delete it manually or create a new Client
-instance (which will effectively delete all cookies).
+The test client is stateful. If a response returns a cookie, then that cookie
+will be stored in the test client and sent with all subsequent ``get()`` and
+``post()`` requests.
+
+Expiration policies for these cookies are not followed. If you want a cookie
+to expire, either delete it manually or create a new ``Client`` instance (which
+will effectively delete all cookies).
-There are two properties of the Test Client which are used to store persistent
-state information. If necessary, these properties can be interrogated as
-part of a test condition.
+A test client has two attributes that store persistent state information. You
+can access these properties as part of a test condition.
=============== ==========================================================
- Property Description
+ Attribute Description
=============== ==========================================================
``cookies`` A Python ``SimpleCookie`` object, containing the current
- values of all the client cookies.
+ values of all the client cookies. See the
+ `Cookie module documentation`_ for more.
``session`` A dictionary-like object containing session information.
See the `session documentation`_ for full details.
=============== ==========================================================
-.. _`session documentation`: ../sessions/
+.. _Cookie module documentation: http://docs.python.org/lib/module-Cookie.html
+.. _session documentation: ../sessions/
Example
~~~~~~~
-The following is a simple unit test using the Test Client::
+The following is a simple unit test using the test client::
import unittest
from django.test.client import Client
class SimpleTest(unittest.TestCase):
def setUp(self):
- # Every test needs a client
+ # Every test needs a client.
self.client = Client()
+
def test_details(self):
- # Issue a GET request
+ # Issue a GET request.
response = self.client.get('/customer/details/')
- # Check that the respose is 200 OK
+ # Check that the respose is 200 OK.
self.failUnlessEqual(response.status_code, 200)
- # Check that the rendered context contains 5 customers
+
+ # Check that the rendered context contains 5 customers.
self.failUnlessEqual(len(response.context['customers']), 5)
TestCase
--------
-Normal python unit tests extend a base class of ``unittest.testCase``.
-Django provides an extension of this base class - ``django.test.TestCase``
-- that provides some additional capabilities that can be useful for
-testing web sites.
+Normal Python unit test classes extend a base class of ``unittest.TestCase``.
+Django provides an extension of this base class -- ``django.test.TestCase``
+-- that provides some additional capabilities that can be useful for
+testing Web sites.
-Moving from a normal unittest TestCase to a Django TestCase is easy - just
-change the base class of your test from ``unittest.TestCase`` to
-``django.test.TestCase``. All of the standard Python unit test facilities
-will continue to be available, but they will be augmented with some useful
-extra facilities.
+Converting a normal ``unittest.TestCase`` to a Django ``TestCase`` is easy:
+just change the base class of your test from ``unittest.TestCase`` to
+``django.test.TestCase``. All of the standard Python unit test functionality
+will continue to be available, but it will be augmented with some useful
+additions.
-Default Test Client
+Default test client
~~~~~~~~~~~~~~~~~~~
+
**New in Django development version**
Every test case in a ``django.test.TestCase`` instance has access to an
-instance of a Django `Test Client`_. This Client can be accessed as
-``self.client``. This client is recreated for each test.
+instance of a Django test client. This client can be accessed as
+``self.client``. This client is recreated for each test, so you don't have to
+worry about state (such as cookies) carrying over from one test to another.
+
+This means, instead of instantiating a ``Client`` in each test::
+
+ import unittest
+ from django.test.client import Client
+
+ class SimpleTest(unittest.TestCase):
+ def test_details(self):
+ client = Client()
+ response = client.get('/customer/details/')
+ self.failUnlessEqual(response.status_code, 200)
+
+ def test_index(self):
+ client = Client()
+ response = client.get('/customer/index/')
+ self.failUnlessEqual(response.status_code, 200)
+
+...you can just refer to ``self.client``, like so::
+
+ from django.test import TestCase
+ from django.test.client import Client
+
+ class SimpleTest(TestCase):
+ def test_details(self):
+ response = self.client.get('/customer/details/')
+ self.failUnlessEqual(response.status_code, 200)
+
+ def test_index(self):
+ response = self.client.get('/customer/index/')
+ self.failUnlessEqual(response.status_code, 200)
Fixture loading
~~~~~~~~~~~~~~~
-A test case for a database-backed website isn't much use if there isn't any
+A test case for a database-backed Web site isn't much use if there isn't any
data in the database. To make it easy to put test data into the database,
-Django provides a fixtures framework.
+Django's custom ``TestCase`` class provides a way of loading **fixtures**.
+
+A fixture is a collection of data that Django knows how to import into a
+database. For example, if your site has user accounts, you might set up a
+fixture of fake user accounts in order to populate your database during tests.
-A *Fixture* is a collection of files that contain the serialized contents of
-the database. Each fixture has a unique name; however, the files that
-comprise the fixture can be distributed over multiple directories, in
-multiple applications.
+The most straightforward way of creating a fixture is to use the
+``manage.py dumpdata`` command. This assumes you already have some data in
+your database. See the `dumpdata documentation`_ for more details.
.. note::
- If you have synchronized a Django project, you have already experienced
- the use of one fixture -- the ``initial_data`` fixture. Every time you
- synchronize the database, Django installs the ``initial_data`` fixture.
- This provides a mechanism to populate a new database with any initial
- data (such as a default set of categories). Fixtures with other names
- can be installed manually using ``django-admin.py loaddata``.
+ If you've ever run ``manage.py syncdb``, you've already used a fixture
+ without even knowing it! When you call ``syncdb`` in the database for
+ the first time, Django installs a fixture called ``initial_data``.
+ This gives you a way of populating a new database with any initial data,
+ such as a default set of categories.
-However, for the purposes of unit testing, each test must be able to
-guarantee the contents of the database at the start of each and every
-test.
+ Fixtures with other names can always be installed manually using the
+ ``manage.py loaddata`` command.
-To define a fixture for a test, all you need to do is add a class
-attribute to your test describing the fixtures you want the test to use.
-For example, the test case from `Writing unittests`_ would
-look like::
+Once you've created a fixture and placed it somewhere in your Django project,
+you can use it in your unit tests by specifying a ``fixtures`` class attribute
+on your ``django.test.TestCase`` subclass::
from django.test import TestCase
from myapp.models import Animal
@@ -439,229 +759,209 @@ look like::
fixtures = ['mammals.json', 'birds']
def setUp(self):
- # test definitions as before
+ # Test definitions as before.
+
+ def testFluffyAnimals(self):
+ # A test that uses the fixtures.
+
+Here's specifically what will happen:
-At the start of each test case, before ``setUp()`` is run, Django will
-flush the database, returning the database the state it was in directly
-after ``syncdb`` was called. Then, all the named fixtures are installed.
-In this example, any JSON fixture called ``mammals``, and any fixture
-named ``birds`` will be installed. See the documentation on
-`loading fixtures`_ for more details on defining and installing fixtures.
+ * At the start of each test case, before ``setUp()`` is run, Django will
+ flush the database, returning the database to the state it was in
+ directly after ``syncdb`` was called.
-.. _`loading fixtures`: ../django-admin/#loaddata-fixture-fixture
+ * Then, all the named fixtures are installed. In this example, Django will
+ install any JSON fixture named ``mammals``, followed by any fixture named
+ ``birds``. See the `loaddata documentation`_ for more details on defining
+ and installing fixtures.
This flush/load procedure is repeated for each test in the test case, so you
can be certain that the outcome of a test will not be affected by
-another test, or the order of test execution.
+another test, or by the order of test execution.
+
+.. _dumpdata documentation: ../django-admin/#dumpdata-appname-appname
+.. _loaddata documentation: ../django-admin/#loaddata-fixture-fixture
Emptying the test outbox
~~~~~~~~~~~~~~~~~~~~~~~~
+
**New in Django development version**
-At the start of each test case, in addition to installing fixtures,
-Django clears the contents of the test e-mail outbox.
+If you use Django's custom ``TestCase`` class, the test runner will clear the
+contents of the test e-mail outbox at the start of each test case.
For more detail on e-mail services during tests, see `E-mail services`_.
Assertions
~~~~~~~~~~
+
**New in Django development version**
-Normal Python unit tests have a wide range of assertions, such as
-``assertTrue`` and ``assertEquals`` that can be used to validate behavior.
-``django.TestCase`` adds to these, providing some assertions
-that can be useful in testing the behavior of web sites.
+As Python's normal ``unittest.TestCase`` class implements assertion
+methods such as ``assertTrue`` and ``assertEquals``, Django's custom
+``TestCase`` class provides a number of custom assertion methods that are
+useful for testing Web applications:
-``assertContains(response, text, count=1, status_code=200)``
- Assert that a response indicates that a page could be retrieved and
- produced the nominated status code, and that ``text`` occurs ``count``
- times in the content of the response.
+``assertContains(response, text, count=None, status_code=200)``
+ Asserts that a ``Response`` instance produced the given ``status_code`` and
+ that ``text`` appears in the content of the response. If ``count`` is
+ provided, ``text`` must occur exactly ``count`` times in the response.
``assertFormError(response, form, field, errors)``
- Assert that a field on a form raised the provided list of errors when
+ Asserts that a field on a form raises the provided list of errors when
rendered on the form.
- ``form`` is the name the form object was given in the template context.
+ ``form`` is the name the ``Form`` instance was given in the template
+ context. Note that this works only for ``newforms.Form`` instances, not
+ ``oldforms.Form`` instances.
``field`` is the name of the field on the form to check. If ``field``
- has a value of ``None``, non-field errors will be checked.
+ has a value of ``None``, non-field errors (errors you can access via
+ ``form.non_field_errors()``) will be checked.
``errors`` is an error string, or a list of error strings, that are
expected as a result of form validation.
``assertTemplateNotUsed(response, template_name)``
- Assert that the template with the given name was *not* used in rendering
+ Asserts that the template with the given name was *not* used in rendering
the response.
``assertRedirects(response, expected_path, status_code=302, target_status_code=200)``
- Assert that the response received produced the nominated status code,
- redirects the browser to the provided path, and that retrieving the provided
- path yields a response with the target status code.
+ Asserts that the response return a ``status_code`` redirect status,
+ it redirected to ``expected_path`` and the subsequent page was received with
+ ``target_status_code``.
``assertTemplateUsed(response, template_name)``
- Assert that the template with the given name was used in rendering the
+ Asserts that the template with the given name was used in rendering the
response.
+ The name is a string such as ``'admin/index.html'``.
+
E-mail services
---------------
**New in Django development version**
-If your view makes use of the `Django e-mail services`_, you don't really
-want e-mail to be sent every time you run a test using that view.
+If any of your Django views send e-mail using `Django's e-mail functionality`_,
+you probably don't want to send e-mail each time you run a test using that
+view. For this reason, Django's test runner automatically redirects all
+Django-sent e-mail to a dummy outbox. This lets you test every aspect of
+sending e-mail -- from the number of messages sent to the contents of each
+message -- without actually sending the messages.
+
+The test runner accomplishes this by transparently replacing the normal
+`SMTPConnection`_ class with a different version. (Don't worry -- this has no
+effect on any other e-mail senders outside of Django, such as your machine's
+mail server, if you're running one.)
+
+During test running, each outgoing e-mail is saved in
+``django.core.mail.outbox``. This is a simple list of all `EmailMessage`_
+instances that have been sent. It does not exist under normal execution
+conditions, i.e., when you're not running unit tests. The outbox is created
+during test setup, along with the dummy `SMTPConnection`_. When the test
+framework is torn down, the standard `SMTPConnection`_ class is restored, and
+the test outbox is destroyed.
-When the Django test framework is initialized, it transparently replaces the
-normal `SMTPConnection`_ class with a dummy implementation that redirects all
-e-mail to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``,
-is a simple list of all `EmailMessage`_ instances that have been sent.
-For example, during test conditions, it would be possible to run the following
-code::
+Here's an example test that examines ``django.core.mail.outbox`` for length
+and contents::
from django.core import mail
+ from django.test import TestCase
- # Send message
- mail.send_mail('Subject here', 'Here is the message.', 'from@example.com',
- ['to@example.com'], fail_silently=False)
+ class EmailTest(TestCase):
+ def test_send_email(self):
+ # Send message.
+ mail.send_mail('Subject here', 'Here is the message.',
+ 'from@example.com', ['to@example.com'],
+ fail_silently=False)
- # One message has been sent
- self.assertEqual(len(mail.outbox), 1)
- # Subject of first message is correct
- self.assertEqual(mail.outbox[0].subject, 'Subject here')
+ # Test that one message has been sent.
+ self.assertEqual(len(mail.outbox), 1)
-The ``mail.outbox`` object does not exist under normal execution conditions.
-The outbox is created during test setup, along with the dummy `SMTPConnection`_.
-When the test framework is torn down, the standard `SMTPConnection`_ class
-is restored, and the test outbox is destroyed.
+ # Verify that the subject of the first message is correct.
+ self.assertEqual(mail.outbox[0].subject, 'Subject here')
As noted `previously`_, the test outbox is emptied at the start of every
-test in a Django TestCase. To empty the outbox manually, assign the empty list
-to mail.outbox::
+test in a Django ``TestCase``. To empty the outbox manually, assign the
+empty list to ``mail.outbox``::
from django.core import mail
# Empty the test outbox
mail.outbox = []
-.. _`Django e-mail services`: ../email/
+.. _`Django's e-mail functionality`: ../email/
.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes
.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes
.. _`previously`: #emptying-the-test-outbox
-Running tests
-=============
+Using different testing frameworks
+==================================
-Run your tests using your project's ``manage.py`` utility::
+Clearly, ``doctest`` and ``unittest`` are not the only Python testing
+frameworks. While Django doesn't provide explicit support for alternative
+frameworks, it does provide a way to invoke tests constructed for an
+alternative framework as if they were normal Django tests.
- $ ./manage.py test
-
-If you only want to run tests for a particular application, add the
-application name to the command line. For example, if your
-``INSTALLED_APPS`` contains ``myproject.polls`` and ``myproject.animals``,
-but you only want to run the animals unit tests, run::
-
- $ ./manage.py test animals
-
-When you run your tests, you'll see a bunch of text flow by as the test
-database is created and models are initialized. This test database is
-created from scratch every time you run your tests.
-
-By default, the test database gets its name by prepending ``test_`` to
-the database name specified by the ``DATABASE_NAME`` setting; all other
-database settings will the same as they would be for the project normally.
-If you wish to use a name other than the default for the test database,
-you can use the ``TEST_DATABASE_NAME`` setting to provide a name.
+When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER``
+setting to determine what to do. By default, ``TEST_RUNNER`` points to
+``'django.test.simple.run_tests'``. This method defines the default Django
+testing behavior. This behavior involves:
-**New in Django development version:** For fine-grained control over the
-character encoding of your database, use the ``TEST_DATABASE_CHARSET`` setting.
-If you're using MySQL, you can also use the ``TEST_DATABASE_COLLATION`` setting
-to control the particular collation used by the test database. See the
-settings_ documentation for details of these advanced settings.
+ #. Performing global pre-test setup.
-.. _settings: ../settings/
+ #. Creating the test database.
-The test database is created by the user in the ``DATABASE_USER`` setting.
-This user needs to have sufficient privileges to create a new database on the
-system.
+ #. Running ``syncdb`` to install models and initial data into the test
+ database.
-Once the test database has been established, Django will run your tests.
-If everything goes well, at the end you'll see::
+ #. Looking for unit tests and doctests in the ``models.py`` and
+ ``tests.py`` files in each installed application.
- ----------------------------------------------------------------------
- Ran 22 tests in 0.221s
+ #. Running the unit tests and doctests that are found.
- OK
+ #. Destroying the test database.
-If there are test failures, however, you'll see full details about what tests
-failed::
+ #. Performing global post-test teardown.
- ======================================================================
- FAIL: Doctest: ellington.core.throttle.models
- ----------------------------------------------------------------------
- Traceback (most recent call last):
- File "/dev/django/test/doctest.py", line 2153, in runTest
- raise self.failureException(self.format_failure(new.getvalue()))
- AssertionError: Failed doctest test for myapp.models
- File "/dev/myapp/models.py", line 0, in models
+If you define your own test runner method and point ``TEST_RUNNER`` at that
+method, Django will execute your test runner whenever you run
+``./manage.py test``. In this way, it is possible to use any test framework
+that can be executed from Python code.
- ----------------------------------------------------------------------
- File "/dev/myapp/models.py", line 14, in myapp.models
- Failed example:
- throttle.check("actor A", "action one", limit=2, hours=1)
- Expected:
- True
- Got:
- False
-
- ----------------------------------------------------------------------
- Ran 2 tests in 0.048s
-
- FAILED (failures=1)
-
-The return code for the script is the total number of failed and erroneous
-tests. If all the tests pass, the return code is 0.
+Defining a test runner
+----------------------
-Regardless of whether the tests pass or fail, the test database is destroyed when
-all the tests have been executed.
+**New in Django development version**
-Using a different testing framework
-===================================
+By convention, a test runner should be called ``run_tests``. The only strict
+requirement is that it has the same arguments as the Django test runner:
-Doctest and Unittest are not the only Python testing frameworks. While
-Django doesn't provide explicit support these alternative frameworks,
-it does provide a mechanism to allow you to invoke tests constructed for
-an alternative framework as if they were normal Django tests.
+``run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[])``
-When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER``
-setting to determine what to do. By default, ``TEST_RUNNER`` points to
-``django.test.simple.run_tests``. This method defines the default Django
-testing behavior. This behavior involves:
+ ``test_labels`` is a list of strings describing the tests to be run. A test
+ label can take one of three forms:
-#. Performing global pre-test setup
-#. Creating the test database
-#. Running ``syncdb`` to install models and initial data into the test database
-#. Looking for Unit Tests and Doctests in ``models.py`` and ``tests.py`` file for each installed application
-#. Running the Unit Tests and Doctests that are found
-#. Destroying the test database
-#. Performing global post-test teardown
+ * ``app.TestCase.test_method`` -- Run a single test method in a test case.
+ * ``app.TestCase`` -- Run all the test methods in a test case.
+ * ``app`` -- Search for and run all tests in the named application.
-If you define your own test runner method and point ``TEST_RUNNER``
-at that method, Django will execute your test runner whenever you run
-``./manage.py test``. In this way, it is possible to use any test
-framework that can be executed from Python code.
+ If ``test_labels`` has a value of ``None``, the test runner should run
+ search for tests in all the applications in ``INSTALLED_APPS``.
-Defining a test runner
-----------------------
-By convention, a test runner should be called ``run_tests``; however, you
-can call it anything you want. The only requirement is that it accept two
-arguments:
+ ``verbosity`` determines the amount of notification and debug information
+ that will be printed to the console; ``0`` is no output, ``1`` is normal
+ output, and ``2`` is verbose output.
-``run_tests(module_list, verbosity=1)``
- The module list is the list of Python modules that contain the models to be
- tested. This is the same format returned by ``django.db.models.get_apps()``
+ If ``interactive`` is ``True``, the test suite has permission to ask the
+ user for instructions when the test suite is executed. An example of this
+ behavior would be asking for permission to delete an existing test
+ database. If ``interactive`` is ``False``, the test suite must be able to
+ run without any manual intervention.
- Verbosity determines the amount of notification and debug information that
- will be printed to the console; ``0`` is no output, ``1`` is normal output,
- and ``2`` is verbose output.
+ ``extra_tests`` is a list of extra ``TestCase`` instances to add to the
+ suite that is executed by the test runner. These extra tests are run
+ in addition to those discovered in the modules listed in ``module_list``.
This method should return the number of tests that failed.
@@ -674,28 +974,36 @@ a number of utility methods in the ``django.test.utils`` module.
``setup_test_environment()``
Performs any global pre-test setup, such as the installing the
instrumentation of the template rendering system and setting up
- the dummy SMTPConnection.
+ the dummy ``SMTPConnection``.
``teardown_test_environment()``
- Performs any global post-test teardown, such as removing the instrumentation
- of the template rendering system and restoring normal e-mail services.
+ Performs any global post-test teardown, such as removing the
+ black magic hooks into the template system and restoring normal e-mail
+ services.
``create_test_db(verbosity=1, autoclobber=False)``
- Creates a new test database, and run ``syncdb`` against it.
+ Creates a new test database and runs ``syncdb`` against it.
- ``verbosity`` has the same behavior as in the test runner.
+ ``verbosity`` has the same behavior as in ``run_tests()``.
- ``Autoclobber`` describes the behavior that will occur if a database with
- the same name as the test database is discovered. If ``autoclobber`` is False,
- the user will be asked to approve destroying the existing database. ``sys.exit``
- is called if the user does not approve. If autoclobber is ``True``, the database
- will be destroyed without consulting the user.
+ ``autoclobber`` describes the behavior that will occur if a database with
+ the same name as the test database is discovered:
+
+ * If ``autoclobber`` is ``False``, the user will be asked to approve
+ destroying the existing database. ``sys.exit`` is called if the user
+ does not approve.
+
+ * If autoclobber is ``True``, the database will be destroyed without
+ consulting the user.
``create_test_db()`` has the side effect of modifying
``settings.DATABASE_NAME`` to match the name of the test database.
+ New in the Django development version, this function returns the name of
+ the test database that it created.
+
``destroy_test_db(old_database_name, verbosity=1)``
- Destroys the database with the name ``settings.DATABASE_NAME`` matching,
- and restores the value of ``settings.DATABASE_NAME`` to the provided name.
+ Destroys the database whose name is in the ``DATABASE_NAME`` setting
+ and restores the value of ``DATABASE_NAME`` to the provided name.
- ``verbosity`` has the same behavior as in the test runner.
+ ``verbosity`` has the same behavior as in ``run_tests()``.
diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt
index fdac9c554e..cf2b76e9be 100644
--- a/docs/tutorial01.txt
+++ b/docs/tutorial01.txt
@@ -22,10 +22,10 @@ installed.
.. admonition:: Where to get help:
If you're having trouble going through this tutorial, please post a message
- to `django-users`_ or drop by `#django`_ on ``irc.freenode.net`` and we'll
+ to `django-users`_ or drop by `#django`_ on ``irc.freenode.net`` and we'll
try to help.
-.. _django-users: http://groups.google.com/group/django-users
+.. _django-users: http://groups.google.com/group/django-users
.. _#django: irc://irc.freenode.net/django
Creating a project
@@ -42,7 +42,7 @@ code, then run the command ``django-admin.py startproject mysite``. This
will create a ``mysite`` directory in your current directory.
.. note::
-
+
You'll need to avoid naming projects after built-in Python or Django
components. In particular, this means you should avoid using names like
``django`` (which will conflict with Django itself) or ``site`` (which
@@ -251,12 +251,12 @@ These concepts are represented by simple Python classes. Edit the
from django.db import models
class Poll(models.Model):
- question = models.CharField(maxlength=200)
+ question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
poll = models.ForeignKey(Poll)
- choice = models.CharField(maxlength=200)
+ choice = models.CharField(max_length=200)
votes = models.IntegerField()
The code is straightforward. Each model is represented by a class that
@@ -279,7 +279,7 @@ name for ``Poll.pub_date``. For all other fields in this model, the field's
machine-readable name will suffice as its human-readable name.
Some ``Field`` classes have required elements. ``CharField``, for example,
-requires that you give it a ``maxlength``. That's used not only in the database
+requires that you give it a ``max_length``. That's used not only in the database
schema, but in validation, as we'll soon see.
Finally, note a relationship is defined, using ``models.ForeignKey``. That tells
@@ -321,7 +321,7 @@ Now Django knows ``mysite`` includes the ``polls`` app. Let's run another comman
python manage.py sql polls
-You should see something similar to the following (the CREATE TABLE SQL statements
+You should see something similar to the following (the CREATE TABLE SQL statements
for the polls app)::
BEGIN;
@@ -341,7 +341,7 @@ for the polls app)::
Note the following:
* The exact output will vary depending on the database you are using.
-
+
* Table names are automatically generated by combining the name of the app
(``polls``) and the lowercase name of the model -- ``poll`` and
``choice``. (You can override this behavior.)
@@ -371,8 +371,8 @@ If you're interested, also run the following commands:
construction of your models.
* ``python manage.py sqlcustom polls`` -- Outputs any custom SQL statements
- (such as table modifications or constraints) that are defined for the
- application.
+ (such as table modifications or constraints) that are defined for the
+ application.
* ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP
TABLE`` statements for this app, according to which tables already exist
@@ -444,8 +444,8 @@ Once you're in the shell, explore the database API::
[]
# Create a new Poll.
- >>> from datetime import datetime
- >>> p = Poll(question="What's up?", pub_date=datetime.now())
+ >>> import datetime
+ >>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())
# Save the object into the database. You have to call save() explicitly.
>>> p.save()
@@ -461,10 +461,10 @@ Once you're in the shell, explore the database API::
>>> p.question
"What's up?"
>>> p.pub_date
- datetime.datetime(2005, 7, 15, 12, 00, 53)
+ datetime.datetime(2007, 7, 15, 12, 00, 53)
# Change values by changing the attributes, then calling save().
- >>> p.pub_date = datetime(2005, 4, 1, 0, 0)
+ >>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
>>> p.save()
# objects.all() displays all the polls in the database.
@@ -474,22 +474,39 @@ Once you're in the shell, explore the database API::
Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful
representation of this object. Let's fix that by editing the polls model (in
-the ``polls/models.py`` file) and adding a ``__str__()`` method to both
+the ``polls/models.py`` file) and adding a ``__unicode__()`` method to both
``Poll`` and ``Choice``::
class Poll(models.Model):
# ...
- def __str__(self):
+ def __unicode__(self):
return self.question
class Choice(models.Model):
# ...
- def __str__(self):
+ def __unicode__(self):
return self.choice
-It's important to add ``__str__()`` methods to your models, not only for your
-own sanity when dealing with the interactive prompt, but also because objects'
-representations are used throughout Django's automatically-generated admin.
+It's important to add ``__unicode__()`` methods to your models, not only for
+your own sanity when dealing with the interactive prompt, but also because
+objects' representations are used throughout Django's automatically-generated
+admin.
+
+.. admonition:: Why ``__unicode__()`` and not ``__str__()``?
+
+ If you're familiar with Python, you might be in the habit of adding
+ ``__str__()`` methods to your classes, not ``__unicode__()`` methods.
+ We use ``__unicode__()`` here because Django models deal with Unicode by
+ default. All data stored in your database is converted to Unicode when it's
+ returned.
+
+ Django models have a default ``__str__()`` method that calls
+ ``__unicode__()`` and converts the result to a UTF-8 bytestring. This means
+ that ``unicode(p)`` will return a Unicode string, and ``str(p)`` will return
+ a normal string, with characters encoded as UTF-8.
+
+ If all of this is jibberish to you, just remember to add ``__unicode__()``
+ methods to your models. With any luck, things should Just Work for you.
Note these are normal Python methods. Let's add a custom method, just for
demonstration::
@@ -509,7 +526,7 @@ Let's jump back into the Python interactive shell by running
>>> from mysite.polls.models import Poll, Choice
- # Make sure our __str__() addition worked.
+ # Make sure our __unicode__() addition worked.
>>> Poll.objects.all()
[<Poll: What's up?>]
@@ -520,9 +537,9 @@ Let's jump back into the Python interactive shell by running
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]
- # Get the poll whose year is 2005. Of course, if you're going through this
+ # Get the poll whose year is 2007. Of course, if you're going through this
# tutorial in another year, change as appropriate.
- >>> Poll.objects.get(pub_date__year=2005)
+ >>> Poll.objects.get(pub_date__year=2007)
<Poll: What's up?>
>>> Poll.objects.get(id=2)
@@ -563,9 +580,9 @@ Let's jump back into the Python interactive shell by running
# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
- # This works as many levels deep as you want. There's no limit.
- # Find all Choices for any poll whose pub_date is in 2005.
- >>> Choice.objects.filter(poll__pub_date__year=2005)
+ # This works as many levels deep as you want; there's no limit.
+ # Find all Choices for any poll whose pub_date is in 2007.
+ >>> Choice.objects.filter(poll__pub_date__year=2007)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Let's delete one of the choices. Use delete() for that.
diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt
index 99f586b4a1..d96c38f2bd 100644
--- a/docs/tutorial02.txt
+++ b/docs/tutorial02.txt
@@ -240,7 +240,7 @@ default, provide enough fields for 3 Choices."
Then change the other fields in ``Choice`` to give them ``core=True``::
- choice = models.CharField(maxlength=200, core=True)
+ choice = models.CharField(max_length=200, core=True)
votes = models.IntegerField(core=True)
This tells Django: "When you edit a Choice on the Poll admin page, the 'choice'
@@ -362,8 +362,8 @@ think they should.
Customize the admin look and feel
=================================
-Clearly, having "Django administration" and "example.com" at the top of each
-admin page is ridiculous. It's just placeholder text.
+Clearly, having "Django administration" at the top of each admin page is
+ridiculous. It's just placeholder text.
That's easy to change, though, using Django's template system. The Django admin
is powered by Django itself, and its interfaces use Django's own template
@@ -389,7 +389,7 @@ as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to
``admin`` subdirectory.
Then, just edit the file and replace the generic Django text with your own
-site's name and URL as you see fit.
+site's name as you see fit.
Note that any of Django's default admin templates can be overridden. To
override a template, just do the same thing you did with ``base_site.html`` --
diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt
index 41febe021d..d49a417dcf 100644
--- a/docs/tutorial03.txt
+++ b/docs/tutorial03.txt
@@ -355,8 +355,9 @@ view code.
Use the template system
=======================
-Back to our ``polls.detail`` view. Given the context variable ``poll``, here's
-what the template might look like::
+Back to the ``detail()`` view for our poll application. Given the context
+variable ``poll``, here's what the "polls/detail.html" template might look
+like::
<h1>{{ poll.question }}</h1>
<ul>
diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt
index 5cc12c445d..bd16fa2924 100644
--- a/docs/tutorial04.txt
+++ b/docs/tutorial04.txt
@@ -8,8 +8,8 @@ application and will focus on simple form processing and cutting down our code.
Write a simple form
===================
-Let's update our poll detail template from the last tutorial, so that the
-template contains an HTML ``<form>`` element::
+Let's update our poll detail template ("polls/detail.html") from the last
+tutorial, so that the template contains an HTML ``<form>`` element::
<h1>{{ poll.question }}</h1>
@@ -193,7 +193,7 @@ Change it like so::
urlpatterns = patterns('',
(r'^$', 'django.views.generic.list_detail.object_list', info_dict),
(r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
- (r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html')),
+ url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'),
(r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
)
@@ -209,6 +209,15 @@ objects" and "display a detail page for a particular type of object."
from the URL to be called ``"object_id"``, so we've changed ``poll_id`` to
``object_id`` for the generic views.
+ * We've added a name, ``poll_results``, to the results view so that we
+ have a way to refer to its URL later on (see the documentation about
+ `naming URL patterns`_ for information). We're also using the `url()`_
+ function from ``django.conf.urls.defaults`` here. It's a good habit to
+ use ``url()`` when you are providing a pattern name like this.
+
+.. _naming URL patterns: ../url_dispatch/#naming-url-patterns
+.. _url(): ../url_dispatch/#url
+
By default, the ``object_detail`` generic view uses a template called
``<app name>/<model name>_detail.html``. In our case, it'll use the template
``"polls/poll_detail.html"``. Thus, rename your ``polls/detail.html`` template to
@@ -255,6 +264,15 @@ the new templates and context variables. Change the template call from
``polls/detail.html`` to ``polls/poll_detail.html``, and pass ``object`` in the
context instead of ``poll``.
+The last thing to do is fix the URL handling to account for the use of generic
+views. In the vote view above, we used the ``reverse()`` function to avoid
+hard-coding our URLs. Now that we've switched to a generic view, we'll need to
+change the ``reverse()`` call to point back to our new generic view. We can't
+simply use the view function anymore -- generic views can be (and are) used
+multiple times -- but we can use the name we've given::
+
+ return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
+
Run the server, and use your new polling app based on generic views.
For full details on generic views, see the `generic views documentation`_.
diff --git a/docs/unicode.txt b/docs/unicode.txt
new file mode 100644
index 0000000000..1ab255970c
--- /dev/null
+++ b/docs/unicode.txt
@@ -0,0 +1,364 @@
+======================
+Unicode data in Django
+======================
+
+**New in Django development version**
+
+Django natively supports Unicode data everywhere. Providing your database can
+somehow store the data, you can safely pass around Unicode strings to
+templates, models and the database.
+
+This document tells you what you need to know if you're writing applications
+that use data or templates that are encoded in something other than ASCII.
+
+Creating the database
+=====================
+
+Make sure your database is configured to be able to store arbitrary string
+data. Normally, this means giving it an encoding of UTF-8 or UTF-16. If you use
+a more restrictive encoding -- for example, latin1 (iso8859-1) -- you won't be
+able to store certain characters in the database, and information will be lost.
+
+ * MySQL users, refer to the `MySQL manual`_ (section 10.3.2 for MySQL 5.1) for
+ details on how to set or alter the database character set encoding.
+
+ * PostgreSQL users, refer to the `PostgreSQL manual`_ (section 21.2.2 in
+ PostgreSQL 8) for details on creating databases with the correct encoding.
+
+ * SQLite users, there is nothing you need to do. SQLite always uses UTF-8
+ for internal encoding.
+
+.. _MySQL manual: http://www.mysql.org/doc/refman/5.1/en/charset-database.html
+.. _PostgreSQL manual: http://www.postgresql.org/docs/8.2/static/multibyte.html#AEN24104
+
+All of Django's database backends automatically convert Unicode strings into
+the appropriate encoding for talking to the database. They also automatically
+convert strings retrieved from the database into Python Unicode strings. You
+don't even need to tell Django what encoding your database uses: that is
+handled transparently.
+
+For more, see the section "The database API" below.
+
+General string handling
+=======================
+
+Whenever you use strings with Django -- e.g., in database lookups, template
+rendering or anywhere else -- you have two choices for encoding those strings.
+You can use Unicode strings, or you can use normal strings (sometimes called
+"bytestrings") that are encoded using UTF-8.
+
+.. admonition:: Warning
+
+ A bytestring does not carry any information with it about its encoding.
+ For that reason, we have to make an assumption, and Django assumes that all
+ bytestrings are in UTF-8.
+
+ If you pass a string to Django that has been encoded in some other format,
+ things will go wrong in interesting ways. Usually, Django will raise a
+ ``UnicodeDecodeError`` at some point.
+
+If your code only uses ASCII data, it's safe to use your normal strings,
+passing them around at will, because ASCII is a subset of UTF-8.
+
+Don't be fooled into thinking that if your ``DEFAULT_CHARSET`` setting is set
+to something other than ``'utf-8'`` you can use that other encoding in your
+bytestrings! ``DEFAULT_CHARSET`` only applies to the strings generated as
+the result of template rendering (and e-mail). Django will always assume UTF-8
+encoding for internal bytestrings. The reason for this is that the
+``DEFAULT_CHARSET`` setting is not actually under your control (if you are the
+application developer). It's under the control of the person installing and
+using your application -- and if that person chooses a different setting, your
+code must still continue to work. Ergo, it cannot rely on that setting.
+
+In most cases when Django is dealing with strings, it will convert them to
+Unicode strings before doing anything else. So, as a general rule, if you pass
+in a bytestring, be prepared to receive a Unicode string back in the result.
+
+Translated strings
+------------------
+
+Aside from Unicode strings and bytestrings, there's a third type of string-like
+object you may encounter when using Django. The framework's
+internationalization features introduce the concept of a "lazy translation" --
+a string that has been marked as translated but whose actual translation result
+isn't determined until the object is used in a string. This feature is useful
+in cases where the translation locale is unknown until the string is used, even
+though the string might have originally been created when the code was first
+imported.
+
+Normally, you won't have to worry about lazy translations. Just be aware that
+if you examine an object and it claims to be a
+``django.utils.functional.__proxy__`` object, it is a lazy translation.
+Calling ``unicode()`` with the lazy translation as the argument will generate a
+Unicode string in the current locale.
+
+For more details about lazy translation objects, refer to the
+internationalization_ documentation.
+
+.. _internationalization: ../i18n/#lazy-translation
+
+Useful utility functions
+------------------------
+
+Because some string operations come up again and again, Django ships with a few
+useful functions that should make working with Unicode and bytestring objects
+a bit easier.
+
+Conversion functions
+~~~~~~~~~~~~~~~~~~~~
+
+The ``django.utils.encoding`` module contains a few functions that are handy
+for converting back and forth between Unicode and bytestrings.
+
+ * ``smart_unicode(s, encoding='utf-8', errors='strict')`` converts its
+ input to a Unicode string. The ``encoding`` parameter specifies the input
+ encoding. (For example, Django uses this internally when processing form
+ input data, which might not be UTF-8 encoded.) The ``errors`` parameter
+ takes any of the values that are accepted by Python's ``unicode()``
+ function for its error handling.
+
+ If you pass ``smart_unicode()`` an object that has a ``__unicode__``
+ method, it will use that method to do the conversion.
+
+ * ``force_unicode(s, encoding='utf-8', errors='strict')`` is identical to
+ ``smart_unicode()`` in almost all cases. The difference is when the
+ first argument is a `lazy translation`_ instance. While
+ ``smart_unicode()`` preserves lazy translations, ``force_unicode()``
+ forces those objects to a Unicode string (causing the translation to
+ occur). Normally, you'll want to use ``smart_unicode()``. However,
+ ``force_unicode()`` is useful in template tags and filters that
+ absolutely *must* have a string to work with, not just something that can
+ be converted to a string.
+
+ * ``smart_str(s, encoding='utf-8', strings_only=False, errors='strict')``
+ is essentially the opposite of ``smart_unicode()``. It forces the first
+ argument to a bytestring. The ``strings_only`` parameter, if set to True,
+ will result in Python integers, booleans and ``None`` not being
+ converted to a string (they keep their original types). This is slightly
+ different semantics from Python's builtin ``str()`` function, but the
+ difference is needed in a few places within Django's internals.
+
+Normally, you'll only need to use ``smart_unicode()``. Call it as early as
+possible on any input data that might be either Unicode or a bytestring, and
+from then on, you can treat the result as always being Unicode.
+
+.. _lazy translation: ../i18n/#lazy-translation
+
+URI and IRI handling
+~~~~~~~~~~~~~~~~~~~~
+
+Web frameworks have to deal with URLs (which are a type of URI_). One
+requirement of URLs is that they are encoded using only ASCII characters.
+However, in an international environment, you might need to construct a
+URL from an IRI_ -- very loosely speaking, a URI that can contain Unicode
+characters. Quoting and converting an IRI to URI can be a little tricky, so
+Django provides some assistance.
+
+ * The function ``django.utils.encoding.iri_to_uri()`` implements the
+ conversion from IRI to URI as required by the specification (`RFC
+ 3987`_).
+
+ * The functions ``django.utils.http.urlquote()`` and
+ ``django.utils.http.urlquote_plus()`` are versions of Python's standard
+ ``urllib.quote()`` and ``urllib.quote_plus()`` that work with non-ASCII
+ characters. (The data is converted to UTF-8 prior to encoding.)
+
+These two groups of functions have slightly different purposes, and it's
+important to keep them straight. Normally, you would use ``urlquote()`` on the
+individual portions of the IRI or URI path so that any reserved characters
+such as '&' or '%' are correctly encoded. Then, you apply ``iri_to_uri()`` to
+the full IRI and it converts any non-ASCII characters to the correct encoded
+values.
+
+.. note::
+ Technically, it isn't correct to say that ``iri_to_uri()`` implements the
+ full algorithm in the IRI specification. It doesn't (yet) perform the
+ international domain name encoding portion of the algorithm.
+
+The ``iri_to_uri()`` function will not change ASCII characters that are
+otherwise permitted in a URL. So, for example, the character '%' is not
+further encoded when passed to ``iri_to_uri()``. This means you can pass a
+full URL to this function and it will not mess up the query string or anything
+like that.
+
+An example might clarify things here::
+
+ >>> urlquote(u'Paris & Orléans')
+ u'Paris%20%26%20Orl%C3%A9ans'
+ >>> iri_to_uri(u'/favorites/François/%s' % urlquote(u'Paris & Orléans'))
+ '/favorites/Fran%C3%A7ois/Paris%20%26%20Orl%C3%A9ans'
+
+If you look carefully, you can see that the portion that was generated by
+``urlquote()`` in the second example was not double-quoted when passed to
+``iri_to_uri()``. This is a very important and useful feature. It means that
+you can construct your IRI without worrying about whether it contains
+non-ASCII characters and then, right at the end, call ``iri_to_uri()`` on the
+result.
+
+The ``iri_to_uri()`` function is also idempotent, which means the following is
+always true::
+
+ iri_to_uri(iri_to_uri(some_string)) = iri_to_uri(some_string)
+
+So you can safely call it multiple times on the same IRI without risking
+double-quoting problems.
+
+.. _URI: http://www.ietf.org/rfc/rfc2396.txt
+.. _IRI: http://www.ietf.org/rfc/rfc3987.txt
+.. _RFC 3987: IRI_
+
+Models
+======
+
+Because all strings are returned from the database as Unicode strings, model
+fields that are character based (CharField, TextField, URLField, etc) will
+contain Unicode values when Django retrieves data from the database. This
+is *always* the case, even if the data could fit into an ASCII bytestring.
+
+You can pass in bytestrings when creating a model or populating a field, and
+Django will convert it to Unicode when it needs to.
+
+Choosing between ``__str__()`` and ``__unicode__()``
+----------------------------------------------------
+
+One consequence of using Unicode by default is that you have to take some care
+when printing data from the model.
+
+In particular, rather than giving your model a ``__str__()`` method, we
+recommended you implement a ``__unicode__()`` method. In the ``__unicode__()``
+method, you can quite safely return the values of all your fields without
+having to worry about whether they fit into a bytestring or not. (The way
+Python works, the result of ``__str__()`` is *always* a bytestring, even if you
+accidentally try to return a Unicode object).
+
+You can still create a ``__str__()`` method on your models if you want, of
+course, but you shouldn't need to do this unless you have a good reason.
+Django's ``Model`` base class automatically provides a ``__str__()``
+implementation that calls ``__unicode__()`` and encodes the result into UTF-8.
+This means you'll normally only need to implement a ``__unicode__()`` method
+and let Django handle the coercion to a bytestring when required.
+
+Taking care in ``get_absolute_url()``
+-------------------------------------
+
+URLs can only contain ASCII characters. If you're constructing a URL from
+pieces of data that might be non-ASCII, be careful to encode the results in a
+way that is suitable for a URL. The ``django.db.models.permalink()`` decorator
+handles this for you automatically.
+
+If you're constructing a URL manually (i.e., *not* using the ``permalink()``
+decorator), you'll need to take care of the encoding yourself. In this case,
+use the ``iri_to_uri()`` and ``urlquote()`` functions that were documented
+above_. For example::
+
+ from django.utils.encoding import iri_to_uri
+ from django.utils.http import urlquote
+
+ def get_absolute_url(self):
+ url = u'/person/%s/?x=0&y=0' % urlquote(self.location)
+ return iri_to_uri(url)
+
+This function returns a correctly encoded URL even if ``self.location`` is
+something like "Jack visited Paris & Orléans". (In fact, the ``iri_to_uri()``
+call isn't strictly necessary in the above example, because all the
+non-ASCII characters would have been removed in quoting in the first line.)
+
+.. _above: `URI and IRI handling`_
+
+The database API
+================
+
+You can pass either Unicode strings or UTF-8 bytestrings as arguments to
+``filter()`` methods and the like in the database API. The following two
+querysets are identical::
+
+ qs = People.objects.filter(name__contains=u'Å')
+ qs = People.objects.filter(name__contains='\xc3\85') # UTF-8 encoding of Å
+
+Templates
+=========
+
+You can use either Unicode or bytestrings when creating templates manually::
+
+ from django.template import Template
+ t1 = Template('This is a bytestring template.')
+ t2 = Template(u'This is a Unicode template.')
+
+But the common case is to read templates from the filesystem, and this creates
+a slight complication: not all filesystems store their data encoded as UTF-8.
+If your template files are not stored with a UTF-8 encoding, set the ``FILE_CHARSET``
+setting to the encoding of the files on disk. When Django reads in a template
+file, it will convert the data from this encoding to Unicode. (``FILE_CHARSET``
+is set to ``'utf-8'`` by default.)
+
+The ``DEFAULT_CHARSET`` setting controls the encoding of rendered templates.
+This is set to UTF-8 by default.
+
+Template tags and filters
+-------------------------
+
+A couple of tips to remember when writing your own template tags and filters:
+
+ * Always return Unicode strings from a template tag's ``render()`` method
+ and from template filters.
+
+ * Use ``force_unicode()`` in preference to ``smart_unicode()`` in these
+ places. Tag rendering and filter calls occur as the template is being
+ rendered, so there is no advantage to postponing the conversion of lazy
+ translation objects into strings. It's easier to work solely with Unicode
+ strings at that point.
+
+E-mail
+======
+
+Django's e-mail framework (in ``django.core.mail``) supports Unicode
+transparently. You can use Unicode data in the message bodies and any headers.
+However, you're still obligated to respect the requirements of the e-mail
+specifications, so, for example, e-mail addresses should use only ASCII
+characters.
+
+The following code example demonstrates that everything except e-mail addresses
+can be non-ASCII::
+
+ from django.core.mail import EmailMessage
+
+ subject = u'My visit to Sør-Trøndelag'
+ sender = u'Arnbjörg Ráðormsdóttir <arnbjorg@example.com>'
+ recipients = ['Fred <fred@example.com']
+ body = u'...'
+ EmailMessage(subject, body, sender, recipients).send()
+
+Form submission
+===============
+
+HTML form submission is a tricky area. There's no guarantee that the
+submission will include encoding information, which means the framework might
+have to guess at the encoding of submitted data.
+
+Django adopts a "lazy" approach to decoding form data. The data in an
+``HttpRequest`` object is only decoded when you access it. In fact, most of
+the data is not decoded at all. Only the ``HttpRequest.GET`` and
+``HttpRequest.POST`` data structures have any decoding applied to them. Those
+two fields will return their members as Unicode data. All other attributes and
+methods of ``HttpRequest`` return data exactly as it was submitted by the
+client.
+
+By default, the ``DEFAULT_CHARSET`` setting is used as the assumed encoding
+for form data. If you need to change this for a particular form, you can set
+the ``encoding`` attribute on an ``HttpRequest`` instance. For example::
+
+ def some_view(request):
+ # We know that the data must be encoded as KOI8-R (for some reason).
+ request.encoding = 'koi8-r'
+ ...
+
+You can even change the encoding after having accessed ``request.GET`` or
+``request.POST``, and all subsequent accesses will use the new encoding.
+
+Most developers won't need to worry about changing form encoding, but this is
+a useful feature for applications that talk to legacy systems whose encoding
+you cannot control.
+
+Django does not decode the data of file uploads, because that data is normally
+treated as collections of bytes, rather than strings. Any automatic decoding
+there would alter the meaning of the stream of bytes.
diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt
index 402b1200b5..76a4e1b5f0 100644
--- a/docs/url_dispatch.txt
+++ b/docs/url_dispatch.txt
@@ -204,8 +204,16 @@ optional extra arguments dictionary. For example::
...
)
+This function takes five arguments, most of which are optional::
+
+ url(regex, view, kwargs=None, name=None, prefix='')
+
See `Naming URL patterns`_ for why the ``name`` parameter is useful.
+The ``prefix`` parameter has the same meaning as the first argument to
+``patterns()`` and is only relevant when you're passing a string as the
+``view`` parameter.
+
handler404
----------
@@ -317,7 +325,7 @@ Old::
from django.conf.urls.defaults import *
urlpatterns = patterns('',
- (r'^/?$', 'django.views.generic.date_based.archive_index'),
+ (r'^$', 'django.views.generic.date_based.archive_index'),
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'django.views.generic.date_based.archive_month'),
(r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'),
)
@@ -327,7 +335,7 @@ New::
from django.conf.urls.defaults import *
urlpatterns = patterns('django.views.generic.date_based',
- (r'^/?$', 'archive_index'),
+ (r'^$', 'archive_index'),
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'),
)
@@ -392,7 +400,7 @@ dictionary of extra keyword arguments to pass to the view function.
For example::
urlpatterns = patterns('blog.views',
- (r'^/blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
+ (r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)
In this example, for a request to ``/blog/2005/``, Django will call the
@@ -404,7 +412,7 @@ This technique is used in `generic views`_ and in the `syndication framework`_
to pass metadata and options to views.
.. _generic views: ../generic_views/
-.. _syndication framework: ../syndication/
+.. _syndication framework: ../syndication_feeds/
.. admonition:: Dealing with conflicts
@@ -512,7 +520,7 @@ view::
This is completely valid, but it leads to problems when you try to do reverse
URL matching (through the ``permalink()`` decorator or the ``{% url %}``
-template tag). Continuing this example, if you wanted to retrieve the URL for
+`template tag`_). Continuing this example, if you wanted to retrieve the URL for
the ``archive`` view, Django's reverse URL matcher would get confused, because
*two* URLpatterns point at that view.
@@ -552,14 +560,16 @@ not restricted to valid Python names.
name, will decrease the chances of collision. We recommend something like
``myapp-comment`` instead of ``comment``.
+.. _template tag: ../templates/#url
+
Utility methods
===============
reverse()
---------
-If you need to use something similar to the ``{% url %}`` template tag in your
-code, Django provides the ``django.core.urlresolvers.reverse()``. The
+If you need to use something similar to the ``{% url %}`` `template tag`_ in
+your code, Django provides the ``django.core.urlresolvers.reverse()``. The
``reverse()`` function has the following signature::
reverse(viewname, urlconf=None, args=None, kwargs=None)
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index 9af13c0e3e..0a09579761 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -1,3 +1,4 @@
+# coding: utf-8
"""
1. Bare-bones model
@@ -7,13 +8,13 @@ This is a basic model with only two non-primary-key fields.
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100, default='Default headline')
+ headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
class Meta:
ordering = ('pub_date','headline')
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS': """
@@ -246,6 +247,19 @@ datetime.datetime(2005, 7, 28, 0, 0)
>>> (s1 | s2 | s3)[::2]
[<Article: Area woman programs in Python>, <Article: Third article>]
+# Slicing works with longs.
+>>> Article.objects.all()[0L]
+<Article: Area woman programs in Python>
+>>> Article.objects.all()[1L:3L]
+[<Article: Second article>, <Article: Third article>]
+>>> s3 = Article.objects.filter(id__exact=3)
+>>> (s1 | s2 | s3)[::2L]
+[<Article: Area woman programs in Python>, <Article: Third article>]
+
+# And can be mixed with ints.
+>>> Article.objects.all()[1:3L]
+[<Article: Second article>, <Article: Third article>]
+
# Slices (without step) are lazy:
>>> Article.objects.all()[0:5].filter()
[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>]
@@ -351,7 +365,7 @@ __test__['API_TESTS'] += """
>>> a101.save()
>>> a101 = Article.objects.get(pk=101)
>>> a101.headline
-'Article 101'
+u'Article 101'
# You can create saved objects in a single step
>>> a10 = Article.objects.create(headline="Article 10", pub_date=datetime(2005, 7, 31, 12, 30, 45))
@@ -364,4 +378,10 @@ year, including Jan. 1 and Dec. 31.
>>> a12 = Article.objects.create(headline='Article 12', pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999))
>>> Article.objects.filter(pub_date__year=2008)
[<Article: Article 11>, <Article: Article 12>]
+
+# Unicode data works, too.
+>>> a = Article(headline=u'\u6797\u539f \u3081\u3050\u307f', pub_date=datetime(2005, 7, 28))
+>>> a.save()
+>>> Article.objects.get(pk=a.id).headline
+u'\u6797\u539f \u3081\u3050\u307f'
"""
diff --git a/tests/modeltests/choices/models.py b/tests/modeltests/choices/models.py
index 37d36fe1d8..550e655e46 100644
--- a/tests/modeltests/choices/models.py
+++ b/tests/modeltests/choices/models.py
@@ -17,10 +17,10 @@ GENDER_CHOICES = (
)
class Person(models.Model):
- name = models.CharField(maxlength=20)
- gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
+ name = models.CharField(max_length=20)
+ gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
@@ -33,7 +33,7 @@ __test__ = {'API_TESTS':"""
>>> s.gender
'F'
>>> a.get_gender_display()
-'Male'
+u'Male'
>>> s.get_gender_display()
-'Female'
+u'Female'
"""}
diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py
index 1283da07cf..e1d0bc6e94 100644
--- a/tests/modeltests/custom_columns/models.py
+++ b/tests/modeltests/custom_columns/models.py
@@ -6,11 +6,11 @@ If your database column name is different than your model attribute, use the
name, in API usage.
If your database table name is different than your model name, use the
-``db_table`` Meta attribute. This has no effect on the API used to
+``db_table`` Meta attribute. This has no effect on the API used to
query the database.
-If you need to use a table name for a many-to-many relationship that differs
-from the default generated name, use the ``db_table`` parameter on the
+If you need to use a table name for a many-to-many relationship that differs
+from the default generated name, use the ``db_table`` parameter on the
ManyToMany field. This has no effect on the API for querying the database.
"""
@@ -18,26 +18,26 @@ ManyToMany field. This has no effect on the API for querying the database.
from django.db import models
class Author(models.Model):
- first_name = models.CharField(maxlength=30, db_column='firstname')
- last_name = models.CharField(maxlength=30, db_column='last')
+ first_name = models.CharField(max_length=30, db_column='firstname')
+ last_name = models.CharField(max_length=30, db_column='last')
- def __str__(self):
- return '%s %s' % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u'%s %s' % (self.first_name, self.last_name)
class Meta:
db_table = 'my_author_table'
ordering = ('last_name','first_name')
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, db_table='my_m2m_table')
- def __str__(self):
+ def __unicode__(self):
return self.headline
class Meta:
ordering = ('headline',)
-
+
__test__ = {'API_TESTS':"""
# Create a Author.
>>> a = Author(first_name='John', last_name='Smith')
@@ -75,9 +75,9 @@ TypeError: Cannot resolve keyword 'firstname' into field. Choices are: article,
>>> a = Author.objects.get(last_name__exact='Smith')
>>> a.first_name
-'John'
+u'John'
>>> a.last_name
-'Smith'
+u'Smith'
>>> a.firstname
Traceback (most recent call last):
...
diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
index 99df875275..40bf77e273 100644
--- a/tests/modeltests/custom_managers/models.py
+++ b/tests/modeltests/custom_managers/models.py
@@ -18,13 +18,13 @@ class PersonManager(models.Manager):
return self.filter(fun=True)
class Person(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
fun = models.BooleanField()
objects = PersonManager()
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
# An example of a custom manager that sets get_query_set().
@@ -33,13 +33,13 @@ class PublishedBookManager(models.Manager):
return super(PublishedBookManager, self).get_query_set().filter(is_published=True)
class Book(models.Model):
- title = models.CharField(maxlength=50)
- author = models.CharField(maxlength=30)
+ title = models.CharField(max_length=50)
+ author = models.CharField(max_length=30)
is_published = models.BooleanField()
published_objects = PublishedBookManager()
authors = models.ManyToManyField(Person, related_name='books')
- def __str__(self):
+ def __unicode__(self):
return self.title
# An example of providing multiple custom managers.
@@ -49,13 +49,13 @@ class FastCarManager(models.Manager):
return super(FastCarManager, self).get_query_set().filter(top_speed__gt=150)
class Car(models.Model):
- name = models.CharField(maxlength=10)
+ name = models.CharField(max_length=10)
mileage = models.IntegerField()
top_speed = models.IntegerField(help_text="In miles per hour.")
cars = models.Manager()
fast_cars = FastCarManager()
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py
index e8fb751d54..b0ca4131a5 100644
--- a/tests/modeltests/custom_methods/models.py
+++ b/tests/modeltests/custom_methods/models.py
@@ -8,10 +8,10 @@ from django.db import models
import datetime
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateField()
- def __str__(self):
+ def __unicode__(self):
return self.headline
def was_published_today(self):
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py
index fd0901da3c..53bbadbfd4 100644
--- a/tests/modeltests/custom_pk/models.py
+++ b/tests/modeltests/custom_pk/models.py
@@ -8,23 +8,23 @@ this behavior by explicitly adding ``primary_key=True`` to a field.
from django.db import models
class Employee(models.Model):
- employee_code = models.CharField(maxlength=10, primary_key=True,
+ employee_code = models.CharField(max_length=10, primary_key=True,
db_column = 'code')
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=20)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=20)
class Meta:
ordering = ('last_name', 'first_name')
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
class Business(models.Model):
- name = models.CharField(maxlength=20, primary_key=True)
+ name = models.CharField(max_length=20, primary_key=True)
employees = models.ManyToManyField(Employee)
class Meta:
verbose_name_plural = 'businesses'
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
@@ -62,7 +62,7 @@ DoesNotExist: Employee matching query does not exist.
>>> Employee.objects.filter(last_name__exact='Jones')
[<Employee: Dan Jones>, <Employee: Fran Jones>]
>>> Employee.objects.in_bulk(['ABC123', 'XYZ456'])
-{'XYZ456': <Employee: Fran Jones>, 'ABC123': <Employee: Dan Jones>}
+{u'XYZ456': <Employee: Fran Jones>, u'ABC123': <Employee: Dan Jones>}
>>> b = Business(name='Sears')
>>> b.save()
@@ -72,7 +72,7 @@ DoesNotExist: Employee matching query does not exist.
>>> fran.business_set.all()
[<Business: Sears>]
>>> Business.objects.in_bulk(['Sears'])
-{'Sears': <Business: Sears>}
+{u'Sears': <Business: Sears>}
>>> Business.objects.filter(name__exact='Sears')
[<Business: Sears>]
diff --git a/tests/modeltests/field_defaults/models.py b/tests/modeltests/field_defaults/models.py
index 8e803d00d8..23c4733b8f 100644
--- a/tests/modeltests/field_defaults/models.py
+++ b/tests/modeltests/field_defaults/models.py
@@ -13,10 +13,10 @@ from django.db import models
from datetime import datetime
class Article(models.Model):
- headline = models.CharField(maxlength=100, default='Default headline')
+ headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField(default=datetime.now)
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/fixtures/models.py b/tests/modeltests/fixtures/models.py
index c75e6723fd..b59c388bbd 100644
--- a/tests/modeltests/fixtures/models.py
+++ b/tests/modeltests/fixtures/models.py
@@ -1,79 +1,79 @@
"""
37. Fixtures.
-Fixtures are a way of loading data into the database in bulk. Fixure data
-can be stored in any serializable format (including JSON and XML). Fixtures
+Fixtures are a way of loading data into the database in bulk. Fixure data
+can be stored in any serializable format (including JSON and XML). Fixtures
are identified by name, and are stored in either a directory named 'fixtures'
-in the application directory, on in one of the directories named in the
+in the application directory, on in one of the directories named in the
FIXTURE_DIRS setting.
"""
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100, default='Default headline')
+ headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __str__(self):
+ def __unicode__(self):
return self.headline
-
+
class Meta:
ordering = ('-pub_date', 'headline')
-
+
__test__ = {'API_TESTS': """
>>> from django.core import management
>>> from django.db.models import get_app
-# Reset the database representation of this app.
+# Reset the database representation of this app.
# This will return the database to a clean initial state.
->>> management.flush(verbosity=0, interactive=False)
+>>> management.call_command('flush', verbosity=0, interactive=False)
# Syncdb introduces 1 initial data object from initial_data.json.
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
# Load fixture 1. Single JSON file, with two objects.
->>> management.load_data(['fixture1.json'], verbosity=0)
+>>> management.call_command('loaddata', 'fixture1.json', verbosity=0)
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Load fixture 2. JSON file imported by default. Overwrites some existing objects
->>> management.load_data(['fixture2.json'], verbosity=0)
+>>> management.call_command('loaddata', 'fixture2.json', verbosity=0)
>>> Article.objects.all()
[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
-# Load fixture 3, XML format.
->>> management.load_data(['fixture3.xml'], verbosity=0)
+# Load fixture 3, XML format.
+>>> management.call_command('loaddata', 'fixture3.xml', verbosity=0)
>>> Article.objects.all()
[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
# Load a fixture that doesn't exist
->>> management.load_data(['unknown.json'], verbosity=0)
+>>> management.call_command('loaddata', 'unknown.json', verbosity=0)
# object list is unaffected
>>> Article.objects.all()
[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
# Reset the database representation of this app. This will delete all data.
->>> management.flush(verbosity=0, interactive=False)
+>>> management.call_command('flush', verbosity=0, interactive=False)
>>> Article.objects.all()
[<Article: Python program becomes self aware>]
# Load fixture 1 again, using format discovery
->>> management.load_data(['fixture1'], verbosity=0)
+>>> management.call_command('loaddata', 'fixture1', verbosity=0)
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Try to load fixture 2 using format discovery; this will fail
-# because there are two fixture2's in the fixtures directory
->>> management.load_data(['fixture2'], verbosity=0) # doctest: +ELLIPSIS
+# because there are two fixture2's in the fixtures directory
+>>> management.call_command('loaddata', 'fixture2', verbosity=0) # doctest: +ELLIPSIS
Multiple fixtures named 'fixture2' in '...fixtures'. Aborting.
>>> Article.objects.all()
[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>]
# Dump the current contents of the database as a JSON fixture
->>> print management.dump_data(['fixtures'], format='json')
+>>> management.call_command('dumpdata', 'fixtures', format='json')
[{"pk": "3", "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": "2", "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": "1", "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]
"""}
@@ -81,7 +81,7 @@ from django.test import TestCase
class SampleTestCase(TestCase):
fixtures = ['fixture1.json', 'fixture2.json']
-
+
def testClassFixtures(self):
"Check that test case has installed 4 fixture objects"
self.assertEqual(Article.objects.count(), 4)
diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py
index 195f67db8f..ce1d824ca8 100644
--- a/tests/modeltests/generic_relations/models.py
+++ b/tests/modeltests/generic_relations/models.py
@@ -24,34 +24,34 @@ class TaggedItem(models.Model):
class Meta:
ordering = ["tag"]
- def __str__(self):
+ def __unicode__(self):
return self.tag
class Animal(models.Model):
- common_name = models.CharField(maxlength=150)
- latin_name = models.CharField(maxlength=150)
+ common_name = models.CharField(max_length=150)
+ latin_name = models.CharField(max_length=150)
tags = generic.GenericRelation(TaggedItem)
- def __str__(self):
+ def __unicode__(self):
return self.common_name
class Vegetable(models.Model):
- name = models.CharField(maxlength=150)
+ name = models.CharField(max_length=150)
is_yucky = models.BooleanField(default=True)
tags = generic.GenericRelation(TaggedItem)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Mineral(models.Model):
- name = models.CharField(maxlength=150)
+ name = models.CharField(max_length=150)
hardness = models.PositiveSmallIntegerField()
# note the lack of an explicit GenericRelation here...
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
@@ -111,17 +111,17 @@ __test__ = {'API_TESTS':"""
# objects are deleted when the source object is deleted.
# Original list of tags:
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
-[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)]
+[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'hairy', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2), (u'yellow', <ContentType: animal>, 1)]
>>> lion.delete()
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
-[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
+[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
# If Generic Relation is not explicitly defined, any related objects
# remain after deletion of the source object.
>>> quartz.delete()
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
-[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
+[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
# If you delete a tag, the objects using the tag are unaffected
# (other than losing a tag)
@@ -130,6 +130,6 @@ __test__ = {'API_TESTS':"""
>>> bacon.tags.all()
[<TaggedItem: salty>]
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
-[('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
+[(u'clearish', <ContentType: mineral>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
"""}
diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py
index 84c6273818..099f1e28a6 100644
--- a/tests/modeltests/get_latest/models.py
+++ b/tests/modeltests/get_latest/models.py
@@ -11,22 +11,22 @@ into the future."
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateField()
expire_date = models.DateField()
class Meta:
get_latest_by = 'pub_date'
- def __str__(self):
+ def __unicode__(self):
return self.headline
class Person(models.Model):
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
birthday = models.DateField()
# Note that this model doesn't have "get_latest_by" set.
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/get_object_or_404/models.py b/tests/modeltests/get_object_or_404/models.py
index 2ad459669f..bd800317d3 100644
--- a/tests/modeltests/get_object_or_404/models.py
+++ b/tests/modeltests/get_object_or_404/models.py
@@ -3,11 +3,11 @@
get_object_or_404 is a shortcut function to be used in view functions for
performing a get() lookup and raising a Http404 exception if a DoesNotExist
-exception was rasied during the get() call.
+exception was raised during the get() call.
get_list_or_404 is a shortcut function to be used in view functions for
performing a filter() lookup and raising a Http404 exception if a DoesNotExist
-exception was rasied during the filter() call.
+exception was raised during the filter() call.
"""
from django.db import models
@@ -15,9 +15,9 @@ from django.http import Http404
from django.shortcuts import get_object_or_404, get_list_or_404
class Author(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
- def __str__(self):
+ def __unicode__(self):
return self.name
class ArticleManager(models.Manager):
@@ -26,11 +26,11 @@ class ArticleManager(models.Manager):
class Article(models.Model):
authors = models.ManyToManyField(Author)
- title = models.CharField(maxlength=50)
+ title = models.CharField(max_length=50)
objects = models.Manager()
by_a_sir = ArticleManager()
- def __str__(self):
+ def __unicode__(self):
return self.title
__test__ = {'API_TESTS':"""
@@ -69,11 +69,28 @@ Http404: No Article matches the given query.
>>> get_object_or_404(Article.by_a_sir, title="Run away!")
<Article: Run away!>
+# QuerySets can be used too.
+>>> get_object_or_404(Article.objects.all(), title__contains="Run")
+<Article: Run away!>
+
+# Just as when using a get() lookup, you will get an error if more than one
+# object is returned.
+>>> get_object_or_404(Author.objects.all())
+Traceback (most recent call last):
+...
+AssertionError: get() returned more than one Author -- it returned ...! Lookup parameters were {}
+
+# Using an EmptyQuerySet raises a Http404 error.
+>>> get_object_or_404(Article.objects.none(), title__contains="Run")
+Traceback (most recent call last):
+...
+Http404: No Article matches the given query.
+
# get_list_or_404 can be used to get lists of objects
>>> get_list_or_404(a.article_set, title__icontains='Run')
[<Article: Run away!>]
-# Http404 is returned if the list is empty
+# Http404 is returned if the list is empty.
>>> get_list_or_404(a.article_set, title__icontains='Shrubbery')
Traceback (most recent call last):
...
@@ -83,4 +100,8 @@ Http404: No Article matches the given query.
>>> get_list_or_404(Article.by_a_sir, title__icontains="Run")
[<Article: Run away!>]
+# QuerySets can be used too.
+>>> get_list_or_404(Article.objects.all(), title__icontains="Run")
+[<Article: Run away!>]
+
"""}
diff --git a/tests/modeltests/get_or_create/models.py b/tests/modeltests/get_or_create/models.py
index f974a82dee..9f025dc582 100644
--- a/tests/modeltests/get_or_create/models.py
+++ b/tests/modeltests/get_or_create/models.py
@@ -8,12 +8,12 @@ parameters. If an object isn't found, it creates one with the given parameters.
from django.db import models
class Person(models.Model):
- first_name = models.CharField(maxlength=100)
- last_name = models.CharField(maxlength=100)
+ first_name = models.CharField(max_length=100)
+ last_name = models.CharField(max_length=100)
birthday = models.DateField()
- def __str__(self):
- return '%s %s' % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u'%s %s' % (self.first_name, self.last_name)
__test__ = {'API_TESTS':"""
# Acting as a divine being, create an Person.
diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py
index 90f2f54632..1afe660dd0 100644
--- a/tests/modeltests/invalid_models/models.py
+++ b/tests/modeltests/invalid_models/models.py
@@ -10,26 +10,26 @@ class FieldErrors(models.Model):
charfield = models.CharField()
decimalfield = models.DecimalField()
filefield = models.FileField()
- prepopulate = models.CharField(maxlength=10, prepopulate_from='bad')
- choices = models.CharField(maxlength=10, choices='bad')
- choices2 = models.CharField(maxlength=10, choices=[(1,2,3),(1,2,3)])
- index = models.CharField(maxlength=10, db_index='bad')
+ prepopulate = models.CharField(max_length=10, prepopulate_from='bad')
+ choices = models.CharField(max_length=10, choices='bad')
+ choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
+ index = models.CharField(max_length=10, db_index='bad')
class Target(models.Model):
- tgt_safe = models.CharField(maxlength=10)
- clash1 = models.CharField(maxlength=10)
- clash2 = models.CharField(maxlength=10)
+ tgt_safe = models.CharField(max_length=10)
+ clash1 = models.CharField(max_length=10)
+ clash2 = models.CharField(max_length=10)
- clash1_set = models.CharField(maxlength=10)
+ clash1_set = models.CharField(max_length=10)
class Clash1(models.Model):
- src_safe = models.CharField(maxlength=10, core=True)
+ src_safe = models.CharField(max_length=10, core=True)
foreign = models.ForeignKey(Target)
m2m = models.ManyToManyField(Target)
class Clash2(models.Model):
- src_safe = models.CharField(maxlength=10, core=True)
+ src_safe = models.CharField(max_length=10, core=True)
foreign_1 = models.ForeignKey(Target, related_name='id')
foreign_2 = models.ForeignKey(Target, related_name='src_safe')
@@ -38,7 +38,7 @@ class Clash2(models.Model):
m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
class Target2(models.Model):
- clash3 = models.CharField(maxlength=10)
+ clash3 = models.CharField(max_length=10)
foreign_tgt = models.ForeignKey(Target)
clashforeign_set = models.ForeignKey(Target)
@@ -46,7 +46,7 @@ class Target2(models.Model):
clashm2m_set = models.ManyToManyField(Target)
class Clash3(models.Model):
- src_safe = models.CharField(maxlength=10, core=True)
+ src_safe = models.CharField(max_length=10, core=True)
foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')
foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')
@@ -61,16 +61,16 @@ class ClashM2M(models.Model):
m2m = models.ManyToManyField(Target2)
class SelfClashForeign(models.Model):
- src_safe = models.CharField(maxlength=10, core=True)
- selfclashforeign = models.CharField(maxlength=10)
+ src_safe = models.CharField(max_length=10, core=True)
+ selfclashforeign = models.CharField(max_length=10)
selfclashforeign_set = models.ForeignKey("SelfClashForeign")
foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id')
foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe')
class ValidM2M(models.Model):
- src_safe = models.CharField(maxlength=10)
- validm2m = models.CharField(maxlength=10)
+ src_safe = models.CharField(max_length=10)
+ validm2m = models.CharField(max_length=10)
# M2M fields are symmetrical by default. Symmetrical M2M fields
# on self don't require a related accessor, so many potential
@@ -84,8 +84,8 @@ class ValidM2M(models.Model):
m2m_4 = models.ManyToManyField('self')
class SelfClashM2M(models.Model):
- src_safe = models.CharField(maxlength=10)
- selfclashm2m = models.CharField(maxlength=10)
+ src_safe = models.CharField(max_length=10)
+ selfclashm2m = models.CharField(max_length=10)
# Non-symmetrical M2M fields _do_ have related accessors, so
# there is potential for clashes.
@@ -100,14 +100,14 @@ class SelfClashM2M(models.Model):
class Model(models.Model):
"But it's valid to call a model Model."
year = models.PositiveIntegerField() #1960
- make = models.CharField(maxlength=10) #Aston Martin
- name = models.CharField(maxlength=10) #DB 4 GT
+ make = models.CharField(max_length=10) #Aston Martin
+ name = models.CharField(max_length=10) #DB 4 GT
class Car(models.Model):
- colour = models.CharField(maxlength=5)
+ colour = models.CharField(max_length=5)
model = models.ForeignKey(Model)
-model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
+model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py
index 9d3e8ca4b4..aa90d1e5ec 100644
--- a/tests/modeltests/lookup/models.py
+++ b/tests/modeltests/lookup/models.py
@@ -8,12 +8,12 @@ from django.db import models
from django.conf import settings
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
class Meta:
ordering = ('-pub_date', 'headline')
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':r"""
@@ -100,7 +100,7 @@ TypeError: in_bulk() got an unexpected keyword argument 'headline__startswith'
# values() returns a list of dictionaries instead of object instances -- and
# you can specify which fields you want to retrieve.
>>> Article.objects.values('headline')
-[{'headline': 'Article 5'}, {'headline': 'Article 6'}, {'headline': 'Article 4'}, {'headline': 'Article 2'}, {'headline': 'Article 3'}, {'headline': 'Article 7'}, {'headline': 'Article 1'}]
+[{'headline': u'Article 5'}, {'headline': u'Article 6'}, {'headline': u'Article 4'}, {'headline': u'Article 2'}, {'headline': u'Article 3'}, {'headline': u'Article 7'}, {'headline': u'Article 1'}]
>>> Article.objects.filter(pub_date__exact=datetime(2005, 7, 27)).values('id')
[{'id': 2}, {'id': 3}, {'id': 7}]
>>> list(Article.objects.values('id', 'headline')) == [{'id': 5, 'headline': 'Article 5'}, {'id': 6, 'headline': 'Article 6'}, {'id': 4, 'headline': 'Article 4'}, {'id': 2, 'headline': 'Article 2'}, {'id': 3, 'headline': 'Article 3'}, {'id': 7, 'headline': 'Article 7'}, {'id': 1, 'headline': 'Article 1'}]
@@ -110,13 +110,13 @@ True
... i = d.items()
... i.sort()
... i
-[('headline', 'Article 5'), ('id', 5)]
-[('headline', 'Article 6'), ('id', 6)]
-[('headline', 'Article 4'), ('id', 4)]
-[('headline', 'Article 2'), ('id', 2)]
-[('headline', 'Article 3'), ('id', 3)]
-[('headline', 'Article 7'), ('id', 7)]
-[('headline', 'Article 1'), ('id', 1)]
+[('headline', u'Article 5'), ('id', 5)]
+[('headline', u'Article 6'), ('id', 6)]
+[('headline', u'Article 4'), ('id', 4)]
+[('headline', u'Article 2'), ('id', 2)]
+[('headline', u'Article 3'), ('id', 3)]
+[('headline', u'Article 7'), ('id', 7)]
+[('headline', u'Article 1'), ('id', 1)]
# You can use values() with iterator() for memory savings, because iterator()
# uses database-level iteration.
@@ -124,17 +124,16 @@ True
... i = d.items()
... i.sort()
... i
-[('headline', 'Article 5'), ('id', 5)]
-[('headline', 'Article 6'), ('id', 6)]
-[('headline', 'Article 4'), ('id', 4)]
-[('headline', 'Article 2'), ('id', 2)]
-[('headline', 'Article 3'), ('id', 3)]
-[('headline', 'Article 7'), ('id', 7)]
-[('headline', 'Article 1'), ('id', 1)]
+[('headline', u'Article 5'), ('id', 5)]
+[('headline', u'Article 6'), ('id', 6)]
+[('headline', u'Article 4'), ('id', 4)]
+[('headline', u'Article 2'), ('id', 2)]
+[('headline', u'Article 3'), ('id', 3)]
+[('headline', u'Article 7'), ('id', 7)]
+[('headline', u'Article 1'), ('id', 1)]
-
-# you can use values() even on extra fields
->>> for d in Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_one'):
+# The values() method works with "extra" fields specified in extra(select).
+>>> for d in Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_one'):
... i = d.items()
... i.sort()
... i
@@ -145,15 +144,24 @@ True
[('id', 3), ('id_plus_one', 4)]
[('id', 7), ('id_plus_one', 8)]
[('id', 1), ('id_plus_one', 2)]
+>>> data = {'id_plus_one': 'id+1', 'id_plus_two': 'id+2', 'id_plus_three': 'id+3',
+... 'id_plus_four': 'id+4', 'id_plus_five': 'id+5', 'id_plus_six': 'id+6',
+... 'id_plus_seven': 'id+7', 'id_plus_eight': 'id+8'}
+>>> result = list(Article.objects.filter(id=1).extra(select=data).values(*data.keys()))[0]
+>>> result = result.items()
+>>> result.sort()
+>>> result
+[('id_plus_eight', 9), ('id_plus_five', 6), ('id_plus_four', 5), ('id_plus_one', 2), ('id_plus_seven', 8), ('id_plus_six', 7), ('id_plus_three', 4), ('id_plus_two', 3)]
-# however, an exception FieldDoesNotExist will still be thrown
-# if you try to access non-existent field (field that is neither on the model nor extra)
->>> Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_two')
+# However, an exception FieldDoesNotExist will be thrown if you specify a
+# non-existent field name in values() (a field that is neither in the model
+# nor in extra(select)).
+>>> Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_two')
Traceback (most recent call last):
...
FieldDoesNotExist: Article has no field named 'id_plus_two'
-# if you don't specify which fields, all are returned
+# If you don't specify field names to values(), all are returned.
>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
True
diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py
index 09affb002f..0ab7a72d57 100644
--- a/tests/modeltests/m2m_and_m2o/models.py
+++ b/tests/modeltests/m2m_and_m2o/models.py
@@ -7,15 +7,15 @@ Make sure to set ``related_name`` if you use relationships to the same table.
from django.db import models
class User(models.Model):
- username = models.CharField(maxlength=20)
+ username = models.CharField(max_length=20)
class Issue(models.Model):
num = models.IntegerField()
cc = models.ManyToManyField(User, blank=True, related_name='test_issue_cc')
client = models.ForeignKey(User, related_name='test_issue_client')
- def __str__(self):
- return str(self.num)
+ def __unicode__(self):
+ return unicode(self.num)
class Meta:
ordering = ('num',)
diff --git a/tests/modeltests/m2m_intermediary/models.py b/tests/modeltests/m2m_intermediary/models.py
index b917db6189..0f93d5a154 100644
--- a/tests/modeltests/m2m_intermediary/models.py
+++ b/tests/modeltests/m2m_intermediary/models.py
@@ -13,26 +13,26 @@ writer").
from django.db import models
class Reporter(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateField()
- def __str__(self):
+ def __unicode__(self):
return self.headline
class Writer(models.Model):
reporter = models.ForeignKey(Reporter)
article = models.ForeignKey(Article)
- position = models.CharField(maxlength=100)
+ position = models.CharField(max_length=100)
- def __str__(self):
- return '%s (%s)' % (self.reporter, self.position)
+ def __unicode__(self):
+ return u'%s (%s)' % (self.reporter, self.position)
__test__ = {'API_TESTS':"""
# Create a few Reporters.
diff --git a/tests/modeltests/m2m_multiple/models.py b/tests/modeltests/m2m_multiple/models.py
index 5a1aa122a9..26a0a2e798 100644
--- a/tests/modeltests/m2m_multiple/models.py
+++ b/tests/modeltests/m2m_multiple/models.py
@@ -10,22 +10,22 @@ Set ``related_name`` to designate what the reverse relationship is called.
from django.db import models
class Category(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Article(models.Model):
- headline = models.CharField(maxlength=50)
+ headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
primary_categories = models.ManyToManyField(Category, related_name='primary_article_set')
secondary_categories = models.ManyToManyField(Category, related_name='secondary_article_set')
class Meta:
ordering = ('pub_date',)
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py
index 15c713a759..98f5ce526a 100644
--- a/tests/modeltests/m2m_recursive/models.py
+++ b/tests/modeltests/m2m_recursive/models.py
@@ -15,11 +15,11 @@ there will be a clash, and tests that symmetry is preserved where appropriate.
from django.db import models
class Person(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
friends = models.ManyToManyField('self')
idols = models.ManyToManyField('self', symmetrical=False, related_name='stalkers')
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/m2o_recursive/models.py b/tests/modeltests/m2o_recursive/models.py
index 0b528faf9e..c38200a25b 100644
--- a/tests/modeltests/m2o_recursive/models.py
+++ b/tests/modeltests/m2o_recursive/models.py
@@ -13,10 +13,10 @@ Set ``related_name`` to designate what the reverse relationship is called.
from django.db import models
class Category(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
parent = models.ForeignKey('self', null=True, related_name='child_set')
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/m2o_recursive2/models.py b/tests/modeltests/m2o_recursive2/models.py
index 5b7c5447ad..47af18ba0e 100644
--- a/tests/modeltests/m2o_recursive2/models.py
+++ b/tests/modeltests/m2o_recursive2/models.py
@@ -10,11 +10,11 @@ Set ``related_name`` to designate what the reverse relationship is called.
from django.db import models
class Person(models.Model):
- full_name = models.CharField(maxlength=20)
+ full_name = models.CharField(max_length=20)
mother = models.ForeignKey('self', null=True, related_name='mothers_child_set')
father = models.ForeignKey('self', null=True, related_name='fathers_child_set')
- def __str__(self):
+ def __unicode__(self):
return self.full_name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py
index 1a44cfe7f4..2ee81f62b3 100644
--- a/tests/modeltests/manipulators/models.py
+++ b/tests/modeltests/manipulators/models.py
@@ -7,18 +7,18 @@ Each model gets an AddManipulator and ChangeManipulator by default.
from django.db import models
class Musician(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
class Album(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
musician = models.ForeignKey(Musician)
release_date = models.DateField(blank=True, null=True)
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
@@ -41,24 +41,24 @@ True
# Attempt to add a Musician without a first_name.
>>> man.get_validation_errors(MultiValueDict({'last_name': ['Blakey']}))
-{'first_name': ['This field is required.']}
+{'first_name': [u'This field is required.']}
# Attempt to add a Musician without a first_name and last_name.
>>> man.get_validation_errors(MultiValueDict({}))
-{'first_name': ['This field is required.'], 'last_name': ['This field is required.']}
+{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.']}
# Attempt to create an Album without a name or musician.
>>> man = Album.AddManipulator()
>>> man.get_validation_errors(MultiValueDict({}))
-{'musician': ['This field is required.'], 'name': ['This field is required.']}
+{'musician': [u'This field is required.'], 'name': [u'This field is required.']}
# Attempt to create an Album with an invalid musician.
>>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['foo']}))
-{'musician': ["Select a valid choice; 'foo' is not in ['', '1']."]}
+{'musician': [u"Select a valid choice; 'foo' is not in [u'', u'1']."]}
# Attempt to create an Album with an invalid release_date.
>>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['1'], 'release_date': 'today'}))
-{'release_date': ['Enter a valid date in YYYY-MM-DD format.']}
+{'release_date': [u'Enter a valid date in YYYY-MM-DD format.']}
# Create an Album without a release_date (because it's optional).
>>> data = MultiValueDict({'name': ['Ella and Basie'], 'musician': ['1']})
diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py
index 5e46ad428d..198c95c4d5 100644
--- a/tests/modeltests/many_to_many/models.py
+++ b/tests/modeltests/many_to_many/models.py
@@ -10,19 +10,19 @@ and a publication has multiple articles.
from django.db import models
class Publication(models.Model):
- title = models.CharField(maxlength=30)
+ title = models.CharField(max_length=30)
- def __str__(self):
+ def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
- def __str__(self):
+ def __unicode__(self):
return self.headline
class Meta:
diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py
index 02f7bf1066..d5d07a1e21 100644
--- a/tests/modeltests/many_to_one/models.py
+++ b/tests/modeltests/many_to_one/models.py
@@ -7,19 +7,19 @@ To define a many-to-one relationship, use ``ForeignKey()`` .
from django.db import models
class Reporter(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
email = models.EmailField()
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
- def __str__(self):
+ def __unicode__(self):
return self.headline
class Meta:
@@ -47,7 +47,7 @@ __test__ = {'API_TESTS':"""
# Article objects have access to their related Reporter objects.
>>> r = a.reporter
>>> r.first_name, r.last_name
-('John', 'Smith')
+(u'John', u'Smith')
# Create an Article via the Reporter object.
>>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29))
@@ -154,8 +154,13 @@ False
>>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_article__reporter.last_name='Smith'"])
[<Article: John's second story>, <Article: This is a test>]
+# And should work fine with the unicode that comes out of
+# newforms.Form.cleaned_data
+>>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_article__reporter.last_name='%s'" % u'Smith'])
+[<Article: John's second story>, <Article: This is a test>]
+
# Find all Articles for the Reporter whose ID is 1.
-# Use direct ID check, pk check, and object comparison
+# Use direct ID check, pk check, and object comparison
>>> Article.objects.filter(reporter__id__exact=1)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__pk=1)
diff --git a/tests/modeltests/many_to_one_null/models.py b/tests/modeltests/many_to_one_null/models.py
index fb0f6ac3b7..60c5888371 100644
--- a/tests/modeltests/many_to_one_null/models.py
+++ b/tests/modeltests/many_to_one_null/models.py
@@ -8,19 +8,19 @@ To define a many-to-one relationship that can have a null foreign key, use
from django.db import models
class Reporter(models.Model):
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
reporter = models.ForeignKey(Reporter, null=True)
class Meta:
ordering = ('headline',)
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 6ffd4d1bce..d27f0b0e54 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -31,20 +31,20 @@ ARTICLE_STATUS = (
)
class Category(models.Model):
- name = models.CharField(maxlength=20)
- url = models.CharField('The URL', maxlength=40)
+ name = models.CharField(max_length=20)
+ url = models.CharField('The URL', max_length=40)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Writer(models.Model):
- name = models.CharField(maxlength=50, help_text='Use both first and last names.')
+ name = models.CharField(max_length=50, help_text='Use both first and last names.')
- def __str__(self):
+ def __unicode__(self):
return self.name
class Article(models.Model):
- headline = models.CharField(maxlength=50)
+ headline = models.CharField(max_length=50)
pub_date = models.DateField()
created = models.DateField(editable=False)
writer = models.ForeignKey(Writer)
@@ -58,14 +58,14 @@ class Article(models.Model):
self.created = datetime.date.today()
return super(Article, self).save()
- def __str__(self):
+ def __unicode__(self):
return self.headline
class PhoneNumber(models.Model):
phone = models.PhoneNumberField()
- description = models.CharField(maxlength=20)
+ description = models.CharField(max_length=20)
- def __str__(self):
+ def __unicode__(self):
return self.phone
__test__ = {'API_TESTS': """
@@ -244,10 +244,10 @@ True
1
>>> test_art = Article.objects.get(id=1)
>>> test_art.headline
-'Test headline'
+u'Test headline'
-You can create a form over a subset of the available fields
-by specifying a 'fields' argument to form_for_instance.
+You can create a form over a subset of the available fields
+by specifying a 'fields' argument to form_for_instance.
>>> PartialArticleForm = form_for_instance(art, fields=('headline','pub_date'))
>>> f = PartialArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04'}, auto_id=False)
>>> print f.as_ul()
@@ -260,7 +260,7 @@ True
1
>>> new_art = Article.objects.get(id=1)
>>> new_art.headline
-'New headline'
+u'New headline'
Add some categories and test the many-to-many form output.
>>> new_art.categories.all()
@@ -332,6 +332,28 @@ Create a new article, with no categories, via the form.
>>> new_art.categories.all()
[]
+Create a new article, with categories, via the form, but use commit=False.
+The m2m data won't be saved until save_m2m() is invoked on the form.
+>>> ArticleForm = form_for_model(Article)
+>>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01',
+... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
+>>> new_art = f.save(commit=False)
+
+# Manually save the instance
+>>> new_art.save()
+>>> new_art.id
+4
+
+# The instance doesn't have m2m data yet
+>>> new_art = Article.objects.get(id=4)
+>>> new_art.categories.all()
+[]
+
+# Save the m2m data on the form
+>>> f.save_m2m()
+>>> new_art.categories.all()
+[<Category: Entertainment>, <Category: It's a test>]
+
Here, we define a custom Form. Because it happens to have the same fields as
the Category model, we can use save_instance() to apply its changes to an
existing Category instance.
diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py
index babef73e0a..ca00e96418 100644
--- a/tests/modeltests/model_inheritance/models.py
+++ b/tests/modeltests/model_inheritance/models.py
@@ -7,24 +7,24 @@ Model inheritance isn't yet supported.
from django.db import models
class Place(models.Model):
- name = models.CharField(maxlength=50)
- address = models.CharField(maxlength=80)
+ name = models.CharField(max_length=50)
+ address = models.CharField(max_length=80)
- def __str__(self):
- return "%s the place" % self.name
+ def __unicode__(self):
+ return u"%s the place" % self.name
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __str__(self):
- return "%s the restaurant" % self.name
+ def __unicode__(self):
+ return u"%s the restaurant" % self.name
class ItalianRestaurant(Restaurant):
serves_gnocchi = models.BooleanField()
- def __str__(self):
- return "%s the italian restaurant" % self.name
+ def __unicode__(self):
+ return u"%s the italian restaurant" % self.name
__test__ = {'API_TESTS':"""
# Make sure Restaurant has the right fields in the right order.
diff --git a/tests/modeltests/mutually_referential/models.py b/tests/modeltests/mutually_referential/models.py
index 5a3897d21a..7cf7bf8bb2 100644
--- a/tests/modeltests/mutually_referential/models.py
+++ b/tests/modeltests/mutually_referential/models.py
@@ -7,11 +7,11 @@ To define a many-to-one relationship, use ``ForeignKey()`` .
from django.db.models import *
class Parent(Model):
- name = CharField(maxlength=100, core=True)
+ name = CharField(max_length=100, core=True)
bestchild = ForeignKey("Child", null=True, related_name="favoured_by")
class Child(Model):
- name = CharField(maxlength=100)
+ name = CharField(max_length=100)
parent = ForeignKey(Parent)
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/one_to_one/models.py b/tests/modeltests/one_to_one/models.py
index 7488204ff1..2f3f22e628 100644
--- a/tests/modeltests/one_to_one/models.py
+++ b/tests/modeltests/one_to_one/models.py
@@ -9,34 +9,34 @@ In this example, a ``Place`` optionally can be a ``Restaurant``.
from django.db import models
class Place(models.Model):
- name = models.CharField(maxlength=50)
- address = models.CharField(maxlength=80)
+ name = models.CharField(max_length=50)
+ address = models.CharField(max_length=80)
- def __str__(self):
- return "%s the place" % self.name
+ def __unicode__(self):
+ return u"%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __str__(self):
- return "%s the restaurant" % self.place.name
+ def __unicode__(self):
+ return u"%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
- def __str__(self):
- return "%s the waiter at %s" % (self.name, self.restaurant)
+ def __unicode__(self):
+ return u"%s the waiter at %s" % (self.name, self.restaurant)
class ManualPrimaryKey(models.Model):
- primary_key = models.CharField(maxlength=10, primary_key=True)
- name = models.CharField(maxlength = 50)
+ primary_key = models.CharField(max_length=10, primary_key=True)
+ name = models.CharField(max_length = 50)
class RelatedModel(models.Model):
link = models.OneToOneField(ManualPrimaryKey)
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length = 50)
__test__ = {'API_TESTS':"""
# Create a couple of Places.
diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py
index 9f926a7373..ee2cfd2b95 100644
--- a/tests/modeltests/or_lookups/models.py
+++ b/tests/modeltests/or_lookups/models.py
@@ -14,13 +14,13 @@ a get_sql method).
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=50)
+ headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
class Meta:
ordering = ('pub_date',)
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
@@ -100,7 +100,7 @@ __test__ = {'API_TESTS':"""
3
>>> list(Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')).values())
-[{'headline': 'Hello and goodbye', 'pub_date': datetime.datetime(2005, 11, 29, 0, 0), 'id': 3}]
+[{'headline': u'Hello and goodbye', 'pub_date': datetime.datetime(2005, 11, 29, 0, 0), 'id': 3}]
>>> Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([1,2])
{1: <Article: Hello>}
diff --git a/tests/modeltests/ordering/models.py b/tests/modeltests/ordering/models.py
index 110ae3d7fc..3e651d4ee7 100644
--- a/tests/modeltests/ordering/models.py
+++ b/tests/modeltests/ordering/models.py
@@ -16,12 +16,12 @@ undefined -- not random, just undefined.
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
class Meta:
ordering = ('-pub_date', 'headline')
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py
index 94deb885f5..a7af2a7089 100644
--- a/tests/modeltests/pagination/models.py
+++ b/tests/modeltests/pagination/models.py
@@ -9,10 +9,10 @@ objects into easily readable pages.
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100, default='Default headline')
+ headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __str__(self):
+ def __unicode__(self):
return self.headline
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/properties/models.py b/tests/modeltests/properties/models.py
index 4ba6b1a808..5326e4ec5f 100644
--- a/tests/modeltests/properties/models.py
+++ b/tests/modeltests/properties/models.py
@@ -7,8 +7,8 @@ Use properties on models just like on any other Python object.
from django.db import models
class Person(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
def _get_full_name(self):
return "%s %s" % (self.first_name, self.last_name)
diff --git a/tests/modeltests/reserved_names/models.py b/tests/modeltests/reserved_names/models.py
index affe3f649d..a11b8d9f88 100644
--- a/tests/modeltests/reserved_names/models.py
+++ b/tests/modeltests/reserved_names/models.py
@@ -10,18 +10,18 @@ reserved-name usage.
from django.db import models
class Thing(models.Model):
- when = models.CharField(maxlength=1, primary_key=True)
- join = models.CharField(maxlength=1)
- like = models.CharField(maxlength=1)
- drop = models.CharField(maxlength=1)
- alter = models.CharField(maxlength=1)
- having = models.CharField(maxlength=1)
- where = models.DateField(maxlength=1)
- has_hyphen = models.CharField(maxlength=1, db_column='has-hyphen')
+ when = models.CharField(max_length=1, primary_key=True)
+ join = models.CharField(max_length=1)
+ like = models.CharField(max_length=1)
+ drop = models.CharField(max_length=1)
+ alter = models.CharField(max_length=1)
+ having = models.CharField(max_length=1)
+ where = models.DateField(max_length=1)
+ has_hyphen = models.CharField(max_length=1, db_column='has-hyphen')
class Meta:
db_table = 'select'
- def __str__(self):
+ def __unicode__(self):
return self.when
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/reverse_lookup/models.py b/tests/modeltests/reverse_lookup/models.py
index 4d6591551a..80408ad761 100644
--- a/tests/modeltests/reverse_lookup/models.py
+++ b/tests/modeltests/reverse_lookup/models.py
@@ -7,24 +7,24 @@ This demonstrates the reverse lookup features of the database API.
from django.db import models
class User(models.Model):
- name = models.CharField(maxlength=200)
+ name = models.CharField(max_length=200)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Poll(models.Model):
- question = models.CharField(maxlength=200)
+ question = models.CharField(max_length=200)
creator = models.ForeignKey(User)
- def __str__(self):
+ def __unicode__(self):
return self.question
class Choice(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
poll = models.ForeignKey(Poll, related_name="poll_choice")
related_poll = models.ForeignKey(Poll, related_name="related_choice")
- def __str(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
diff --git a/tests/modeltests/save_delete_hooks/models.py b/tests/modeltests/save_delete_hooks/models.py
index 6e24c308ba..c1b1d8f08b 100644
--- a/tests/modeltests/save_delete_hooks/models.py
+++ b/tests/modeltests/save_delete_hooks/models.py
@@ -8,11 +8,11 @@ the methods.
from django.db import models
class Person(models.Model):
- first_name = models.CharField(maxlength=20)
- last_name = models.CharField(maxlength=20)
+ first_name = models.CharField(max_length=20)
+ last_name = models.CharField(max_length=20)
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
def save(self):
print "Before save"
diff --git a/tests/modeltests/select_related/models.py b/tests/modeltests/select_related/models.py
index cd34bd1d84..43efab3a7d 100644
--- a/tests/modeltests/select_related/models.py
+++ b/tests/modeltests/select_related/models.py
@@ -12,50 +12,50 @@ from django.db import models
# Who remembers high school biology?
class Domain(models.Model):
- name = models.CharField(maxlength=50)
- def __str__(self):
+ name = models.CharField(max_length=50)
+ def __unicode__(self):
return self.name
class Kingdom(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
domain = models.ForeignKey(Domain)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Phylum(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
kingdom = models.ForeignKey(Kingdom)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Klass(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
phylum = models.ForeignKey(Phylum)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Order(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
klass = models.ForeignKey(Klass)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Family(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
order = models.ForeignKey(Order)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Genus(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
family = models.ForeignKey(Family)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Species(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
genus = models.ForeignKey(Genus)
- def __str__(self):
+ def __unicode__(self):
return self.name
def create_tree(stringtree):
diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py
index 8d44d5eae7..2ee6cfce67 100644
--- a/tests/modeltests/serializers/models.py
+++ b/tests/modeltests/serializers/models.py
@@ -8,41 +8,41 @@ to and from "flat" data (i.e. strings).
from django.db import models
class Category(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Author(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __str__(self):
+ def __unicode__(self):
return self.name
class Article(models.Model):
author = models.ForeignKey(Author)
- headline = models.CharField(maxlength=50)
+ headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
categories = models.ManyToManyField(Category)
class Meta:
ordering = ('pub_date',)
- def __str__(self):
+ def __unicode__(self):
return self.headline
class AuthorProfile(models.Model):
author = models.OneToOneField(Author)
date_of_birth = models.DateField()
- def __str__(self):
- return "Profile of %s" % self.author
+ def __unicode__(self):
+ return u"Profile of %s" % self.author
__test__ = {'API_TESTS':"""
# Create some data:
diff --git a/tests/modeltests/str/models.py b/tests/modeltests/str/models.py
index 81230d538c..644c6025ab 100644
--- a/tests/modeltests/str/models.py
+++ b/tests/modeltests/str/models.py
@@ -1,23 +1,38 @@
+# -*- coding: utf-8 -*-
"""
-2. Adding __str__() to models
+2. Adding __str__() or __unicode__() to models
-Although it's not a strict requirement, each model should have a ``__str__()``
-method to return a "human-readable" representation of the object. Do this not
-only for your own sanity when dealing with the interactive prompt, but also
-because objects' representations are used throughout Django's
-automatically-generated admin.
+Although it's not a strict requirement, each model should have a
+``_str__()`` or ``__unicode__()`` method to return a "human-readable"
+representation of the object. Do this not only for your own sanity when dealing
+with the interactive prompt, but also because objects' representations are used
+throughout Django's automatically-generated admin.
+
+Normally, you should write ``__unicode__()`` method, since this will work for
+all field types (and Django will automatically provide an appropriate
+``__str__()`` method). However, you can write a ``__str__()`` method directly,
+if you prefer. You must be careful to encode the results correctly, though.
"""
from django.db import models
class Article(models.Model):
- headline = models.CharField(maxlength=100)
+ headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
def __str__(self):
+ # Caution: this is only safe if you are certain that headline will be
+ # in ASCII.
return self.headline
-__test__ = {'API_TESTS':"""
+class InternationalArticle(models.Model):
+ headline = models.CharField(max_length=100)
+ pub_date = models.DateTimeField()
+
+ def __unicode__(self):
+ return self.headline
+
+__test__ = {'API_TESTS':ur"""
# Create an Article.
>>> from datetime import datetime
>>> a = Article(headline='Area man programs in Python', pub_date=datetime(2005, 7, 28))
@@ -28,4 +43,10 @@ __test__ = {'API_TESTS':"""
>>> a
<Article: Area man programs in Python>
+
+>>> a1 = InternationalArticle(headline=u'Girl wins €12.500 in lottery', pub_date=datetime(2005, 7, 28))
+
+# The default str() output will be the UTF-8 encoded output of __unicode__().
+>>> str(a1)
+'Girl wins \xe2\x82\xac12.500 in lottery'
"""}
diff --git a/tests/modeltests/test_client/fixtures/testdata.json b/tests/modeltests/test_client/fixtures/testdata.json
index 5c9e415240..e9d3ebe9a8 100644
--- a/tests/modeltests/test_client/fixtures/testdata.json
+++ b/tests/modeltests/test_client/fixtures/testdata.json
@@ -16,5 +16,23 @@
"email": "testclient@example.com",
"date_joined": "2006-12-17 07:03:31"
}
+ },
+ {
+ "pk": "2",
+ "model": "auth.user",
+ "fields": {
+ "username": "inactive",
+ "first_name": "Inactive",
+ "last_name": "User",
+ "is_active": false,
+ "is_superuser": false,
+ "is_staff": false,
+ "last_login": "2006-12-17 07:03:31",
+ "groups": [],
+ "user_permissions": [],
+ "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",
+ "email": "testclient@example.com",
+ "date_joined": "2006-12-17 07:03:31"
+ }
}
] \ No newline at end of file
diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py
index 5ebf29678c..e1f3987847 100644
--- a/tests/modeltests/test_client/models.py
+++ b/tests/modeltests/test_client/models.py
@@ -1,3 +1,4 @@
+# coding: utf-8
"""
38. Testing using the Test Client
@@ -27,11 +28,14 @@ class ClientTest(TestCase):
def test_get_view(self):
"GET a view"
- response = self.client.get('/test_client/get_view/')
+ # The data is ignored, but let's check it doesn't crash the system
+ # anyway.
+ data = {'var': u'\xf2'}
+ response = self.client.get('/test_client/get_view/', data)
# Check some response details
self.assertContains(response, 'This is a test')
- self.assertEqual(response.context['var'], 42)
+ self.assertEqual(response.context['var'], u'\xf2')
self.assertEqual(response.template.name, 'GET Template')
def test_get_post_view(self):
@@ -118,6 +122,18 @@ class ClientTest(TestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "Valid POST Template")
+ def test_valid_form_with_hints(self):
+ "GET a form, providing hints in the GET data"
+ hints = {
+ 'text': 'Hello World',
+ 'multi': ('b','c','e')
+ }
+ response = self.client.get('/test_client/form_view/', data=hints)
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, "Form GET Template")
+ # Check that the multi-value data has been rolled out ok
+ self.assertContains(response, 'Select a valid choice.', 0)
+
def test_incomplete_data_form(self):
"POST incomplete data to a form"
post_data = {
@@ -224,6 +240,29 @@ class ClientTest(TestCase):
login = self.client.login(username='otheruser', password='nopassword')
self.failIf(login)
+ def test_view_with_inactive_login(self):
+ "Request a page that is protected with @login, but use an inactive login"
+
+ login = self.client.login(username='inactive', password='password')
+ self.failIf(login)
+
+ def test_logout(self):
+ "Request a logout after logging in"
+ # Log in
+ self.client.login(username='testclient', password='password')
+
+ # Request a page that requires a login
+ response = self.client.get('/test_client/login_protected_view/')
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.context['user'].username, 'testclient')
+
+ # Log out
+ self.client.logout()
+
+ # Request a page that requires a login
+ response = self.client.get('/test_client/login_protected_view/')
+ self.assertRedirects(response, '/accounts/login/')
+
def test_session_modifying_view(self):
"Request a page that modifies the session"
# Session value isn't set initially
@@ -281,4 +320,4 @@ class ClientTest(TestCase):
self.assertEqual(mail.outbox[1].from_email, 'from@example.com')
self.assertEqual(mail.outbox[1].to[0], 'second@example.com')
self.assertEqual(mail.outbox[1].to[1], 'third@example.com')
- \ No newline at end of file
+
diff --git a/tests/modeltests/test_client/tests.py b/tests/modeltests/test_client/tests.py
new file mode 100644
index 0000000000..09f292e037
--- /dev/null
+++ b/tests/modeltests/test_client/tests.py
@@ -0,0 +1,20 @@
+# Validate that you can override the default test suite
+
+import unittest
+
+def suite():
+ """
+ Define a suite that deliberately ignores a test defined in
+ this module.
+ """
+
+ testSuite = unittest.TestSuite()
+ testSuite.addTest(SampleTests('testGoodStuff'))
+ return testSuite
+
+class SampleTests(unittest.TestCase):
+ def testGoodStuff(self):
+ pass
+
+ def testBadStuff(self):
+ self.fail("This test shouldn't run")
diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py
index 9bdf213b35..81b4a2f283 100644
--- a/tests/modeltests/test_client/views.py
+++ b/tests/modeltests/test_client/views.py
@@ -10,7 +10,7 @@ from django.shortcuts import render_to_response
def get_view(request):
"A simple view that expects a GET request, and returns a rendered template"
t = Template('This is a test. {{ var }} is the value.', name='GET Template')
- c = Context({'var': 42})
+ c = Context({'var': request.GET.get('var', 42)})
return HttpResponse(t.render(c))
@@ -84,7 +84,7 @@ def form_view(request):
t = Template('Invalid POST data. {{ form.errors }}', name='Invalid POST Template')
c = Context({'form': form})
else:
- form = TestForm()
+ form = TestForm(request.GET)
t = Template('Viewing base form. {{ form }}.', name='Form GET Template')
c = Context({'form': form})
@@ -107,7 +107,6 @@ def form_view_with_template(request):
'message': message
}
)
-
def login_protected_view(request):
"A simple view that is login protected."
diff --git a/tests/modeltests/transactions/models.py b/tests/modeltests/transactions/models.py
index e1fad8063e..06d21bbdd4 100644
--- a/tests/modeltests/transactions/models.py
+++ b/tests/modeltests/transactions/models.py
@@ -10,12 +10,12 @@ manually.
from django.db import models
class Reporter(models.Model):
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
email = models.EmailField()
- def __str__(self):
- return "%s %s" % (self.first_name, self.last_name)
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
__test__ = {'API_TESTS':"""
>>> from django.db import connection, transaction
@@ -96,4 +96,4 @@ Exception: I meant to do that
Traceback (most recent call last):
...
TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
-""" \ No newline at end of file
+"""
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py
index b31f981aac..aacd041678 100644
--- a/tests/modeltests/validation/models.py
+++ b/tests/modeltests/validation/models.py
@@ -12,12 +12,12 @@ from django.db import models
class Person(models.Model):
is_child = models.BooleanField()
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
birthdate = models.DateField()
favorite_moment = models.DateTimeField()
email = models.EmailField()
- def __str__(self):
+ def __unicode__(self):
return self.name
__test__ = {'API_TESTS':"""
@@ -42,7 +42,7 @@ __test__ = {'API_TESTS':"""
>>> p = Person(**dict(valid_params, id='foo'))
>>> p.validate()
-{'id': ['This value must be an integer.']}
+{'id': [u'This value must be an integer.']}
>>> p = Person(**dict(valid_params, id=None))
>>> p.validate()
@@ -76,7 +76,7 @@ False
>>> p = Person(**dict(valid_params, is_child='foo'))
>>> p.validate()
-{'is_child': ['This value must be either True or False.']}
+{'is_child': [u'This value must be either True or False.']}
>>> p = Person(**dict(valid_params, name=u'Jose'))
>>> p.validate()
@@ -88,7 +88,7 @@ u'Jose'
>>> p.validate()
{}
>>> p.name
-'227'
+u'227'
>>> p = Person(**dict(valid_params, birthdate=datetime.date(2000, 5, 3)))
>>> p.validate()
@@ -116,7 +116,7 @@ datetime.date(2000, 5, 3)
>>> p = Person(**dict(valid_params, birthdate='foo'))
>>> p.validate()
-{'birthdate': ['Enter a valid date in YYYY-MM-DD format.']}
+{'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']}
>>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23)))
>>> p.validate()
@@ -144,10 +144,10 @@ u'john@example.com'
>>> p = Person(**dict(valid_params, email=22))
>>> p.validate()
-{'email': ['Enter a valid e-mail address.']}
+{'email': [u'Enter a valid e-mail address.']}
# Make sure that Date and DateTime return validation errors and don't raise Python errors.
>>> Person(name='John Doe', is_child=True, email='abc@def.com').validate()
-{'favorite_moment': ['This field is required.'], 'birthdate': ['This field is required.']}
+{'favorite_moment': [u'This field is required.'], 'birthdate': [u'This field is required.']}
"""}
diff --git a/tests/regressiontests/bug639/models.py b/tests/regressiontests/bug639/models.py
index 7cfdfc82ef..fc241aba8c 100644
--- a/tests/regressiontests/bug639/models.py
+++ b/tests/regressiontests/bug639/models.py
@@ -2,7 +2,7 @@ import tempfile
from django.db import models
class Photo(models.Model):
- title = models.CharField(maxlength=30)
+ title = models.CharField(max_length=30)
image = models.FileField(upload_to=tempfile.gettempdir())
# Support code for the tests; this keeps track of how many times save() gets
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index 9dc7161c03..752083bd2f 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -1,10 +1,12 @@
+# -*- coding: utf-8 -*-
+
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
from django.core.cache import cache
import time, unittest
-# functions/classes for complex data type tests
+# functions/classes for complex data type tests
def f():
return 42
class C:
@@ -19,8 +21,8 @@ class Cache(unittest.TestCase):
def test_non_existent(self):
# get with non-existent keys
- self.assertEqual(cache.get("does not exist"), None)
- self.assertEqual(cache.get("does not exist", "bang!"), "bang!")
+ self.assertEqual(cache.get("does_not_exist"), None)
+ self.assertEqual(cache.get("does_not_exist", "bang!"), "bang!")
def test_get_many(self):
# get_many
@@ -42,17 +44,16 @@ class Cache(unittest.TestCase):
def test_has_key(self):
# has_key
- cache.set("hello", "goodbye")
- self.assertEqual(cache.has_key("hello"), True)
- self.assertEqual(cache.has_key("goodbye"), False)
+ cache.set("hello1", "goodbye1")
+ self.assertEqual(cache.has_key("hello1"), True)
+ self.assertEqual(cache.has_key("goodbye1"), False)
- def test_in(self):
- cache.set("hello", "goodbye")
- self.assertEqual("hello" in cache, True)
- self.assertEqual("goodbye" in cache, False)
+ def test_in(self):
+ cache.set("hello2", "goodbye2")
+ self.assertEqual("hello2" in cache, True)
+ self.assertEqual("goodbye2" in cache, False)
def test_data_types(self):
- # test data types
stuff = {
'string' : 'this is a string',
'int' : 42,
@@ -62,15 +63,23 @@ class Cache(unittest.TestCase):
'function' : f,
'class' : C,
}
- for (key, value) in stuff.items():
- cache.set(key, value)
- self.assertEqual(cache.get(key), value)
-
+
def test_expiration(self):
# expiration
cache.set('expire', 'very quickly', 1)
time.sleep(2)
self.assertEqual(cache.get("expire"), None)
+ def test_unicode(self):
+ stuff = {
+ u'ascii': u'ascii_value',
+ u'unicode_ascii': u'Iñtërnâtiônàlizætiøn1',
+ u'Iñtërnâtiônàlizætiøn': u'Iñtërnâtiônàlizætiøn2',
+ u'ascii': {u'x' : 1 }
+ }
+ for (key, value) in stuff.items():
+ cache.set(key, value)
+ self.assertEqual(cache.get(key), value)
+
if __name__ == '__main__':
- unittest.main() \ No newline at end of file
+ unittest.main()
diff --git a/tests/regressiontests/datastructures/tests.py b/tests/regressiontests/datastructures/tests.py
index 18eb4fcccd..3920e1ca40 100644
--- a/tests/regressiontests/datastructures/tests.py
+++ b/tests/regressiontests/datastructures/tests.py
@@ -64,4 +64,13 @@ True
['Holovaty']
>>> d['person']['2']['firstname']
['Adrian']
+
+### FileDict ################################################################
+
+>>> d = FileDict({'content': 'once upon a time...'})
+>>> repr(d)
+"{'content': '<omitted>'}"
+>>> d = FileDict({'other-key': 'once upon a time...'})
+>>> repr(d)
+"{'other-key': 'once upon a time...'}"
"""
diff --git a/tests/regressiontests/datatypes/models.py b/tests/regressiontests/datatypes/models.py
index 8c5c8c285d..ff9666bc0c 100644
--- a/tests/regressiontests/datatypes/models.py
+++ b/tests/regressiontests/datatypes/models.py
@@ -7,7 +7,7 @@ from django.db import models
from django.conf import settings
class Donut(models.Model):
- name = models.CharField(maxlength=100)
+ name = models.CharField(max_length=100)
is_frosted = models.BooleanField(default=False)
has_sprinkles = models.NullBooleanField()
baked_date = models.DateField(null=True)
diff --git a/tests/regressiontests/dateformat/tests.py b/tests/regressiontests/dateformat/tests.py
index f9f84145c5..30c9a4e6dd 100644
--- a/tests/regressiontests/dateformat/tests.py
+++ b/tests/regressiontests/dateformat/tests.py
@@ -1,54 +1,54 @@
r"""
>>> format(my_birthday, '')
-''
+u''
>>> format(my_birthday, 'a')
-'p.m.'
+u'p.m.'
>>> format(my_birthday, 'A')
-'PM'
+u'PM'
>>> format(my_birthday, 'd')
-'08'
+u'08'
>>> format(my_birthday, 'j')
-'8'
+u'8'
>>> format(my_birthday, 'l')
-'Sunday'
+u'Sunday'
>>> format(my_birthday, 'L')
-'False'
+u'False'
>>> format(my_birthday, 'm')
-'07'
+u'07'
>>> format(my_birthday, 'M')
-'Jul'
+u'Jul'
>>> format(my_birthday, 'b')
-'jul'
+u'jul'
>>> format(my_birthday, 'n')
-'7'
+u'7'
>>> format(my_birthday, 'N')
-'July'
+u'July'
>>> no_tz or format(my_birthday, 'O') == '+0100'
True
>>> format(my_birthday, 'P')
-'10 p.m.'
+u'10 p.m.'
>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100'
True
>>> format(my_birthday, 's')
-'00'
+u'00'
>>> format(my_birthday, 'S')
-'th'
+u'th'
>>> format(my_birthday, 't')
-'31'
+u'31'
>>> no_tz or format(my_birthday, 'T') == 'CET'
True
>>> no_tz or format(my_birthday, 'U') == '300531600'
True
>>> format(my_birthday, 'w')
-'0'
+u'0'
>>> format(my_birthday, 'W')
-'27'
+u'27'
>>> format(my_birthday, 'y')
-'79'
+u'79'
>>> format(my_birthday, 'Y')
-'1979'
+u'1979'
>>> format(my_birthday, 'z')
-'189'
+u'189'
>>> no_tz or format(my_birthday, 'Z') == '3600'
True
@@ -62,10 +62,10 @@ True
True
>>> format(my_birthday, r'Y z \C\E\T')
-'1979 189 CET'
+u'1979 189 CET'
>>> format(my_birthday, r'jS o\f F')
-'8th of July'
+u'8th of July'
"""
from django.utils import dateformat, translation
diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py
index b35636aba6..a1efae66f6 100644
--- a/tests/regressiontests/defaultfilters/tests.py
+++ b/tests/regressiontests/defaultfilters/tests.py
@@ -2,197 +2,211 @@
r"""
>>> floatformat(7.7)
-'7.7'
+u'7.7'
>>> floatformat(7.0)
-'7'
+u'7'
>>> floatformat(0.7)
-'0.7'
+u'0.7'
>>> floatformat(0.07)
-'0.1'
+u'0.1'
>>> floatformat(0.007)
-'0.0'
+u'0.0'
>>> floatformat(0.0)
-'0'
+u'0'
>>> floatformat(7.7,3)
-'7.700'
+u'7.700'
>>> floatformat(6.000000,3)
-'6.000'
+u'6.000'
>>> floatformat(13.1031,-3)
-'13.103'
+u'13.103'
>>> floatformat(11.1197, -2)
-'11.12'
+u'11.12'
>>> floatformat(11.0000, -2)
-'11'
+u'11'
>>> floatformat(11.000001, -2)
-'11.00'
+u'11.00'
>>> floatformat(8.2798, 3)
-'8.280'
->>> floatformat('foo')
-''
->>> floatformat(13.1031, 'bar')
-'13.1031'
->>> floatformat('foo', 'bar')
-''
+u'8.280'
+>>> floatformat(u'foo')
+u''
+>>> floatformat(13.1031, u'bar')
+u'13.1031'
+>>> floatformat(u'foo', u'bar')
+u''
->>> addslashes('"double quotes" and \'single quotes\'')
-'\\"double quotes\\" and \\\'single quotes\\\''
+>>> addslashes(u'"double quotes" and \'single quotes\'')
+u'\\"double quotes\\" and \\\'single quotes\\\''
->>> addslashes(r'\ : backslashes, too')
-'\\\\ : backslashes, too'
+>>> addslashes(ur'\ : backslashes, too')
+u'\\\\ : backslashes, too'
->>> capfirst('hello world')
-'Hello world'
+>>> capfirst(u'hello world')
+u'Hello world'
->>> fix_ampersands('Jack & Jill & Jeroboam')
-'Jack &amp; Jill &amp; Jeroboam'
+>>> fix_ampersands(u'Jack & Jill & Jeroboam')
+u'Jack &amp; Jill &amp; Jeroboam'
->>> linenumbers('line 1\nline 2')
-'1. line 1\n2. line 2'
+>>> linenumbers(u'line 1\nline 2')
+u'1. line 1\n2. line 2'
->>> linenumbers('\n'.join(['x'] * 10))
-'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
+>>> linenumbers(u'\n'.join([u'x'] * 10))
+u'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
>>> lower('TEST')
-'test'
+u'test'
>>> lower(u'\xcb') # uppercase E umlaut
u'\xeb'
>>> make_list('abc')
-['a', 'b', 'c']
+[u'a', u'b', u'c']
>>> make_list(1234)
-['1', '2', '3', '4']
+[u'1', u'2', u'3', u'4']
>>> slugify(' Jack & Jill like numbers 1,2,3 and 4 and silly characters ?%.$!/')
-'jack-jill-like-numbers-123-and-4-and-silly-characters'
+u'jack-jill-like-numbers-123-and-4-and-silly-characters'
->>> stringformat(1, '03d')
-'001'
+>>> slugify(u"Un \xe9l\xe9phant \xe0 l'or\xe9e du bois")
+u'un-elephant-a-loree-du-bois'
->>> stringformat(1, 'z')
-''
+>>> stringformat(1, u'03d')
+u'001'
+
+>>> stringformat(1, u'z')
+u''
>>> title('a nice title, isn\'t it?')
-"A Nice Title, Isn't It?"
+u"A Nice Title, Isn't It?"
+
+>>> title(u'discoth\xe8que')
+u'Discoth\xe8que'
+>>> truncatewords(u'A sentence with a few words in it', 1)
+u'A ...'
->>> truncatewords('A sentence with a few words in it', 1)
-'A ...'
+>>> truncatewords(u'A sentence with a few words in it', 5)
+u'A sentence with a few ...'
->>> truncatewords('A sentence with a few words in it', 5)
-'A sentence with a few ...'
+>>> truncatewords(u'A sentence with a few words in it', 100)
+u'A sentence with a few words in it'
->>> truncatewords('A sentence with a few words in it', 100)
-'A sentence with a few words in it'
+>>> truncatewords(u'A sentence with a few words in it', 'not a number')
+u'A sentence with a few words in it'
->>> truncatewords('A sentence with a few words in it', 'not a number')
-'A sentence with a few words in it'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 0)
+u''
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 0)
-''
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 2)
+u'<p>one <a href="#">two ...</a></p>'
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 2)
-'<p>one <a href="#">two ...</a></p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 4)
+u'<p>one <a href="#">two - three <br>four ...</a></p>'
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4)
-'<p>one <a href="#">two - three <br>four ...</a></p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 5)
+u'<p>one <a href="#">two - three <br>four</a> five</p>'
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 5)
-'<p>one <a href="#">two - three <br>four</a> five</p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 100)
+u'<p>one <a href="#">two - three <br>four</a> five</p>'
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 100)
-'<p>one <a href="#">two - three <br>four</a> five</p>'
+>>> truncatewords_html(u'\xc5ngstr\xf6m was here', 1)
+u'\xc5ngstr\xf6m ...'
->>> upper('Mixed case input')
-'MIXED CASE INPUT'
+>>> upper(u'Mixed case input')
+u'MIXED CASE INPUT'
>>> upper(u'\xeb') # lowercase e umlaut
u'\xcb'
->>> urlencode('jack & jill')
-'jack%20%26%20jill'
+>>> urlencode(u'fran\xe7ois & jill')
+u'fran%C3%A7ois%20%26%20jill'
>>> urlencode(1)
-'1'
+u'1'
+>>> iriencode(u'S\xf8r-Tr\xf8ndelag')
+u'S%C3%B8r-Tr%C3%B8ndelag'
+>>> iriencode(urlencode(u'fran\xe7ois & jill'))
+u'fran%C3%A7ois%20%26%20jill'
+>>> urlizetrunc(u'http://short.com/', 20)
+u'<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
->>> urlizetrunc('http://short.com/', 20)
-'<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
+>>> urlizetrunc(u'http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
+u'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google....</a>'
>>> urlizetrunc('http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
-'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google...</a>'
+u'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google...</a>'
# Check truncating of URIs which are the exact length
>>> uri = 'http://31characteruri.com/test/'
>>> len(uri)
31
>>> urlizetrunc(uri, 31)
-'<a href="http://31characteruri.com/test/" rel="nofollow">http://31characteruri.com/test/</a>'
+u'<a href="http://31characteruri.com/test/" rel="nofollow">http://31characteruri.com/test/</a>'
>>> urlizetrunc(uri, 30)
-'<a href="http://31characteruri.com/test/" rel="nofollow">http://31characteruri.com/t...</a>'
+u'<a href="http://31characteruri.com/test/" rel="nofollow">http://31characteruri.com/t...</a>'
>>> urlizetrunc(uri, 2)
-'<a href="http://31characteruri.com/test/" rel="nofollow">...</a>'
+u'<a href="http://31characteruri.com/test/" rel="nofollow">...</a>'
>>> wordcount('')
0
->>> wordcount('oneword')
+>>> wordcount(u'oneword')
1
->>> wordcount('lots of words')
+>>> wordcount(u'lots of words')
3
->>> wordwrap('this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
-"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
+>>> wordwrap(u'this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
+u"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
->>> wordwrap('this is a short paragraph of text.\n But this line should be indented',14)
-'this is a\nshort\nparagraph of\ntext.\n But this\nline should be\nindented'
+>>> wordwrap(u'this is a short paragraph of text.\n But this line should be indented',14)
+u'this is a\nshort\nparagraph of\ntext.\n But this\nline should be\nindented'
->>> wordwrap('this is a short paragraph of text.\n But this line should be indented',15)
-'this is a short\nparagraph of\ntext.\n But this line\nshould be\nindented'
+>>> wordwrap(u'this is a short paragraph of text.\n But this line should be indented',15)
+u'this is a short\nparagraph of\ntext.\n But this line\nshould be\nindented'
->>> ljust('test', 10)
-'test '
+>>> ljust(u'test', 10)
+u'test '
->>> ljust('test', 3)
-'test'
+>>> ljust(u'test', 3)
+u'test'
->>> rjust('test', 10)
-' test'
+>>> rjust(u'test', 10)
+u' test'
->>> rjust('test', 3)
-'test'
+>>> rjust(u'test', 3)
+u'test'
->>> center('test', 6)
-' test '
+>>> center(u'test', 6)
+u' test '
->>> cut('a string to be mangled', 'a')
-' string to be mngled'
+>>> cut(u'a string to be mangled', 'a')
+u' string to be mngled'
->>> cut('a string to be mangled', 'ng')
-'a stri to be maled'
+>>> cut(u'a string to be mangled', 'ng')
+u'a stri to be maled'
->>> cut('a string to be mangled', 'strings')
-'a string to be mangled'
+>>> cut(u'a string to be mangled', 'strings')
+u'a string to be mangled'
->>> escape('<some html & special characters > here')
-'&lt;some html &amp; special characters &gt; here'
+>>> escape(u'<some html & special characters > here')
+u'&lt;some html &amp; special characters &gt; here'
>>> escape(u'<some html & special characters > here ĐÅ€£')
u'&lt;some html &amp; special characters &gt; here \xc4\x90\xc3\x85\xe2\x82\xac\xc2\xa3'
->>> linebreaks('line 1')
-'<p>line 1</p>'
+>>> linebreaks(u'line 1')
+u'<p>line 1</p>'
->>> linebreaks('line 1\nline 2')
-'<p>line 1<br />line 2</p>'
+>>> linebreaks(u'line 1\nline 2')
+u'<p>line 1<br />line 2</p>'
->>> removetags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
-'some <b>html</b> with alert("You smell") disallowed tags'
+>>> removetags(u'some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
+u'some <b>html</b> with alert("You smell") disallowed tags'
->>> striptags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
-'some html with alert("You smell") disallowed tags'
+>>> striptags(u'some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
+u'some html with alert("You smell") disallowed tags'
>>> dictsort([{'age': 23, 'name': 'Barbara-Ann'},
... {'age': 63, 'name': 'Ra Ra Rasputin'},
@@ -207,16 +221,16 @@ u'&lt;some html &amp; special characters &gt; here \xc4\x90\xc3\x85\xe2\x82\xac\
>>> first([0,1,2])
0
->>> first('')
-''
+>>> first(u'')
+u''
->>> first('test')
-'t'
+>>> first(u'test')
+u't'
->>> join([0,1,2], 'glue')
-'0glue1glue2'
+>>> join([0,1,2], u'glue')
+u'0glue1glue2'
->>> length('1234')
+>>> length(u'1234')
4
>>> length([1,2,3,4])
@@ -231,37 +245,37 @@ False
>>> length_is('a', 1)
True
->>> length_is('a', 10)
+>>> length_is(u'a', 10)
False
->>> slice_('abcdefg', '0')
-''
+>>> slice_(u'abcdefg', u'0')
+u''
->>> slice_('abcdefg', '1')
-'a'
+>>> slice_(u'abcdefg', u'1')
+u'a'
->>> slice_('abcdefg', '-1')
-'abcdef'
+>>> slice_(u'abcdefg', u'-1')
+u'abcdef'
->>> slice_('abcdefg', '1:2')
-'b'
+>>> slice_(u'abcdefg', u'1:2')
+u'b'
->>> slice_('abcdefg', '1:3')
-'bc'
+>>> slice_(u'abcdefg', u'1:3')
+u'bc'
->>> slice_('abcdefg', '0::2')
-'aceg'
+>>> slice_(u'abcdefg', u'0::2')
+u'aceg'
->>> unordered_list(['item 1', []])
-'\t<li>item 1</li>'
+>>> unordered_list([u'item 1', []])
+u'\t<li>item 1</li>'
->>> unordered_list(['item 1', [['item 1.1', []]]])
-'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
+>>> unordered_list([u'item 1', [[u'item 1.1', []]]])
+u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
->>> unordered_list(['item 1', [['item 1.1', []], ['item 1.2', []]]])
-'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
+>>> unordered_list([u'item 1', [[u'item 1.1', []], [u'item 1.2', []]]])
+u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
->>> add('1', '2')
+>>> add(u'1', u'2')
3
>>> get_digit(123, 1)
@@ -279,43 +293,43 @@ False
>>> get_digit(123, 0)
123
->>> get_digit('xyz', 0)
-'xyz'
+>>> get_digit(u'xyz', 0)
+u'xyz'
# real testing of date() is in dateformat.py
->>> date(datetime.datetime(2005, 12, 29), "d F Y")
-'29 December 2005'
->>> date(datetime.datetime(2005, 12, 29), r'jS o\f F')
-'29th of December'
+>>> date(datetime.datetime(2005, 12, 29), u"d F Y")
+u'29 December 2005'
+>>> date(datetime.datetime(2005, 12, 29), ur'jS o\f F')
+u'29th of December'
# real testing of time() is done in dateformat.py
->>> time(datetime.time(13), "h")
-'01'
+>>> time(datetime.time(13), u"h")
+u'01'
->>> time(datetime.time(0), "h")
-'12'
+>>> time(datetime.time(0), u"h")
+u'12'
# real testing is done in timesince.py, where we can provide our own 'now'
>>> timesince(datetime.datetime.now() - datetime.timedelta(1))
-'1 day'
+u'1 day'
->>> default("val", "default")
-'val'
+>>> default(u"val", u"default")
+u'val'
->>> default(None, "default")
-'default'
+>>> default(None, u"default")
+u'default'
->>> default('', "default")
-'default'
+>>> default(u'', u"default")
+u'default'
->>> default_if_none("val", "default")
-'val'
+>>> default_if_none(u"val", u"default")
+u'val'
->>> default_if_none(None, "default")
-'default'
+>>> default_if_none(None, u"default")
+u'default'
->>> default_if_none('', "default")
-''
+>>> default_if_none(u'', u"default")
+u''
>>> divisibleby(4, 2)
True
@@ -324,139 +338,139 @@ True
False
>>> yesno(True)
-'yes'
+u'yes'
>>> yesno(False)
-'no'
+u'no'
>>> yesno(None)
-'maybe'
+u'maybe'
->>> yesno(True, 'certainly,get out of town,perhaps')
-'certainly'
+>>> yesno(True, u'certainly,get out of town,perhaps')
+u'certainly'
->>> yesno(False, 'certainly,get out of town,perhaps')
-'get out of town'
+>>> yesno(False, u'certainly,get out of town,perhaps')
+u'get out of town'
->>> yesno(None, 'certainly,get out of town,perhaps')
-'perhaps'
+>>> yesno(None, u'certainly,get out of town,perhaps')
+u'perhaps'
->>> yesno(None, 'certainly,get out of town')
-'get out of town'
+>>> yesno(None, u'certainly,get out of town')
+u'get out of town'
>>> filesizeformat(1023)
-'1023 bytes'
+u'1023 bytes'
>>> filesizeformat(1024)
-'1.0 KB'
+u'1.0 KB'
>>> filesizeformat(10*1024)
-'10.0 KB'
+u'10.0 KB'
>>> filesizeformat(1024*1024-1)
-'1024.0 KB'
+u'1024.0 KB'
>>> filesizeformat(1024*1024)
-'1.0 MB'
+u'1.0 MB'
>>> filesizeformat(1024*1024*50)
-'50.0 MB'
+u'50.0 MB'
>>> filesizeformat(1024*1024*1024-1)
-'1024.0 MB'
+u'1024.0 MB'
>>> filesizeformat(1024*1024*1024)
-'1.0 GB'
+u'1.0 GB'
>>> pluralize(1)
-''
+u''
>>> pluralize(0)
-'s'
+u's'
>>> pluralize(2)
-'s'
+u's'
>>> pluralize([1])
-''
+u''
>>> pluralize([])
-'s'
+u's'
>>> pluralize([1,2,3])
-'s'
+u's'
->>> pluralize(1,'es')
-''
+>>> pluralize(1,u'es')
+u''
->>> pluralize(0,'es')
-'es'
+>>> pluralize(0,u'es')
+u'es'
->>> pluralize(2,'es')
-'es'
+>>> pluralize(2,u'es')
+u'es'
->>> pluralize(1,'y,ies')
-'y'
+>>> pluralize(1,u'y,ies')
+u'y'
->>> pluralize(0,'y,ies')
-'ies'
+>>> pluralize(0,u'y,ies')
+u'ies'
->>> pluralize(2,'y,ies')
-'ies'
+>>> pluralize(2,u'y,ies')
+u'ies'
->>> pluralize(0,'y,ies,error')
-''
+>>> pluralize(0,u'y,ies,error')
+u''
->>> phone2numeric('0800 flowers')
-'0800 3569377'
+>>> phone2numeric(u'0800 flowers')
+u'0800 3569377'
# Filters shouldn't break if passed non-strings
>>> addslashes(123)
-'123'
+u'123'
>>> linenumbers(123)
-'1. 123'
+u'1. 123'
>>> lower(123)
-'123'
+u'123'
>>> make_list(123)
-['1', '2', '3']
+[u'1', u'2', u'3']
>>> slugify(123)
-'123'
+u'123'
>>> title(123)
-'123'
+u'123'
>>> truncatewords(123, 2)
-'123'
+u'123'
>>> upper(123)
-'123'
+u'123'
>>> urlencode(123)
-'123'
+u'123'
>>> urlize(123)
-'123'
+u'123'
>>> urlizetrunc(123, 1)
-'123'
+u'123'
>>> wordcount(123)
1
>>> wordwrap(123, 2)
-'123'
+u'123'
>>> ljust('123', 4)
-'123 '
+u'123 '
>>> rjust('123', 4)
-' 123'
+u' 123'
>>> center('123', 5)
-' 123 '
+u' 123 '
>>> center('123', 6)
-' 123 '
+u' 123 '
>>> cut(123, '2')
-'13'
+u'13'
>>> escape(123)
-'123'
+u'123'
>>> linebreaks(123)
-'<p>123</p>'
+u'<p>123</p>'
>>> linebreaksbr(123)
-'123'
+u'123'
>>> removetags(123, 'a')
-'123'
+u'123'
>>> striptags(123)
-'123'
+u'123'
"""
diff --git a/tests/regressiontests/fixtures_regress/fixtures/pretty.xml b/tests/regressiontests/fixtures_regress/fixtures/pretty.xml
new file mode 100644
index 0000000000..68e5710c6a
--- /dev/null
+++ b/tests/regressiontests/fixtures_regress/fixtures/pretty.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+ <object pk="1" model="fixtures_regress.stuff">
+ <field type="CharField" name="name">
+ <None/>
+ </field>
+ <field to="auth.user" name="owner" rel="ManyToOneRel">
+ <None/>
+ </field>
+ </object>
+</django-objects> \ No newline at end of file
diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py
index dd407df353..c6a50f73ce 100644
--- a/tests/regressiontests/fixtures_regress/models.py
+++ b/tests/regressiontests/fixtures_regress/models.py
@@ -1,24 +1,32 @@
from django.db import models
+from django.contrib.auth.models import User
class Animal(models.Model):
- name = models.CharField(maxlength=150)
- latin_name = models.CharField(maxlength=150)
+ name = models.CharField(max_length=150)
+ latin_name = models.CharField(max_length=150)
- def __str__(self):
- return self.common_name
+ def __unicode__(self):
+ return self.common_name
class Plant(models.Model):
- name = models.CharField(maxlength=150)
+ name = models.CharField(max_length=150)
class Meta:
# For testing when upper case letter in app name; regression for #4057
db_table = "Fixtures_regress_plant"
+class Stuff(models.Model):
+ name = models.CharField(max_length=20, null=True)
+ owner = models.ForeignKey(User, null=True)
+
+ def __unicode__(self):
+ return unicode(self.name) + u' is owned by ' + unicode(self.owner)
+
__test__ = {'API_TESTS':"""
>>> from django.core import management
# Load a fixture that uses PK=1
->>> management.load_data(['sequence'], verbosity=0)
+>>> management.call_command('loaddata', 'sequence', verbosity=0)
# Create a new animal. Without a sequence reset, this new object
# will take a PK of 1 (on Postgres), and the save will fail.
@@ -26,4 +34,13 @@ __test__ = {'API_TESTS':"""
>>> animal = Animal(name='Platypus', latin_name='Ornithorhynchus anatinus')
>>> animal.save()
-"""} \ No newline at end of file
+###############################################
+# Regression test for ticket #4558 -- pretty printing of XML fixtures
+# doesn't affect parsing of None values.
+
+# Load a pretty-printed XML fixture with Nulls.
+>>> management.call_command('loaddata', 'pretty.xml', verbosity=0)
+>>> Stuff.objects.all()
+[<Stuff: None is owned by None>]
+
+"""}
diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py
index ede89de2a0..a896013b0d 100644
--- a/tests/regressiontests/forms/localflavor.py
+++ b/tests/regressiontests/forms/localflavor.py
@@ -913,11 +913,11 @@ ValidationError: [u'This field requires only numbers.']
>>> f.clean('375.788.573-000')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 14 characters.']
+ValidationError: [u'Ensure this value has at most 14 characters (it has 15).']
>>> f.clean('123.456.78')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 11 characters.']
+ValidationError: [u'Ensure this value has at least 11 characters (it has 10).']
>>> f.clean('123456789555')
Traceback (most recent call last):
...
@@ -1208,11 +1208,11 @@ u'230880-3449'
>>> f.clean('230880343')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 10 characters.']
+ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
>>> f.clean('230880343234')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 11 characters.']
+ValidationError: [u'Ensure this value has at most 11 characters (it has 12).']
>>> f.clean('abcdefghijk')
Traceback (most recent call last):
...
@@ -1254,18 +1254,18 @@ ValidationError: [u'Enter a valid value.']
>>> f.clean('123456')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 7 characters.']
+ValidationError: [u'Ensure this value has at least 7 characters (it has 6).']
>>> f.clean('123456555')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters.']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
>>> f.clean('abcdefg')
Traceback (most recent call last):
ValidationError: [u'Enter a valid value.']
>>> f.clean(' 1234567 ')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 8 characters.']
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
>>> f.clean(' 12367 ')
Traceback (most recent call last):
...
@@ -1303,9 +1303,9 @@ strict.
>>> rut = CLRutField()
>>> rut.clean('11-6')
-'11-6'
+u'11-6'
>>> rut.clean('116')
-'11-6'
+u'11-6'
# valid format, bad verifier.
>>> rut.clean('11.111.111-0')
@@ -1318,13 +1318,13 @@ Traceback (most recent call last):
ValidationError: [u'The Chilean RUT is not valid.']
>>> rut.clean('767484100')
-'76.748.410-0'
+u'76.748.410-0'
>>> rut.clean('78.412.790-7')
-'78.412.790-7'
+u'78.412.790-7'
>>> rut.clean('8.334.6043')
-'8.334.604-3'
+u'8.334.604-3'
>>> rut.clean('76793310-K')
-'76.793.310-K'
+u'76.793.310-K'
Strict RUT usage (does not allow imposible values)
>>> rut = CLRutField(strict=True)
@@ -1346,7 +1346,7 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
>>> rut.clean('78.412.790-7')
-'78.412.790-7'
+u'78.412.790-7'
>>> rut.clean('8.334.6043')
Traceback (most recent call last):
...
@@ -1356,4 +1356,94 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+## CLRegionSelect #########################################################
+>>> from django.contrib.localflavor.cl.forms import CLRegionSelect
+>>> f = CLRegionSelect()
+
+>>> f.render('foo', 'bar')
+u'<select name="foo">\n<option value="RM">Regi\xf3n Metropolitana de Santiago</option>\n<option value="I">Regi\xf3n de Tarapac\xe1</option>\n<option value="II">Regi\xf3n de Antofagasta</option>\n<option value="III">Regi\xf3n de Atacama</option>\n<option value="IV">Regi\xf3n de Coquimbo</option>\n<option value="V">Regi\xf3n de Valpara\xedso</option>\n<option value="VI">Regi\xf3n del Libertador Bernardo O&#39;Higgins</option>\n<option value="VII">Regi\xf3n del Maule</option>\n<option value="VIII">Regi\xf3n del B\xedo B\xedo</option>\n<option value="IX">Regi\xf3n de la Araucan\xeda</option>\n<option value="X">Regi\xf3n de los Lagos</option>\n<option value="XI">Regi\xf3n de Ays\xe9n del General Carlos Ib\xe1\xf1ez del Campo</option>\n<option value="XII">Regi\xf3n de Magallanes y la Ant\xe1rtica Chilena</option>\n<option value="XIV">Regi\xf3n de Los R\xedos</option>\n<option value="XV">Regi\xf3n de Arica-Parinacota</option>\n</select>'
+
+# SKPostalCodeField #########################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKPostalCodeField
+>>> f = SKPostalCodeField()
+>>> f.clean('84545x')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
+>>> f.clean('91909')
+u'91909'
+>>> f.clean('917 01')
+u'91701'
+
+# SKRegionSelect ############################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKRegionSelect
+>>> w = SKRegionSelect()
+>>> w.render('regions', 'TT')
+u'<select name="regions">\n<option value="BB">Banska Bystrica region</option>\n<option value="BA">Bratislava region</option>\n<option value="KE">Kosice region</option>\n<option value="NR">Nitra region</option>\n<option value="PO">Presov region</option>\n<option value="TN">Trencin region</option>\n<option value="TT" selected="selected">Trnava region</option>\n<option value="ZA">Zilina region</option>\n</select>'
+
+# SKDistrictSelect ##########################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKDistrictSelect
+>>> w = SKDistrictSelect()
+>>> w.render('Districts', 'RK')
+u'<select name="Districts">\n<option value="BB">Banska Bystrica</option>\n<option value="BS">Banska Stiavnica</option>\n<option value="BJ">Bardejov</option>\n<option value="BN">Banovce nad Bebravou</option>\n<option value="BR">Brezno</option>\n<option value="BA1">Bratislava I</option>\n<option value="BA2">Bratislava II</option>\n<option value="BA3">Bratislava III</option>\n<option value="BA4">Bratislava IV</option>\n<option value="BA5">Bratislava V</option>\n<option value="BY">Bytca</option>\n<option value="CA">Cadca</option>\n<option value="DT">Detva</option>\n<option value="DK">Dolny Kubin</option>\n<option value="DS">Dunajska Streda</option>\n<option value="GA">Galanta</option>\n<option value="GL">Gelnica</option>\n<option value="HC">Hlohovec</option>\n<option value="HE">Humenne</option>\n<option value="IL">Ilava</option>\n<option value="KK">Kezmarok</option>\n<option value="KN">Komarno</option>\n<option value="KE1">Kosice I</option>\n<option value="KE2">Kosice II</option>\n<option value="KE3">Kosice III</option>\n<option value="KE4">Kosice IV</option>\n<option value="KEO">Kosice - okolie</option>\n<option value="KA">Krupina</option>\n<option value="KM">Kysucke Nove Mesto</option>\n<option value="LV">Levice</option>\n<option value="LE">Levoca</option>\n<option value="LM">Liptovsky Mikulas</option>\n<option value="LC">Lucenec</option>\n<option value="MA">Malacky</option>\n<option value="MT">Martin</option>\n<option value="ML">Medzilaborce</option>\n<option value="MI">Michalovce</option>\n<option value="MY">Myjava</option>\n<option value="NO">Namestovo</option>\n<option value="NR">Nitra</option>\n<option value="NM">Nove Mesto nad Vahom</option>\n<option value="NZ">Nove Zamky</option>\n<option value="PE">Partizanske</option>\n<option value="PK">Pezinok</option>\n<option value="PN">Piestany</option>\n<option value="PT">Poltar</option>\n<option value="PP">Poprad</option>\n<option value="PB">Povazska Bystrica</option>\n<option value="PO">Presov</option>\n<option value="PD">Prievidza</option>\n<option value="PU">Puchov</option>\n<option value="RA">Revuca</option>\n<option value="RS">Rimavska Sobota</option>\n<option value="RV">Roznava</option>\n<option value="RK" selected="selected">Ruzomberok</option>\n<option value="SB">Sabinov</option>\n<option value="SC">Senec</option>\n<option value="SE">Senica</option>\n<option value="SI">Skalica</option>\n<option value="SV">Snina</option>\n<option value="SO">Sobrance</option>\n<option value="SN">Spisska Nova Ves</option>\n<option value="SL">Stara Lubovna</option>\n<option value="SP">Stropkov</option>\n<option value="SK">Svidnik</option>\n<option value="SA">Sala</option>\n<option value="TO">Topolcany</option>\n<option value="TV">Trebisov</option>\n<option value="TN">Trencin</option>\n<option value="TT">Trnava</option>\n<option value="TR">Turcianske Teplice</option>\n<option value="TS">Tvrdosin</option>\n<option value="VK">Velky Krtis</option>\n<option value="VT">Vranov nad Toplou</option>\n<option value="ZM">Zlate Moravce</option>\n<option value="ZV">Zvolen</option>\n<option value="ZC">Zarnovica</option>\n<option value="ZH">Ziar nad Hronom</option>\n<option value="ZA">Zilina</option>\n</select>'
+
+# PLVoivodeshipSelect ##########################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLVoivodeshipSelect
+>>> f = PLVoivodeshipSelect()
+>>> f.render('voivodeships','pomerania')
+u'<select name="voivodeships">\n<option value="lower_silesia">Lower Silesia</option>\n<option value="kuyavia-pomerania">Kuyavia-Pomerania</option>\n<option value="lublin">Lublin</option>\n<option value="lubusz">Lubusz</option>\n<option value="lodz">Lodz</option>\n<option value="lesser_poland">Lesser Poland</option>\n<option value="masovia">Masovia</option>\n<option value="opole">Opole</option>\n<option value="subcarpatia">Subcarpatia</option>\n<option value="podlasie">Podlasie</option>\n<option value="pomerania" selected="selected">Pomerania</option>\n<option value="silesia">Silesia</option>\n<option value="swietokrzyskie">Swietokrzyskie</option>\n<option value="warmia-masuria">Warmia-Masuria</option>\n<option value="greater_poland">Greater Poland</option>\n<option value="west_pomerania">West Pomerania</option>\n</select>'
+
+# PLAdministrativeUnitSelect ##########################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLAdministrativeUnitSelect
+>>> f = PLAdministrativeUnitSelect()
+>>> f.render('administrativeunit','katowice')
+u'<select name="administrativeunit">\n<option value="wroclaw">Wroc\u0142aw</option>\n<option value="jeleniagora">Jelenia G\xf3ra</option>\n<option value="legnica">Legnica</option>\n<option value="boleslawiecki">boles\u0142awiecki</option>\n<option value="dzierzoniowski">dzier\u017coniowski</option>\n<option value="glogowski">g\u0142ogowski</option>\n<option value="gorowski">g\xf3rowski</option>\n<option value="jaworski">jaworski</option>\n<option value="jeleniogorski">jeleniog\xf3rski</option>\n<option value="kamiennogorski">kamiennog\xf3rski</option>\n<option value="klodzki">k\u0142odzki</option>\n<option value="legnicki">legnicki</option>\n<option value="lubanski">luba\u0144ski</option>\n<option value="lubinski">lubi\u0144ski</option>\n<option value="lwowecki">lw\xf3wecki</option>\n<option value="milicki">milicki</option>\n<option value="olesnicki">ole\u015bnicki</option>\n<option value="olawski">o\u0142awski</option>\n<option value="polkowicki">polkowicki</option>\n<option value="strzelinski">strzeli\u0144ski</option>\n<option value="sredzki">\u015bredzki</option>\n<option value="swidnicki">\u015bwidnicki</option>\n<option value="trzebnicki">trzebnicki</option>\n<option value="walbrzyski">wa\u0142brzyski</option>\n<option value="wolowski">wo\u0142owski</option>\n<option value="wroclawski">wroc\u0142awski</option>\n<option value="zabkowicki">z\u0105bkowicki</option>\n<option value="zgorzelecki">zgorzelecki</option>\n<option value="zlotoryjski">z\u0142otoryjski</option>\n<option value="bydgoszcz">Bydgoszcz</option>\n<option value="torun">Toru\u0144</option>\n<option value="wloclawek">W\u0142oc\u0142awek</option>\n<option value="grudziadz">Grudzi\u0105dz</option>\n<option value="aleksandrowski">aleksandrowski</option>\n<option value="brodnicki">brodnicki</option>\n<option value="bydgoski">bydgoski</option>\n<option value="chelminski">che\u0142mi\u0144ski</option>\n<option value="golubsko-dobrzynski">golubsko-dobrzy\u0144ski</option>\n<option value="grudziadzki">grudzi\u0105dzki</option>\n<option value="inowroclawski">inowroc\u0142awski</option>\n<option value="lipnowski">lipnowski</option>\n<option value="mogilenski">mogile\u0144ski</option>\n<option value="nakielski">nakielski</option>\n<option value="radziejowski">radziejowski</option>\n<option value="rypinski">rypi\u0144ski</option>\n<option value="sepolenski">s\u0119pole\u0144ski</option>\n<option value="swiecki">\u015bwiecki</option>\n<option value="torunski">toru\u0144ski</option>\n<option value="tucholski">tucholski</option>\n<option value="wabrzeski">w\u0105brzeski</option>\n<option value="wloclawski">wroc\u0142awski</option>\n<option value="zninski">\u017ani\u0144ski</option>\n<option value="lublin">Lublin</option>\n<option value="biala-podlaska">Bia\u0142a Podlaska</option>\n<option value="chelm">Che\u0142m</option>\n<option value="zamosc">Zamo\u015b\u0107</option>\n<option value="bialski">bialski</option>\n<option value="bilgorajski">bi\u0142gorajski</option>\n<option value="chelmski">che\u0142mski</option>\n<option value="hrubieszowski">hrubieszowski</option>\n<option value="janowski">janowski</option>\n<option value="krasnostawski">krasnostawski</option>\n<option value="krasnicki">kra\u015bnicki</option>\n<option value="lubartowski">lubartowski</option>\n<option value="lubelski">lubelski</option>\n<option value="leczynski">\u0142\u0119czy\u0144ski</option>\n<option value="lukowski">\u0142ukowski</option>\n<option value="opolski">opolski</option>\n<option value="parczewski">parczewski</option>\n<option value="pulawski">pu\u0142awski</option>\n<option value="radzynski">radzy\u0144ski</option>\n<option value="rycki">rycki</option>\n<option value="swidnicki">\u015bwidnicki</option>\n<option value="tomaszowski">tomaszowski</option>\n<option value="wlodawski">w\u0142odawski</option>\n<option value="zamojski">zamojski</option>\n<option value="gorzow-wielkopolski">Gorz\xf3w Wielkopolski</option>\n<option value="zielona-gora">Zielona G\xf3ra</option>\n<option value="gorzowski">gorzowski</option>\n<option value="krosnienski">kro\u015bnie\u0144ski</option>\n<option value="miedzyrzecki">mi\u0119dzyrzecki</option>\n<option value="nowosolski">nowosolski</option>\n<option value="slubicki">s\u0142ubicki</option>\n<option value="strzelecko-drezdenecki">strzelecko-drezdenecki</option>\n<option value="sulecinski">sule\u0144ci\u0144ski</option>\n<option value="swiebodzinski">\u015bwiebodzi\u0144ski</option>\n<option value="wschowski">wschowski</option>\n<option value="zielonogorski">zielonog\xf3rski</option>\n<option value="zaganski">\u017caga\u0144ski</option>\n<option value="zarski">\u017carski</option>\n<option value="lodz">\u0141\xf3d\u017a</option>\n<option value="piotrkow-trybunalski">Piotrk\xf3w Trybunalski</option>\n<option value="skierniewice">Skierniewice</option>\n<option value="belchatowski">be\u0142chatowski</option>\n<option value="brzezinski">brzezi\u0144ski</option>\n<option value="kutnowski">kutnowski</option>\n<option value="laski">\u0142aski</option>\n<option value="leczycki">\u0142\u0119czycki</option>\n<option value="lowicki">\u0142owicki</option>\n<option value="lodzki wschodni">\u0142\xf3dzki wschodni</option>\n<option value="opoczynski">opoczy\u0144ski</option>\n<option value="pabianicki">pabianicki</option>\n<option value="pajeczanski">paj\u0119cza\u0144ski</option>\n<option value="piotrkowski">piotrkowski</option>\n<option value="poddebicki">podd\u0119bicki</option>\n<option value="radomszczanski">radomszcza\u0144ski</option>\n<option value="rawski">rawski</option>\n<option value="sieradzki">sieradzki</option>\n<option value="skierniewicki">skierniewicki</option>\n<option value="tomaszowski">tomaszowski</option>\n<option value="wielunski">wielu\u0144ski</option>\n<option value="wieruszowski">wieruszowski</option>\n<option value="zdunskowolski">zdu\u0144skowolski</option>\n<option value="zgierski">zgierski</option>\n<option value="krakow">Krak\xf3w</option>\n<option value="tarnow">Tarn\xf3w</option>\n<option value="nowy-sacz">Nowy S\u0105cz</option>\n<option value="bochenski">boche\u0144ski</option>\n<option value="brzeski">brzeski</option>\n<option value="chrzanowski">chrzanowski</option>\n<option value="dabrowski">d\u0105browski</option>\n<option value="gorlicki">gorlicki</option>\n<option value="krakowski">krakowski</option>\n<option value="limanowski">limanowski</option>\n<option value="miechowski">miechowski</option>\n<option value="myslenicki">my\u015blenicki</option>\n<option value="nowosadecki">nowos\u0105decki</option>\n<option value="nowotarski">nowotarski</option>\n<option value="olkuski">olkuski</option>\n<option value="oswiecimski">o\u015bwi\u0119cimski</option>\n<option value="proszowicki">proszowicki</option>\n<option value="suski">suski</option>\n<option value="tarnowski">tarnowski</option>\n<option value="tatrzanski">tatrza\u0144ski</option>\n<option value="wadowicki">wadowicki</option>\n<option value="wielicki">wielicki</option>\n<option value="warszawa">Warszawa</option>\n<option value="ostroleka">Ostro\u0142\u0119ka</option>\n<option value="plock">P\u0142ock</option>\n<option value="radom">Radom</option>\n<option value="siedlce">Siedlce</option>\n<option value="bialobrzeski">bia\u0142obrzeski</option>\n<option value="ciechanowski">ciechanowski</option>\n<option value="garwolinski">garwoli\u0144ski</option>\n<option value="gostyninski">gostyni\u0144ski</option>\n<option value="grodziski">grodziski</option>\n<option value="grojecki">gr\xf3jecki</option>\n<option value="kozienicki">kozenicki</option>\n<option value="legionowski">legionowski</option>\n<option value="lipski">lipski</option>\n<option value="losicki">\u0142osicki</option>\n<option value="makowski">makowski</option>\n<option value="minski">mi\u0144ski</option>\n<option value="mlawski">m\u0142awski</option>\n<option value="nowodworski">nowodworski</option>\n<option value="ostrolecki">ostro\u0142\u0119cki</option>\n<option value="ostrowski">ostrowski</option>\n<option value="otwocki">otwocki</option>\n<option value="piaseczynski">piaseczy\u0144ski</option>\n<option value="plocki">p\u0142ocki</option>\n<option value="plonski">p\u0142o\u0144ski</option>\n<option value="pruszkowski">pruszkowski</option>\n<option value="przasnyski">przasnyski</option>\n<option value="przysuski">przysuski</option>\n<option value="pultuski">pu\u0142tuski</option>\n<option value="radomski">radomski</option>\n<option value="siedlecki">siedlecki</option>\n<option value="sierpecki">sierpecki</option>\n<option value="sochaczewski">sochaczewski</option>\n<option value="sokolowski">soko\u0142owski</option>\n<option value="szydlowiecki">szyd\u0142owiecki</option>\n<option value="warszawski-zachodni">warszawski zachodni</option>\n<option value="wegrowski">w\u0119growski</option>\n<option value="wolominski">wo\u0142omi\u0144ski</option>\n<option value="wyszkowski">wyszkowski</option>\n<option value="zwolenski">zwole\u0144ski</option>\n<option value="zurominski">\u017curomi\u0144ski</option>\n<option value="zyrardowski">\u017cyrardowski</option>\n<option value="opole">Opole</option>\n<option value="brzeski">brzeski</option>\n<option value="glubczycki">g\u0142ubczyski</option>\n<option value="kedzierzynsko-kozielski">k\u0119dzierzy\u0144ski-kozielski</option>\n<option value="kluczborski">kluczborski</option>\n<option value="krapkowicki">krapkowicki</option>\n<option value="namyslowski">namys\u0142owski</option>\n<option value="nyski">nyski</option>\n<option value="oleski">oleski</option>\n<option value="opolski">opolski</option>\n<option value="prudnicki">prudnicki</option>\n<option value="strzelecki">strzelecki</option>\n<option value="rzeszow">Rzesz\xf3w</option>\n<option value="krosno">Krosno</option>\n<option value="przemysl">Przemy\u015bl</option>\n<option value="tarnobrzeg">Tarnobrzeg</option>\n<option value="bieszczadzki">bieszczadzki</option>\n<option value="brzozowski">brzozowski</option>\n<option value="debicki">d\u0119bicki</option>\n<option value="jaroslawski">jaros\u0142awski</option>\n<option value="jasielski">jasielski</option>\n<option value="kolbuszowski">kolbuszowski</option>\n<option value="krosnienski">kro\u015bnie\u0144ski</option>\n<option value="leski">leski</option>\n<option value="lezajski">le\u017cajski</option>\n<option value="lubaczowski">lubaczowski</option>\n<option value="lancucki">\u0142a\u0144cucki</option>\n<option value="mielecki">mielecki</option>\n<option value="nizanski">ni\u017ca\u0144ski</option>\n<option value="przemyski">przemyski</option>\n<option value="przeworski">przeworski</option>\n<option value="ropczycko-sedziszowski">ropczycko-s\u0119dziszowski</option>\n<option value="rzeszowski">rzeszowski</option>\n<option value="sanocki">sanocki</option>\n<option value="stalowowolski">stalowowolski</option>\n<option value="strzyzowski">strzy\u017cowski</option>\n<option value="tarnobrzeski">tarnobrzeski</option>\n<option value="bialystok">Bia\u0142ystok</option>\n<option value="lomza">\u0141om\u017ca</option>\n<option value="suwalki">Suwa\u0142ki</option>\n<option value="augustowski">augustowski</option>\n<option value="bialostocki">bia\u0142ostocki</option>\n<option value="bielski">bielski</option>\n<option value="grajewski">grajewski</option>\n<option value="hajnowski">hajnowski</option>\n<option value="kolnenski">kolne\u0144ski</option>\n<option value="\u0142omzynski">\u0142om\u017cy\u0144ski</option>\n<option value="moniecki">moniecki</option>\n<option value="sejnenski">sejne\u0144ski</option>\n<option value="siemiatycki">siematycki</option>\n<option value="sokolski">sok\xf3lski</option>\n<option value="suwalski">suwalski</option>\n<option value="wysokomazowiecki">wysokomazowiecki</option>\n<option value="zambrowski">zambrowski</option>\n<option value="gdansk">Gda\u0144sk</option>\n<option value="gdynia">Gdynia</option>\n<option value="slupsk">S\u0142upsk</option>\n<option value="sopot">Sopot</option>\n<option value="bytowski">bytowski</option>\n<option value="chojnicki">chojnicki</option>\n<option value="czluchowski">cz\u0142uchowski</option>\n<option value="kartuski">kartuski</option>\n<option value="koscierski">ko\u015bcierski</option>\n<option value="kwidzynski">kwidzy\u0144ski</option>\n<option value="leborski">l\u0119borski</option>\n<option value="malborski">malborski</option>\n<option value="nowodworski">nowodworski</option>\n<option value="gdanski">gda\u0144ski</option>\n<option value="pucki">pucki</option>\n<option value="slupski">s\u0142upski</option>\n<option value="starogardzki">starogardzki</option>\n<option value="sztumski">sztumski</option>\n<option value="tczewski">tczewski</option>\n<option value="wejherowski">wejcherowski</option>\n<option value="katowice" selected="selected">Katowice</option>\n<option value="bielsko-biala">Bielsko-Bia\u0142a</option>\n<option value="bytom">Bytom</option>\n<option value="chorzow">Chorz\xf3w</option>\n<option value="czestochowa">Cz\u0119stochowa</option>\n<option value="dabrowa-gornicza">D\u0105browa G\xf3rnicza</option>\n<option value="gliwice">Gliwice</option>\n<option value="jastrzebie-zdroj">Jastrz\u0119bie Zdr\xf3j</option>\n<option value="jaworzno">Jaworzno</option>\n<option value="myslowice">Mys\u0142owice</option>\n<option value="piekary-slaskie">Piekary \u015al\u0105skie</option>\n<option value="ruda-slaska">Ruda \u015al\u0105ska</option>\n<option value="rybnik">Rybnik</option>\n<option value="siemianowice-slaskie">Siemianowice \u015al\u0105skie</option>\n<option value="sosnowiec">Sosnowiec</option>\n<option value="swietochlowice">\u015awi\u0119toch\u0142owice</option>\n<option value="tychy">Tychy</option>\n<option value="zabrze">Zabrze</option>\n<option value="zory">\u017bory</option>\n<option value="bedzinski">b\u0119dzi\u0144ski</option>\n<option value="bielski">bielski</option>\n<option value="bierunsko-ledzinski">bieru\u0144sko-l\u0119dzi\u0144ski</option>\n<option value="cieszynski">cieszy\u0144ski</option>\n<option value="czestochowski">cz\u0119stochowski</option>\n<option value="gliwicki">gliwicki</option>\n<option value="klobucki">k\u0142obucki</option>\n<option value="lubliniecki">lubliniecki</option>\n<option value="mikolowski">miko\u0142owski</option>\n<option value="myszkowski">myszkowski</option>\n<option value="pszczynski">pszczy\u0144ski</option>\n<option value="raciborski">raciborski</option>\n<option value="rybnicki">rybnicki</option>\n<option value="tarnogorski">tarnog\xf3rski</option>\n<option value="wodzislawski">wodzis\u0142awski</option>\n<option value="zawiercianski">zawiercia\u0144ski</option>\n<option value="zywiecki">\u017cywiecki</option>\n<option value="kielce">Kielce</option>\n<option value="buski">buski</option>\n<option value="jedrzejowski">j\u0119drzejowski</option>\n<option value="kazimierski">kazimierski</option>\n<option value="kielecki">kielecki</option>\n<option value="konecki">konecki</option>\n<option value="opatowski">opatowski</option>\n<option value="ostrowiecki">ostrowiecki</option>\n<option value="pinczowski">pi\u0144czowski</option>\n<option value="sandomierski">sandomierski</option>\n<option value="skarzyski">skar\u017cyski</option>\n<option value="starachowicki">starachowicki</option>\n<option value="staszowski">staszowski</option>\n<option value="wloszczowski">w\u0142oszczowski</option>\n<option value="olsztyn">Olsztyn</option>\n<option value="elblag">Elbl\u0105g</option>\n<option value="bartoszycki">bartoszycki</option>\n<option value="braniewski">braniewski</option>\n<option value="dzialdowski">dzia\u0142dowski</option>\n<option value="elblaski">elbl\u0105ski</option>\n<option value="elcki">e\u0142cki</option>\n<option value="gizycki">gi\u017cycki</option>\n<option value="goldapski">go\u0142dapski</option>\n<option value="ilawski">i\u0142awski</option>\n<option value="ketrzynski">k\u0119trzy\u0144ski</option>\n<option value="lidzbarski">lidzbarski</option>\n<option value="mragowski">mr\u0105gowski</option>\n<option value="nidzicki">nidzicki</option>\n<option value="nowomiejski">nowomiejski</option>\n<option value="olecki">olecki</option>\n<option value="olsztynski">olszty\u0144ski</option>\n<option value="ostrodzki">ostr\xf3dzki</option>\n<option value="piski">piski</option>\n<option value="szczycienski">szczycie\u0144ski</option>\n<option value="wegorzewski">w\u0119gorzewski</option>\n<option value="poznan">Pozna\u0144</option>\n<option value="kalisz">Kalisz</option>\n<option value="konin">Konin</option>\n<option value="leszno">Leszno</option>\n<option value="chodzieski">chodziejski</option>\n<option value="czarnkowsko-trzcianecki">czarnkowsko-trzcianecki</option>\n<option value="gnieznienski">gnie\u017anie\u0144ski</option>\n<option value="gostynski">gosty\u0144ski</option>\n<option value="grodziski">grodziski</option>\n<option value="jarocinski">jaroci\u0144ski</option>\n<option value="kaliski">kaliski</option>\n<option value="kepinski">k\u0119pi\u0144ski</option>\n<option value="kolski">kolski</option>\n<option value="koninski">koni\u0144ski</option>\n<option value="koscianski">ko\u015bcia\u0144ski</option>\n<option value="krotoszynski">krotoszy\u0144ski</option>\n<option value="leszczynski">leszczy\u0144ski</option>\n<option value="miedzychodzki">mi\u0119dzychodzki</option>\n<option value="nowotomyski">nowotomyski</option>\n<option value="obornicki">obornicki</option>\n<option value="ostrowski">ostrowski</option>\n<option value="ostrzeszowski">ostrzeszowski</option>\n<option value="pilski">pilski</option>\n<option value="pleszewski">pleszewski</option>\n<option value="poznanski">pozna\u0144ski</option>\n<option value="rawicki">rawicki</option>\n<option value="slupecki">s\u0142upecki</option>\n<option value="szamotulski">szamotulski</option>\n<option value="sredzki">\u015bredzki</option>\n<option value="sremski">\u015bremski</option>\n<option value="turecki">turecki</option>\n<option value="wagrowiecki">w\u0105growiecki</option>\n<option value="wolsztynski">wolszty\u0144ski</option>\n<option value="wrzesinski">wrzesi\u0144ski</option>\n<option value="zlotowski">z\u0142otowski</option>\n<option value="bialogardzki">bia\u0142ogardzki</option>\n<option value="choszczenski">choszcze\u0144ski</option>\n<option value="drawski">drawski</option>\n<option value="goleniowski">goleniowski</option>\n<option value="gryficki">gryficki</option>\n<option value="gryfinski">gryfi\u0144ski</option>\n<option value="kamienski">kamie\u0144ski</option>\n<option value="kolobrzeski">ko\u0142obrzeski</option>\n<option value="koszalinski">koszali\u0144ski</option>\n<option value="lobeski">\u0142obeski</option>\n<option value="mysliborski">my\u015bliborski</option>\n<option value="policki">policki</option>\n<option value="pyrzycki">pyrzycki</option>\n<option value="slawienski">s\u0142awie\u0144ski</option>\n<option value="stargardzki">stargardzki</option>\n<option value="szczecinecki">szczecinecki</option>\n<option value="swidwinski">\u015bwidwi\u0144ski</option>\n<option value="walecki">wa\u0142ecki</option>\n</select>'
+
+# PLPostalCodeField ##############################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLPostalCodeField
+>>> f = PLPostalCodeField()
+>>> f.clean('43--434')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XX-XXX.']
+>>> f.clean('41-403')
+u'41-403'
+
+# PLTaxNumberField ###############################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLTaxNumberField
+>>> f = PLTaxNumberField()
+>>> f.clean('43-343-234-323')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
+>>> f.clean('43-34-234-323')
+u'43-34-234-323'
+>>> f.clean('433-344-24-23')
+u'433-344-24-23'
+
+# PLNationalIdentificationNumberField ############################################
+
+>>> from django.contrib.localflavor.pl.forms import PLNationalIdentificationNumberField
+>>> f = PLNationalIdentificationNumberField()
+>>> f.clean('80071610614')
+u'80071610614'
+>>> f.clean('80071610610')
+Traceback (most recent call last):
+...
+ValidationError: [u'Wrong checksum for the National Identification Number.']
+>>> f.clean('80')
+Traceback (most recent call last):
+...
+ValidationError: [u'National Identification Number consists of 11 digits.']
+>>> f.clean('800716106AA')
+Traceback (most recent call last):
+...
+ValidationError: [u'National Identification Number consists of 11 digits.']
"""
diff --git a/tests/regressiontests/forms/regressions.py b/tests/regressiontests/forms/regressions.py
index 5fe057b5d8..784ef49902 100644
--- a/tests/regressiontests/forms/regressions.py
+++ b/tests/regressiontests/forms/regressions.py
@@ -16,24 +16,63 @@ u'<p>F1: <input type="text" class="special" name="f1" maxlength="10" /></p>\n<p>
#######################
There were some problems with form translations in #3600
->>> from django.utils.translation import gettext_lazy, activate, deactivate
+>>> from django.utils.translation import ugettext_lazy, activate, deactivate
>>> class SomeForm(Form):
-... username = CharField(max_length=10, label=gettext_lazy('Username'))
+... username = CharField(max_length=10, label=ugettext_lazy('Username'))
>>> f = SomeForm()
>>> print f.as_p()
<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>
+
+Translations are done at rendering time, so multi-lingual apps can define forms
+early and still send back the right translation.
+
+# XFAIL
>>> activate('de')
>>> print f.as_p()
<p><label for="id_username">Benutzername:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>
+>>> activate('pl')
+>>> f.as_p()
+u'<p><label for="id_username">Nazwa u\u017cytkownika:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>'
>>> deactivate()
Unicode decoding problems...
->>> GENDERS = (('0', u'En tied\xe4'), ('1', u'Mies'), ('2', u'Nainen'))
+>>> GENDERS = ((u'\xc5', u'En tied\xe4'), (u'\xf8', u'Mies'), (u'\xdf', u'Nainen'))
>>> class SomeForm(Form):
-... somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect())
+... somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label=u'\xc5\xf8\xdf')
>>> f = SomeForm()
>>> f.as_p()
-u'<p><label for="id_somechoice_0">Somechoice:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="0" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="1" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="2" name="somechoice" /> Nainen</label></li>\n</ul></p>'
+u'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>'
+
+Testing choice validation with UTF-8 bytestrings as input (these are the
+Russian abbreviations "мес." and "шт.".
+
+>>> UNITS = (('\xd0\xbc\xd0\xb5\xd1\x81.', '\xd0\xbc\xd0\xb5\xd1\x81.'), ('\xd1\x88\xd1\x82.', '\xd1\x88\xd1\x82.'))
+>>> f = ChoiceField(choices=UNITS)
+>>> f.clean(u'\u0448\u0442.')
+u'\u0448\u0442.'
+>>> f.clean('\xd1\x88\xd1\x82.')
+u'\u0448\u0442.'
+
+Translated error messages used to be buggy.
+>>> activate('ru')
+>>> f = SomeForm({})
+>>> f.as_p()
+u'<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>'
+>>> deactivate()
+
+#######################
+# Miscellaneous Tests #
+#######################
+
+There once was a problem with Form fields called "data". Let's make sure that
+doesn't come back.
+>>> class DataForm(Form):
+... data = CharField(max_length=10)
+>>> f = DataForm({'data': 'xyzzy'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'data': u'xyzzy'}
#######################
# Miscellaneous Tests #
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 0808ebe97e..78442677eb 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -4,6 +4,7 @@ from regressions import regression_tests
form_tests = r"""
>>> from django.newforms import *
+>>> from django.newforms.widgets import RadioFieldRenderer
>>> import datetime
>>> import time
>>> import re
@@ -172,27 +173,29 @@ u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
# FileInput Widget ############################################################
+FileInput widgets don't ever show the value, because the old value is of no use
+if you are updating the form or if the provided file generated an error.
>>> w = FileInput()
>>> w.render('email', '')
u'<input type="file" name="email" />'
>>> w.render('email', None)
u'<input type="file" name="email" />'
>>> w.render('email', 'test@example.com')
-u'<input type="file" name="email" value="test@example.com" />'
+u'<input type="file" name="email" />'
>>> w.render('email', 'some "quoted" & ampersanded value')
-u'<input type="file" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
+u'<input type="file" name="email" />'
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u'<input type="file" name="email" value="test@example.com" class="fun" />'
+u'<input type="file" name="email" class="fun" />'
You can also pass 'attrs' to the constructor:
>>> w = FileInput(attrs={'class': 'fun'})
>>> w.render('email', '')
u'<input type="file" class="fun" name="email" />'
>>> w.render('email', 'foo@example.com')
-u'<input type="file" class="fun" value="foo@example.com" name="email" />'
+u'<input type="file" class="fun" name="email" />'
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
+u'<input type="file" class="fun" name="email" />'
# Textarea Widget #############################################################
@@ -614,11 +617,11 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
</ul>
-The render() method returns a RadioFieldRenderer object, whose str() is a <ul>.
+RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
You can manipulate that object directly to customize the way the RadioSelect
is rendered.
>>> w = RadioSelect()
->>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
>>> for inp in r:
... print inp
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
@@ -644,10 +647,21 @@ beatle J P Paul False
beatle J G George False
beatle J R Ringo False
+You can create your own custom renderers for RadioSelect to use.
+>>> class MyRenderer(RadioFieldRenderer):
+... def render(self):
+... return u'<br />\n'.join([unicode(choice) for choice in self])
+>>> w = RadioSelect(renderer=MyRenderer)
+>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+<label><input type="radio" name="beatle" value="J" /> John</label><br />
+<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
+<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
+<label><input type="radio" name="beatle" value="R" /> Ringo</label>
+
A RadioFieldRenderer object also allows index access to individual RadioInput
objects.
>>> w = RadioSelect()
->>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
>>> print r[1]
<label><input type="radio" name="beatle" value="P" /> Paul</label>
>>> print r[0]
@@ -896,7 +910,7 @@ u'1234567890'
>>> f.clean('1234567890a')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 10 characters.']
+ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
CharField accepts an optional min_length parameter:
>>> f = CharField(min_length=10, required=False)
@@ -905,7 +919,7 @@ u''
>>> f.clean('12345')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 10 characters.']
+ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
>>> f.clean('1234567890')
u'1234567890'
>>> f.clean('1234567890a')
@@ -919,7 +933,7 @@ ValidationError: [u'This field is required.']
>>> f.clean('12345')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 10 characters.']
+ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
>>> f.clean('1234567890')
u'1234567890'
>>> f.clean('1234567890a')
@@ -1176,6 +1190,10 @@ ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
Decimal("1.5")
>>> f.clean('0.5')
Decimal("0.5")
+>>> f.clean('.5')
+Decimal("0.5")
+>>> f.clean('00.50')
+Decimal("0.50")
# DateField ###################################################################
@@ -1439,11 +1457,11 @@ RegexField also access min_length and max_length parameters, for convenience.
>>> f.clean('123')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 5 characters.']
+ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
>>> f.clean('abc')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 5 characters.']
+ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
>>> f.clean('12345')
u'12345'
>>> f.clean('1234567890')
@@ -1451,7 +1469,7 @@ u'1234567890'
>>> f.clean('12345678901')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 10 characters.']
+ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
>>> f.clean('12345a')
Traceback (most recent call last):
...
@@ -1508,13 +1526,49 @@ EmailField also access min_length and max_length parameters, for convenience.
>>> f.clean('a@foo.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 10 characters.']
+ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
>>> f.clean('alf@foo.com')
u'alf@foo.com'
>>> f.clean('alf123456788@foo.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 15 characters.']
+ValidationError: [u'Ensure this value has at most 15 characters (it has 20).']
+
+# FileField ##################################################################
+
+>>> f = FileField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f.clean({})
+Traceback (most recent call last):
+...
+ValidationError: [u'No file was submitted.']
+
+>>> f.clean('some content that is not a file')
+Traceback (most recent call last):
+...
+ValidationError: [u'No file was submitted. Check the encoding type on the form.']
+
+>>> f.clean({'filename': 'name', 'content':None})
+Traceback (most recent call last):
+...
+ValidationError: [u'The submitted file is empty.']
+
+>>> f.clean({'filename': 'name', 'content':''})
+Traceback (most recent call last):
+...
+ValidationError: [u'The submitted file is empty.']
+
+>>> type(f.clean({'filename': 'name', 'content':'Some File Content'}))
+<class 'django.newforms.fields.UploadedFile'>
# URLField ##################################################################
@@ -1618,13 +1672,13 @@ URLField also access min_length and max_length parameters, for convenience.
>>> f.clean('http://f.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at least 15 characters.']
+ValidationError: [u'Ensure this value has at least 15 characters (it has 12).']
>>> f.clean('http://example.com')
u'http://example.com'
>>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 20 characters.']
+ValidationError: [u'Ensure this value has at most 20 characters (it has 37).']
# BooleanField ################################################################
@@ -1796,7 +1850,7 @@ u'test@example.com'
>>> f.clean('longemailaddress@example.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 20 characters.']
+ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
>>> f.clean('not an e-mail')
Traceback (most recent call last):
...
@@ -1816,7 +1870,7 @@ u'test@example.com'
>>> f.clean('longemailaddress@example.com')
Traceback (most recent call last):
...
-ValidationError: [u'Ensure this value has at most 20 characters.']
+ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
>>> f.clean('not an e-mail')
Traceback (most recent call last):
...
@@ -2557,7 +2611,7 @@ Instances of a dynamic Form do not persist fields from one Form instance to
the next.
>>> class MyForm(Form):
... def __init__(self, data=None, auto_id=False, field_list=[]):
-... Form.__init__(self, data, auto_id)
+... Form.__init__(self, data, auto_id=auto_id)
... for field in field_list:
... self.fields[field[0]] = field[1]
>>> field_list = [('field1', CharField()), ('field2', CharField())]
@@ -2575,7 +2629,7 @@ the next.
... default_field_1 = CharField()
... default_field_2 = CharField()
... def __init__(self, data=None, auto_id=False, field_list=[]):
-... Form.__init__(self, data, auto_id)
+... Form.__init__(self, data, auto_id=auto_id)
... for field in field_list:
... self.fields[field[0]] = field[1]
>>> field_list = [('field1', CharField()), ('field2', CharField())]
@@ -3230,6 +3284,35 @@ is different than its data. This is handled transparently, though.
<option value="3" selected="selected">No</option>
</select>
+# Forms with FileFields ################################################
+
+FileFields are a special case because they take their data from the request.FILES,
+not request.POST.
+
+>>> class FileForm(Form):
+... file1 = FileField()
+>>> f = FileForm(auto_id=False)
+>>> print f
+<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>
+
+>>> f = FileForm(data={}, files={}, auto_id=False)
+>>> print f
+<tr><th>File1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="file" name="file1" /></td></tr>
+
+>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':''}}, auto_id=False)
+>>> print f
+<tr><th>File1:</th><td><ul class="errorlist"><li>The submitted file is empty.</li></ul><input type="file" name="file1" /></td></tr>
+
+>>> f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False)
+>>> print f
+<tr><th>File1:</th><td><ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul><input type="file" name="file1" /></td></tr>
+
+>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':'some content'}}, auto_id=False)
+>>> print f
+<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>
+>>> f.is_valid()
+True
+
# Basic form processing in a view #############################################
>>> from django.template import Template, Context
@@ -3267,7 +3350,7 @@ Case 2: POST with erroneous data (a redisplayed form, with errors).
<form action="" method="post">
<table>
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
-<tr><th>Username:</th><td><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
+<tr><th>Username:</th><td><ul class="errorlist"><li>Ensure this value has at most 10 characters (it has 23).</li></ul><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
<tr><th>Password1:</th><td><input type="password" name="password1" value="foo" /></td></tr>
<tr><th>Password2:</th><td><input type="password" name="password2" value="bar" /></td></tr>
</table>
@@ -3374,7 +3457,7 @@ does not have help text, nothing will be output.
<input type="submit" />
</form>
>>> Template('{{ form.password1.help_text }}').render(Context({'form': UserRegistration(auto_id=False)}))
-''
+u''
The label_tag() method takes an optional attrs argument: a dictionary of HTML
attributes to add to the <label> tag.
@@ -3552,6 +3635,29 @@ True
<option value="2016">2016</option>
</select>
+Using a SelectDateWidget in a form:
+
+>>> class GetDate(Form):
+... mydate = DateField(widget=SelectDateWidget)
+>>> a = GetDate({'mydate_month':'4', 'mydate_day':'1', 'mydate_year':'2008'})
+>>> print a.is_valid()
+True
+>>> print a.cleaned_data['mydate']
+2008-04-01
+
+As with any widget that implements get_value_from_datadict,
+we must be prepared to accept the input from the "as_hidden"
+rendering as well.
+
+>>> print a['mydate'].as_hidden()
+<input type="hidden" name="mydate" value="2008-4-1" id="id_mydate" />
+>>> b=GetDate({'mydate':'2008-4-1'})
+>>> print b.is_valid()
+True
+>>> print b.cleaned_data['mydate']
+2008-04-01
+
+
# MultiWidget and MultiValueField #############################################
# MultiWidgets are widgets composed of other widgets. They are usually
# combined with MultiValueFields - a field that is composed of other fields.
diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
index e7245104e9..9d5ca2006a 100644
--- a/tests/regressiontests/httpwrappers/tests.py
+++ b/tests/regressiontests/httpwrappers/tests.py
@@ -94,7 +94,7 @@ MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
>>> q['name'] = 'john'
>>> q['name']
-'john'
+u'john'
>>> del q['name']
>>> 'name' in q
@@ -106,10 +106,10 @@ False
'default'
>>> q.get('name', 'default')
-'john'
+u'john'
>>> q.getlist('name')
-['john']
+[u'john']
>>> q.getlist('foo')
[]
@@ -117,18 +117,18 @@ False
>>> q.setlist('foo', ['bar', 'baz'])
>>> q.get('foo', 'default')
-'baz'
+u'baz'
>>> q.getlist('foo')
-['bar', 'baz']
+[u'bar', u'baz']
>>> q.appendlist('foo', 'another')
>>> q.getlist('foo')
-['bar', 'baz', 'another']
+[u'bar', u'baz', u'another']
>>> q['foo']
-'another'
+u'another'
>>> q.has_key('foo')
True
@@ -137,16 +137,16 @@ True
True
>>> q.items()
-[('foo', 'another'), ('name', 'john')]
+[(u'foo', u'another'), (u'name', u'john')]
>>> q.lists()
-[('foo', ['bar', 'baz', 'another']), ('name', ['john'])]
+[(u'foo', [u'bar', u'baz', u'another']), (u'name', [u'john'])]
>>> q.keys()
-['foo', 'name']
+[u'foo', u'name']
>>> q.values()
-['another', 'john']
+[u'another', u'john']
>>> len(q)
2
@@ -155,16 +155,16 @@ True
# Displays last value
>>> q['foo']
-'hello'
+u'hello'
>>> q.get('foo', 'not available')
-'hello'
+u'hello'
>>> q.getlist('foo')
-['bar', 'baz', 'another', 'hello']
+[u'bar', u'baz', u'another', u'hello']
>>> q.pop('foo')
-['bar', 'baz', 'another', 'hello']
+[u'bar', u'baz', u'another', u'hello']
>>> q.pop('foo', 'not there')
'not there'
@@ -173,13 +173,13 @@ True
'not there'
>>> q.setdefault('foo', 'bar')
-'bar'
+u'bar'
>>> q['foo']
-'bar'
+u'bar'
>>> q.getlist('foo')
-['bar']
+[u'bar']
>>> q.urlencode()
'foo=bar&name=john'
@@ -196,12 +196,12 @@ True
>>> q = QueryDict('foo=bar')
>>> q['foo']
-'bar'
+u'bar'
>>> q['bar']
Traceback (most recent call last):
...
-MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {'foo': ['bar']}>"
+MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {u'foo': [u'bar']}>"
>>> q['something'] = 'bar'
Traceback (most recent call last):
@@ -209,13 +209,13 @@ Traceback (most recent call last):
AttributeError: This QueryDict instance is immutable
>>> q.get('foo', 'default')
-'bar'
+u'bar'
>>> q.get('bar', 'default')
'default'
>>> q.getlist('foo')
-['bar']
+[u'bar']
>>> q.getlist('bar')
[]
@@ -243,16 +243,16 @@ False
False
>>> q.items()
-[('foo', 'bar')]
+[(u'foo', u'bar')]
>>> q.lists()
-[('foo', ['bar'])]
+[(u'foo', [u'bar'])]
>>> q.keys()
-['foo']
+[u'foo']
>>> q.values()
-['bar']
+[u'bar']
>>> len(q)
1
@@ -292,7 +292,7 @@ AttributeError: This QueryDict instance is immutable
>>> q = QueryDict('vote=yes&vote=no')
>>> q['vote']
-'no'
+u'no'
>>> q['something'] = 'bar'
Traceback (most recent call last):
@@ -300,13 +300,13 @@ Traceback (most recent call last):
AttributeError: This QueryDict instance is immutable
>>> q.get('vote', 'default')
-'no'
+u'no'
>>> q.get('foo', 'default')
'default'
>>> q.getlist('vote')
-['yes', 'no']
+[u'yes', u'no']
>>> q.getlist('foo')
[]
@@ -334,16 +334,16 @@ False
False
>>> q.items()
-[('vote', 'no')]
+[(u'vote', u'no')]
>>> q.lists()
-[('vote', ['yes', 'no'])]
+[(u'vote', [u'yes', u'no'])]
>>> q.keys()
-['vote']
+[u'vote']
>>> q.values()
-['no']
+[u'no']
>>> len(q)
1
@@ -381,6 +381,16 @@ Traceback (most recent call last):
...
AttributeError: This QueryDict instance is immutable
+# QueryDicts must be able to handle invalid input encoding (in this case, bad
+# UTF-8 encoding).
+>>> q = QueryDict('foo=bar&foo=\xff')
+
+>>> q['foo']
+u'\ufffd'
+
+>>> q.getlist('foo')
+[u'bar', u'\ufffd']
+
"""
from django.http import QueryDict
diff --git a/tests/regressiontests/humanize/tests.py b/tests/regressiontests/humanize/tests.py
index eca65f7575..196488ba6e 100644
--- a/tests/regressiontests/humanize/tests.py
+++ b/tests/regressiontests/humanize/tests.py
@@ -1,5 +1,8 @@
import unittest
+from datetime import timedelta, date
from django.template import Template, Context, add_to_builtins
+from django.utils.dateformat import DateFormat
+from django.utils.translation import ugettext as _
add_to_builtins('django.contrib.humanize.templatetags.humanize')
@@ -8,14 +11,13 @@ class HumanizeTests(unittest.TestCase):
def humanize_tester(self, test_list, result_list, method):
# Using max below ensures we go through both lists
# However, if the lists are not equal length, this raises an exception
- for index in xrange(len(max(test_list,result_list))):
+ for index in xrange(max(len(test_list), len(result_list))):
test_content = test_list[index]
t = Template('{{ test_content|%s }}' % method)
rendered = t.render(Context(locals())).strip()
self.assertEqual(rendered, result_list[index],
- msg="""%s test failed, produced %s,
-should've produced %s""" % (method, rendered, result_list[index]))
-
+ msg="%s test failed, produced %s, should've produced %s" % (method, rendered, result_list[index]))
+
def test_ordinal(self):
test_list = ('1','2','3','4','11','12',
'13','101','102','103','111',
@@ -43,12 +45,26 @@ should've produced %s""" % (method, rendered, result_list[index]))
self.humanize_tester(test_list, result_list, 'intword')
def test_apnumber(self):
- test_list = [str(x) for x in xrange(1,11)]
- result_list = ('one', 'two', 'three', 'four', 'five', 'six',
- 'seven', 'eight', 'nine', '10')
+ test_list = [str(x) for x in range(1, 11)]
+ result_list = (u'one', u'two', u'three', u'four', u'five', u'six',
+ u'seven', u'eight', u'nine', u'10')
self.humanize_tester(test_list, result_list, 'apnumber')
+ def test_naturalday(self):
+ from django.template import defaultfilters
+ today = date.today()
+ yesterday = today - timedelta(days=1)
+ tomorrow = today + timedelta(days=1)
+ someday = today - timedelta(days=10)
+ notdate = u"I'm not a date value"
+
+ test_list = (today, yesterday, tomorrow, someday, notdate)
+ someday_result = defaultfilters.date(someday)
+ result_list = (_(u'today'), _(u'yesterday'), _(u'tomorrow'),
+ someday_result, u"I'm not a date value")
+ self.humanize_tester(test_list, result_list, 'naturalday')
+
if __name__ == '__main__':
unittest.main()
-
+
diff --git a/tests/regressiontests/i18n/__init__.py b/tests/regressiontests/i18n/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/i18n/__init__.py
diff --git a/tests/regressiontests/i18n/models.py b/tests/regressiontests/i18n/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/i18n/models.py
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
new file mode 100644
index 0000000000..8a7d2bee3e
--- /dev/null
+++ b/tests/regressiontests/i18n/tests.py
@@ -0,0 +1,33 @@
+# coding: utf-8
+
+ur"""
+Format string interpolation should work with *_lazy objects.
+
+>>> from django.utils.translation import ugettext_lazy, activate, deactivate, gettext_lazy
+>>> s = ugettext_lazy('Add %(name)s')
+>>> d = {'name': 'Ringo'}
+>>> s % d
+u'Add Ringo'
+>>> activate('de')
+>>> s % d
+u'Ringo hinzuf\xfcgen'
+>>> activate('pl')
+>>> s % d
+u'Dodaj Ringo'
+>>> deactivate()
+
+It should be possible to compare *_lazy objects.
+
+>>> s1 = ugettext_lazy('Add %(name)s')
+>>> s == s1
+True
+>>> s2 = gettext_lazy('Add %(name)s')
+>>> s3 = gettext_lazy('Add %(name)s')
+>>> s2 == s3
+True
+>>> s == s2
+True
+>>> s4 = ugettext_lazy('Some other string')
+>>> s == s4
+False
+"""
diff --git a/tests/regressiontests/initial_sql_regress/models.py b/tests/regressiontests/initial_sql_regress/models.py
index dedbba8e5c..7cf725991a 100644
--- a/tests/regressiontests/initial_sql_regress/models.py
+++ b/tests/regressiontests/initial_sql_regress/models.py
@@ -5,7 +5,7 @@ Regression tests for initial SQL insertion.
from django.db import models
class Simple(models.Model):
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length = 50)
__test__ = {'API_TESTS':""}
diff --git a/tests/regressiontests/invalid_admin_options/models.py b/tests/regressiontests/invalid_admin_options/models.py
index 43bcc533ba..14db463735 100644
--- a/tests/regressiontests/invalid_admin_options/models.py
+++ b/tests/regressiontests/invalid_admin_options/models.py
@@ -12,7 +12,7 @@ model_errors = ""
##This should fail gracefully but is causing a metaclass error
#class BadAdminOption(models.Model):
# "Test nonexistent admin option"
-# name = models.CharField(maxlength=30)
+# name = models.CharField(max_length=30)
#
# class Admin:
# nonexistent = 'option'
@@ -22,7 +22,7 @@ model_errors = ""
class ListDisplayBadOne(models.Model):
"Test list_display, list_display must be a list or tuple"
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
class Admin:
list_display = 'first_name'
@@ -32,7 +32,7 @@ model_errors += """invalid_admin_options.listdisplaybadone: "admin.list_display"
class ListDisplayBadTwo(models.Model):
"Test list_display, list_display items must be attributes, methods or properties."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
class Admin:
list_display = ['first_name','nonexistent']
@@ -41,7 +41,7 @@ model_errors += """invalid_admin_options.listdisplaybadtwo: "admin.list_display"
"""
class ListDisplayBadThree(models.Model):
"Test list_display, list_display items can not be a ManyToManyField."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
nick_names = models.ManyToManyField('ListDisplayGood')
class Admin:
@@ -52,7 +52,7 @@ model_errors += """invalid_admin_options.listdisplaybadthree: "admin.list_displa
class ListDisplayGood(models.Model):
"Test list_display, Admin list_display can be a attribute, method or property."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
def _last_name(self):
return self.first_name
@@ -66,8 +66,8 @@ class ListDisplayGood(models.Model):
class ListDisplayLinksBadOne(models.Model):
"Test list_display_links, item must be included in list_display."
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
list_display = ['last_name']
@@ -78,8 +78,8 @@ model_errors += """invalid_admin_options.listdisplaylinksbadone: "admin.list_dis
class ListDisplayLinksBadTwo(models.Model):
"Test list_display_links, must be a list or tuple."
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
list_display = ['first_name','last_name']
@@ -92,8 +92,8 @@ model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "admin.list_dis
## This is failing but the validation which should fail is not.
#class ListDisplayLinksBadThree(models.Model):
# "Test list_display_links, must define list_display to use list_display_links."
-# first_name = models.CharField(maxlength=30)
-# last_name = models.CharField(maxlength=30)
+# first_name = models.CharField(max_length=30)
+# last_name = models.CharField(max_length=30)
#
# class Admin:
# list_display_links = ('first_name',)
@@ -103,7 +103,7 @@ model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "admin.list_dis
class ListDisplayLinksGood(models.Model):
"Test list_display_links, Admin list_display_list can be a attribute, method or property."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
def _last_name(self):
return self.first_name
@@ -118,7 +118,7 @@ class ListDisplayLinksGood(models.Model):
class ListFilterBadOne(models.Model):
"Test list_filter, must be a list or tuple."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
class Admin:
list_filter = 'first_name'
@@ -128,7 +128,7 @@ model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter",
class ListFilterBadTwo(models.Model):
"Test list_filter, must be a field not a property or method."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
def _last_name(self):
return self.first_name
@@ -146,7 +146,7 @@ invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name
class DateHierarchyBadOne(models.Model):
"Test date_hierarchy, must be a date or datetime field."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
birth_day = models.DateField()
class Admin:
@@ -158,7 +158,7 @@ class DateHierarchyBadOne(models.Model):
class DateHierarchyBadTwo(models.Model):
"Test date_hieracrhy, must be a field."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
birth_day = models.DateField()
class Admin:
@@ -169,7 +169,7 @@ model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierar
class DateHierarchyGood(models.Model):
"Test date_hieracrhy, must be a field."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
birth_day = models.DateField()
class Admin:
@@ -177,7 +177,7 @@ class DateHierarchyGood(models.Model):
class SearchFieldsBadOne(models.Model):
"Test search_fields, must be a list or tuple."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
class Admin:
search_fields = ('nonexistent')
@@ -188,7 +188,7 @@ class SearchFieldsBadOne(models.Model):
class SearchFieldsBadTwo(models.Model):
"Test search_fields, must be a field."
- first_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
def _last_name(self):
return self.first_name
@@ -203,8 +203,8 @@ class SearchFieldsBadTwo(models.Model):
class SearchFieldsGood(models.Model):
"Test search_fields, must be a list or tuple."
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
search_fields = ['first_name','last_name']
@@ -212,7 +212,7 @@ class SearchFieldsGood(models.Model):
class JsBadOne(models.Model):
"Test js, must be a list or tuple"
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
class Admin:
js = 'test.js'
@@ -223,7 +223,7 @@ class JsBadOne(models.Model):
class SaveAsBad(models.Model):
"Test save_as, should be True or False"
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
class Admin:
save_as = 'not True or False'
@@ -234,7 +234,7 @@ class SaveAsBad(models.Model):
class SaveOnTopBad(models.Model):
"Test save_on_top, should be True or False"
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
class Admin:
save_on_top = 'not True or False'
@@ -245,7 +245,7 @@ class SaveOnTopBad(models.Model):
class ListSelectRelatedBad(models.Model):
"Test list_select_related, should be True or False"
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
class Admin:
list_select_related = 'not True or False'
@@ -256,7 +256,7 @@ class ListSelectRelatedBad(models.Model):
class ListPerPageBad(models.Model):
"Test list_per_page, should be a positive integer value."
- name = models.CharField(maxlength=30)
+ name = models.CharField(max_length=30)
class Admin:
list_per_page = 89.3
@@ -267,8 +267,8 @@ class ListPerPageBad(models.Model):
class FieldsBadOne(models.Model):
"Test fields, should be a tuple"
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
fields = 'not a tuple'
@@ -279,8 +279,8 @@ class FieldsBadOne(models.Model):
class FieldsBadTwo(models.Model):
"""Test fields, 'fields' dict option is required."""
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
fields = ('Name', {'description': 'this fieldset needs fields'})
@@ -291,8 +291,8 @@ class FieldsBadTwo(models.Model):
class FieldsBadThree(models.Model):
"""Test fields, 'classes' and 'description' are the only allowable extra dict options."""
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'})
@@ -303,8 +303,8 @@ class FieldsBadThree(models.Model):
class FieldsGood(models.Model):
"Test fields, working example"
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
birth_day = models.DateField()
class Admin:
@@ -315,8 +315,8 @@ class FieldsGood(models.Model):
class OrderingBad(models.Model):
"Test ordering, must be a field."
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=30)
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
class Admin:
ordering = 'nonexistent'
@@ -328,7 +328,7 @@ class OrderingBad(models.Model):
## TODO: Add a manager validator, this should fail gracefully.
#class ManagerBad(models.Model):
# "Test manager, must be a manager object."
-# first_name = models.CharField(maxlength=30)
+# first_name = models.CharField(max_length=30)
#
# class Admin:
# manager = 'nonexistent'
diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py
index 8ddec98da4..57bbcd8489 100644
--- a/tests/regressiontests/many_to_one_regress/models.py
+++ b/tests/regressiontests/many_to_one_regress/models.py
@@ -12,15 +12,15 @@ class Second(models.Model):
# Protect against repetition of #1839, #2415 and #2536.
class Third(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
third = models.ForeignKey('self', null=True, related_name='child_set')
class Parent(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
bestchild = models.ForeignKey('Child', null=True, related_name='favored_by')
class Child(models.Model):
- name = models.CharField(maxlength=20)
+ name = models.CharField(max_length=20)
parent = models.ForeignKey(Parent)
diff --git a/tests/regressiontests/maxlength/__init__.py b/tests/regressiontests/maxlength/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/maxlength/__init__.py
diff --git a/tests/regressiontests/maxlength/models.py b/tests/regressiontests/maxlength/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/maxlength/models.py
diff --git a/tests/regressiontests/maxlength/tests.py b/tests/regressiontests/maxlength/tests.py
new file mode 100644
index 0000000000..8a5f874c78
--- /dev/null
+++ b/tests/regressiontests/maxlength/tests.py
@@ -0,0 +1,160 @@
+# Test access to max_length while still providing full backwards compatibility
+# with legacy maxlength attribute.
+"""
+
+Don't print out the deprecation warnings during testing.
+>>> from warnings import filterwarnings
+>>> filterwarnings("ignore")
+
+# legacy_maxlength function
+
+>>> from django.utils.maxlength import legacy_maxlength
+
+>>> legacy_maxlength(None, None)
+
+
+>>> legacy_maxlength(10, None)
+10
+
+>>> legacy_maxlength(None, 10)
+10
+
+>>> legacy_maxlength(10, 12)
+Traceback (most recent call last):
+...
+TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+
+>>> legacy_maxlength(0, 10)
+Traceback (most recent call last):
+...
+TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+
+>>> legacy_maxlength(0, None)
+0
+
+>>> legacy_maxlength(None, 0)
+0
+
+#===============================================================================
+# Fields
+#===============================================================================
+
+# Set up fields
+>>> from django.db.models import fields
+>>> new = fields.Field(max_length=15)
+>>> old = fields.Field(maxlength=10)
+
+# Ensure both max_length and legacy maxlength are not able to both be specified
+>>> fields.Field(maxlength=10, max_length=15)
+Traceback (most recent call last):
+ ...
+TypeError: field can not take both the max_length argument and the legacy maxlength argument.
+
+# Test max_length
+>>> new.max_length
+15
+>>> old.max_length
+10
+
+# Test accessing maxlength
+>>> new.maxlength
+15
+>>> old.maxlength
+10
+
+# Test setting maxlength
+>>> new.maxlength += 1
+>>> old.maxlength += 1
+>>> new.max_length
+16
+>>> old.max_length
+11
+
+# SlugField __init__ passes through max_length so test that too
+>>> fields.SlugField('new', max_length=15).max_length
+15
+>>> fields.SlugField('empty').max_length
+50
+>>> fields.SlugField('old', maxlength=10).max_length
+10
+
+#===============================================================================
+# (old)forms
+#===============================================================================
+
+>>> from django import oldforms
+
+# Test max_length attribute
+
+>>> oldforms.TextField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vTextField" name="new" size="30" value="" maxlength="15" />'
+
+>>> oldforms.IntegerField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vIntegerField" name="new" size="10" value="" maxlength="15" />'
+
+>>> oldforms.SmallIntegerField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vSmallIntegerField" name="new" size="5" value="" maxlength="15" />'
+
+>>> oldforms.PositiveIntegerField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vPositiveIntegerField" name="new" size="10" value="" maxlength="15" />'
+
+>>> oldforms.PositiveSmallIntegerField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vPositiveSmallIntegerField" name="new" size="5" value="" maxlength="15" />'
+
+>>> oldforms.DatetimeField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vDatetimeField" name="new" size="30" value="" maxlength="15" />'
+
+>>> oldforms.EmailField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vEmailField" name="new" size="50" value="" maxlength="15" />'
+>>> oldforms.EmailField('new').render('')
+u'<input type="text" id="id_new" class="vEmailField" name="new" size="50" value="" maxlength="75" />'
+
+>>> oldforms.URLField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vURLField" name="new" size="50" value="" maxlength="15" />'
+>>> oldforms.URLField('new').render('')
+u'<input type="text" id="id_new" class="vURLField" name="new" size="50" value="" maxlength="200" />'
+
+>>> oldforms.IPAddressField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vIPAddressField" name="new" size="15" value="" maxlength="15" />'
+>>> oldforms.IPAddressField('new').render('')
+u'<input type="text" id="id_new" class="vIPAddressField" name="new" size="15" value="" maxlength="15" />'
+
+>>> oldforms.CommaSeparatedIntegerField('new', max_length=15).render('')
+u'<input type="text" id="id_new" class="vCommaSeparatedIntegerField" name="new" size="20" value="" maxlength="15" />'
+
+
+# Test legacy maxlength attribute
+
+>>> oldforms.TextField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vTextField" name="old" size="30" value="" maxlength="10" />'
+
+>>> oldforms.IntegerField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vIntegerField" name="old" size="10" value="" maxlength="10" />'
+
+>>> oldforms.SmallIntegerField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vSmallIntegerField" name="old" size="5" value="" maxlength="10" />'
+
+>>> oldforms.PositiveIntegerField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vPositiveIntegerField" name="old" size="10" value="" maxlength="10" />'
+
+>>> oldforms.PositiveSmallIntegerField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vPositiveSmallIntegerField" name="old" size="5" value="" maxlength="10" />'
+
+>>> oldforms.DatetimeField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vDatetimeField" name="old" size="30" value="" maxlength="10" />'
+
+>>> oldforms.EmailField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vEmailField" name="old" size="50" value="" maxlength="10" />'
+
+>>> oldforms.URLField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vURLField" name="old" size="50" value="" maxlength="10" />'
+
+>>> oldforms.IPAddressField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vIPAddressField" name="old" size="15" value="" maxlength="10" />'
+
+>>> oldforms.CommaSeparatedIntegerField('old', maxlength=10).render('')
+u'<input type="text" id="id_old" class="vCommaSeparatedIntegerField" name="old" size="20" value="" maxlength="10" />'
+"""
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod()
diff --git a/tests/regressiontests/model_fields/__init__.py b/tests/regressiontests/model_fields/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/model_fields/__init__.py
diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/model_fields/models.py
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
new file mode 100644
index 0000000000..e279a0669f
--- /dev/null
+++ b/tests/regressiontests/model_fields/tests.py
@@ -0,0 +1,18 @@
+"""
+>>> from django.db.models.fields import *
+
+# DecimalField
+
+>>> f = DecimalField()
+
+>>> f.to_python(3)
+Decimal("3")
+
+>>> f.to_python("3.14")
+Decimal("3.14")
+
+>>> f.to_python("abc")
+Traceback (most recent call last):
+...
+ValidationError: [u'This value must be a decimal number.']
+"""
diff --git a/tests/regressiontests/model_regress/__init__.py b/tests/regressiontests/model_regress/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/model_regress/__init__.py
diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py
new file mode 100644
index 0000000000..7aa9e2a7c4
--- /dev/null
+++ b/tests/regressiontests/model_regress/models.py
@@ -0,0 +1,40 @@
+# coding: utf-8
+from django.db import models
+
+CHOICES = (
+ (1, 'first'),
+ (2, 'second'),
+)
+
+class Article(models.Model):
+ headline = models.CharField(max_length=100, default='Default headline')
+ pub_date = models.DateTimeField()
+ status = models.IntegerField(blank=True, null=True, choices=CHOICES)
+ misc_data = models.CharField(max_length=100, blank=True)
+
+ class Meta:
+ ordering = ('pub_date','headline')
+ # A utf-8 verbose name (Ångström's Articles) to test they are valid.
+ verbose_name = "\xc3\x85ngstr\xc3\xb6m's Articles"
+
+ def __unicode__(self):
+ return self.headline
+
+__test__ = {'API_TESTS': """
+(NOTE: Part of the regression test here is merely parsing the model
+declaration. The verbose_name, in particular, did not always work.)
+
+An empty choice field should return None for the display name.
+
+>>> from datetime import datetime
+>>> a = Article(headline="Look at me!", pub_date=datetime.now())
+>>> a.save()
+>>> a.get_status_display() is None
+True
+
+Empty strings should be returned as Unicode
+>>> a2 = Article.objects.get(pk=a.id)
+>>> a2.misc_data
+u''
+"""
+}
diff --git a/tests/regressiontests/null_queries/models.py b/tests/regressiontests/null_queries/models.py
index 21944d9e7a..2aa36b2c1a 100644
--- a/tests/regressiontests/null_queries/models.py
+++ b/tests/regressiontests/null_queries/models.py
@@ -1,17 +1,17 @@
from django.db import models
class Poll(models.Model):
- question = models.CharField(maxlength=200)
+ question = models.CharField(max_length=200)
- def __str__(self):
- return "Q: %s " % self.question
+ def __unicode__(self):
+ return u"Q: %s " % self.question
class Choice(models.Model):
poll = models.ForeignKey(Poll)
- choice = models.CharField(maxlength=200)
+ choice = models.CharField(max_length=200)
- def __str__(self):
- return "Choice: %s in poll %s" % (self.choice, self.poll)
+ def __unicode__(self):
+ return u"Choice: %s in poll %s" % (self.choice, self.poll)
__test__ = {'API_TESTS':"""
# Regression test for the use of None as a query value. None is interpreted as
diff --git a/tests/regressiontests/one_to_one_regress/models.py b/tests/regressiontests/one_to_one_regress/models.py
index b81f4266e1..c5ffd3fb3c 100644
--- a/tests/regressiontests/one_to_one_regress/models.py
+++ b/tests/regressiontests/one_to_one_regress/models.py
@@ -1,26 +1,26 @@
from django.db import models
class Place(models.Model):
- name = models.CharField(maxlength=50)
- address = models.CharField(maxlength=80)
+ name = models.CharField(max_length=50)
+ address = models.CharField(max_length=80)
- def __str__(self):
- return "%s the place" % self.name
+ def __unicode__(self):
+ return u"%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __str__(self):
- return "%s the restaurant" % self.place.name
+ def __unicode__(self):
+ return u"%s the restaurant" % self.place.name
class Favorites(models.Model):
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length = 50)
restaurants = models.ManyToManyField(Restaurant)
- def __str__(self):
- return "Favorites for %s" % self.name
+ def __unicode__(self):
+ return u"Favorites for %s" % self.name
__test__ = {'API_TESTS':"""
# Regression test for #1064 and #1506: Check that we create models via the m2m
diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py
index b441885f10..e9df508822 100644
--- a/tests/regressiontests/serializers_regress/models.py
+++ b/tests/regressiontests/serializers_regress/models.py
@@ -16,7 +16,7 @@ class BooleanData(models.Model):
data = models.BooleanField(null=True)
class CharData(models.Model):
- data = models.CharField(maxlength=30, null=True)
+ data = models.CharField(max_length=30, null=True)
class DateData(models.Model):
data = models.DateField(null=True)
@@ -90,7 +90,7 @@ class Tag(models.Model):
ordering = ["data"]
class GenericData(models.Model):
- data = models.CharField(maxlength=30)
+ data = models.CharField(max_length=30)
tags = generic.GenericRelation(Tag)
@@ -102,13 +102,13 @@ class Anchor(models.Model):
"""This is a model that can be used as
something for other models to point at"""
- data = models.CharField(maxlength=30)
+ data = models.CharField(max_length=30)
class UniqueAnchor(models.Model):
"""This is a model that can be used as
something for other models to point at"""
- data = models.CharField(unique=True, maxlength=30)
+ data = models.CharField(unique=True, max_length=30)
class FKData(models.Model):
data = models.ForeignKey(Anchor, null=True)
@@ -117,7 +117,8 @@ class M2MData(models.Model):
data = models.ManyToManyField(Anchor, null=True)
class O2OData(models.Model):
- data = models.OneToOneField(Anchor, null=True)
+ # One to one field can't be null, since it is a PK.
+ data = models.OneToOneField(Anchor)
class FKSelfData(models.Model):
data = models.ForeignKey('self', null=True)
@@ -143,7 +144,7 @@ class BooleanPKData(models.Model):
data = models.BooleanField(primary_key=True)
class CharPKData(models.Model):
- data = models.CharField(maxlength=30, primary_key=True)
+ data = models.CharField(max_length=30, primary_key=True)
# class DatePKData(models.Model):
# data = models.DateField(primary_key=True)
@@ -175,8 +176,9 @@ class IntegerPKData(models.Model):
class IPAddressPKData(models.Model):
data = models.IPAddressField(primary_key=True)
-class NullBooleanPKData(models.Model):
- data = models.NullBooleanField(primary_key=True)
+# This is just a Boolean field with null=True, and we can't test a PK value of NULL.
+# class NullBooleanPKData(models.Model):
+# data = models.NullBooleanField(primary_key=True)
class PhonePKData(models.Model):
data = models.PhoneNumberField(primary_key=True)
@@ -206,6 +208,19 @@ class USStatePKData(models.Model):
# data = models.XMLField(primary_key=True)
class ComplexModel(models.Model):
- field1 = models.CharField(maxlength=10)
- field2 = models.CharField(maxlength=10)
- field3 = models.CharField(maxlength=10)
+ field1 = models.CharField(max_length=10)
+ field2 = models.CharField(max_length=10)
+ field3 = models.CharField(max_length=10)
+
+# Tests for handling fields with pre_save functions, or
+# models with save functions that modify data
+class AutoNowDateTimeData(models.Model):
+ data = models.DateTimeField(null=True, auto_now=True)
+
+class ModifyingSaveData(models.Model):
+ data = models.IntegerField(null=True)
+
+ def save(self):
+ "A save method that modifies the data in the object"
+ self.data = 666
+ super(ModifyingSaveData, self).save(raw)
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
index febcfa822e..24111308d7 100644
--- a/tests/regressiontests/serializers_regress/tests.py
+++ b/tests/regressiontests/serializers_regress/tests.py
@@ -24,17 +24,20 @@ except ImportError:
from django.utils import _decimal as decimal
# A set of functions that can be used to recreate
-# test data objects of various kinds
+# test data objects of various kinds.
+# The save method is a raw base model save, to make
+# sure that the data in the database matches the
+# exact test case.
def data_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data
- instance.save()
+ models.Model.save(instance, raw=True)
return instance
def generic_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data[0]
- instance.save()
+ models.Model.save(instance, raw=True)
for tag in data[1:]:
instance.tags.create(data=tag)
return instance
@@ -42,25 +45,25 @@ def generic_create(pk, klass, data):
def fk_create(pk, klass, data):
instance = klass(id=pk)
setattr(instance, 'data_id', data)
- instance.save()
+ models.Model.save(instance, raw=True)
return instance
def m2m_create(pk, klass, data):
instance = klass(id=pk)
- instance.save()
+ models.Model.save(instance, raw=True)
instance.data = data
return instance
def o2o_create(pk, klass, data):
instance = klass()
instance.data_id = data
- instance.save()
+ models.Model.save(instance, raw=True)
return instance
def pk_create(pk, klass, data):
instance = klass()
instance.data = data
- instance.save()
+ models.Model.save(instance, raw=True)
return instance
# A set of functions that can be used to compare
@@ -111,6 +114,9 @@ test_data = [
(data_obj, 13, CharData, "null"),
(data_obj, 14, CharData, "NULL"),
(data_obj, 15, CharData, None),
+ # (We use something that will fit into a latin1 database encoding here,
+ # because that is still the default used on many system setups.)
+ (data_obj, 16, CharData, u'\xa5'),
(data_obj, 20, DateData, datetime.date(2006,6,16)),
(data_obj, 21, DateData, None),
(data_obj, 30, DateTimeData, datetime.datetime(2006,6,16,10,42,37)),
@@ -230,8 +236,8 @@ The end."""),
(pk_obj, 682, IntegerPKData, 0),
# (XX, ImagePKData
(pk_obj, 690, IPAddressPKData, "127.0.0.1"),
- (pk_obj, 700, NullBooleanPKData, True),
- (pk_obj, 701, NullBooleanPKData, False),
+ # (pk_obj, 700, NullBooleanPKData, True),
+ # (pk_obj, 701, NullBooleanPKData, False),
(pk_obj, 710, PhonePKData, "212-634-5789"),
(pk_obj, 720, PositiveIntegerPKData, 123456789),
(pk_obj, 730, PositiveSmallIntegerPKData, 12),
@@ -246,6 +252,9 @@ The end."""),
# (pk_obj, 770, TimePKData, datetime.time(10,42,37)),
(pk_obj, 780, USStatePKData, "MA"),
# (pk_obj, 790, XMLPKData, "<foo></foo>"),
+
+ (data_obj, 800, AutoNowDateTimeData, datetime.datetime(2006,6,16,10,42,37)),
+ (data_obj, 810, ModifyingSaveData, 42),
]
# Because Oracle treats the empty string as NULL, Oracle is expected to fail
@@ -264,7 +273,7 @@ class SerializerTests(unittest.TestCase):
def serializerTest(format, self):
# Clear the database first
- management.flush(verbosity=0, interactive=False)
+ management.call_command('flush', verbosity=0, interactive=False)
# Create all the objects defined in the test data
objects = []
@@ -282,7 +291,7 @@ def serializerTest(format, self):
serialized_data = serializers.serialize(format, objects, indent=2)
# Flush the database and recreate from the serialized data
- management.flush(verbosity=0, interactive=False)
+ management.call_command('flush', verbosity=0, interactive=False)
transaction.enter_transaction_management()
transaction.managed(True)
for obj in serializers.deserialize(format, serialized_data):
@@ -297,10 +306,10 @@ def serializerTest(format, self):
def fieldsTest(format, self):
# Clear the database first
- management.flush(verbosity=0, interactive=False)
+ management.call_command('flush', verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
- obj.save()
+ obj.save(raw=True)
# Serialize then deserialize the test database
serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3'))
@@ -313,10 +322,10 @@ def fieldsTest(format, self):
def streamTest(format, self):
# Clear the database first
- management.flush(verbosity=0, interactive=False)
+ management.call_command('flush', verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
- obj.save()
+ obj.save(raw=True)
# Serialize the test database to a stream
stream = StringIO()
diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py
index 441bb3f8a3..12ebd0cf07 100644
--- a/tests/regressiontests/string_lookup/models.py
+++ b/tests/regressiontests/string_lookup/models.py
@@ -1,46 +1,55 @@
+# -*- coding: utf-8 -*-
from django.db import models
class Foo(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
+ friend = models.CharField(max_length=50, blank=True)
- def __str__(self):
+ def __unicode__(self):
return "Foo %s" % self.name
class Bar(models.Model):
- name = models.CharField(maxlength=50)
+ name = models.CharField(max_length=50)
normal = models.ForeignKey(Foo, related_name='normal_foo')
fwd = models.ForeignKey("Whiz")
back = models.ForeignKey("Foo")
- def __str__(self):
+ def __unicode__(self):
return "Bar %s" % self.place.name
class Whiz(models.Model):
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length = 50)
- def __str__(self):
+ def __unicode__(self):
return "Whiz %s" % self.name
class Child(models.Model):
parent = models.OneToOneField('Base')
- name = models.CharField(maxlength = 50)
+ name = models.CharField(max_length = 50)
- def __str__(self):
+ def __unicode__(self):
return "Child %s" % self.name
-
+
class Base(models.Model):
+ name = models.CharField(max_length = 50)
+
+ def __unicode__(self):
+ return "Base %s" % self.name
+
+class Article(models.Model):
name = models.CharField(maxlength = 50)
+ text = models.TextField()
def __str__(self):
- return "Base %s" % self.name
+ return "Article %s" % self.name
-__test__ = {'API_TESTS':"""
-# Regression test for #1661 and #1662: Check that string form referencing of models works,
-# both as pre and post reference, on all RelatedField types.
+__test__ = {'API_TESTS': ur"""
+# Regression test for #1661 and #1662: Check that string form referencing of
+# models works, both as pre and post reference, on all RelatedField types.
>>> f1 = Foo(name="Foo1")
>>> f1.save()
->>> f2 = Foo(name="Foo1")
+>>> f2 = Foo(name="Foo2")
>>> f2.save()
>>> w1 = Whiz(name="Whiz1")
@@ -56,7 +65,7 @@ __test__ = {'API_TESTS':"""
<Whiz: Whiz Whiz1>
>>> b1.back
-<Foo: Foo Foo1>
+<Foo: Foo Foo2>
>>> base1 = Base(name="Base1")
>>> base1.save()
@@ -66,4 +75,27 @@ __test__ = {'API_TESTS':"""
>>> child1.parent
<Base: Base Base1>
+
+# Regression tests for #3937: make sure we can use unicode characters in
+# queries.
+# BUG: These tests fail on MySQL, but it's a problem with the test setup. A
+# properly configured UTF-8 database can handle this.
+
+>>> fx = Foo(name='Bjorn', friend=u'François')
+>>> fx.save()
+>>> Foo.objects.get(friend__contains=u'\xe7')
+<Foo: Foo Bjorn>
+
+# We can also do the above query using UTF-8 strings.
+>>> Foo.objects.get(friend__contains='\xc3\xa7')
+<Foo: Foo Bjorn>
+
+# Regression tests for #5087: make sure we can perform queries on TextFields.
+>>> a = Article(name='Test', text='The quick brown fox jumps over the lazy dog.')
+>>> a.save()
+>>> Article.objects.get(text__exact='The quick brown fox jumps over the lazy dog.')
+<Article: Article Test>
+
+>>> Article.objects.get(text__contains='quick brown fox')
+<Article: Article Test>
"""}
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 8801100bcc..0f7ac2f352 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -6,12 +6,22 @@ if __name__ == '__main__':
# before importing 'template'.
settings.configure()
+import os
+import unittest
+from datetime import datetime, timedelta
+
from django import template
from django.template import loader
-from django.utils.translation import activate, deactivate, install
+from django.template.loaders import app_directories, filesystem
+from django.utils.translation import activate, deactivate, install, ugettext as _
from django.utils.tzinfo import LocalTimezone
-from datetime import datetime, timedelta
-import unittest
+
+from unicode import unicode_tests
+
+# Some other tests we would like to run
+__test__ = {
+ 'unicode': unicode_tests,
+}
#################################
# Custom template tag for tests #
@@ -63,12 +73,52 @@ class OtherClass:
def method(self):
return "OtherClass.method"
-class UnicodeInStrClass:
- "Class whose __str__ returns a Unicode object."
+class UTF8Class:
+ "Class whose __str__ returns non-ASCII data"
def __str__(self):
- return u'ŠĐĆŽćžšđ'
+ return u'ŠĐĆŽćžšđ'.encode('utf-8')
class Templates(unittest.TestCase):
+ def test_loaders_security(self):
+ def test_template_sources(path, template_dirs, expected_sources):
+ # Fix expected sources so they are normcased and abspathed
+ expected_sources = [os.path.normcase(os.path.abspath(s)) for s in expected_sources]
+ # Test app_directories loader
+ sources = app_directories.get_template_sources(path, template_dirs)
+ self.assertEqual(list(sources), expected_sources)
+ # Test filesystem loader
+ sources = filesystem.get_template_sources(path, template_dirs)
+ self.assertEqual(list(sources), expected_sources)
+
+ template_dirs = ['/dir1', '/dir2']
+ test_template_sources('index.html', template_dirs,
+ ['/dir1/index.html', '/dir2/index.html'])
+ test_template_sources('/etc/passwd', template_dirs,
+ [])
+ test_template_sources('etc/passwd', template_dirs,
+ ['/dir1/etc/passwd', '/dir2/etc/passwd'])
+ test_template_sources('../etc/passwd', template_dirs,
+ [])
+ test_template_sources('../../../etc/passwd', template_dirs,
+ [])
+ test_template_sources('/dir1/index.html', template_dirs,
+ ['/dir1/index.html'])
+ test_template_sources('../dir2/index.html', template_dirs,
+ ['/dir2/index.html'])
+ test_template_sources('/dir1blah', template_dirs,
+ [])
+ test_template_sources('../dir1blah', template_dirs,
+ [])
+
+ # Case insensitive tests (for win32). Not run unless we're on
+ # a case insensitive operating system.
+ if os.path.normcase('/TEST') == os.path.normpath('/test'):
+ template_dirs = ['/dir1', '/DIR2']
+ test_template_sources('index.html', template_dirs,
+ ['/dir1/index.html', '/dir2/index.html'])
+ test_template_sources('/DIR1/index.HTML', template_dirs,
+ ['/dir1/index.html'])
+
def test_templates(self):
# NOW and NOW_tz are used by timesince tag tests.
NOW = datetime.now()
@@ -215,9 +265,9 @@ class Templates(unittest.TestCase):
# Empty strings can be passed as arguments to filters
'filter-syntax17': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),
- # If a variable has a __str__() that returns a Unicode object, the
- # value will be converted to a bytestring.
- 'filter-syntax18': (r'{{ var }}', {'var': UnicodeInStrClass()}, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'),
+ # Make sure that any unicode strings are converted to bytestrings
+ # in the final output.
+ 'filter-syntax18': (r'{{ var }}', {'var': UTF8Class()}, u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'),
# Numbers as filter arguments should work
'filter-syntax19': ('{{ var|truncatewords:1 }}', {"var": "hello world"}, "hello ..."),
@@ -596,7 +646,7 @@ class Templates(unittest.TestCase):
# translation of a constant string
'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
- ### HANDLING OF TEMPLATE_TAG_IF_INVALID ###################################
+ ### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')),
@@ -729,6 +779,8 @@ class Templates(unittest.TestCase):
'url02' : ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
'url04' : ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
+ 'url05' : (u'{% url метка_оператора v %}', {'v': u'Ω'},
+ '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
# Failures
'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
diff --git a/tests/regressiontests/templates/unicode.py b/tests/regressiontests/templates/unicode.py
new file mode 100644
index 0000000000..efda11c2da
--- /dev/null
+++ b/tests/regressiontests/templates/unicode.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+
+unicode_tests = ur"""
+Templates can be created from unicode strings.
+>>> from django.template import *
+>>> t1 = Template(u'ŠĐĆŽćžšđ {{ var }}')
+
+Templates can also be created from bytestrings. These are assumed by encoded
+using UTF-8.
+
+>>> s = '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91 {{ var }}'
+>>> t2 = Template(s)
+>>> s = '\x80\xc5\xc0'
+>>> Template(s)
+Traceback (most recent call last):
+ ...
+TemplateEncodingError: Templates can only be constructed from unicode or UTF-8 strings.
+
+Contexts can be constructed from unicode or UTF-8 bytestrings.
+
+>>> c1 = Context({'var': 'foo'})
+>>> c2 = Context({u'var': 'foo'})
+>>> c3 = Context({'var': u'Đđ'})
+>>> c4 = Context({u'var': '\xc4\x90\xc4\x91'})
+
+Since both templates and all four contexts represent the same thing, they all
+render the same (and are returned as unicode objects).
+
+>>> t1.render(c3) == t2.render(c3)
+True
+>>> type(t1.render(c3))
+<type 'unicode'>
+"""
diff --git a/tests/regressiontests/templates/urls.py b/tests/regressiontests/templates/urls.py
index 5fbade5c58..d79f38e0a7 100644
--- a/tests/regressiontests/templates/urls.py
+++ b/tests/regressiontests/templates/urls.py
@@ -1,3 +1,4 @@
+# coding: utf-8
from django.conf.urls.defaults import *
from regressiontests.templates import views
@@ -8,4 +9,7 @@ urlpatterns = patterns('',
(r'^client/(\d+)/$', views.client),
(r'^client/(\d+)/(?P<action>[^/]+)/$', views.client_action),
url(r'^named-client/(\d+)/$', views.client, name="named.client"),
+
+ # Unicode strings are permitted everywhere.
+ url(ur'^Юникод/(\w+)/$', views.client, name=u"метка_оператора"),
)
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index 40d022a47a..e17770cd03 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -4,7 +4,49 @@ Regression tests for the Test Client, especially the customized assertions.
"""
from django.test import Client, TestCase
from django.core import mail
+import os
+class AssertContainsTests(TestCase):
+ def test_contains(self):
+ "Responses can be inspected for content, including counting repeated substrings"
+ response = self.client.get('/test_client_regress/no_template_view/')
+
+ self.assertContains(response, 'never', 0)
+ self.assertContains(response, 'once')
+ self.assertContains(response, 'once', 1)
+ self.assertContains(response, 'twice')
+ self.assertContains(response, 'twice', 2)
+
+ try:
+ self.assertContains(response, 'never', 1)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Found 0 instances of 'never' in response (expected 1)")
+
+ try:
+ self.assertContains(response, 'once', 0)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Found 1 instances of 'once' in response (expected 0)")
+
+ try:
+ self.assertContains(response, 'once', 2)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Found 1 instances of 'once' in response (expected 2)")
+
+ try:
+ self.assertContains(response, 'twice', 1)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Found 2 instances of 'twice' in response (expected 1)")
+
+ try:
+ self.assertContains(response, 'thrice')
+ except AssertionError, e:
+ self.assertEquals(str(e), "Couldn't find 'thrice' in response")
+
+ try:
+ self.assertContains(response, 'thrice', 3)
+ except AssertionError, e:
+ self.assertEquals(str(e), "Found 0 instances of 'thrice' in response (expected 3)")
+
class AssertTemplateUsedTests(TestCase):
fixtures = ['testdata.json']
@@ -59,7 +101,7 @@ class AssertTemplateUsedTests(TestCase):
try:
self.assertTemplateUsed(response, "Valid POST Template")
except AssertionError, e:
- self.assertEquals(str(e), "Template 'Valid POST Template' was not one of the templates used to render the response. Templates used: ['form_view.html', 'base.html']")
+ self.assertEquals(str(e), "Template 'Valid POST Template' was not one of the templates used to render the response. Templates used: form_view.html, base.html")
class AssertRedirectsTests(TestCase):
def test_redirect_page(self):
@@ -69,7 +111,7 @@ class AssertRedirectsTests(TestCase):
try:
self.assertRedirects(response, '/test_client/get_view/')
except AssertionError, e:
- self.assertEquals(str(e), "Response didn't redirect as expected: Reponse code was 301 (expected 302)")
+ self.assertEquals(str(e), "Response didn't redirect as expected: Response code was 301 (expected 302)")
def test_incorrect_target(self):
"An assertion is raised if the response redirects to another target"
@@ -78,10 +120,10 @@ class AssertRedirectsTests(TestCase):
# Should redirect to get_view
self.assertRedirects(response, '/test_client/some_view/')
except AssertionError, e:
- self.assertEquals(str(e), "Response didn't redirect as expected: Reponse code was 301 (expected 302)")
+ self.assertEquals(str(e), "Response didn't redirect as expected: Response code was 301 (expected 302)")
def test_target_page(self):
- "An assertion is raised if the reponse redirect target cannot be retrieved as expected"
+ "An assertion is raised if the response redirect target cannot be retrieved as expected"
response = self.client.get('/test_client/double_redirect_view/')
try:
# The redirect target responds with a 301 code, not 200
@@ -162,3 +204,12 @@ class AssertFormErrorTests(TestCase):
except AssertionError, e:
self.assertEqual(str(e), "The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [u'Enter a valid e-mail address.'])")
+class AssertFileUploadTests(TestCase):
+ def test_simple_upload(self):
+ fd = open(os.path.join(os.path.dirname(__file__), "views.py"))
+ post_data = {
+ 'name': 'Ringo',
+ 'file_field': fd,
+ }
+ response = self.client.post('/test_client_regress/file_upload/', post_data)
+ self.assertEqual(response.status_code, 200)
diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py
index e9cd0aea15..160f9f992d 100644
--- a/tests/regressiontests/test_client_regress/urls.py
+++ b/tests/regressiontests/test_client_regress/urls.py
@@ -1,7 +1,7 @@
from django.conf.urls.defaults import *
-from django.views.generic.simple import redirect_to
import views
urlpatterns = patterns('',
(r'^no_template_view/$', views.no_template_view),
+ (r'^file_upload/$', views.file_upload_view),
)
diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py
index d8dd2b349c..d3fbcf8448 100644
--- a/tests/regressiontests/test_client_regress/views.py
+++ b/tests/regressiontests/test_client_regress/views.py
@@ -1,8 +1,20 @@
from django.core.mail import EmailMessage, SMTPConnection
-from django.http import HttpResponse
+from django.http import HttpResponse, HttpResponseServerError
from django.shortcuts import render_to_response
def no_template_view(request):
"A simple view that expects a GET request, and returns a rendered template"
- return HttpResponse("No template used")
+ return HttpResponse("No template used. Sample content: twice once twice. Content ends.")
+
+def file_upload_view(request):
+ """
+ Check that a file upload can be updated into the POST dictionary without
+ going pear-shaped.
+ """
+ form_data = request.POST.copy()
+ form_data.update(request.FILES)
+ if isinstance(form_data['file_field'], dict) and isinstance(form_data['name'], unicode):
+ return HttpResponse('')
+ else:
+ return HttpResponseServerError()
diff --git a/tests/regressiontests/text/tests.py b/tests/regressiontests/text/tests.py
index f758ecaf90..0fd22b58b0 100644
--- a/tests/regressiontests/text/tests.py
+++ b/tests/regressiontests/text/tests.py
@@ -1,17 +1,38 @@
-"""
-# Tests for stuff in django.utils.text.
+# coding: utf-8
+r"""
+# Tests for stuff in django.utils.text and other text munging util functions.
>>> from django.utils.text import *
### smart_split ###########################################################
>>> list(smart_split(r'''This is "a person" test.'''))
-['This', 'is', '"a person"', 'test.']
+[u'This', u'is', u'"a person"', u'test.']
>>> print list(smart_split(r'''This is "a person's" test.'''))[2]
"a person's"
->>> print list(smart_split(r'''This is "a person\\"s" test.'''))[2]
+>>> print list(smart_split(r'''This is "a person\"s" test.'''))[2]
"a person"s"
>>> list(smart_split('''"a 'one'''))
-['"a', "'one"]
+[u'"a', u"'one"]
>>> print list(smart_split(r'''all friends' tests'''))[1]
friends'
+
+### urlquote #############################################################
+>>> from django.utils.http import urlquote, urlquote_plus
+>>> urlquote(u'Paris & Orl\xe9ans')
+u'Paris%20%26%20Orl%C3%A9ans'
+>>> urlquote_plus(u'Paris & Orl\xe9ans')
+u'Paris+%26+Orl%C3%A9ans'
+
+### iri_to_uri ###########################################################
+>>> from django.utils.encoding import iri_to_uri
+>>> iri_to_uri(u'red%09ros\xe9#red')
+'red%09ros%C3%A9#red'
+>>> iri_to_uri(u'/blog/for/J\xfcrgen M\xfcnster/')
+'/blog/for/J%C3%BCrgen%20M%C3%BCnster/'
+>>> iri_to_uri(u'locations/%s' % urlquote_plus(u'Paris & Orl\xe9ans'))
+'locations/Paris+%26+Orl%C3%A9ans'
+
+iri_to_uri() is idempotent:
+>>> iri_to_uri(iri_to_uri(u'red%09ros\xe9#red'))
+'red%09ros%C3%A9#red'
"""
diff --git a/tests/regressiontests/utils/__init__.py b/tests/regressiontests/utils/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/utils/__init__.py
diff --git a/tests/regressiontests/utils/models.py b/tests/regressiontests/utils/models.py
new file mode 100644
index 0000000000..97a72bab14
--- /dev/null
+++ b/tests/regressiontests/utils/models.py
@@ -0,0 +1 @@
+# Test runner needs a models.py file.
diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py
new file mode 100644
index 0000000000..258aea697e
--- /dev/null
+++ b/tests/regressiontests/utils/tests.py
@@ -0,0 +1,115 @@
+"""
+Tests for django.utils.
+"""
+
+from unittest import TestCase
+
+from django.utils import html
+
+class TestUtilsHtml(TestCase):
+
+ def check_output(self, function, value, output=None):
+ """
+ Check that function(value) equals output. If output is None,
+ check that function(value) equals value.
+ """
+ if output is None:
+ output = value
+ self.assertEqual(function(value), output)
+
+ def test_escape(self):
+ f = html.escape
+ items = (
+ ('&','&amp;'),
+ ('<', '&lt;'),
+ ('>', '&gt;'),
+ ('"', '&quot;'),
+ ("'", '&#39;'),
+ )
+ # Substitution patterns for testing the above items.
+ patterns = ("%s", "asdf%sfdsa", "%s1", "1%sb")
+ for value, output in items:
+ for pattern in patterns:
+ self.check_output(f, pattern % value, pattern % output)
+ # Check repeated values.
+ self.check_output(f, value * 2, output * 2)
+ # Verify it doesn't double replace &.
+ self.check_output(f, '<&', '&lt;&amp;')
+
+ def test_linebreaks(self):
+ f = html.linebreaks
+ items = (
+ ("para1\n\npara2\r\rpara3", "<p>para1</p>\n\n<p>para2</p>\n\n<p>para3</p>"),
+ ("para1\nsub1\rsub2\n\npara2", "<p>para1<br />sub1<br />sub2</p>\n\n<p>para2</p>"),
+ ("para1\r\n\r\npara2\rsub1\r\rpara4", "<p>para1</p>\n\n<p>para2<br />sub1</p>\n\n<p>para4</p>"),
+ ("para1\tmore\n\npara2", "<p>para1\tmore</p>\n\n<p>para2</p>"),
+ )
+ for value, output in items:
+ self.check_output(f, value, output)
+
+ def test_strip_tags(self):
+ f = html.strip_tags
+ items = (
+ ('<adf>a', 'a'),
+ ('</adf>a', 'a'),
+ ('<asdf><asdf>e', 'e'),
+ ('<f', '<f'),
+ ('</fe', '</fe'),
+ ('<x>b<y>', 'b'),
+ )
+ for value, output in items:
+ self.check_output(f, value, output)
+
+ def test_strip_spaces_between_tags(self):
+ f = html.strip_spaces_between_tags
+ # Strings that should come out untouched.
+ items = (' <adf>', '<adf> ', ' </adf> ', ' <f> x</f>')
+ for value in items:
+ self.check_output(f, value)
+ # Strings that have spaces to strip.
+ items = (
+ ('<d> </d>', '<d></d>'),
+ ('<p>hello </p>\n<p> world</p>', '<p>hello </p><p> world</p>'),
+ ('\n<p>\t</p>\n<p> </p>\n', '\n<p></p><p></p>\n'),
+ )
+ for value, output in items:
+ self.check_output(f, value, output)
+
+ def test_strip_entities(self):
+ f = html.strip_entities
+ # Strings that should come out untouched.
+ values = ("&", "&a", "&a", "a&#a")
+ for value in values:
+ self.check_output(f, value)
+ # Valid entities that should be stripped from the patterns.
+ entities = ("&#1;", "&#12;", "&a;", "&fdasdfasdfasdf;")
+ patterns = (
+ ("asdf %(entity)s ", "asdf "),
+ ("%(entity)s%(entity)s", ""),
+ ("&%(entity)s%(entity)s", "&"),
+ ("%(entity)s3", "3"),
+ )
+ for entity in entities:
+ for in_pattern, output in patterns:
+ self.check_output(f, in_pattern % {'entity': entity}, output)
+
+ def test_fix_ampersands(self):
+ f = html.fix_ampersands
+ # Strings without ampersands or with ampersands already encoded.
+ values = ("a&#1;", "b", "&a;", "&amp; &x; ", "asdf")
+ patterns = (
+ ("%s", "%s"),
+ ("&%s", "&amp;%s"),
+ ("&%s&", "&amp;%s&amp;"),
+ )
+ for value in values:
+ for in_pattern, out_pattern in patterns:
+ self.check_output(f, in_pattern % value, out_pattern % value)
+ # Strings with ampersands that need encoding.
+ items = (
+ ("&#;", "&amp;#;"),
+ ("&#875 ;", "&amp;#875 ;"),
+ ("&#4abc;", "&amp;#4abc;"),
+ )
+ for value, output in items:
+ self.check_output(f, value, output)
diff --git a/tests/runtests.py b/tests/runtests.py
index 7d1ee1e29c..85aea50180 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -51,7 +51,7 @@ class InvalidModelTestCase(unittest.TestCase):
self.model_label = model_label
def runTest(self):
- from django.core import management
+ from django.core.management.validation import get_validation_errors
from django.db.models.loading import load_app
from cStringIO import StringIO
@@ -60,8 +60,14 @@ class InvalidModelTestCase(unittest.TestCase):
except Exception, e:
self.fail('Unable to load invalid model module')
+ # Make sure sys.stdout is not a tty so that we get errors without
+ # coloring attached (makes matching the results easier). We restore
+ # sys.stderr afterwards.
+ orig_stdout = sys.stdout
s = StringIO()
- count = management.get_validation_errors(s, module)
+ sys.stdout = s
+ count = get_validation_errors(s, module)
+ sys.stdout = orig_stdout
s.seek(0)
error_log = s.read()
actual = error_log.split('\n')
@@ -73,7 +79,7 @@ class InvalidModelTestCase(unittest.TestCase):
self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
self.assert_(not missing, "Missing Errors: " + '\n'.join(missing))
-def django_tests(verbosity, tests_to_run):
+def django_tests(verbosity, interactive, test_labels):
from django.conf import settings
old_installed_apps = settings.INSTALLED_APPS
@@ -94,6 +100,8 @@ def django_tests(verbosity, tests_to_run):
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
)
+ if not hasattr(settings, 'SITE_ID'):
+ settings.SITE_ID = 1
# Load all the ALWAYS_INSTALLED_APPS.
# (This import statement is intentionally delayed until after we
@@ -109,14 +117,13 @@ def django_tests(verbosity, tests_to_run):
# if the model was named on the command line, or
# no models were named (i.e., run all), import
# this model and add it to the list to test.
- if not tests_to_run or model_name in tests_to_run:
+ if not test_labels or model_name in set([label.split('.')[0] for label in test_labels]):
if verbosity >= 1:
print "Importing model %s" % model_name
mod = load_app(model_label)
if mod:
if model_label not in settings.INSTALLED_APPS:
settings.INSTALLED_APPS.append(model_label)
- test_models.append(mod)
except Exception, e:
sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:]))
continue
@@ -125,12 +132,12 @@ def django_tests(verbosity, tests_to_run):
extra_tests = []
for model_dir, model_name in get_invalid_models():
model_label = '.'.join([model_dir, model_name])
- if not tests_to_run or model_name in tests_to_run:
+ if not test_labels or model_name in test_labels:
extra_tests.append(InvalidModelTestCase(model_label))
# Run the test suite, including the extra validation tests.
from django.test.simple import run_tests
- failures = run_tests(test_models, verbosity, extra_tests=extra_tests)
+ failures = run_tests(test_labels, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests)
if failures:
sys.exit(failures)
@@ -149,6 +156,8 @@ if __name__ == "__main__":
parser.add_option('-v','--verbosity', action='store', dest='verbosity', default='0',
type='choice', choices=['0', '1', '2'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
+ parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
+ help='Tells Django to NOT prompt the user for input of any kind.')
parser.add_option('--settings',
help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
options, args = parser.parse_args()
@@ -157,4 +166,4 @@ if __name__ == "__main__":
elif "DJANGO_SETTINGS_MODULE" not in os.environ:
parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. "
"Set it or use --settings.")
- django_tests(int(options.verbosity), args)
+ django_tests(int(options.verbosity), options.interactive, args)