diff options
author | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-05-14 15:58:54 +0000 |
---|---|---|
committer | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-05-14 15:58:54 +0000 |
commit | c53378eb4b66742df4d8bcb4b9135e4fda343498 (patch) | |
tree | ad46ed3d7f7f2bae60c9b65f79bece61dcf7ea0a | |
parent | bcc26d8eeae483814ad80c80a0336311b17de8bf (diff) | |
download | django-c53378eb4b66742df4d8bcb4b9135e4fda343498.tar.gz |
boulder-oracle-sprint: Merged to [5234]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5235 bcc190cf-cafb-0310-a4f2-bffc1f526a37
25 files changed, 3604 insertions, 99 deletions
@@ -78,6 +78,7 @@ answer newbie questions, and generally made Django that much better: flavio.curella@gmail.com Jure Cuhalev <gandalf@owca.info> dackze+django@gmail.com + David Danier <goliath.mailinglist@gmx.de> Dirk Datzert <dummy@habmalnefrage.de> Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/> dave@thebarproject.com @@ -85,6 +86,7 @@ answer newbie questions, and generally made Django that much better: Alex Dedul deric@monowerks.com Max Derkachev <mderk@yandex.ru> + Jordan Dimov <s3x3y1@gmail.com> dne@mayonnaise.net Maximillian Dornseif <md@hudora.de> Jeremy Dunck <http://dunck.us/> diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 61751db8cd..9abc8d6a6c 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -38,6 +38,7 @@ LANGUAGE_CODE = 'en-us' LANGUAGES = ( ('ar', gettext_noop('Arabic')), ('bn', gettext_noop('Bengali')), + ('bg', gettext_noop('Bulgarian')), ('ca', gettext_noop('Catalan')), ('cs', gettext_noop('Czech')), ('cy', gettext_noop('Welsh')), diff --git a/django/conf/locale/bg/LC_MESSAGES/django.mo b/django/conf/locale/bg/LC_MESSAGES/django.mo Binary files differnew file mode 100644 index 0000000000..bfa09dcc23 --- /dev/null +++ b/django/conf/locale/bg/LC_MESSAGES/django.mo diff --git a/django/conf/locale/bg/LC_MESSAGES/django.po b/django/conf/locale/bg/LC_MESSAGES/django.po new file mode 100644 index 0000000000..9c1030685e --- /dev/null +++ b/django/conf/locale/bg/LC_MESSAGES/django.po @@ -0,0 +1,2670 @@ +# translation of django.po to Bulgarian +# +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-04-05 01:32+1000\n" +"PO-Revision-Date: 2007-05-12 17:45+0300\n" +"Last-Translator: Jordan Dimov <s3x3y1@gmail.com>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: db/models/manipulators.py:307 +#, python-format +msgid "%(object)s with this %(type)s already exists for the given %(field)s." +msgstr "%(object)s с този %(type)s вече съществува за зададеното %(field)s.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\" (или \"Command\" на Mac-а) за да направите повече от един избор. " + +#: 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 не е валидна." +msgstr[1] "" + +#: 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 "Това поле не може да има празна стойност." + +#: db/models/fields/__init__.py:457 core/validators.py:148 +msgid "Enter a valid date in YYYY-MM-DD format." +msgstr "Въведете валидна дата в формат ГГГГ-ММ-ДД." + +#: db/models/fields/__init__.py:526 core/validators.py:157 +msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." +msgstr "Въведете валидна дата и час в формат ГГГГ-ММ-ДД ЧЧ:ММ." + +#: 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] "година" +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/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 "p.m." + +#: utils/dateformat.py:41 +msgid "a.m." +msgstr "a.m." + +#: utils/dateformat.py:46 +msgid "PM" +msgstr "PM" + +#: utils/dateformat.py:47 +msgid "AM" +msgstr "AM" + +#: utils/dateformat.py:95 +msgid "midnight" +msgstr "полунощ" + +#: utils/dateformat.py:97 +msgid "noon" +msgstr "обяд" + +#: utils/translation/trans_real.py:358 +msgid "DATE_FORMAT" +msgstr "j N, Y" + +#: utils/translation/trans_real.py:359 +msgid "DATETIME_FORMAT" +msgstr "j N, Y, P" + +#: utils/translation/trans_real.py:360 +msgid "TIME_FORMAT" +msgstr "P" + +#: utils/translation/trans_real.py:376 +msgid "YEAR_MONTH_FORMAT" +msgstr "F Y" + +#: utils/translation/trans_real.py:377 +msgid "MONTH_DAY_FORMAT" +msgstr "j F" + +#: 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 символа." +msgstr[1] "" + +#: 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 "Въведете цяло число между -32768 и 32767." + +#: 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 и 32767." + +#: 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 "Телефонните номера трябва да бъдат в формат XX-XXXX-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 "Въведете zip код в формат XXXXX или XXXXX-XXXX." + +#: 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 "ключ на сесията" + +#: 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/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 "Браузерът, който използвате не поддържа cookies, а те са необходими за да можете да се логнете. " + +#: 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 "С този email адрес няма обвързан потребителски акаунт. Сигурни ли сте, че сте се регистрирали?" + +#: 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 "e-mail адрес" + +#: 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 милион" +msgstr[1] "%(value).1f милиона" + +#: contrib/humanize/templatetags/humanize.py:50 +#, python-format +msgid "%(value).1f billion" +msgid_plural "%(value).1f billion" +msgstr[0] "%(value).1f милиард" +msgstr[1] "%(value).1f милиарда" + +#: contrib/humanize/templatetags/humanize.py:53 +#, python-format +msgid "%(value).1f trillion" +msgid_plural "%(value).1f trillion" +msgstr[0] "%(value).1f трилион" +msgstr[1] "%(value).1f трилионаn" + +#: 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 "Това може да бъде или абсолютен път (като горното) или пълен URL, започващ с 'http://'." + +#: 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" +msgstr "ID на обекта" + +#: 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 "рейтинг #1" + +#: contrib/comments/models.py:71 +msgid "rating #2" +msgstr "рейтинг #2" + +#: contrib/comments/models.py:72 +msgid "rating #3" +msgstr "рейтинг #3" + +#: contrib/comments/models.py:73 +msgid "rating #4" +msgstr "рейтинг #4" + +#: contrib/comments/models.py:74 +msgid "rating #5" +msgstr "рейтинг #5" + +#: contrib/comments/models.py:75 +msgid "rating #6" +msgstr "рейтинг #6" + +#: contrib/comments/models.py:76 +msgid "rating #7" +msgstr "рейтинг #7" + +#: contrib/comments/models.py:77 +msgid "rating #8" +msgstr "рейтинг #8" + +#: 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:304 +msgid "IP address" +msgstr "IP адрес" + +#: 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 "Content обект" + +#: 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 "" +"Пуснат от %(user)s на %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" + +#: contrib/comments/models.py:168 +msgid "person's name" +msgstr "име на човека" + +#: contrib/comments/models.py:171 +msgid "ip address" +msgstr "ip адрес" + +#: 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 "%(score)d рейтинг от %(user)s" + +#: contrib/comments/models.py:258 +#, python-format +msgid "" +"This comment was flagged by %(user)s:\n" +"\n" +"%(text)s" +msgstr "" +"Този коментар бе флагнат от %(user)s:\n" +"\n" +"%(text)s" + +#: 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 "Флаг от %r" + +#: 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 "Изтриване от модератор %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 "Анонимните потребители не могат да гласуват" + +#: contrib/comments/views/karma.py:23 +msgid "Invalid comment ID" +msgstr "Невалидно ID на коментар" + +#: contrib/comments/views/karma.py:25 +msgid "No voting for yourself" +msgstr "Не можете да гласувате за себе си" + +#: 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: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] "" +"Този коментар е от потребител, който има по-малко от %(count)s " +"коментар:\n" +"\n" +"%(text)s" +msgstr[1] "" +"Този коментар е от потребител, който има по-малко от %(count)s " +"коментара:\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 "" +"Този коментар е от съмнителен потребител:\n" +"\n" +"%(text)s" + +#: contrib/comments/views/comments.py:188 +#: contrib/comments/views/comments.py:280 +msgid "Only POSTs are allowed" +msgstr "Само POST заявките са позволени" + +#: 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:196 +#: contrib/comments/views/comments.py:286 +msgid "Somebody tampered with the comment form (security violation)" +msgstr "Някой е променял формата за коментари (нарушение на сигурността)" + +#: 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-то на обекта е невалидно" + +#: contrib/comments/views/comments.py:257 +#: contrib/comments/views/comments.py:321 +msgid "The comment form didn't provide either 'preview' or 'post'" +msgstr "Формата за коментарите не предоставя нито преглед нито постване. " + +#: contrib/sites/models.py:10 +msgid "domain name" +msgstr "име на домейна" + +#: contrib/sites/models.py:11 +msgid "display name" +msgstr "наименование" + +#: contrib/sites/models.py:15 +msgid "site" +msgstr "сайт" + +#: contrib/sites/models.py:16 +msgid "sites" +msgstr "сайтове" + +#: contrib/admin/filterspecs.py:40 +#, python-format +msgid "" +"<h3>By %s:</h3>\n" +"<ul>\n" +msgstr "" +"<h3>По %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 +msgid "All" +msgstr "Всички" + +#: contrib/admin/filterspecs.py:109 +msgid "Any date" +msgstr "Коя-да-е дата" + +#: contrib/admin/filterspecs.py:110 +msgid "Today" +msgstr "Днес" + +#: contrib/admin/filterspecs.py:113 +msgid "Past 7 days" +msgstr "Последните 7 дни" + +#: contrib/admin/filterspecs.py:115 +msgid "This month" +msgstr "Този месец" + +#: contrib/admin/filterspecs.py:117 +msgid "This year" +msgstr "Тази година" + +#: contrib/admin/models.py:16 +msgid "action time" +msgstr "време на действие" + +#: contrib/admin/models.py:19 +msgid "object id" +msgstr "id на обекта" + +#: contrib/admin/models.py:20 +msgid "object repr" +msgstr "repr на обекта" + +#: contrib/admin/models.py:21 +msgid "action flag" +msgstr "флаг за действие" + +#: contrib/admin/models.py:22 +msgid "change message" +msgstr "смени съобщение" + +#: contrib/admin/models.py:25 +msgid "log entry" +msgstr "записка" + +#: contrib/admin/models.py:26 +msgid "log entries" +msgstr "записки" + +#: contrib/admin/templatetags/admin_list.py:247 +msgid "All dates" +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/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/templates/admin_doc/bookmarklets.html:3 +msgid "Bookmarklets" +msgstr "Bookmarklet-и" + +#: 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/templates/admin_doc/bookmarklets.html:5 +msgid "Documentation bookmarklets" +msgstr "Bookmarklet-и за документация" + +#: 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\">За да инсталирате bookmarklet-и, задърпайте линка в bookmarks\n" +"toolbar-а, или щракнете с десния бутон и добавете линка в отметките. Сега можете да\n" +"изберете bookmarklet-а от която и да е страница. Някой от тези\n" +"bookmarklet-и могат да се разглеждат само от компютър, който е маркиран \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 "Препраща от която и да е страница към документацията за изгледа, който я е генерирал. " + +#: 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 "Показва типът на съдържанието и 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/admin/submit_line.html:3 +#: contrib/admin/templates/admin/delete_confirmation.html:9 +msgid "Delete" +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/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 "Server Error <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 "Малък проблем. Администраторът на сайта е уведомен за случилото се. Благодарим за проявеното разбиране. " + +#: contrib/admin/templates/admin/filter.html:2 +#, python-format +msgid " By %(filter_title)s " +msgstr " По %(filter_title)s " + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +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/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] "1 резултат" +msgstr[1] "%(counter)s резултата" + +#: 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: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 "j N, 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 "Този обект няма исторя на промените. Вероятно не е добавен чрез административния панел. " + +#: 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/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/delete_confirmation.html:26 +msgid "Yes, I'm sure" +msgstr "Абсолютно" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "Покажи всички" + +#: contrib/admin/templates/admin/change_list.html:12 +#, python-format +msgid "Add %(name)s" +msgstr "Добави %(name)s" + +#: 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] "Коригирайте долу допуснатата грешка. " +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/base.html:25 +msgid "Welcome," +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/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:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: 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/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/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/auth/user/add_form.html:12 +msgid "Username" +msgstr "Потребител" + +#: 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/auth/user/add_form.html:23 +#: contrib/admin/templates/admin/auth/user/change_password.html:39 +msgid "Password (again)" +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/auth/user/change_password.html:28 +#, python-format +msgid "Enter a new password for the user <strong>%(username)s</strong>." +msgstr "Въведете нова парола за потребител <strong>%(username)s</strong>." + +#: 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/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_email.html:2 +msgid "You're receiving this e-mail because you requested a password reset" +msgstr "Получавате този e-mail, защото сте поръчали да Ви бъде издадена нова парола " + +#: contrib/admin/templates/registration/password_reset_email.html:3 +#, python-format +msgid "for your user account at %(site_name)s" +msgstr "за Вашия потребителски акаунт в %(site_name)s" + +#: contrib/admin/templates/registration/password_reset_email.html:5 +#, python-format +msgid "Your new password is: %(new_password)s" +msgstr "Новата Ви парола е: %(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 "Тази парола може да си я смените като щракнете тук: " + +#: 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 "Готините хора от %(site_name)s" + +#: 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/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: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/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_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: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 "Забравена парола? Няма проблеми. Въведете си e-mail адреса по-долу и ще ви изпратим нова!" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "E-mail address:" +msgstr "E-mail адрес:" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "Reset my password" +msgstr "Нова парола" + +#: contrib/admin/views/main.py:223 +msgid "Site administration" +msgstr "Администрация на сайта" + +#: 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\" бе успешно добавен. " + +#: 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 "Може да го редактирате пак по-долу. " + +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 +#, python-format +msgid "You may add another %s below." +msgstr "Може да добавите още един обект %s по-долу. " + +#: contrib/admin/views/main.py:289 +#, python-format +msgid "Add %s" +msgstr "Добави %s" + +#: contrib/admin/views/main.py:335 +#, python-format +msgid "Added %s." +msgstr "Добавен %s." + +#: contrib/admin/views/main.py:337 +#, python-format +msgid "Changed %s." +msgstr "Променен %s." + +#: contrib/admin/views/main.py:339 +#, python-format +msgid "Deleted %s." +msgstr "Изтрит %s." + +#: contrib/admin/views/main.py:342 +msgid "No fields changed." +msgstr "Няма променени полета." + +#: contrib/admin/views/main.py:345 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "Обектът %(name)s \"%(obj)s\" бе успешно актуализиран. " + +#: 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\" бе успешно добавен. Може да го редактирате по-долу. " + +#: contrib/admin/views/main.py:391 +#, python-format +msgid "Change %s" +msgstr "Промени %s" + +#: 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" + +#: contrib/admin/views/main.py:481 +#, python-format +msgid "One or more %(fieldname)s in %(name)s:" +msgstr "Едно или повече %(fieldname)s в %(name)s:" + +#: contrib/admin/views/main.py:514 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "Обектът %(name)s \"%(obj)s\" бе успешно изтрит. " + +#: contrib/admin/views/main.py:517 +msgid "Are you sure?" +msgstr "Сериозно?" + +#: contrib/admin/views/main.py:539 +#, python-format +msgid "Change history: %s" +msgstr "История на промените: %s" + +#: contrib/admin/views/main.py:573 +#, python-format +msgid "Select %s" +msgstr "Изберете %s" + +#: contrib/admin/views/main.py:573 +#, python-format +msgid "Select %s to change" +msgstr "Изберете %s за промяна" + +#: contrib/admin/views/main.py:768 +msgid "Database error" +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 +msgid "" +"Looks like your browser isn't configured to accept cookies. Please enable " +"cookies, reload this page, and try again." +msgstr "Браузерът ви май не е настроен да приема cookies. Пуснете ги и заредете страницата на ново. " + +#: 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 "E-mail адресът ти не ти е потребителско име. Пробвай '%s'." + +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "таг:" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "филтър:" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "изглед:" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "Приложението %r липсва" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %(name)r not found in app %(label)r" +msgstr "Моделът %(name)r го няма в приложение %(label)r" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%(label)s.%(type)s` object" +msgstr "свързаният обект `%(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 +msgid "model:" +msgstr "модел:" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%(label)s.%(name)s` objects" +msgstr "свързани `%(label)s.%(name)s` обекти" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "всички %s" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "брой %s" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "Полета на %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 "Цяло число" + +#: contrib/admin/views/doc.py:292 +msgid "Boolean (Either True or False)" +msgstr "Boolean (True или False)" + +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 +#, python-format +msgid "String (up to %(maxlength)s)" +msgstr "Стринг (до %(maxlength)s символа)" + +#: contrib/admin/views/doc.py:294 +msgid "Comma-separated integers" +msgstr "Цели числа, разделени с запетая" + +#: contrib/admin/views/doc.py:295 +msgid "Date (without time)" +msgstr "Дата (без час)" + +#: contrib/admin/views/doc.py:296 +msgid "Date (with time)" +msgstr "Дата (и час)" + +#: contrib/admin/views/doc.py:297 +msgid "E-mail address" +msgstr "E-mail адрес" + +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 +msgid "File path" +msgstr "Път към файл" + +#: contrib/admin/views/doc.py:300 +msgid "Decimal number" +msgstr "Десетична дроб" + +#: contrib/admin/views/doc.py:306 +msgid "Boolean (Either True, False or None)" +msgstr "Boolean (Възможните стойности са True, False или None)" + +#: contrib/admin/views/doc.py:307 +msgid "Relation to parent model" +msgstr "Връзка с родителския обект" + +#: contrib/admin/views/doc.py:308 +msgid "Phone number" +msgstr "Телефонен номер" + +#: contrib/admin/views/doc.py:313 +msgid "Text" +msgstr "Текст" + +#: contrib/admin/views/doc.py:314 +msgid "Time" +msgstr "Час" + +#: contrib/admin/views/doc.py:316 +msgid "U.S. state (two uppercase letters)" +msgstr "американски щат (две главни букви)" + +#: contrib/admin/views/doc.py:317 +msgid "XML text" +msgstr "XML текст" + +#: contrib/admin/views/doc.py:343 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s не прилича на обект от тип urlpattern" + +#: contrib/admin/views/auth.py:30 +msgid "Add user" +msgstr "Добави потребител" + +#: contrib/admin/views/auth.py:57 +msgid "Password changed successfully." +msgstr "Паролата бе успешно сменена. " + +#: contrib/admin/views/auth.py:64 +#, python-format +msgid "Change password: %s" +msgstr "Смени парола: %s" + +#: newforms/fields.py:103 newforms/fields.py:256 +#, python-format +msgid "Ensure this value has at most %d characters." +msgstr "Тази стойност трябва да има не повече от %d символа. " + +#: newforms/fields.py:105 newforms/fields.py:258 +#, python-format +msgid "Ensure this value has at least %d characters." +msgstr "Тази стойност трябва да има поне %d символа. " + +#: newforms/fields.py:128 core/validators.py:120 +msgid "Enter a whole number." +msgstr "Въведете цяло число. " + +#: newforms/fields.py:130 +#, python-format +msgid "Ensure this value is less than or equal to %s." +msgstr "Тази стойност трябва да е по-малка или равна на %s. " + +#: newforms/fields.py:132 +#, python-format +msgid "Ensure this value is greater than or equal to %s." +msgstr "Тази стойност трябва да е по-голяма или равна на %s." + +#: newforms/fields.py:165 +msgid "Enter a valid date." +msgstr "Въведете валидна дата. " + +#: newforms/fields.py:192 +msgid "Enter a valid time." +msgstr "Въведете валиден час." + +#: newforms/fields.py:228 +msgid "Enter a valid date/time." +msgstr "Въведете валидна дата / час. " + +#: newforms/fields.py:242 +msgid "Enter a valid value." +msgstr "Въведете валидна стойност. " + +#: newforms/fields.py:271 core/validators.py:162 +msgid "Enter a valid e-mail address." +msgstr "Въведете валиден e-mail адрес. " + +#: newforms/fields.py:289 newforms/fields.py:311 +msgid "Enter a valid URL." +msgstr "Въведете валиден URL. " + +#: newforms/fields.py:313 +msgid "This URL appears to be a broken link." +msgstr "Този URL май е счупен линк. " + +#: newforms/fields.py:362 newforms/models.py:165 +msgid "Select a valid choice. That choice is not one of the available choices." +msgstr "Направете валиден избор. Този не е един от възможните избори. " + +#: newforms/fields.py:380 newforms/fields.py:456 newforms/models.py:182 +msgid "Enter a list of values." +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 не е един от възможните избори. " + +#: template/defaultfilters.py:491 +msgid "yes,no,maybe" +msgstr "да,не,може-би" + +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "Обектът %(verbose_name)s бе успешно създаден. " + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "Обектът %(verbose_name)s бе успешно актуализиран." + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "Обектът %(verbose_name)s бе затрит." + +#: core/validators.py:64 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Тази стойност може да съдържа само букви, цифри и подчертавки. " + +#: 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:80 +msgid "Lowercase letters are not allowed here." +msgstr "Тук не се допускат малки букви. " + +#: core/validators.py:87 +msgid "Enter only digits separated by commas." +msgstr "Въведете само цифри, разделени със запетая. " + +#: core/validators.py:99 +msgid "Enter valid e-mail addresses separated by commas." +msgstr "Въведете валидни e-mail адреси разделени със запетая. " + +#: core/validators.py:103 +msgid "Please enter a valid IP address." +msgstr "Въведете валиден IP адрес. " + +#: core/validators.py:107 +msgid "Empty values are not allowed here." +msgstr "Тук не се допускат празни стойности. " + +#: core/validators.py:111 +msgid "Non-numeric characters aren't allowed here." +msgstr "Тук не се допускат символи, които не са цифри. " + +#: core/validators.py:115 +msgid "This value can't be comprised solely of digits." +msgstr "Тази стойност не може да бъде само цифри. " + +#: core/validators.py:124 +msgid "Only alphabetical characters are allowed here." +msgstr "Само букви и цифри се допускат тук. " + +#: core/validators.py:139 +msgid "Year must be 1900 or later." +msgstr "Годината трябва да бъде от 1900 нагоре." + +#: 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 "Въведете валиден час във формат ЧЧ:ММ. " + +#: 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:185 +#, python-format +msgid "The URL %s does not point to a valid image." +msgstr "URL %s не сочи към валидна картинка. " + +#: 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:197 +#, python-format +msgid "The URL %s does not point to a valid QuickTime video." +msgstr "URL %s не сочи към валиден QuickTime видео клип." + +#: core/validators.py:201 +msgid "A valid URL is required." +msgstr "Изисква се валиден URL." + +#: core/validators.py:215 +#, python-format +msgid "" +"Valid HTML is required. Specific errors are:\n" +"%s" +msgstr "" +"Изисква се валиден HTML. Конкретните грешки са:\n" +"%s" + +#: core/validators.py:222 +#, python-format +msgid "Badly formed XML: %s" +msgstr "Неправилно форматиран XML: %s" + +#: core/validators.py:239 +#, python-format +msgid "Invalid URL: %s" +msgstr "Невалиден URL: %s" + +#: core/validators.py:244 core/validators.py:246 +#, python-format +msgid "The URL %s is a broken link." +msgstr "Този URL %s е счупен линк. " + +#: core/validators.py:252 +msgid "Enter a valid U.S. state abbreviation." +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] "Ей-шш! Думичката %s не е позволена тук. " +msgstr[1] "Ей-шш! Думичките %s не са позволени тук. " + +#: core/validators.py:273 +#, python-format +msgid "This field must match the '%s' field." +msgstr "Това поле трябва да съвпада с полето '%s' ." + +#: core/validators.py:292 +msgid "Please enter something for at least one field." +msgstr "Въведете нещичко поне за едното поле. " + +#: core/validators.py:301 core/validators.py:312 +msgid "Please enter both fields or leave them both empty." +msgstr "Или въведете и двете полета или ги оставете празни." + +#: 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:333 +#, python-format +msgid "This field must be given if %(field)s is not %(value)s" +msgstr "Това поле трябва да е зададено ако %(field)s не е %(value)s" + +#: core/validators.py:352 +msgid "Duplicate values are not allowed." +msgstr "Не са позволени стойности, които се повтарят. " + +#: 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:418 +msgid "Please enter a valid decimal number." +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] "Въведете валидна десетична дроб с не-повече от %s цифра." +msgstr[1] "Въведете валидна десетична дроб с не-повече от %s цифри. " + +#: 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 цифра." +msgstr[1] "Въведете валидна десетична дроб, цялата част на която да не надхвърля %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 цифра след десетичната точка." +msgstr[1] "Въведете валидна десетична дроб с не-повече от %s цифри след десетичната точка. " + +#: core/validators.py:438 +#, python-format +msgid "Make sure your uploaded file is at least %s bytes big." +msgstr "Файлът, който сте качили трябва да бъде поне %s байта." + +#: core/validators.py:439 +#, python-format +msgid "Make sure your uploaded file is at most %s bytes big." +msgstr "Размерът на файла, който сте качили не трябва да надхвърля %s байта. " + +#: core/validators.py:456 +msgid "The format for this field is wrong." +msgstr "Форматът на това поле е грешен." + +#: core/validators.py:471 +msgid "This field is invalid." +msgstr "Това поле не е валидно" + +#: core/validators.py:507 +#, python-format +msgid "Could not retrieve anything from %s." +msgstr "Не получихме нищо от %s." + +#: 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: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: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:552 +#, python-format +msgid "" +"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" +"(start)s\".)" +msgstr "" +"\"%(attr)s\" на ред %(line)s е невалиден атрибут. (Редът започва с \"%" +"(start)s\".)" + +#: core/validators.py:557 +#, python-format +msgid "" +"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" +"(start)s\".)" +msgstr "" +"\"<%(tag)s>\" на ред %(line)s е невалиден таг. (Редът започва с \"%" +"(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\".)" +msgstr "На някой от таговете на ред %(line)s му липсват един или повече задължителни атрибута. (Редът започва с \"%(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\".)" +msgstr "Атрибутът \"%(attr)s\" на ред %(line)s има невалидна стойност. (Редът започва с \"%(start)s\".)" + diff --git a/django/conf/locale/bg/LC_MESSAGES/djangojs.mo b/django/conf/locale/bg/LC_MESSAGES/djangojs.mo Binary files differnew file mode 100644 index 0000000000..e912789236 --- /dev/null +++ b/django/conf/locale/bg/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/bg/LC_MESSAGES/djangojs.po b/django/conf/locale/bg/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..2caffdca53 --- /dev/null +++ b/django/conf/locale/bg/LC_MESSAGES/djangojs.po @@ -0,0 +1,106 @@ +# translation of djangojs.po to Bulgarian +# +msgid "" +msgstr "" +"Project-Id-Version: djangojs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2005-12-09 11:51+0100\n" +"PO-Revision-Date: 2007-05-12 17:51+0300\n" +"Last-Translator: Jordan Dimov <s3x3y1@gmail.com>\n" +"Language-Team: Bulgarian\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 "Налични %s" + +#: 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 "Избрахме %s" + +#: 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:26 +#: 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:27 +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:45 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 +msgid "Now" +msgstr "Сега" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 +msgid "Clock" +msgstr "Часовник" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 +msgid "Choose a time" +msgstr "Избери време" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 +msgid "Midnight" +msgstr "Полунощ" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 +msgid "6 a.m." +msgstr "6 a.m." + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 +msgid "Noon" +msgstr "По обяд" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 +msgid "Cancel" +msgstr "Отказ" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 +msgid "Today" +msgstr "Днес" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 +msgid "Calendar" +msgstr "Календар" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 +msgid "Yesterday" +msgstr "Вчера" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 +msgid "Tomorrow" +msgstr "Утре" + diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py index d052acf579..41727d8fa3 100644 --- a/django/contrib/localflavor/is_/forms.py +++ b/django/contrib/localflavor/is_/forms.py @@ -41,7 +41,7 @@ class ISIdNumberField(RegexField): method is modulo 11. """ check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0] - return sum(int(value[i]) * check[i] for i in range(10)) % 11 == 0 + return sum([int(value[i]) * check[i] for i in range(10)]) % 11 == 0 def _format(self, value): """ diff --git a/django/core/management.py b/django/core/management.py index 91de11f3b3..79e57ff0c8 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -1463,20 +1463,24 @@ def load_data(fixture_labels, verbosity=1): if verbosity > 1: print "No %s fixture '%s' in %s." % \ (format, fixture_name, humanize(fixture_dir)) - 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) + + 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, ..." diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py index 29ce6bf9bd..66dbbff335 100644 --- a/django/core/serializers/python.py +++ b/django/core/serializers/python.py @@ -37,7 +37,7 @@ class Serializer(base.Serializer): def handle_fk_field(self, obj, field): related = getattr(obj, field.name) if related is not None: - related = related._get_pk_val() + related = getattr(related, field.rel.field_name) self._current[field.name] = related def handle_m2m_field(self, obj, field): @@ -80,7 +80,10 @@ def Deserializer(object_list, **options): # Handle FK fields elif field.rel and isinstance(field.rel, models.ManyToOneRel): - data[field.attname] = field.rel.to._meta.pk.to_python(field_value) + 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: diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py index 3a0fdb5395..633001f5f0 100644 --- a/django/core/serializers/xml_serializer.py +++ b/django/core/serializers/xml_serializer.py @@ -82,7 +82,7 @@ class Serializer(base.Serializer): self._start_relational_field(field) related = getattr(obj, field.name) if related is not None: - self.xml.characters(str(related._get_pk_val())) + self.xml.characters(str(getattr(related, field.rel.field_name))) else: self.xml.addQuickElement("None") self.xml.endElement("field") @@ -181,7 +181,7 @@ class Deserializer(base.Deserializer): if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None': return None else: - return field.rel.to._meta.pk.to_python( + return field.rel.to._meta.get_field(field.rel.field_name).to_python( getInnerText(node).strip().encode(self.encoding)) def _handle_m2m_field_node(self, node, field): diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 66479eb557..96420a7cf0 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -242,7 +242,7 @@ def get_sql_sequence_reset(style, model_list): if isinstance(f, models.AutoField): output.append("%s setval('%s', (%s max(%s) %s %s));" % \ (style.SQL_KEYWORD('SELECT'), - style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)), + style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), style.SQL_KEYWORD('SELECT'), style.SQL_FIELD(quote_name(f.column)), style.SQL_KEYWORD('FROM'), @@ -251,7 +251,7 @@ def get_sql_sequence_reset(style, model_list): for f in model._meta.many_to_many: output.append("%s setval('%s', (%s max(%s) %s %s));" % \ (style.SQL_KEYWORD('SELECT'), - style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()), + style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), style.SQL_KEYWORD('SELECT'), style.SQL_FIELD(quote_name('id')), style.SQL_KEYWORD('FROM'), diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index c85504bfaa..e27f4f61e0 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -199,7 +199,7 @@ def get_sql_sequence_reset(style, model_list): if isinstance(f, models.AutoField): output.append("%s setval('%s', (%s max(%s) %s %s));" % \ (style.SQL_KEYWORD('SELECT'), - style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)), + style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), style.SQL_KEYWORD('SELECT'), style.SQL_FIELD(quote_name(f.column)), style.SQL_KEYWORD('FROM'), @@ -208,7 +208,7 @@ def get_sql_sequence_reset(style, model_list): for f in model._meta.many_to_many: output.append("%s setval('%s', (%s max(%s) %s %s));" % \ (style.SQL_KEYWORD('SELECT'), - style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()), + style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), style.SQL_KEYWORD('SELECT'), style.SQL_FIELD(quote_name('id')), style.SQL_KEYWORD('FROM'), diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 9fafd20787..f624e005e9 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -184,8 +184,8 @@ class BaseForm(StrAndUnicode): try: value = field.clean(value) self.clean_data[name] = value - if hasattr(self, 'clean_%s' % name): - value = getattr(self, 'clean_%s' % name)() + if hasattr(self, 'do_clean_%s' % name): + value = getattr(self, 'do_clean_%s' % name)() self.clean_data[name] = value except ValidationError, e: errors[name] = e.messages @@ -255,6 +255,8 @@ class BoundField(StrAndUnicode): attrs['id'] = auto_id if not self.form.is_bound: data = self.form.initial.get(self.name, self.field.initial) + if callable(data): + data = data() else: data = self.data return widget.render(self.html_name, data, attrs=attrs) diff --git a/django/newforms/models.py b/django/newforms/models.py index a60002b705..ea99ca9ea0 100644 --- a/django/newforms/models.py +++ b/django/newforms/models.py @@ -12,17 +12,7 @@ from widgets import Select, SelectMultiple, MultipleHiddenInput __all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields', 'ModelChoiceField', 'ModelMultipleChoiceField') -def model_save(self, commit=True): - """ - Creates and returns model instance according to self.clean_data. - - This method is created for any form_for_model Form. - """ - if self.errors: - raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name) - return save_instance(self, self._model(), commit) - -def save_instance(form, instance, commit=True): +def save_instance(form, instance, fields=None, fail_message='saved', commit=True): """ Saves bound Form ``form``'s clean_data into model instance ``instance``. @@ -33,15 +23,19 @@ def save_instance(form, instance, commit=True): from django.db import models opts = instance.__class__._meta if form.errors: - raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name) + raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message)) clean_data = form.clean_data for f in opts.fields: if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data: continue + if fields and f.name not in fields: + continue setattr(instance, f.name, clean_data[f.name]) if commit: instance.save() for f in opts.many_to_many: + if fields and f.name not in fields: + continue if f.name in clean_data: setattr(instance, f.attname, clean_data[f.name]) # GOTCHA: If many-to-many data is given and commit=False, the many-to-many @@ -50,13 +44,19 @@ def save_instance(form, instance, commit=True): # exception in that case. return instance -def make_instance_save(instance): - "Returns the save() method for a form_for_instance Form." +def make_model_save(model, fields, fail_message): + "Returns the save() method for a Form." def save(self, commit=True): - return save_instance(self, instance, commit) + return save_instance(self, model(), fields, fail_message, commit) + return save + +def make_instance_save(instance, fields, fail_message): + "Returns the save() method for a Form." + def save(self, commit=True): + return save_instance(self, instance, fields, fail_message, commit) return save -def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfield()): +def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()): """ Returns a Form class for the given Django model class. @@ -71,13 +71,16 @@ def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfiel for f in opts.fields + opts.many_to_many: if not f.editable: continue + if fields and not f.name in fields: + continue formfield = formfield_callback(f) if formfield: field_list.append((f.name, formfield)) - fields = SortedDictFromList(field_list) - return type(opts.object_name + 'Form', (form,), {'base_fields': fields, '_model': model, 'save': model_save}) + base_fields = SortedDictFromList(field_list) + return type(opts.object_name + 'Form', (form,), + {'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')}) -def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): +def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): """ Returns a Form class for the given Django model instance. @@ -94,13 +97,15 @@ def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kw for f in opts.fields + opts.many_to_many: if not f.editable: continue + if fields and not f.name in fields: + continue current_value = f.value_from_object(instance) formfield = formfield_callback(f, initial=current_value) if formfield: field_list.append((f.name, formfield)) - fields = SortedDictFromList(field_list) + base_fields = SortedDictFromList(field_list) return type(opts.object_name + 'InstanceForm', (form,), - {'base_fields': fields, '_model': model, 'save': make_instance_save(instance)}) + {'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')}) def form_for_fields(field_list): "Returns a Form class for the given list of Django database field instances." diff --git a/django/test/testcases.py b/django/test/testcases.py index 788e215ca1..dd1f73befd 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -45,16 +45,16 @@ class TestCase(unittest.TestCase): if hasattr(self, 'fixtures'): management.load_data(self.fixtures, verbosity=0) mail.outbox = [] - - def run(self, result=None): - """Wrapper around default run method to perform common Django test set up. - This means that user-defined Test Cases aren't required to include a call - to super().setUp(). - + + def __call__(self, result=None): + """ + Wrapper around default __call__ method to perform common Django test + set up. This means that user-defined Test Cases aren't required to + include a call to super().setUp(). """ self.client = Client() self._pre_setup() - super(TestCase, self).run(result) + super(TestCase, self).__call__(result) def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200): """Assert that a response redirected to a specific URL, and that the @@ -62,7 +62,7 @@ class TestCase(unittest.TestCase): """ self.assertEqual(response.status_code, status_code, - "Response didn't redirect: Reponse code was %d (expected %d)" % + "Response didn't redirect as expected: Reponse code was %d (expected %d)" % (response.status_code, status_code)) scheme, netloc, path, params, query, fragment = urlparse(response['Location']) self.assertEqual(path, expected_path, @@ -70,7 +70,7 @@ class TestCase(unittest.TestCase): redirect_response = self.client.get(path) self.assertEqual(redirect_response.status_code, target_status_code, "Couldn't retrieve redirection page '%s': response code was %d (expected %d)" % - (path, response.status_code, status_code)) + (path, redirect_response.status_code, target_status_code)) def assertContains(self, response, text, count=1, status_code=200): """Assert that a response indicates that a page was retreived successfully, @@ -108,7 +108,7 @@ class TestCase(unittest.TestCase): for err in errors: if field: if field in context[form].errors: - self.assertTrue(err in context[form].errors[field], + self.failUnless(err in context[form].errors[field], "The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" % (field, form, i, err, list(context[form].errors[field]))) elif field in context[form].fields: @@ -117,7 +117,7 @@ class TestCase(unittest.TestCase): else: self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field)) else: - self.assertTrue(err in context[form].non_field_errors(), + self.failUnless(err in context[form].non_field_errors(), "The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" % (form, i, err, list(context[form].non_field_errors()))) if not found_form: @@ -127,7 +127,7 @@ class TestCase(unittest.TestCase): "Assert that the template with the provided name was used in rendering the response" if isinstance(response.template, list): template_names = [t.name for t in response.template] - self.assertTrue(template_name in template_names, + 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)) elif response.template: @@ -140,9 +140,9 @@ class TestCase(unittest.TestCase): def assertTemplateNotUsed(self, response, template_name): "Assert that the template with the provided name was NOT used in rendering the response" if isinstance(response.template, list): - self.assertFalse(template_name in [t.name for t in response.template], + self.failIf(template_name in [t.name for t in response.template], "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) -
\ No newline at end of file + diff --git a/docs/databrowse.txt b/docs/databrowse.txt index e9691cc879..9c03e7e4ea 100644 --- a/docs/databrowse.txt +++ b/docs/databrowse.txt @@ -44,7 +44,11 @@ How to use Databrowse It doesn't matter where you put this, as long as it gets executed at some point. A good place for it is in your URLconf file (``urls.py``). - 3. Add the following line to your URLconf:: + 3. Change your URLconf to import the ``databrowse`` module:: + + from django.contrib import databrowse + + ...and add the following line to your URLconf:: (r'^databrowse/(.*)', databrowse.site.root), diff --git a/docs/i18n.txt b/docs/i18n.txt index 1d7a0063b2..27abadacc9 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -236,7 +236,7 @@ To pluralize, specify both the singular and plural forms with the ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and ``{% endblocktrans %}``. Example:: - {% blocktrans count list|count as counter %} + {% blocktrans count list|length as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. diff --git a/docs/newforms.txt b/docs/newforms.txt index ddb850f54c..7c861ed405 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -9,28 +9,30 @@ framework. This document explains how to use this new library. Migration plan ============== -``django.newforms`` currently is only available in Django beginning -with the 0.96 release. the Django development version -- i.e., it's -not available in the Django 0.95 release. For the next Django release, -our plan is to do the following: +``django.newforms`` is new in Django's 0.96 release, but, as it won't be new +forever, we plan to rename it to ``django.forms`` in the future. The current +``django.forms`` package will be available as ``django.oldforms`` until Django +1.0, when we plan to remove it for good. - * As of revision [4208], we've copied the current ``django.forms`` to - ``django.oldforms``. This allows you to upgrade your code *now* rather - than waiting for the backwards-incompatible change and rushing to fix - your code after the fact. Just change your import statements like this:: +That has direct repercussions on the forward compatibility of your code. Please +read the following migration plan and code accordingly: + + * The old forms framework (the current ``django.forms``) has been copied to + ``django.oldforms``. Thus, you can start upgrading your code *now*, + rather than waiting for the future backwards-incompatible change, by + changing your import statements like this:: from django import forms # old from django import oldforms as forms # new - * At an undecided future date, we will move the current ``django.newforms`` - to ``django.forms``. This will be a backwards-incompatible change, and - anybody who is still using the old version of ``django.forms`` at that - time will need to change their import statements, as described in the - previous bullet. + * In the next Django release (0.97), we will move the current + ``django.newforms`` to ``django.forms``. This will be a + backwards-incompatible change, and anybody who is still using the old + version of ``django.forms`` at that time will need to change their import + statements, as described in the previous bullet. * We will remove ``django.oldforms`` in the release *after* the next Django - release -- the release that comes after the release in which we're - creating the new ``django.forms``. + release -- either 0.98 or 1.0, whichever comes first. With this in mind, we recommend you use the following import statement when using ``django.newforms``:: @@ -184,7 +186,7 @@ e-mail address:: >>> f.is_valid() False -Access the ``Form`` attribute ``errors`` to get a dictionary of error messages:: +Access the ``errors`` attribute to get a dictionary of error messages:: >>> f.errors {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']} @@ -197,6 +199,10 @@ You can access ``errors`` without having to call ``is_valid()`` first. The form's data will be validated the first time either you call ``is_valid()`` or access ``errors``. +The validation routines will only get called once, regardless of how many times +you access ``errors`` or call ``is_valid()``. This means that if validation has +side effects, those side effects will only be triggered once. + Behavior of unbound forms ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -274,6 +280,27 @@ but ``clean_data`` contains only the form's fields:: >>> f.clean_data # Doesn't contain extra_field_1, etc. {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} +``clean_data`` will include a key and value for *all* fields defined in the +``Form``, even if the data didn't include a value for fields that are not +required. In this example, the data dictionary doesn't include a value for the +``nick_name`` field, but ``clean_data`` includes it, with an empty value:: + + >>> class OptionalPersonForm(Form): + ... first_name = CharField() + ... last_name = CharField() + ... nick_name = CharField(required=False) + >>> data = {'first_name': u'John', 'last_name': u'Lennon'} + >>> f = OptionalPersonForm(data) + >>> f.is_valid() + True + >>> f.clean_data + {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} + +In this above example, the ``clean_data`` value for ``nick_name`` is set to an +empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat +empty values as an empty string. Each field type knows what its "blank" value +is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. + Behavior of unbound forms ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -454,7 +481,7 @@ field:: If ``auto_id`` is set to a string containing the format character ``'%s'``, then the form output will include ``<label>`` tags, and will generate ``id`` attributes based on the format string. For example, for a format string -``'field_%s'``, a field named ``subject`` will get the ``id`` +``'field_%s'``, a field named ``subject`` will get the ``id`` value ``'field_subject'``. Continuing our example:: >>> f = ContactForm(auto_id='id_for_%s') @@ -493,8 +520,9 @@ How errors are displayed If you render a bound ``Form`` object, the act of rendering will automatically run the form's validation if it hasn't already happened, and the HTML output -will include the validation errors as a ``<ul>`` near the field. The particular -positioning of the error messages depends on the output method you're using:: +will include the validation errors as a ``<ul class="errorlist">`` near the +field. The particular positioning of the error messages depends on the output +method you're using:: >>> data = {'subject': '', ... 'message': 'Hi there', @@ -556,7 +584,8 @@ The field-specific output honors the form object's ``auto_id`` setting:: <input type="text" name="message" id="id_message" /> For a field's list of errors, access the field's ``errors`` attribute. This -is a list-like object that is displayed as an HTML ``<ul>`` when printed:: +is a list-like object that is displayed as an HTML ``<ul class="errorlist">`` +when printed:: >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} >>> f = ContactForm(data, auto_id=False) @@ -646,7 +675,7 @@ Core field arguments Each ``Field`` class constructor takes at least these arguments. Some ``Field`` classes take additional, field-specific arguments, but the following -should *always* be available: +should *always* be accepted: ``required`` ~~~~~~~~~~~~ @@ -704,7 +733,7 @@ field.) The ``label`` argument lets you specify the "human-friendly" label for this field. This is used when the ``Field`` is displayed in a ``Form``. -As explained in _`Outputting forms as HTML` above, the default label for a +As explained in "Outputting forms as HTML" above, the default label for a ``Field`` is generated from the field name by converting all underscores to spaces and upper-casing the first letter. Specify ``label`` if that default behavior doesn't result in an adequate label. @@ -779,14 +808,15 @@ 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`` ~~~~~~~~~~~~~ The ``help_text`` argument lets you specify descriptive text for this ``Field``. If you provide ``help_text``, it will be displayed next to the -``Field`` when the ``Field`` is rendered in a ``Form``. +``Field`` when the ``Field`` is rendered by one of the convenience ``Form`` +methods (e.g., ``as_ul()``). Here's a full example ``Form`` that implements ``help_text`` for two of its fields. We've specified ``auto_id=False`` to simplify the output:: @@ -860,6 +890,212 @@ level and at the form instance level, and the latter gets precedence:: <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> +Built-in ``Field`` classes +-------------------------- + +Naturally, the ``newforms`` library comes with a set of ``Field`` classes that +represent common validation needs. This section documents each built-in field. + +For each field, we describe the default widget used if you don't specify +``widget``. We also specify the value returned when you provide an empty value +(see the section on ``required`` above to understand what that means). + +``BooleanField`` +~~~~~~~~~~~~~~~~ + + * Default widget: ``CheckboxInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``True`` or ``False`` value. + * Validates nothing (i.e., it never raises a ``ValidationError``). + +``CharField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates nothing, unless ``max_length`` or ``min_length`` is provided. + +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. + +``ChoiceField`` +~~~~~~~~~~~~~~~ + + * Default widget: ``Select`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value exists in the list of choices. + +Takes one extra argument, ``choices``, which is an iterable (e.g., a list or +tuple) of 2-tuples to use as choices for this field. + +``DateField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.date`` object. + * Validates that the given value is either a ``datetime.date``, + ``datetime.datetime`` or string formatted in a particular date format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.date`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' + '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' + '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' + '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' + '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' + +``DateTimeField`` +~~~~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.datetime`` object. + * Validates that the given value is either a ``datetime.datetime``, + ``datetime.date`` or string formatted in a particular datetime format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.datetime`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' + '%Y-%m-%d %H:%M', # '2006-10-25 14:30' + '%Y-%m-%d', # '2006-10-25' + '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' + '%m/%d/%Y %H:%M', # '10/25/2006 14:30' + '%m/%d/%Y', # '10/25/2006' + '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' + '%m/%d/%y %H:%M', # '10/25/06 14:30' + '%m/%d/%y', # '10/25/06' + +``EmailField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid e-mail address, using a + moderately complex regular expression. + +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. + +``IntegerField`` +~~~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python integer or long integer. + * Validates that the given value is an integer. Leading and trailing + whitespace is allowed, as in Python's ``int()`` function. + +``MultipleChoiceField`` +~~~~~~~~~~~~~~~~~~~~~~~ + + * Default widget: ``SelectMultiple`` + * Empty value: ``[]`` (an empty list) + * Normalizes to: A list of Unicode objects. + * Validates that every value in the given list of values exists in the list + of choices. + +Takes one extra argument, ``choices``, which is an iterable (e.g., a list or +tuple) of 2-tuples to use as choices for this field. + +``NullBooleanField`` +~~~~~~~~~~~~~~~~~~~~ + + * Default widget: ``NullBooleanSelect`` + * Empty value: ``None`` + * Normalizes to: A Python ``True``, ``False`` or ``None`` value. + * Validates nothing (i.e., it never raises a ``ValidationError``). + +``RegexField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value matches against a certain regular + expression. + +Takes one required argument, ``regex``, which is a regular expression specified +either as a string or a compiled regular expression object. + +Also takes the following optional arguments: + + ====================== ===================================================== + Argument Description + ====================== ===================================================== + ``max_length`` Ensures the string has at most this many characters. + ``min_length`` Ensures the string has at least this many characters. + ``error_message`` Error message to return for failed validation. If no + message is provided, a generic error message will be + used. + ====================== ===================================================== + +``TimeField`` +~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.time`` object. + * Validates that the given value is either a ``datetime.time`` or string + formatted in a particular time format. + +Takes one optional argument, ``input_formats``, which is a list of formats used +to attempt to convert a string to a valid ``datetime.time`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%H:%M:%S', # '14:30:59' + '%H:%M', # '14:30' + +``URLField`` +~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid URL. + +Takes the following optional arguments: + + ======================== ===================================================== + Argument Description + ======================== ===================================================== + ``max_length`` Ensures the string has at most this many characters. + ``min_length`` Ensures the string has at least this many characters. + ``verify_exists`` If ``True``, the validator will attempt to load the + given URL, raising ``ValidationError`` if the page + gives a 404. Defaults to ``False``. + ``validator_user_agent`` String used as the user-agent used when checking for + a URL's existence. Defaults to the value of the + ``URL_VALIDATOR_USER_AGENT`` setting. + ======================== ===================================================== + +Slightly complex built-in ``Field`` classes +------------------------------------------- + +The following are not yet documented here. See the unit tests, linked-to from +the bottom of this document, for examples of their use. + +``ComboField`` +~~~~~~~~~~~~~~ + +``MultiValueField`` +~~~~~~~~~~~~~~~~~~~ + +``SplitDateTimeField`` +~~~~~~~~~~~~~~~~~~~~~~ + Creating custom fields ---------------------- @@ -870,6 +1106,308 @@ custom ``Field`` classes. To do this, just create a subclass of mentioned above (``required``, ``label``, ``initial``, ``widget``, ``help_text``). +Generating forms for models +=========================== + +If you're building a database-driven app, chances are you'll have forms that +map closely to Django models. For instance, you might have a ``BlogComment`` +model, and you want to create a form that lets people submit comments. In this +case, it would be redundant to define the field types in your form, because +you've already defined the fields in your model. + +For this reason, Django provides a few helper functions that let you create a +``Form`` class from a Django model. + +``form_for_model()`` +-------------------- + +The method ``django.newforms.form_for_model()`` creates a form based on the +definition of a specific model. Pass it the model class, and it will return a +``Form`` class that contains a form field for each model field. + +For example:: + + >>> from django.newforms import form_for_model + + # Create the form class. + >>> ArticleForm = form_for_model(Article) + + # Create an empty form instance. + >>> f = ArticleForm() + +It bears repeating that ``form_for_model()`` takes the model *class*, not a +model instance, and it returns a ``Form`` *class*, not a ``Form`` instance. + +Field types +~~~~~~~~~~~ + +The generated ``Form`` class will have a form field for every model field. Each +model field has a corresponding default form field. For example, a +``CharField`` on a model is represented as a ``CharField`` on a form. A +model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is +the full list of conversions: + + =============================== ======================================== + Model field Form field + =============================== ======================================== + ``AutoField`` Not represented in the form + ``BooleanField`` ``BooleanField`` + ``CharField`` ``CharField`` with ``max_length`` set to + the model field's ``maxlength`` + ``CommaSeparatedIntegerField`` ``CharField`` + ``DateField`` ``DateField`` + ``DateTimeField`` ``DateTimeField`` + ``EmailField`` ``EmailField`` + ``FileField`` ``CharField`` + ``FilePathField`` ``CharField`` + ``FloatField`` ``CharField`` + ``ForeignKey`` ``ModelChoiceField`` (see below) + ``ImageField`` ``CharField`` + ``IntegerField`` ``IntegerField`` + ``IPAddressField`` ``CharField`` + ``ManyToManyField`` ``ModelMultipleChoiceField`` (see + below) + ``NullBooleanField`` ``CharField`` + ``PhoneNumberField`` ``USPhoneNumberField`` + (from ``django.contrib.localflavor.us``) + ``PositiveIntegerField`` ``IntegerField`` + ``PositiveSmallIntegerField`` ``IntegerField`` + ``SlugField`` ``CharField`` + ``SmallIntegerField`` ``IntegerField`` + ``TextField`` ``CharField`` with ``widget=Textarea`` + ``TimeField`` ``TimeField`` + ``URLField`` ``URLField`` with ``verify_exists`` set + to the model field's ``verify_exists`` + ``USStateField`` ``CharField`` with + ``widget=USStateSelect`` + (``USStateSelect`` is from + ``django.contrib.localflavor.us``) + ``XMLField`` ``CharField`` with ``widget=Textarea`` + =============================== ======================================== + +As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field +types are special cases: + + * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``, + which is a ``ChoiceField`` whose choices are a model ``QuerySet``. + + * ``ManyToManyField`` is represented by + ``django.newforms.ModelMultipleChoiceField``, which is a + ``MultipleChoiceField`` whose choices are a model ``QuerySet``. + +In addition, each generated form field has attributes set as follows: + + * If the model field has ``blank=True``, then ``required`` is set to + ``False`` on the form field. Otherwise, ``required=True``. + + * The form field's ``label`` is set to the ``verbose_name`` of the model + field, with the first character capitalized. + + * The form field's ``help_text`` is set to the ``help_text`` of the model + field. + + * If the model field has ``choices`` set, then the form field's ``widget`` + will be set to ``Select``, with choices coming from the model field's + ``choices``. + +Finally, note that you can override the form field used for a given model +field. See "Overriding the default field types" below. + +A full example +~~~~~~~~~~~~~~ + +Consider this set of models:: + + from django.db import models + + TITLE_CHOICES = ( + ('MR', 'Mr.'), + ('MRS', 'Mrs.'), + ('MS', 'Ms.'), + ) + + class Author(models.Model): + name = models.CharField(maxlength=100) + title = models.CharField(maxlength=3, choices=TITLE_CHOICES) + birth_date = models.DateField(blank=True, null=True) + + def __str__(self): + return self.name + + class Book(models.Model): + name = models.CharField(maxlength=100) + authors = models.ManyToManyField(Author) + +With these models, a call to ``form_for_model(Author)`` would return a ``Form`` +class equivalent to this:: + + class AuthorForm(forms.Form): + name = forms.CharField(max_length=100) + title = forms.CharField(max_length=3, + widget=forms.Select(choices=TITLE_CHOICES)) + birth_date = forms.DateField(required=False) + +A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to +this:: + + class BookForm(forms.Form): + name = forms.CharField(max_length=100) + authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) + +The ``save()`` method +~~~~~~~~~~~~~~~~~~~~~ + +Every form produced by ``form_for_model()`` also has a ``save()`` method. This +method creates and saves a database object from the data bound to the form. For +example:: + + # Create a form instance from POST data. + >>> f = ArticleForm(request.POST) + + # Save a new Article object from the form's data. + >>> new_article = f.save() + +Note that ``save()`` will raise a ``ValueError`` if the data in the form +doesn't validate -- i.e., ``if form.errors``. + +Using an alternate base class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to add custom methods to the form generated by +``form_for_model()``, write a class that extends ``django.newforms.BaseForm`` +and contains your custom methods. Then, use the ``form`` argument to +``form_for_model()`` to tell it to use your custom form as its base class. +For example:: + + # Create the new base class. + >>> class MyBase(BaseForm): + ... def my_method(self): + ... # Do whatever the method does + + # Create the form class with a different base class. + >>> ArticleForm = form_for_model(Article, form=MyBase) + + # Instantiate the form. + >>> f = ArticleForm() + + # Use the base class method. + >>> f.my_method() + +Using a subset of fields on the form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**New in Django development version** + +In some cases, you may not want all the model fields to appear on the generated +form. There are two ways of telling ``form_for_model()`` to use only a subset +of the model fields: + + 1. Set ``editable=False`` on the model field. As a result, *any* form + created from the model via ``form_for_model()`` will not include that + field. + + 2. Use the ``fields`` argument to ``form_for_model()``. This argument, if + given, should be a list of field names to include in the form. + + For example, if you want a form for the ``Author`` model (defined above) + that includes only the ``name`` and ``title`` fields, you would specify + ``fields`` like this:: + + PartialArticleForm = form_for_model(Author, fields=('name', 'title')) + +.. note:: + + If you specify ``fields`` when creating a form with ``form_for_model()``, + make sure that the fields that are *not* specified can provide default + values, or are allowed to have a value of ``None``. If a field isn't + specified on a form, the object created from the form can't provide + a value for that attribute, which will prevent the new instance from + being saved. + +Overriding the default field types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default field types, as described in the "Field types" table above, are +sensible defaults; if you have a ``DateField`` in your model, chances are you'd +want that to be represented as a ``DateField`` in your form. But +``form_for_model()`` gives you the flexibility of changing the form field type +for a given model field. You do this by specifying a **formfield callback**. + +A formfield callback is a function that, when provided with a model field, +returns a form field instance. When constructing a form, ``form_for_model()`` +asks the formfield callback to provide form field types. + +By default, ``form_for_model()`` calls the ``formfield()`` method on the model +field:: + + def default_callback(field, **kwargs): + return field.formfield(**kwargs) + +The ``kwargs`` are any keyword arguments that might be passed to the form +field, such as ``required=True`` or ``label='Foo'``. + +For example, if you wanted to use ``MyDateFormField`` for any ``DateField`` +field on the model, you could define the callback:: + + >>> def my_callback(field, **kwargs): + ... if isinstance(field, models.DateField): + ... return MyDateFormField(**kwargs) + ... else: + ... return field.formfield(**kwargs) + + >>> ArticleForm = form_for_model(formfield_callback=my_callback) + +Note that your callback needs to handle *all* possible model field types, not +just the ones that you want to behave differently to the default. That's why +this example has an ``else`` clause that implements the default behavior. + +Finding the model associated with a form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The model class that was used to construct the form is available +using the ``_model`` property of the generated form:: + + >>> ArticleForm = form_for_model(Article) + >>> ArticleForm._model + <class 'myapp.models.Article'> + +``form_for_instance()`` +----------------------- + +``form_for_instance()`` is like ``form_for_model()``, but it takes a model +instance instead of a model class:: + + # Create an Author. + >>> a = Author(name='Joe Smith', title='MR', birth_date=None) + >>> a.save() + + # Create a form for this particular Author. + >>> AuthorForm = form_for_instance(a) + + # Instantiate the form. + >>> f = AuthorForm() + +When a form created by ``form_for_instance()`` is created, the initial +data values for the form fields are drawn from the instance. However, +this data is not bound to the form. You will need to bind data to the +form before the form can be saved. + +When you call ``save()`` on a form created by ``form_for_instance()``, +the database instance will be updated. As in ``form_for_model()``, ``save()`` +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()``. + +When should you use ``form_for_model()`` and ``form_for_instance()``? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be +shortcuts for the common case. If you want to create a form whose fields map to +more than one model, or a form that contains fields that *aren't* on a model, +you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way +isn't that difficult, after all. + More coming soon ================ @@ -880,6 +1418,3 @@ what's possible. If you're really itching to learn and use this library, please be patient. We're working hard on finishing both the code and documentation. - -Widgets -======= diff --git a/docs/testing.txt b/docs/testing.txt index b44b67c20a..92edf46e09 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -177,7 +177,7 @@ tools that can be used to establish tests and test conditions. * `Test Client`_ * `TestCase`_ -* `Email services`_ +* `E-mail services`_ Test Client ----------- @@ -459,9 +459,9 @@ 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 email outbox. +Django clears the contents of the test e-mail outbox. -For more detail on email services during tests, see `Email services`_. +For more detail on e-mail services during tests, see `E-mail services`_. Assertions ~~~~~~~~~~ @@ -502,16 +502,17 @@ that can be useful in testing the behavior of web sites. Assert that the template with the given name was used in rendering the response. -Email services --------------- +E-mail services +--------------- + **New in Django development version** -If your view makes use of the `Django email services`_, you don't really -want email to be sent every time you run a test using that view. +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. When the Django test framework is initialized, it transparently replaces the normal `SMTPConnection`_ class with a dummy implementation that redirects all -email to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``, +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:: @@ -541,7 +542,7 @@ to mail.outbox:: # Empty the test outbox mail.outbox = [] -.. _`Django email services`: ../email/ +.. _`Django e-mail services`: ../email/ .. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes .. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes .. _`previously`: #emptying-the-test-outbox @@ -669,7 +670,7 @@ a number of utility methods in the ``django.test.utils`` module. ``teardown_test_environment()`` Performs any global post-test teardown, such as removing the instrumentation - of the template rendering system and restoring normal email services. + of the template rendering system and restoring normal e-mail services. ``create_test_db(verbosity=1, autoclobber=False)`` Creates a new test database, and run ``syncdb`` against it. diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index a23529b566..e78f5f7bd7 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -179,6 +179,18 @@ fields with the 'choices' attribute are represented by a ChoiceField. <option value="3">Third test</option> </select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr> +You can restrict a form to a subset of the complete list of fields +by providing a 'fields' argument. If you try to save a +model created with such a form, you need to ensure that the fields +that are _not_ on the form have default values, or are allowed to have +a value of None. If a field isn't specified on a form, the object created +from the form can't provide a value for that field! +>>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) +>>> f = PartialArticleForm(auto_id=False) +>>> print f +<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> +<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> + You can pass a custom Form class to form_for_model. Make sure it's a subclass of BaseForm, not Form. >>> class CustomForm(BaseForm): @@ -224,7 +236,23 @@ current values are inserted as 'initial' data in each Field. <option value="2">It's a test</option> <option value="3">Third test</option> </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> ->>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1', 'article': 'Hello.'}) +>>> f = TestArticleForm({'headline': u'Test headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) +>>> f.is_valid() +True +>>> test_art = f.save() +>>> test_art.id +1 +>>> test_art = Article.objects.get(id=1) +>>> test_art.headline +'Test headline' + +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() +<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> +<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> >>> f.is_valid() True >>> new_art = f.save() diff --git a/tests/regressiontests/forms/regressions.py b/tests/regressiontests/forms/regressions.py index 5daabc03af..789ac81715 100644 --- a/tests/regressiontests/forms/regressions.py +++ b/tests/regressiontests/forms/regressions.py @@ -34,4 +34,18 @@ Unicode decoding problems... >>> 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>' + +####################### +# 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.clean_data +{'data': u'xyzzy'} """ diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 0d3a65277c..82be58dd0c 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -1916,6 +1916,34 @@ True >>> p.clean_data {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} +clean_data will include a key and value for *all* fields defined in the Form, +even if the Form's data didn't include a value for fields that are not +required. In this example, the data dictionary doesn't include a value for the +"nick_name" field, but clean_data includes it. For CharFields, it's set to the +empty string. +>>> class OptionalPersonForm(Form): +... first_name = CharField() +... last_name = CharField() +... nick_name = CharField(required=False) +>>> data = {'first_name': u'John', 'last_name': u'Lennon'} +>>> f = OptionalPersonForm(data) +>>> f.is_valid() +True +>>> f.clean_data +{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} + +For DateFields, it's set to None. +>>> class OptionalPersonForm(Form): +... first_name = CharField() +... last_name = CharField() +... birth_date = DateField(required=False) +>>> data = {'first_name': u'John', 'last_name': u'Lennon'} +>>> f = OptionalPersonForm(data) +>>> f.is_valid() +True +>>> f.clean_data +{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'} + "auto_id" tells the Form to add an "id" attribute to each form element. If it's a string that contains '%s', Django will use that as a format string into which the field's name will be inserted. It will also put a <label> around @@ -2275,7 +2303,7 @@ returns a list of input. Validation errors are HTML-escaped when output as HTML. >>> class EscapingForm(Form): ... special_name = CharField() -... def clean_special_name(self): +... def do_clean_special_name(self): ... raise ValidationError("Something's wrong with '%s'" % self.clean_data['special_name']) >>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False) @@ -2298,7 +2326,7 @@ including the current field (e.g., the field XXX if you're in clean_XXX()). ... username = CharField(max_length=10) ... password1 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput) -... def clean_password2(self): +... def do_clean_password2(self): ... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: ... raise ValidationError(u'Please make sure your passwords match.') ... return self.clean_data['password2'] @@ -2752,6 +2780,64 @@ then the latter will get precedence. <li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li> <li>Password: <input type="password" name="password" /></li> +# Callable initial data ######################################################## + +The previous technique dealt with raw values as initial data, but it's also +possible to specify callable data. + +>>> class UserRegistration(Form): +... username = CharField(max_length=10) +... password = CharField(widget=PasswordInput) + +We need to define functions that get called later. +>>> def initial_django(): +... return 'django' +>>> def initial_stephane(): +... return 'stephane' + +Here, we're not submitting any data, so the initial value will be displayed. +>>> p = UserRegistration(initial={'username': initial_django}, auto_id=False) +>>> print p.as_ul() +<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li> +<li>Password: <input type="password" name="password" /></li> + +The 'initial' parameter is meaningless if you pass data. +>>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False) +>>> print p.as_ul() +<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li> +<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> +>>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False) +>>> print p.as_ul() +<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li> +<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> +>>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False) +>>> print p.as_ul() +<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li> +<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> + +A callable 'initial' value is *not* used as a fallback if data is not provided. +In this example, we don't provide a value for 'username', and the form raises a +validation error rather than using the initial value for 'username'. +>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django}) +>>> p.errors +{'username': [u'This field is required.']} +>>> p.is_valid() +False + +If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(), +then the latter will get precedence. +>>> class UserRegistration(Form): +... username = CharField(max_length=10, initial=initial_django) +... password = CharField(widget=PasswordInput) +>>> p = UserRegistration(auto_id=False) +>>> print p.as_ul() +<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li> +<li>Password: <input type="password" name="password" /></li> +>>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False) +>>> print p.as_ul() +<li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li> +<li>Password: <input type="password" name="password" /></li> + # Help text ################################################################### You can specify descriptive text for a field by using the 'help_text' argument @@ -3320,7 +3406,7 @@ True </select> # MultiWidget and MultiValueField ############################################# -# MultiWidgets are widgets composed of other widgets. They are usually +# MultiWidgets are widgets composed of other widgets. They are usually # combined with MultiValueFields - a field that is composed of other fields. # MulitWidgets can themselved be composed of other MultiWidgets. # SplitDateTimeWidget is one example of a MultiWidget. @@ -3328,7 +3414,7 @@ True >>> class ComplexMultiWidget(MultiWidget): ... def __init__(self, attrs=None): ... widgets = ( -... TextInput(), +... TextInput(), ... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), ... SplitDateTimeWidget(), ... ) @@ -3353,13 +3439,13 @@ True <input type="text" name="name_2_0" value="2007-04-25" /><input type="text" name="name_2_1" value="06:24:00" /> >>> class ComplexField(MultiValueField): -... def __init__(self, required=True, widget=None, label=None, initial=None): +... def __init__(self, required=True, widget=None, label=None, initial=None): ... fields = ( -... CharField(), +... CharField(), ... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), ... SplitDateTimeField() ... ) -... super(ComplexField, self).__init__(fields, required, widget, label, initial) +... super(ComplexField, self).__init__(fields, required, widget, label, initial) ... ... def compress(self, data_list): ... if data_list: diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index c287b6e0d6..fea5c94cab 100644 --- a/tests/regressiontests/serializers_regress/models.py +++ b/tests/regressiontests/serializers_regress/models.py @@ -100,6 +100,12 @@ class Anchor(models.Model): something for other models to point at""" data = models.CharField(maxlength=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) class FKData(models.Model): data = models.ForeignKey(Anchor, null=True) @@ -116,6 +122,10 @@ class FKSelfData(models.Model): class M2MSelfData(models.Model): data = models.ManyToManyField('self', null=True, symmetrical=False) + +class FKDataToField(models.Model): + data = models.ForeignKey(UniqueAnchor, null=True, to_field='data') + # The following test classes are for validating the # deserialization of objects that use a user-defined # field as the primary key. diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 97b3fbacbe..317739dac4 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -159,6 +159,7 @@ The end."""), (data_obj, 300, Anchor, "Anchor 1"), (data_obj, 301, Anchor, "Anchor 2"), + (data_obj, 302, UniqueAnchor, "UAnchor 1"), (fk_obj, 400, FKData, 300), # Post reference (fk_obj, 401, FKData, 500), # Pre reference @@ -184,8 +185,13 @@ The end."""), (m2m_obj, 445, M2MSelfData, []), (m2m_obj, 446, M2MSelfData, []), + (fk_obj, 450, FKDataToField, "UAnchor 1"), + (fk_obj, 451, FKDataToField, "UAnchor 2"), + (fk_obj, 452, FKDataToField, None), + (data_obj, 500, Anchor, "Anchor 3"), (data_obj, 501, Anchor, "Anchor 4"), + (data_obj, 502, UniqueAnchor, "UAnchor 2"), (pk_obj, 601, BooleanPKData, True), (pk_obj, 602, BooleanPKData, False), diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py index c39fafe314..40d022a47a 100644 --- a/tests/regressiontests/test_client_regress/models.py +++ b/tests/regressiontests/test_client_regress/models.py @@ -60,7 +60,35 @@ class AssertTemplateUsedTests(TestCase): 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']") + +class AssertRedirectsTests(TestCase): + def test_redirect_page(self): + "An assertion is raised if the original page couldn't be retrieved as expected" + # This page will redirect with code 301, not 302 + response = self.client.get('/test_client/permanent_redirect_view/') + 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)") + + def test_incorrect_target(self): + "An assertion is raised if the response redirects to another target" + response = self.client.get('/test_client/permanent_redirect_view/') + try: + # 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)") + def test_target_page(self): + "An assertion is raised if the reponse 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 + self.assertRedirects(response, '/test_client/permanent_redirect_view/') + except AssertionError, e: + self.assertEquals(str(e), "Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)") + class AssertFormErrorTests(TestCase): def test_unknown_form(self): "An assertion is raised if the form name is unknown" |