mirror of
https://github.com/django/django.git
synced 2025-07-03 17:29:12 +00:00
gis: Merged revisions 7981-8001,8003-8011,8013-8033,8035-8036,8038-8039,8041-8063,8065-8076,8078-8139,8141-8154,8156-8214 via svnmerge from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@8215 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
45b73c9a46
commit
aa239e3e54
13
AUTHORS
13
AUTHORS
@ -41,6 +41,7 @@ And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
|
|||||||
people who have submitted patches, reported bugs, added translations, helped
|
people who have submitted patches, reported bugs, added translations, helped
|
||||||
answer newbie questions, and generally made Django that much better:
|
answer newbie questions, and generally made Django that much better:
|
||||||
|
|
||||||
|
ajs <adi@sieker.info>
|
||||||
alang@bright-green.com
|
alang@bright-green.com
|
||||||
Marty Alchin <gulopine@gamemusic.org>
|
Marty Alchin <gulopine@gamemusic.org>
|
||||||
atlithorn <atlithorn@gmail.com>
|
atlithorn <atlithorn@gmail.com>
|
||||||
@ -70,7 +71,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Esdras Beleza <linux@esdrasbeleza.com>
|
Esdras Beleza <linux@esdrasbeleza.com>
|
||||||
Chris Bennett <chrisrbennett@yahoo.com>
|
Chris Bennett <chrisrbennett@yahoo.com>
|
||||||
James Bennett
|
James Bennett
|
||||||
Ben Godfrey <http://aftnn.org>
|
Julian Bez
|
||||||
Arvis Bickovskis <viestards.lists@gmail.com>
|
Arvis Bickovskis <viestards.lists@gmail.com>
|
||||||
Paul Bissex <http://e-scribe.com/>
|
Paul Bissex <http://e-scribe.com/>
|
||||||
Simon Blanchard
|
Simon Blanchard
|
||||||
@ -150,8 +151,10 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Stefane Fermgier <sf@fermigier.com>
|
Stefane Fermgier <sf@fermigier.com>
|
||||||
Afonso Fernández Nogueira <fonzzo.django@gmail.com>
|
Afonso Fernández Nogueira <fonzzo.django@gmail.com>
|
||||||
J. Pablo Fernandez <pupeno@pupeno.com>
|
J. Pablo Fernandez <pupeno@pupeno.com>
|
||||||
|
Maciej Fijalkowski
|
||||||
Matthew Flanagan <http://wadofstuff.blogspot.com>
|
Matthew Flanagan <http://wadofstuff.blogspot.com>
|
||||||
Eric Floehr <eric@intellovations.com>
|
Eric Floehr <eric@intellovations.com>
|
||||||
|
Eric Florenzano <floguy@gmail.com>
|
||||||
Vincent Foley <vfoleybourgon@yahoo.ca>
|
Vincent Foley <vfoleybourgon@yahoo.ca>
|
||||||
Rudolph Froger <rfroger@estrate.nl>
|
Rudolph Froger <rfroger@estrate.nl>
|
||||||
Jorge Gajon <gajon@gajon.org>
|
Jorge Gajon <gajon@gajon.org>
|
||||||
@ -164,6 +167,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
glin@seznam.cz
|
glin@seznam.cz
|
||||||
martin.glueck@gmail.com
|
martin.glueck@gmail.com
|
||||||
Artyom Gnilov <boobsd@gmail.com>
|
Artyom Gnilov <boobsd@gmail.com>
|
||||||
|
Ben Godfrey <http://aftnn.org>
|
||||||
GomoX <gomo@datafull.com>
|
GomoX <gomo@datafull.com>
|
||||||
Guilherme Mesquita Gondim <semente@taurinus.org>
|
Guilherme Mesquita Gondim <semente@taurinus.org>
|
||||||
Mario Gonzalez <gonzalemario@gmail.com>
|
Mario Gonzalez <gonzalemario@gmail.com>
|
||||||
@ -172,6 +176,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Owen Griffiths
|
Owen Griffiths
|
||||||
Espen Grindhaug <http://grindhaug.org/>
|
Espen Grindhaug <http://grindhaug.org/>
|
||||||
Thomas Güttler <hv@tbz-pariv.de>
|
Thomas Güttler <hv@tbz-pariv.de>
|
||||||
|
Horst Gutmann <zerok@zerokspot.com>
|
||||||
dAniel hAhler
|
dAniel hAhler
|
||||||
hambaloney
|
hambaloney
|
||||||
Brian Harring <ferringb@gmail.com>
|
Brian Harring <ferringb@gmail.com>
|
||||||
@ -234,6 +239,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Stuart Langridge <http://www.kryogenix.org/>
|
Stuart Langridge <http://www.kryogenix.org/>
|
||||||
Paul Lanier <planier@google.com>
|
Paul Lanier <planier@google.com>
|
||||||
Nicola Larosa <nico@teknico.net>
|
Nicola Larosa <nico@teknico.net>
|
||||||
|
Lau Bech Lauritzen
|
||||||
Rune Rønde Laursen <runerl@skjoldhoej.dk>
|
Rune Rønde Laursen <runerl@skjoldhoej.dk>
|
||||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||||
lcordier@point45.com
|
lcordier@point45.com
|
||||||
@ -276,6 +282,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||||
mrmachine <real.human@mrmachine.net>
|
mrmachine <real.human@mrmachine.net>
|
||||||
Robin Munn <http://www.geekforgod.com/>
|
Robin Munn <http://www.geekforgod.com/>
|
||||||
|
James Murty
|
||||||
msundstr
|
msundstr
|
||||||
Robert Myers <myer0052@gmail.com>
|
Robert Myers <myer0052@gmail.com>
|
||||||
Nebojša Dorđević
|
Nebojša Dorđević
|
||||||
@ -301,6 +308,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
phil@produxion.net
|
phil@produxion.net
|
||||||
phil.h.smith@gmail.com
|
phil.h.smith@gmail.com
|
||||||
Gustavo Picon
|
Gustavo Picon
|
||||||
|
Michael Placentra II <someone@michaelplacentra2.net>
|
||||||
Luke Plant <http://lukeplant.me.uk/>
|
Luke Plant <http://lukeplant.me.uk/>
|
||||||
plisk
|
plisk
|
||||||
Mihai Preda <mihai_preda@yahoo.com>
|
Mihai Preda <mihai_preda@yahoo.com>
|
||||||
@ -338,8 +346,10 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Pete Shinners <pete@shinners.org>
|
Pete Shinners <pete@shinners.org>
|
||||||
Leo Shklovskii
|
Leo Shklovskii
|
||||||
jason.sidabras@gmail.com
|
jason.sidabras@gmail.com
|
||||||
|
Brenton Simpson <http://theillustratedlife.com>
|
||||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||||
Ben Slavin <benjamin.slavin@gmail.com>
|
Ben Slavin <benjamin.slavin@gmail.com>
|
||||||
|
sloonz <simon.lipp@insa-lyon.fr>
|
||||||
SmileyChris <smileychris@gmail.com>
|
SmileyChris <smileychris@gmail.com>
|
||||||
smurf@smurf.noris.de
|
smurf@smurf.noris.de
|
||||||
Vsevolod Solovyov
|
Vsevolod Solovyov
|
||||||
@ -398,6 +408,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
charly.wilhelm@gmail.com
|
charly.wilhelm@gmail.com
|
||||||
Rachel Willmer <http://www.willmer.com/kb/>
|
Rachel Willmer <http://www.willmer.com/kb/>
|
||||||
Gary Wilson <gary.wilson@gmail.com>
|
Gary Wilson <gary.wilson@gmail.com>
|
||||||
|
Jakub Wilk <ubanus@users.sf.net>
|
||||||
Jakub Wiśniowski <restless.being@gmail.com>
|
Jakub Wiśniowski <restless.being@gmail.com>
|
||||||
Maciej Wiśniowski <pigletto@gmail.com>
|
Maciej Wiśniowski <pigletto@gmail.com>
|
||||||
wojtek
|
wojtek
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
VERSION = (0, 97, 'pre')
|
VERSION = (1, 0, 'alpha')
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
"Returns the version as a human-format string."
|
"Returns the version as a human-format string."
|
||||||
|
@ -188,6 +188,9 @@ APPEND_SLASH = True
|
|||||||
# Whether to prepend the "www." subdomain to URLs that don't have it.
|
# Whether to prepend the "www." subdomain to URLs that don't have it.
|
||||||
PREPEND_WWW = False
|
PREPEND_WWW = False
|
||||||
|
|
||||||
|
# Override the server-derived value of SCRIPT_NAME
|
||||||
|
FORCE_SCRIPT_NAME = None
|
||||||
|
|
||||||
# List of compiled regular expression objects representing User-Agent strings
|
# List of compiled regular expression objects representing User-Agent strings
|
||||||
# that are not allowed to visit any page, systemwide. Use this for bad
|
# that are not allowed to visit any page, systemwide. Use this for bad
|
||||||
# robots/crawlers. Here are a few examples:
|
# robots/crawlers. Here are a few examples:
|
||||||
@ -363,6 +366,9 @@ LOGOUT_URL = '/accounts/logout/'
|
|||||||
|
|
||||||
LOGIN_REDIRECT_URL = '/accounts/profile/'
|
LOGIN_REDIRECT_URL = '/accounts/profile/'
|
||||||
|
|
||||||
|
# The number of days a password reset link is valid for
|
||||||
|
PASSWORD_RESET_TIMEOUT_DAYS = 3
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# TESTING #
|
# TESTING #
|
||||||
###########
|
###########
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1066,7 +1066,7 @@ msgstr "Sélectionnez %s"
|
|||||||
#: contrib/admin/views/main.py:583
|
#: contrib/admin/views/main.py:583
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select %s to change"
|
msgid "Select %s to change"
|
||||||
msgstr "Sélectionnez %s pour changer"
|
msgstr "Sélectionnez l'objet %s à changer"
|
||||||
|
|
||||||
#: contrib/admin/views/main.py:784
|
#: contrib/admin/views/main.py:784
|
||||||
msgid "Database error"
|
msgid "Database error"
|
||||||
@ -4093,107 +4093,107 @@ msgstr "midi"
|
|||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Monday"
|
msgid "Monday"
|
||||||
msgstr "Lundi"
|
msgstr "lundi"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Tuesday"
|
msgid "Tuesday"
|
||||||
msgstr "Mardi"
|
msgstr "mardi"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Wednesday"
|
msgid "Wednesday"
|
||||||
msgstr "Mercredi"
|
msgstr "mercredi"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Thursday"
|
msgid "Thursday"
|
||||||
msgstr "Jeudi"
|
msgstr "jeudi"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Friday"
|
msgid "Friday"
|
||||||
msgstr "Vendredi"
|
msgstr "vendredi"
|
||||||
|
|
||||||
#: utils/dates.py:7
|
#: utils/dates.py:7
|
||||||
msgid "Saturday"
|
msgid "Saturday"
|
||||||
msgstr "Samedi"
|
msgstr "samedi"
|
||||||
|
|
||||||
#: utils/dates.py:7
|
#: utils/dates.py:7
|
||||||
msgid "Sunday"
|
msgid "Sunday"
|
||||||
msgstr "Dimanche"
|
msgstr "dimanche"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Mon"
|
msgid "Mon"
|
||||||
msgstr "Lun"
|
msgstr "lun"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Tue"
|
msgid "Tue"
|
||||||
msgstr "Mar"
|
msgstr "mar"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Wed"
|
msgid "Wed"
|
||||||
msgstr "Mer"
|
msgstr "mer"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Thu"
|
msgid "Thu"
|
||||||
msgstr "Jeu"
|
msgstr "jeu"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Fri"
|
msgid "Fri"
|
||||||
msgstr "Ven"
|
msgstr "ven"
|
||||||
|
|
||||||
#: utils/dates.py:11
|
#: utils/dates.py:11
|
||||||
msgid "Sat"
|
msgid "Sat"
|
||||||
msgstr "Sam"
|
msgstr "sam"
|
||||||
|
|
||||||
#: utils/dates.py:11
|
#: utils/dates.py:11
|
||||||
msgid "Sun"
|
msgid "Sun"
|
||||||
msgstr "Dim"
|
msgstr "dim"
|
||||||
|
|
||||||
#: utils/dates.py:18
|
#: utils/dates.py:18
|
||||||
msgid "January"
|
msgid "January"
|
||||||
msgstr "Janvier"
|
msgstr "janvier"
|
||||||
|
|
||||||
#: utils/dates.py:18
|
#: utils/dates.py:18
|
||||||
msgid "February"
|
msgid "February"
|
||||||
msgstr "Février"
|
msgstr "février"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "March"
|
msgid "March"
|
||||||
msgstr "Mars"
|
msgstr "mars"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "April"
|
msgid "April"
|
||||||
msgstr "Avril"
|
msgstr "avril"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr "Mai"
|
msgstr "mai"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "June"
|
msgid "June"
|
||||||
msgstr "Juin"
|
msgstr "juin"
|
||||||
|
|
||||||
#: utils/dates.py:19 utils/dates.py:31
|
#: utils/dates.py:19 utils/dates.py:31
|
||||||
msgid "July"
|
msgid "July"
|
||||||
msgstr "Juillet"
|
msgstr "juillet"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "August"
|
msgid "August"
|
||||||
msgstr "Août"
|
msgstr "août"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "September"
|
msgid "September"
|
||||||
msgstr "Septembre"
|
msgstr "septembre"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "October"
|
msgid "October"
|
||||||
msgstr "Octobre"
|
msgstr "octobre"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "November"
|
msgid "November"
|
||||||
msgstr "Novembre"
|
msgstr "novembre"
|
||||||
|
|
||||||
#: utils/dates.py:20
|
#: utils/dates.py:20
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr "Décembre"
|
msgstr "décembre"
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "jan"
|
msgid "jan"
|
||||||
@ -4245,31 +4245,31 @@ msgstr "déc"
|
|||||||
|
|
||||||
#: utils/dates.py:31
|
#: utils/dates.py:31
|
||||||
msgid "Jan."
|
msgid "Jan."
|
||||||
msgstr "Jan."
|
msgstr "jan."
|
||||||
|
|
||||||
#: utils/dates.py:31
|
#: utils/dates.py:31
|
||||||
msgid "Feb."
|
msgid "Feb."
|
||||||
msgstr "Fév."
|
msgstr "fév."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Aug."
|
msgid "Aug."
|
||||||
msgstr "Août"
|
msgstr "août"
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Sept."
|
msgid "Sept."
|
||||||
msgstr "Sept."
|
msgstr "sept."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Oct."
|
msgid "Oct."
|
||||||
msgstr "Oct."
|
msgstr "oct."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Nov."
|
msgid "Nov."
|
||||||
msgstr "Nov."
|
msgstr "nov."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Dec."
|
msgid "Dec."
|
||||||
msgstr "Déc."
|
msgstr "déc."
|
||||||
|
|
||||||
#: utils/text.py:127
|
#: utils/text.py:127
|
||||||
msgid "or"
|
msgid "or"
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -6,7 +6,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2008-02-22 21:55+0400\n"
|
"POT-Creation-Date: 2008-07-15 21:17+0400\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: David Avsajanishvili <avsd05@gmail.com>\n"
|
"Last-Translator: David Avsajanishvili <avsd05@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -14,191 +14,199 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: conf/global_settings.py:39
|
#: conf/global_settings.py:44
|
||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "არაბული"
|
msgstr "არაბული"
|
||||||
|
|
||||||
#: conf/global_settings.py:40
|
#: conf/global_settings.py:45
|
||||||
msgid "Bengali"
|
msgid "Bengali"
|
||||||
msgstr "ბენგალიური"
|
msgstr "ბენგალიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:41
|
#: conf/global_settings.py:46
|
||||||
msgid "Bulgarian"
|
msgid "Bulgarian"
|
||||||
msgstr "ბულგარული"
|
msgstr "ბულგარული"
|
||||||
|
|
||||||
#: conf/global_settings.py:42
|
#: conf/global_settings.py:47
|
||||||
msgid "Catalan"
|
msgid "Catalan"
|
||||||
msgstr "კატალანური"
|
msgstr "კატალანური"
|
||||||
|
|
||||||
#: conf/global_settings.py:43
|
#: conf/global_settings.py:48
|
||||||
msgid "Czech"
|
msgid "Czech"
|
||||||
msgstr "ჩეხური"
|
msgstr "ჩეხური"
|
||||||
|
|
||||||
#: conf/global_settings.py:44
|
#: conf/global_settings.py:49
|
||||||
msgid "Welsh"
|
msgid "Welsh"
|
||||||
msgstr "უელსური"
|
msgstr "უელსური"
|
||||||
|
|
||||||
#: conf/global_settings.py:45
|
#: conf/global_settings.py:50
|
||||||
msgid "Danish"
|
msgid "Danish"
|
||||||
msgstr "დანიური"
|
msgstr "დანიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:46
|
#: conf/global_settings.py:51
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "გერმანული"
|
msgstr "გერმანული"
|
||||||
|
|
||||||
#: conf/global_settings.py:47
|
#: conf/global_settings.py:52
|
||||||
msgid "Greek"
|
msgid "Greek"
|
||||||
msgstr "ბერძნული"
|
msgstr "ბერძნული"
|
||||||
|
|
||||||
#: conf/global_settings.py:48
|
#: conf/global_settings.py:53
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "ინგლისური"
|
msgstr "ინგლისური"
|
||||||
|
|
||||||
#: conf/global_settings.py:49
|
#: conf/global_settings.py:54
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "ესპანური"
|
msgstr "ესპანური"
|
||||||
|
|
||||||
#: conf/global_settings.py:50
|
#: conf/global_settings.py:55
|
||||||
|
msgid "Estonian"
|
||||||
|
msgstr "ესტონური"
|
||||||
|
|
||||||
|
#: conf/global_settings.py:56
|
||||||
msgid "Argentinean Spanish"
|
msgid "Argentinean Spanish"
|
||||||
msgstr "არგენტინის ესპანური"
|
msgstr "არგენტინის ესპანური"
|
||||||
|
|
||||||
#: conf/global_settings.py:51
|
#: conf/global_settings.py:57
|
||||||
msgid "Basque"
|
msgid "Basque"
|
||||||
msgstr "ბასკური"
|
msgstr "ბასკური"
|
||||||
|
|
||||||
#: conf/global_settings.py:52
|
#: conf/global_settings.py:58
|
||||||
msgid "Persian"
|
msgid "Persian"
|
||||||
msgstr "სპარსული"
|
msgstr "სპარსული"
|
||||||
|
|
||||||
#: conf/global_settings.py:53
|
#: conf/global_settings.py:59
|
||||||
msgid "Finnish"
|
msgid "Finnish"
|
||||||
msgstr "ფინური"
|
msgstr "ფინური"
|
||||||
|
|
||||||
#: conf/global_settings.py:54
|
#: conf/global_settings.py:60
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "ფრანგული"
|
msgstr "ფრანგული"
|
||||||
|
|
||||||
#: conf/global_settings.py:55
|
#: conf/global_settings.py:61
|
||||||
msgid "Irish"
|
msgid "Irish"
|
||||||
msgstr "ირლანდიური"
|
msgstr "ირლანდიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:56
|
#: conf/global_settings.py:62
|
||||||
msgid "Galician"
|
msgid "Galician"
|
||||||
msgstr "გალიციური"
|
msgstr "გალიციური"
|
||||||
|
|
||||||
#: conf/global_settings.py:57
|
#: conf/global_settings.py:63
|
||||||
msgid "Hungarian"
|
msgid "Hungarian"
|
||||||
msgstr "უნგრული"
|
msgstr "უნგრული"
|
||||||
|
|
||||||
#: conf/global_settings.py:58
|
#: conf/global_settings.py:64
|
||||||
msgid "Hebrew"
|
msgid "Hebrew"
|
||||||
msgstr "ებრაული"
|
msgstr "ებრაული"
|
||||||
|
|
||||||
#: conf/global_settings.py:59
|
#: conf/global_settings.py:65
|
||||||
msgid "Croatian"
|
msgid "Croatian"
|
||||||
msgstr "ხორვატიული"
|
msgstr "ხორვატიული"
|
||||||
|
|
||||||
#: conf/global_settings.py:60
|
#: conf/global_settings.py:66
|
||||||
msgid "Icelandic"
|
msgid "Icelandic"
|
||||||
msgstr "ისლანდიური"
|
msgstr "ისლანდიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:61
|
#: conf/global_settings.py:67
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr "იტალიური"
|
msgstr "იტალიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:62
|
#: conf/global_settings.py:68
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr "იაპონური"
|
msgstr "იაპონური"
|
||||||
|
|
||||||
#: conf/global_settings.py:63
|
#: conf/global_settings.py:69
|
||||||
msgid "Georgian"
|
msgid "Georgian"
|
||||||
msgstr "ქართული"
|
msgstr "ქართული"
|
||||||
|
|
||||||
#: conf/global_settings.py:64
|
#: conf/global_settings.py:70
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr "კორეული"
|
msgstr "კორეული"
|
||||||
|
|
||||||
#: conf/global_settings.py:65
|
#: conf/global_settings.py:71
|
||||||
msgid "Khmer"
|
msgid "Khmer"
|
||||||
msgstr "ხმერული"
|
msgstr "ხმერული"
|
||||||
|
|
||||||
#: conf/global_settings.py:66
|
#: conf/global_settings.py:72
|
||||||
msgid "Kannada"
|
msgid "Kannada"
|
||||||
msgstr "კანნადა"
|
msgstr "კანნადა"
|
||||||
|
|
||||||
#: conf/global_settings.py:67
|
#: conf/global_settings.py:73
|
||||||
msgid "Latvian"
|
msgid "Latvian"
|
||||||
msgstr "ლატვიური"
|
msgstr "ლატვიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:68
|
#: conf/global_settings.py:74
|
||||||
|
msgid "Lithuanian"
|
||||||
|
msgstr "ლიტვური"
|
||||||
|
|
||||||
|
#: conf/global_settings.py:75
|
||||||
msgid "Macedonian"
|
msgid "Macedonian"
|
||||||
msgstr "მაკედონური"
|
msgstr "მაკედონური"
|
||||||
|
|
||||||
#: conf/global_settings.py:69
|
#: conf/global_settings.py:76
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "ჰოლანდიური"
|
msgstr "ჰოლანდიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:70
|
#: conf/global_settings.py:77
|
||||||
msgid "Norwegian"
|
msgid "Norwegian"
|
||||||
msgstr "ნორვეგიული"
|
msgstr "ნორვეგიული"
|
||||||
|
|
||||||
#: conf/global_settings.py:71
|
#: conf/global_settings.py:78
|
||||||
msgid "Polish"
|
msgid "Polish"
|
||||||
msgstr "პოლონური"
|
msgstr "პოლონური"
|
||||||
|
|
||||||
#: conf/global_settings.py:72
|
#: conf/global_settings.py:79
|
||||||
msgid "Portugese"
|
msgid "Portugese"
|
||||||
msgstr "პორტუგალიური"
|
msgstr "პორტუგალიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:73
|
#: conf/global_settings.py:80
|
||||||
msgid "Brazilian"
|
msgid "Brazilian Portuguese"
|
||||||
msgstr "ბრაზილიური"
|
msgstr "ბრაზილიური პორტუგალიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:74
|
#: conf/global_settings.py:81
|
||||||
msgid "Romanian"
|
msgid "Romanian"
|
||||||
msgstr "რუმინული"
|
msgstr "რუმინული"
|
||||||
|
|
||||||
#: conf/global_settings.py:75
|
#: conf/global_settings.py:82
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "რუსული"
|
msgstr "რუსული"
|
||||||
|
|
||||||
#: conf/global_settings.py:76
|
#: conf/global_settings.py:83
|
||||||
msgid "Slovak"
|
msgid "Slovak"
|
||||||
msgstr "სლოვარური"
|
msgstr "სლოვარური"
|
||||||
|
|
||||||
#: conf/global_settings.py:77
|
#: conf/global_settings.py:84
|
||||||
msgid "Slovenian"
|
msgid "Slovenian"
|
||||||
msgstr "სლოვენიური"
|
msgstr "სლოვენიური"
|
||||||
|
|
||||||
#: conf/global_settings.py:78
|
#: conf/global_settings.py:85
|
||||||
msgid "Serbian"
|
msgid "Serbian"
|
||||||
msgstr "სერბული"
|
msgstr "სერბული"
|
||||||
|
|
||||||
#: conf/global_settings.py:79
|
#: conf/global_settings.py:86
|
||||||
msgid "Swedish"
|
msgid "Swedish"
|
||||||
msgstr "შვედური"
|
msgstr "შვედური"
|
||||||
|
|
||||||
#: conf/global_settings.py:80
|
#: conf/global_settings.py:87
|
||||||
msgid "Tamil"
|
msgid "Tamil"
|
||||||
msgstr "თამილური"
|
msgstr "თამილური"
|
||||||
|
|
||||||
#: conf/global_settings.py:81
|
#: conf/global_settings.py:88
|
||||||
msgid "Telugu"
|
msgid "Telugu"
|
||||||
msgstr "ტელუგუ"
|
msgstr "ტელუგუ"
|
||||||
|
|
||||||
#: conf/global_settings.py:82
|
#: conf/global_settings.py:89
|
||||||
msgid "Turkish"
|
msgid "Turkish"
|
||||||
msgstr "თურქული"
|
msgstr "თურქული"
|
||||||
|
|
||||||
#: conf/global_settings.py:83
|
#: conf/global_settings.py:90
|
||||||
msgid "Ukrainian"
|
msgid "Ukrainian"
|
||||||
msgstr "უკრაინული"
|
msgstr "უკრაინული"
|
||||||
|
|
||||||
#: conf/global_settings.py:84
|
#: conf/global_settings.py:91
|
||||||
msgid "Simplified Chinese"
|
msgid "Simplified Chinese"
|
||||||
msgstr "გამარტივებული ჩინური"
|
msgstr "გამარტივებული ჩინური"
|
||||||
|
|
||||||
#: conf/global_settings.py:85
|
#: conf/global_settings.py:92
|
||||||
msgid "Traditional Chinese"
|
msgid "Traditional Chinese"
|
||||||
msgstr "ტრადიციული ჩინური"
|
msgstr "ტრადიციული ჩინური"
|
||||||
|
|
||||||
@ -322,7 +330,7 @@ msgid ""
|
|||||||
"There's been an error. It's been reported to the site administrators via e-"
|
"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."
|
"mail and should be fixed shortly. Thanks for your patience."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"აქ იყო შეცდომა. იგი გადაგზავნილია საიტის ადმინისტრატორის ელექტრონულ ფოსტაზე "
|
"სისტემაში მოხდა შეცდომა. იგი გადაგზავნილია საიტის ადმინისტრატორის ელექტრონულ ფოსტაზე "
|
||||||
"და მალე გამოსწორდება. გმადლობთ მოთმინებისათვის."
|
"და მალე გამოსწორდება. გმადლობთ მოთმინებისათვის."
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/base.html:26
|
#: contrib/admin/templates/admin/base.html:26
|
||||||
@ -477,7 +485,7 @@ msgid "Password:"
|
|||||||
msgstr "პაროლი:"
|
msgstr "პაროლი:"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/login.html:25
|
#: contrib/admin/templates/admin/login.html:25
|
||||||
#: contrib/admin/views/decorators.py:25
|
#: contrib/admin/views/decorators.py:31
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "შესვლა"
|
msgstr "შესვლა"
|
||||||
|
|
||||||
@ -799,7 +807,7 @@ msgstr "პაროლი წარმატებით შეიცვალ
|
|||||||
msgid "Change password: %s"
|
msgid "Change password: %s"
|
||||||
msgstr "შევცვალოთ პაროლი: %s"
|
msgstr "შევცვალოთ პაროლი: %s"
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:11 contrib/auth/forms.py:60
|
#: contrib/admin/views/decorators.py:17 contrib/auth/forms.py:60
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter a correct username and password. Note that both fields are case-"
|
"Please enter a correct username and password. Note that both fields are case-"
|
||||||
"sensitive."
|
"sensitive."
|
||||||
@ -807,7 +815,7 @@ msgstr ""
|
|||||||
"გთხოვთ, შეიყვანოთ სწორი მომხმარებლის სახელი და პაროლი. გაითვალისწინეთ, რომ "
|
"გთხოვთ, შეიყვანოთ სწორი მომხმარებლის სახელი და პაროლი. გაითვალისწინეთ, რომ "
|
||||||
"ორივე ველი დამოკიდებულია რეგისტრზე."
|
"ორივე ველი დამოკიდებულია რეგისტრზე."
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:63
|
#: contrib/admin/views/decorators.py:69
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please log in again, because your session has expired. Don't worry: Your "
|
"Please log in again, because your session has expired. Don't worry: Your "
|
||||||
"submission has been saved."
|
"submission has been saved."
|
||||||
@ -815,7 +823,7 @@ msgstr ""
|
|||||||
"გთხოვთ, შეხვიდეთ კიდევ ერთხელ, რადგანაც თქვენი სესიის დრო ამოიწურა. ნუ "
|
"გთხოვთ, შეხვიდეთ კიდევ ერთხელ, რადგანაც თქვენი სესიის დრო ამოიწურა. ნუ "
|
||||||
"ღელავთ: თქვენს მიერ შეტანილი ცვლილებები შენახულია."
|
"ღელავთ: თქვენს მიერ შეტანილი ცვლილებები შენახულია."
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:70
|
#: contrib/admin/views/decorators.py:76
|
||||||
msgid ""
|
msgid ""
|
||||||
"Looks like your browser isn't configured to accept cookies. Please enable "
|
"Looks like your browser isn't configured to accept cookies. Please enable "
|
||||||
"cookies, reload this page, and try again."
|
"cookies, reload this page, and try again."
|
||||||
@ -823,17 +831,17 @@ msgstr ""
|
|||||||
"როგორც ჩანს, თქვენი ბროუზერი არ ღებულობს cookie-ებს. გთხოვთ, ჩართოთ cookie-"
|
"როგორც ჩანს, თქვენი ბროუზერი არ ღებულობს cookie-ებს. გთხოვთ, ჩართოთ cookie-"
|
||||||
"ების მიღების ფუნქცია, განაახლეთ ეს გვერდი და სცადეთ კიდევ ერთხელ."
|
"ების მიღების ფუნქცია, განაახლეთ ეს გვერდი და სცადეთ კიდევ ერთხელ."
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:84
|
#: contrib/admin/views/decorators.py:89
|
||||||
msgid "Usernames cannot contain the '@' character."
|
|
||||||
msgstr "მომხმარებლის სახელი არ უნდა შეიცავდეს სიმბოლოს '@'."
|
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:86
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Your e-mail address is not your username. Try '%s' instead."
|
msgid "Your e-mail address is not your username. Try '%s' instead."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"ელ-ფოსტის მისამართი არ არის თქვენი მომხმარებლის სახელი. სცადეთ '%s' მის "
|
"ელ-ფოსტის მისამართი არ არის თქვენი მომხმარებლის სახელი. სცადეთ '%s' მის "
|
||||||
"ნაცვლად."
|
"ნაცვლად."
|
||||||
|
|
||||||
|
#: contrib/admin/views/decorators.py:93
|
||||||
|
msgid "Usernames cannot contain the '@' character."
|
||||||
|
msgstr "მომხმარებლის სახელი არ უნდა შეიცავდეს სიმბოლოს '@'."
|
||||||
|
|
||||||
#: contrib/admin/views/doc.py:48 contrib/admin/views/doc.py:50
|
#: contrib/admin/views/doc.py:48 contrib/admin/views/doc.py:50
|
||||||
#: contrib/admin/views/doc.py:52
|
#: contrib/admin/views/doc.py:52
|
||||||
msgid "tag:"
|
msgid "tag:"
|
||||||
@ -957,7 +965,7 @@ msgstr "ტექსტი"
|
|||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "დრო"
|
msgstr "დრო"
|
||||||
|
|
||||||
#: contrib/admin/views/doc.py:318 contrib/flatpages/models.py:7
|
#: contrib/admin/views/doc.py:318 contrib/flatpages/models.py:8
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1065,7 +1073,7 @@ msgstr "ავირჩიოთ %s"
|
|||||||
msgid "Select %s to change"
|
msgid "Select %s to change"
|
||||||
msgstr "აირჩიეთ %s შესაცვლელად"
|
msgstr "აირჩიეთ %s შესაცვლელად"
|
||||||
|
|
||||||
#: contrib/admin/views/main.py:784
|
#: contrib/admin/views/main.py:765
|
||||||
msgid "Database error"
|
msgid "Database error"
|
||||||
msgstr "მონაცემთა ბაზის შეცდომა"
|
msgstr "მონაცემთა ბაზის შეცდომა"
|
||||||
|
|
||||||
@ -1129,15 +1137,15 @@ msgstr "უფლებები"
|
|||||||
msgid "group"
|
msgid "group"
|
||||||
msgstr "ჯგუფი"
|
msgstr "ჯგუფი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:98 contrib/auth/models.py:141
|
#: contrib/auth/models.py:98 contrib/auth/models.py:148
|
||||||
msgid "groups"
|
msgid "groups"
|
||||||
msgstr "ჯგუფები"
|
msgstr "ჯგუფები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:131
|
#: contrib/auth/models.py:138
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr "მომხმარებლის სახელი"
|
msgstr "მომხმარებლის სახელი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:131
|
#: contrib/auth/models.py:138
|
||||||
msgid ""
|
msgid ""
|
||||||
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
||||||
"digits and underscores)."
|
"digits and underscores)."
|
||||||
@ -1145,23 +1153,23 @@ msgstr ""
|
|||||||
"აუცილებელია. 30 ან ნაკლები სიმბოლო. მხოლოდ ლათინური ასოები, ციფრები და "
|
"აუცილებელია. 30 ან ნაკლები სიმბოლო. მხოლოდ ლათინური ასოები, ციფრები და "
|
||||||
"ხაზგასმა."
|
"ხაზგასმა."
|
||||||
|
|
||||||
#: contrib/auth/models.py:132
|
#: contrib/auth/models.py:139
|
||||||
msgid "first name"
|
msgid "first name"
|
||||||
msgstr "სახელი"
|
msgstr "სახელი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:133
|
#: contrib/auth/models.py:140
|
||||||
msgid "last name"
|
msgid "last name"
|
||||||
msgstr "გვარი"
|
msgstr "გვარი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:134
|
#: contrib/auth/models.py:141
|
||||||
msgid "e-mail address"
|
msgid "e-mail address"
|
||||||
msgstr "ელ. ფოსტა"
|
msgstr "ელ. ფოსტა"
|
||||||
|
|
||||||
#: contrib/auth/models.py:135
|
#: contrib/auth/models.py:142
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr "პაროლი"
|
msgstr "პაროლი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:135
|
#: contrib/auth/models.py:142
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
||||||
"password form</a>."
|
"password form</a>."
|
||||||
@ -1169,46 +1177,46 @@ msgstr ""
|
|||||||
"გამოიყენეთ '[algo]$[salt]$[hexdigest]' ან <a href=\"password/\">პაროლის "
|
"გამოიყენეთ '[algo]$[salt]$[hexdigest]' ან <a href=\"password/\">პაროლის "
|
||||||
"შეცვლის ფორმა</a>."
|
"შეცვლის ფორმა</a>."
|
||||||
|
|
||||||
#: contrib/auth/models.py:136
|
#: contrib/auth/models.py:143
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "თანამშრომლობის სტატუსი"
|
msgstr "თანამშრომლობის სტატუსი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:136
|
#: contrib/auth/models.py:143
|
||||||
msgid "Designates whether the user can log into this admin site."
|
msgid "Designates whether the user can log into this admin site."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"განსაზღვრავს, აქვს თუ არა მომხმარებელს ადმინისტრირების საიტზე შესვლის უფლება."
|
"განსაზღვრავს, აქვს თუ არა მომხმარებელს ადმინისტრირების საიტზე შესვლის უფლება."
|
||||||
|
|
||||||
#: contrib/auth/models.py:137
|
#: contrib/auth/models.py:144
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "აქტიურია"
|
msgstr "აქტიურია"
|
||||||
|
|
||||||
#: contrib/auth/models.py:137
|
#: contrib/auth/models.py:144
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates whether this user can log into the Django admin. Unselect this "
|
"Designates whether this user should be treated as active. Unselect this "
|
||||||
"instead of deleting accounts."
|
"instead of deleting accounts."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"განსაზღვრავს, აქვს თუ არა მომხმარებელს Django-ს ადმინისტრირების საიტზე "
|
"განსაზღვრავს, რომ მომხმარებელი გააქტიურებულია. "
|
||||||
"შესვლის შესაძლებლობა. გადანიშნეთ ეს დროშა მომხმარებლის წაშლის მაგივრად."
|
"მომხმარებლის წაშლის მაგივრად გადანიშნეთ ეს დროშა."
|
||||||
|
|
||||||
#: contrib/auth/models.py:138
|
#: contrib/auth/models.py:145
|
||||||
msgid "superuser status"
|
msgid "superuser status"
|
||||||
msgstr "სუპერმომხმარებლის სტატუსი"
|
msgstr "სუპერმომხმარებლის სტატუსი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:138
|
#: contrib/auth/models.py:145
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates that this user has all permissions without explicitly assigning "
|
"Designates that this user has all permissions without explicitly assigning "
|
||||||
"them."
|
"them."
|
||||||
msgstr "განსაზღვრავს, რომ ამ მომხმარებელს აქვს ყველა უფლება."
|
msgstr "განსაზღვრავს, რომ ამ მომხმარებელს აქვს ყველა უფლება."
|
||||||
|
|
||||||
#: contrib/auth/models.py:139
|
#: contrib/auth/models.py:146
|
||||||
msgid "last login"
|
msgid "last login"
|
||||||
msgstr "ბოლო შესვლა"
|
msgstr "ბოლო შესვლა"
|
||||||
|
|
||||||
#: contrib/auth/models.py:140
|
#: contrib/auth/models.py:147
|
||||||
msgid "date joined"
|
msgid "date joined"
|
||||||
msgstr "გაწევრიანების თარიღი"
|
msgstr "გაწევრიანების თარიღი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:142
|
#: contrib/auth/models.py:149
|
||||||
msgid ""
|
msgid ""
|
||||||
"In addition to the permissions manually assigned, this user will also get "
|
"In addition to the permissions manually assigned, this user will also get "
|
||||||
"all permissions granted to each group he/she is in."
|
"all permissions granted to each group he/she is in."
|
||||||
@ -1216,39 +1224,39 @@ msgstr ""
|
|||||||
"ინდივიდუალურად მითითებული უფლებების გარდა, ეს მომხმარებელი მიიღებს აგრეთვე "
|
"ინდივიდუალურად მითითებული უფლებების გარდა, ეს მომხმარებელი მიიღებს აგრეთვე "
|
||||||
"ყველა იმ ჯგუფის უფლებას, რომელშიც იგი გაწევრიანებულია."
|
"ყველა იმ ჯგუფის უფლებას, რომელშიც იგი გაწევრიანებულია."
|
||||||
|
|
||||||
#: contrib/auth/models.py:143
|
#: contrib/auth/models.py:150
|
||||||
msgid "user permissions"
|
msgid "user permissions"
|
||||||
msgstr "მომხმარებლის უფლებები"
|
msgstr "მომხმარებლის უფლებები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:147
|
#: contrib/auth/models.py:154
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "მომხმარებელი"
|
msgstr "მომხმარებელი"
|
||||||
|
|
||||||
#: contrib/auth/models.py:148
|
#: contrib/auth/models.py:155
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "მომხმარებლები"
|
msgstr "მომხმარებლები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:154
|
#: contrib/auth/models.py:160
|
||||||
msgid "Personal info"
|
msgid "Personal info"
|
||||||
msgstr "პირადი ინფორმაცია"
|
msgstr "პირადი ინფორმაცია"
|
||||||
|
|
||||||
#: contrib/auth/models.py:155
|
#: contrib/auth/models.py:161
|
||||||
msgid "Permissions"
|
msgid "Permissions"
|
||||||
msgstr "უფლებები"
|
msgstr "უფლებები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:156
|
#: contrib/auth/models.py:162
|
||||||
msgid "Important dates"
|
msgid "Important dates"
|
||||||
msgstr "მნიშვნელოვანი თარიღები"
|
msgstr "მნიშვნელოვანი თარიღები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:157
|
#: contrib/auth/models.py:163
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr "ჯგუფები"
|
msgstr "ჯგუფები"
|
||||||
|
|
||||||
#: contrib/auth/models.py:316
|
#: contrib/auth/models.py:323
|
||||||
msgid "message"
|
msgid "message"
|
||||||
msgstr "შეტყობინება"
|
msgstr "შეტყობინება"
|
||||||
|
|
||||||
#: contrib/auth/views.py:47
|
#: contrib/auth/views.py:49
|
||||||
msgid "Logged out"
|
msgid "Logged out"
|
||||||
msgstr "გამოსული ხართ"
|
msgstr "გამოსული ხართ"
|
||||||
|
|
||||||
@ -1546,42 +1554,42 @@ msgstr "კომენტარის ID არასწორია"
|
|||||||
msgid "No voting for yourself"
|
msgid "No voting for yourself"
|
||||||
msgstr "საკუთარი თავისათვის ხმის მიცემა აკრძალულია"
|
msgstr "საკუთარი თავისათვის ხმის მიცემა აკრძალულია"
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:37
|
#: contrib/contenttypes/models.py:67
|
||||||
msgid "python model class name"
|
msgid "python model class name"
|
||||||
msgstr "python-ის მოდელის კლასის სახელი"
|
msgstr "python-ის მოდელის კლასის სახელი"
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:40
|
#: contrib/contenttypes/models.py:71
|
||||||
msgid "content type"
|
msgid "content type"
|
||||||
msgstr "კონტენტის ტიპი"
|
msgstr "კონტენტის ტიპი"
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:41
|
#: contrib/contenttypes/models.py:72
|
||||||
msgid "content types"
|
msgid "content types"
|
||||||
msgstr "კონტენტის ტიპები"
|
msgstr "კონტენტის ტიპები"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:8
|
#: contrib/flatpages/models.py:9
|
||||||
msgid ""
|
msgid ""
|
||||||
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
|
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"მაგალითი: '/about/contact/'. ყურადღება მიაქციეთ დახრილ ხაზებს თავში და "
|
"მაგალითი: '/about/contact/'. ყურადღება მიაქციეთ დახრილ ხაზებს თავში და "
|
||||||
"ბოლოში."
|
"ბოლოში."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:9
|
#: contrib/flatpages/models.py:10
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "სათაური"
|
msgstr "სათაური"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:10
|
#: contrib/flatpages/models.py:11
|
||||||
msgid "content"
|
msgid "content"
|
||||||
msgstr "კონტენტი"
|
msgstr "კონტენტი"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:11
|
#: contrib/flatpages/models.py:12
|
||||||
msgid "enable comments"
|
msgid "enable comments"
|
||||||
msgstr "ჩავრთოთ კომენტარები"
|
msgstr "ჩავრთოთ კომენტარები"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:12
|
#: contrib/flatpages/models.py:13
|
||||||
msgid "template name"
|
msgid "template name"
|
||||||
msgstr "შაბლონის სახელი"
|
msgstr "შაბლონის სახელი"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:13
|
#: contrib/flatpages/models.py:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
||||||
"will use 'flatpages/default.html'."
|
"will use 'flatpages/default.html'."
|
||||||
@ -1589,24 +1597,28 @@ msgstr ""
|
|||||||
"მაგალითი: 'flatpages/contact_page.html'. თუ იგი მითითებული არ არის, "
|
"მაგალითი: 'flatpages/contact_page.html'. თუ იგი მითითებული არ არის, "
|
||||||
"გამოყენებული იქნება 'flatpages/default.html'."
|
"გამოყენებული იქნება 'flatpages/default.html'."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:14
|
#: contrib/flatpages/models.py:15
|
||||||
msgid "registration required"
|
msgid "registration required"
|
||||||
msgstr "რეგისტრაცია აუცილებელია"
|
msgstr "რეგისტრაცია აუცილებელია"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:14
|
#: contrib/flatpages/models.py:15
|
||||||
msgid "If this is checked, only logged-in users will be able to view the page."
|
msgid "If this is checked, only logged-in users will be able to view the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"თუ ეს დროშა ჩართულია, მხოლო შემოსულ მომხმარებლებს ექნებათ გვერდის "
|
"თუ ეს დროშა ჩართულია, მხოლო შემოსულ მომხმარებლებს ექნებათ გვერდის "
|
||||||
"დათვალიერების საშუალება."
|
"დათვალიერების საშუალება."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:18
|
#: contrib/flatpages/models.py:20
|
||||||
msgid "flat page"
|
msgid "flat page"
|
||||||
msgstr "უბრალო გვერდი"
|
msgstr "უბრალო გვერდი"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:19
|
#: contrib/flatpages/models.py:21
|
||||||
msgid "flat pages"
|
msgid "flat pages"
|
||||||
msgstr "უბრალო გვერდები"
|
msgstr "უბრალო გვერდები"
|
||||||
|
|
||||||
|
#: contrib/flatpages/models.py:27
|
||||||
|
msgid "Advanced options"
|
||||||
|
msgstr "დამატებითი პარამეტრები"
|
||||||
|
|
||||||
#: contrib/humanize/templatetags/humanize.py:19
|
#: contrib/humanize/templatetags/humanize.py:19
|
||||||
msgid "th"
|
msgid "th"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -3632,23 +3644,23 @@ msgstr "გადამისამართება"
|
|||||||
msgid "redirects"
|
msgid "redirects"
|
||||||
msgstr "გადამისამართებები"
|
msgstr "გადამისამართებები"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:41
|
#: contrib/sessions/models.py:45
|
||||||
msgid "session key"
|
msgid "session key"
|
||||||
msgstr "სესიის გასაღები"
|
msgstr "სესიის გასაღები"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:42
|
#: contrib/sessions/models.py:47
|
||||||
msgid "session data"
|
msgid "session data"
|
||||||
msgstr "სესიის მონაცემები"
|
msgstr "სესიის მონაცემები"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:43
|
#: contrib/sessions/models.py:48
|
||||||
msgid "expire date"
|
msgid "expire date"
|
||||||
msgstr "ამოწურვის თარიღი"
|
msgstr "ამოწურვის თარიღი"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:48
|
#: contrib/sessions/models.py:53
|
||||||
msgid "session"
|
msgid "session"
|
||||||
msgstr "სესია"
|
msgstr "სესია"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:49
|
#: contrib/sessions/models.py:54
|
||||||
msgid "sessions"
|
msgid "sessions"
|
||||||
msgstr "სესიები"
|
msgstr "სესიები"
|
||||||
|
|
||||||
@ -3720,7 +3732,7 @@ msgstr "არაციფრული სიმბოლოები აქ დ
|
|||||||
msgid "This value can't be comprised solely of digits."
|
msgid "This value can't be comprised solely of digits."
|
||||||
msgstr "ეს მნიშვნელობა არ უნდა შედგებოდეს მხოლოდ ციფრებისაგან."
|
msgstr "ეს მნიშვნელობა არ უნდა შედგებოდეს მხოლოდ ციფრებისაგან."
|
||||||
|
|
||||||
#: core/validators.py:128 newforms/fields.py:151
|
#: core/validators.py:128 newforms/fields.py:157
|
||||||
msgid "Enter a whole number."
|
msgid "Enter a whole number."
|
||||||
msgstr "შეიყვანეთ მთელი რიცხვი"
|
msgstr "შეიყვანეთ მთელი რიცხვი"
|
||||||
|
|
||||||
@ -3737,7 +3749,7 @@ msgstr "წელი უნდა იყოს 1900 ან მეტი."
|
|||||||
msgid "Invalid date: %s"
|
msgid "Invalid date: %s"
|
||||||
msgstr "არასწორი თარიღი: %s"
|
msgstr "არასწორი თარიღი: %s"
|
||||||
|
|
||||||
#: core/validators.py:156 db/models/fields/__init__.py:518
|
#: core/validators.py:156 db/models/fields/__init__.py:565
|
||||||
msgid "Enter a valid date in YYYY-MM-DD format."
|
msgid "Enter a valid date in YYYY-MM-DD format."
|
||||||
msgstr "შეიყვანეთ სწორი თარიღი YYYY-MM-DD ფორმატში."
|
msgstr "შეიყვანეთ სწორი თარიღი YYYY-MM-DD ფორმატში."
|
||||||
|
|
||||||
@ -3745,21 +3757,20 @@ msgstr "შეიყვანეთ სწორი თარიღი YYYY-MM-D
|
|||||||
msgid "Enter a valid time in HH:MM format."
|
msgid "Enter a valid time in HH:MM format."
|
||||||
msgstr "შეიყვანეთ სწორი დრო HH:MM ფორმატში."
|
msgstr "შეიყვანეთ სწორი დრო HH:MM ფორმატში."
|
||||||
|
|
||||||
#: core/validators.py:165 db/models/fields/__init__.py:595
|
#: core/validators.py:165 db/models/fields/__init__.py:642
|
||||||
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
|
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
|
||||||
msgstr "შეიყვანეთ სწორი თარიღი და დრო YYYY-MM-DD HH:MM ფორმატში."
|
msgstr "შეიყვანეთ სწორი თარიღი და დრო YYYY-MM-DD HH:MM ფორმატში."
|
||||||
|
|
||||||
#: core/validators.py:170 newforms/fields.py:402
|
#: core/validators.py:170 newforms/fields.py:408
|
||||||
msgid "Enter a valid e-mail address."
|
msgid "Enter a valid e-mail address."
|
||||||
msgstr "შეიყვანეთ სწორი ელ. ფოსტის მისამართი."
|
msgstr "შეიყვანეთ სწორი ელ. ფოსტის მისამართი."
|
||||||
|
|
||||||
#: core/validators.py:182 core/validators.py:474 newforms/fields.py:432
|
#: core/validators.py:182 core/validators.py:474 newforms/fields.py:426
|
||||||
#: oldforms/__init__.py:687
|
|
||||||
msgid "No file was submitted. Check the encoding type on the form."
|
msgid "No file was submitted. Check the encoding type on the form."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"ფაილი არ იყო გამოგზავნილი. შეამოწმეთ კოდირების ტიპი მოცემული ფორმისათვის."
|
"ფაილი არ იყო გამოგზავნილი. შეამოწმეთ კოდირების ტიპი მოცემული ფორმისათვის."
|
||||||
|
|
||||||
#: core/validators.py:193 newforms/fields.py:458
|
#: core/validators.py:193 newforms/fields.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Upload a valid image. The file you uploaded was either not an image or a "
|
"Upload a valid image. The file you uploaded was either not an image or a "
|
||||||
"corrupted image."
|
"corrupted image."
|
||||||
@ -3878,9 +3889,9 @@ msgid "Please enter a valid decimal number with at most %s total digit."
|
|||||||
msgid_plural ""
|
msgid_plural ""
|
||||||
"Please enter a valid decimal number with at most %s total digits."
|
"Please enter a valid decimal number with at most %s total digits."
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
"გთხოვთ, შეიყვანოთ სწორი, არაუმეტეს %s თანრიგისაგან შემდგარი ათობითი რიცხვი"
|
"გთხოვთ, შეიყვანოთ სწორი, არაუმეტეს %s თანრიგისაგან შემდგარი ათობითი რიცხვი."
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
"გთხოვთ, შეიყვანოთ სწორი, არაუმეტეს %s თანრიგისაგან შემდგარი ათობითი რიცხვი"
|
"გთხოვთ, შეიყვანოთ სწორი, არაუმეტეს %s თანრიგისაგან შემდგარი ათობითი რიცხვი."
|
||||||
|
|
||||||
#: core/validators.py:447
|
#: core/validators.py:447
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -4009,53 +4020,53 @@ msgstr "%(object)s მოცემული %(type)s-ით უკვე არ
|
|||||||
msgid "%(optname)s with this %(fieldname)s already exists."
|
msgid "%(optname)s with this %(fieldname)s already exists."
|
||||||
msgstr "%(optname)s მოცემული %(fieldname)s-ით უკვე არსებობს."
|
msgstr "%(optname)s მოცემული %(fieldname)s-ით უკვე არსებობს."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:161 db/models/fields/__init__.py:318
|
#: db/models/fields/__init__.py:184 db/models/fields/__init__.py:356
|
||||||
#: db/models/fields/__init__.py:750 db/models/fields/__init__.py:761
|
#: db/models/fields/__init__.py:799 db/models/fields/__init__.py:810
|
||||||
#: newforms/fields.py:45 oldforms/__init__.py:374
|
#: newforms/fields.py:51 oldforms/__init__.py:374
|
||||||
msgid "This field is required."
|
msgid "This field is required."
|
||||||
msgstr "ეს ველი აუცილებელია."
|
msgstr "ეს ველი აუცილებელია."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:418
|
#: db/models/fields/__init__.py:465
|
||||||
msgid "This value must be an integer."
|
msgid "This value must be an integer."
|
||||||
msgstr "ეს მნიშვნელობა უნდა იყოს მთელი."
|
msgstr "ეს მნიშვნელობა უნდა იყოს მთელი."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:457
|
#: db/models/fields/__init__.py:504
|
||||||
msgid "This value must be either True or False."
|
msgid "This value must be either True or False."
|
||||||
msgstr "ეს მნიშვნელობა უნდა იყოს True ან False."
|
msgstr "ეს მნიშვნელობა უნდა იყოს True ან False."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:481
|
#: db/models/fields/__init__.py:528
|
||||||
msgid "This field cannot be null."
|
msgid "This field cannot be null."
|
||||||
msgstr "ეს მნიშვნელობა არ შეიძლება იყოს null."
|
msgstr "ეს მნიშვნელობა არ შეიძლება იყოს null."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:659
|
#: db/models/fields/__init__.py:706
|
||||||
msgid "This value must be a decimal number."
|
msgid "This value must be a decimal number."
|
||||||
msgstr "ეს მნიშვნელობა უნდა იყოს ათობითი რიცხვი."
|
msgstr "ეს მნიშვნელობა უნდა იყოს ათობითი რიცხვი."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:770
|
#: db/models/fields/__init__.py:819
|
||||||
msgid "Enter a valid filename."
|
msgid "Enter a valid filename."
|
||||||
msgstr "შეიყვანეთ სწორი ფაილის სახელი."
|
msgstr "შეიყვანეთ სწორი ფაილის სახელი."
|
||||||
|
|
||||||
#: db/models/fields/__init__.py:941
|
#: db/models/fields/__init__.py:1013
|
||||||
msgid "This value must be either None, True or False."
|
msgid "This value must be either None, True or False."
|
||||||
msgstr "ეს მნიშვნელობა უნდა იყოს None, True ან False."
|
msgstr "ეს მნიშვნელობა უნდა იყოს None, True ან False."
|
||||||
|
|
||||||
#: db/models/fields/related.py:55
|
#: db/models/fields/related.py:94
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please enter a valid %s."
|
msgid "Please enter a valid %s."
|
||||||
msgstr "გთხოვთ, შეიყვანოთ სწორი %s."
|
msgstr "გთხოვთ, შეიყვანოთ სწორი %s."
|
||||||
|
|
||||||
#: db/models/fields/related.py:658
|
#: db/models/fields/related.py:756
|
||||||
msgid "Separate multiple IDs with commas."
|
msgid "Separate multiple IDs with commas."
|
||||||
msgstr "გამოყავით ID-ები მძიმეებით."
|
msgstr "გამოყავით ID-ები მძიმეებით."
|
||||||
|
|
||||||
#: db/models/fields/related.py:660
|
#: db/models/fields/related.py:758
|
||||||
msgid ""
|
msgid ""
|
||||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"დააჭირეთ \"Control\", ან \"Command\" Mac-ზე, ერთზე მეტი მნიშვნელობის "
|
"დააჭირეთ \"Control\", ან \"Command\" Mac-ზე, ერთზე მეტი მნიშვნელობის "
|
||||||
"ასარჩევად."
|
"ასარჩევად."
|
||||||
|
|
||||||
#: db/models/fields/related.py:707
|
#: db/models/fields/related.py:805
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
|
||||||
msgid_plural ""
|
msgid_plural ""
|
||||||
@ -4065,99 +4076,99 @@ msgstr[0] ""
|
|||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
"გთხოვთ, შეიყვანოთ სწორი %(self)s ID-ები. მნიშვნელობები %(value)r არასწორია."
|
"გთხოვთ, შეიყვანოთ სწორი %(self)s ID-ები. მნიშვნელობები %(value)r არასწორია."
|
||||||
|
|
||||||
#: newforms/fields.py:46
|
#: newforms/fields.py:52
|
||||||
msgid "Enter a valid value."
|
msgid "Enter a valid value."
|
||||||
msgstr "შეიყვანეთ სწორი მნიშვნელობა."
|
msgstr "შეიყვანეთ სწორი მნიშვნელობა."
|
||||||
|
|
||||||
#: newforms/fields.py:123
|
#: newforms/fields.py:129
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"დარწმუნდით, რომ მნიშვნელობა შედგება არაუმეტეს %(max)d სიმბოლოსაგან (ახლა "
|
"დარწმუნდით, რომ მნიშვნელობა შედგება არაუმეტეს %(max)d სიმბოლოსაგან (ახლა "
|
||||||
"მისი სიგრძეა %(length)d)."
|
"მისი სიგრძეა %(length)d)."
|
||||||
|
|
||||||
#: newforms/fields.py:124
|
#: newforms/fields.py:130
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"დარწმუნდით, რომ მნიშვნელობა შედგება არანაკლებ %(min)d სიმბოლოსაგან (ახლა "
|
"დარწმუნდით, რომ მნიშვნელობა შედგება არანაკლებ %(min)d სიმბოლოსაგან (ახლა "
|
||||||
"მისი სიგრძეა %(length)d)."
|
"მისი სიგრძეა %(length)d)."
|
||||||
|
|
||||||
#: newforms/fields.py:152 newforms/fields.py:181 newforms/fields.py:210
|
#: newforms/fields.py:158 newforms/fields.py:187 newforms/fields.py:216
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is less than or equal to %s."
|
msgid "Ensure this value is less than or equal to %s."
|
||||||
msgstr "დარწმუნდით, რომ მნიშვნელობა ნაკლებია ან ტოლია %s-ზე."
|
msgstr "დარწმუნდით, რომ მნიშვნელობა ნაკლებია ან ტოლია %s-ზე."
|
||||||
|
|
||||||
#: newforms/fields.py:153 newforms/fields.py:182 newforms/fields.py:211
|
#: newforms/fields.py:159 newforms/fields.py:188 newforms/fields.py:217
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure this value is greater than or equal to %s."
|
msgid "Ensure this value is greater than or equal to %s."
|
||||||
msgstr "დარწმუნდით, რომ მნიშვნელობა მეტია ან ტოლია %s-ზე."
|
msgstr "დარწმუნდით, რომ მნიშვნელობა მეტია ან ტოლია %s-ზე."
|
||||||
|
|
||||||
#: newforms/fields.py:180 newforms/fields.py:209
|
#: newforms/fields.py:186 newforms/fields.py:215
|
||||||
msgid "Enter a number."
|
msgid "Enter a number."
|
||||||
msgstr "შეიყვანეთ რიცხვი."
|
msgstr "შეიყვანეთ რიცხვი."
|
||||||
|
|
||||||
#: newforms/fields.py:212
|
#: newforms/fields.py:218
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits in total."
|
msgid "Ensure that there are no more than %s digits in total."
|
||||||
msgstr "დარწმუნდით, რომ მნიშვნელობა %s თანრიგს არ აღემატება."
|
msgstr "დარწმუნდით, რომ მნიშვნელობა %s თანრიგს არ აღემატება."
|
||||||
|
|
||||||
#: newforms/fields.py:213
|
#: newforms/fields.py:219
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s decimal places."
|
msgid "Ensure that there are no more than %s decimal places."
|
||||||
msgstr "დარწმუნდით, რომ წილადი ნაწილი %s თანრიგს არ აღემატება."
|
msgstr "დარწმუნდით, რომ წილადი ნაწილი %s თანრიგს არ აღემატება."
|
||||||
|
|
||||||
#: newforms/fields.py:214
|
#: newforms/fields.py:220
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ensure that there are no more than %s digits before the decimal point."
|
msgid "Ensure that there are no more than %s digits before the decimal point."
|
||||||
msgstr "დარწმუნდით, რომ მთელი ნაწილი %s თანრიგს არ აღემატება."
|
msgstr "დარწმუნდით, რომ მთელი ნაწილი %s თანრიგს არ აღემატება."
|
||||||
|
|
||||||
#: newforms/fields.py:262 newforms/fields.py:723
|
#: newforms/fields.py:268 newforms/fields.py:781
|
||||||
msgid "Enter a valid date."
|
msgid "Enter a valid date."
|
||||||
msgstr "შეიყვანეთ სწორი თარიღი."
|
msgstr "შეიყვანეთ სწორი თარიღი."
|
||||||
|
|
||||||
#: newforms/fields.py:295 newforms/fields.py:724
|
#: newforms/fields.py:301 newforms/fields.py:782
|
||||||
msgid "Enter a valid time."
|
msgid "Enter a valid time."
|
||||||
msgstr "შეიყვანეთ სწორი დრო."
|
msgstr "შეიყვანეთ სწორი დრო."
|
||||||
|
|
||||||
#: newforms/fields.py:334
|
#: newforms/fields.py:340
|
||||||
msgid "Enter a valid date/time."
|
msgid "Enter a valid date/time."
|
||||||
msgstr "შეიყვანეთ სწორი თარიღი და დრო."
|
msgstr "შეიყვანეთ სწორი თარიღი და დრო."
|
||||||
|
|
||||||
#: newforms/fields.py:433
|
#: newforms/fields.py:427
|
||||||
msgid "No file was submitted."
|
msgid "No file was submitted."
|
||||||
msgstr "ფაილი არ იყო გამოგზავნილი."
|
msgstr "ფაილი არ იყო გამოგზავნილი."
|
||||||
|
|
||||||
#: newforms/fields.py:434 oldforms/__init__.py:689
|
#: newforms/fields.py:428 oldforms/__init__.py:693
|
||||||
msgid "The submitted file is empty."
|
msgid "The submitted file is empty."
|
||||||
msgstr "გამოგზავნილი ფაილი ცარიელია."
|
msgstr "გამოგზავნილი ფაილი ცარიელია."
|
||||||
|
|
||||||
#: newforms/fields.py:496
|
#: newforms/fields.py:524
|
||||||
msgid "Enter a valid URL."
|
msgid "Enter a valid URL."
|
||||||
msgstr "შეიყვანეთ სწორი URL."
|
msgstr "შეიყვანეთ სწორი URL."
|
||||||
|
|
||||||
#: newforms/fields.py:497
|
#: newforms/fields.py:525
|
||||||
msgid "This URL appears to be a broken link."
|
msgid "This URL appears to be a broken link."
|
||||||
msgstr "როგორც ჩანს, URL არის გაწყვეტილი ბმული."
|
msgstr "როგორც ჩანს, URL არის გაწყვეტილი ბმული."
|
||||||
|
|
||||||
#: newforms/fields.py:559 newforms/models.py:300
|
#: newforms/fields.py:590 newforms/models.py:306
|
||||||
msgid "Select a valid choice. That choice is not one of the available choices."
|
msgid "Select a valid choice. That choice is not one of the available choices."
|
||||||
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. ეს არჩევანი დასაშვები არ არის."
|
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. ეს არჩევანი დასაშვები არ არის."
|
||||||
|
|
||||||
#: newforms/fields.py:598
|
#: newforms/fields.py:629
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %(value)s is not one of the available choices."
|
msgid "Select a valid choice. %(value)s is not one of the available choices."
|
||||||
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. %(value)s დასაშვები არ არის."
|
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. %(value)s დასაშვები არ არის."
|
||||||
|
|
||||||
#: newforms/fields.py:599 newforms/fields.py:661 newforms/models.py:360
|
#: newforms/fields.py:630 newforms/fields.py:692 newforms/models.py:373
|
||||||
msgid "Enter a list of values."
|
msgid "Enter a list of values."
|
||||||
msgstr "შეიყვანეთ მნიშვნელობების სია."
|
msgstr "შეიყვანეთ მნიშვნელობების სია."
|
||||||
|
|
||||||
#: newforms/fields.py:752
|
#: newforms/fields.py:810
|
||||||
msgid "Enter a valid IPv4 address."
|
msgid "Enter a valid IPv4 address."
|
||||||
msgstr "შეიყვანეთ სწორი IPv4 მისამართი."
|
msgstr "შეიყვანეთ სწორი IPv4 მისამართი."
|
||||||
|
|
||||||
#: newforms/models.py:361
|
#: newforms/models.py:374
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Select a valid choice. %s is not one of the available choices."
|
msgid "Select a valid choice. %s is not one of the available choices."
|
||||||
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. %s დასაშვები არ არის."
|
msgstr "აირჩიეთ დასაშვები მნიშვნელობა. %s დასაშვები არ არის."
|
||||||
@ -4180,40 +4191,40 @@ msgstr ""
|
|||||||
"აირჩიეთ დასაშვები მნიშვნელობა; '%(data)s' არ არის %(choices)s მნიშვნელობების "
|
"აირჩიეთ დასაშვები მნიშვნელობა; '%(data)s' არ არის %(choices)s მნიშვნელობების "
|
||||||
"სიაში."
|
"სიაში."
|
||||||
|
|
||||||
#: oldforms/__init__.py:745
|
#: oldforms/__init__.py:754
|
||||||
msgid "Enter a whole number between -32,768 and 32,767."
|
msgid "Enter a whole number between -32,768 and 32,767."
|
||||||
msgstr "შეიყვანეთ მთელი რიცხვი -32,768-დან 32,767-მდე."
|
msgstr "შეიყვანეთ მთელი რიცხვი -32,768-დან 32,767-მდე."
|
||||||
|
|
||||||
#: oldforms/__init__.py:755
|
#: oldforms/__init__.py:764
|
||||||
msgid "Enter a positive number."
|
msgid "Enter a positive number."
|
||||||
msgstr "შეიყვანეთ დადებითი რიცხვი."
|
msgstr "შეიყვანეთ დადებითი რიცხვი."
|
||||||
|
|
||||||
#: oldforms/__init__.py:765
|
#: oldforms/__init__.py:774
|
||||||
msgid "Enter a whole number between 0 and 32,767."
|
msgid "Enter a whole number between 0 and 32,767."
|
||||||
msgstr "შეიყვანეთ მთელი რიცხვი 0-დან 32,767-მდე."
|
msgstr "შეიყვანეთ მთელი რიცხვი 0-დან 32,767-მდე."
|
||||||
|
|
||||||
#: template/defaultfilters.py:691
|
#: template/defaultfilters.py:698
|
||||||
msgid "yes,no,maybe"
|
msgid "yes,no,maybe"
|
||||||
msgstr "კი,არა,შესაძლოა"
|
msgstr "კი,არა,შესაძლოა"
|
||||||
|
|
||||||
#: template/defaultfilters.py:722
|
#: template/defaultfilters.py:729
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(size)d byte"
|
msgid "%(size)d byte"
|
||||||
msgid_plural "%(size)d bytes"
|
msgid_plural "%(size)d bytes"
|
||||||
msgstr[0] "%(size)d ბაიტი"
|
msgstr[0] "%(size)d ბაიტი"
|
||||||
msgstr[1] "%(size)d ბაიტი"
|
msgstr[1] "%(size)d ბაიტი"
|
||||||
|
|
||||||
#: template/defaultfilters.py:724
|
#: template/defaultfilters.py:731
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%.1f KB"
|
msgid "%.1f KB"
|
||||||
msgstr "%.1f კბაიტი"
|
msgstr "%.1f კბაიტი"
|
||||||
|
|
||||||
#: template/defaultfilters.py:726
|
#: template/defaultfilters.py:733
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%.1f MB"
|
msgid "%.1f MB"
|
||||||
msgstr "%.1f მბაიტი"
|
msgstr "%.1f მბაიტი"
|
||||||
|
|
||||||
#: template/defaultfilters.py:727
|
#: template/defaultfilters.py:734
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%.1f GB"
|
msgid "%.1f GB"
|
||||||
msgstr "%.1f გბაიტი"
|
msgstr "%.1f გბაიტი"
|
||||||
@ -4422,7 +4433,7 @@ msgstr "ნოემ."
|
|||||||
msgid "Dec."
|
msgid "Dec."
|
||||||
msgstr "დეკ."
|
msgstr "დეკ."
|
||||||
|
|
||||||
#: utils/text.py:127
|
#: utils/text.py:128
|
||||||
msgid "or"
|
msgid "or"
|
||||||
msgstr "ან"
|
msgstr "ან"
|
||||||
|
|
||||||
@ -4476,23 +4487,23 @@ msgstr ""
|
|||||||
msgid ", %(number)d %(type)s"
|
msgid ", %(number)d %(type)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: utils/translation/trans_real.py:404
|
#: utils/translation/trans_real.py:412
|
||||||
msgid "DATE_FORMAT"
|
msgid "DATE_FORMAT"
|
||||||
msgstr "d.m.Y"
|
msgstr "d.m.Y"
|
||||||
|
|
||||||
#: utils/translation/trans_real.py:405
|
#: utils/translation/trans_real.py:413
|
||||||
msgid "DATETIME_FORMAT"
|
msgid "DATETIME_FORMAT"
|
||||||
msgstr "d.m.Y H:i"
|
msgstr "d.m.Y H:i"
|
||||||
|
|
||||||
#: utils/translation/trans_real.py:406
|
#: utils/translation/trans_real.py:414
|
||||||
msgid "TIME_FORMAT"
|
msgid "TIME_FORMAT"
|
||||||
msgstr "H:i"
|
msgstr "H:i"
|
||||||
|
|
||||||
#: utils/translation/trans_real.py:422
|
#: utils/translation/trans_real.py:430
|
||||||
msgid "YEAR_MONTH_FORMAT"
|
msgid "YEAR_MONTH_FORMAT"
|
||||||
msgstr "d.m.Y"
|
msgstr "d.m.Y"
|
||||||
|
|
||||||
#: utils/translation/trans_real.py:423
|
#: utils/translation/trans_real.py:431
|
||||||
msgid "MONTH_DAY_FORMAT"
|
msgid "MONTH_DAY_FORMAT"
|
||||||
msgstr "d.m.Y"
|
msgstr "d.m.Y"
|
||||||
|
|
||||||
@ -4510,3 +4521,6 @@ msgstr "%(verbose_name)s წარმატებით შეიცვალა
|
|||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(verbose_name)s was deleted."
|
msgid "The %(verbose_name)s was deleted."
|
||||||
msgstr "%(verbose_name)s წაიშალა."
|
msgstr "%(verbose_name)s წაიშალა."
|
||||||
|
|
||||||
|
#~ msgid "Brazilian"
|
||||||
|
#~ msgstr "ბრაზილიური"
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1358,7 +1358,7 @@ msgstr "aprovado pela equipe"
|
|||||||
|
|
||||||
#: contrib/comments/models.py:187
|
#: contrib/comments/models.py:187
|
||||||
msgid "free comment"
|
msgid "free comment"
|
||||||
msgstr "fomentário livre"
|
msgstr "comentário livre"
|
||||||
|
|
||||||
#: contrib/comments/models.py:188
|
#: contrib/comments/models.py:188
|
||||||
msgid "free comments"
|
msgid "free comments"
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -7,15 +7,17 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
|
"POT-Creation-Date: 2008-07-29 12:07+0200\n"
|
||||||
"PO-Revision-Date: 2007-02-20 18:51+0100\n"
|
"PO-Revision-Date: 2008-07-29 12:53+0100\n"
|
||||||
"Last-Translator: Petar Marić <petar.maric@gmail.com>\n"
|
"Last-Translator: Nebojsa Djordjevic <djnesh@gmail.com>\n"
|
||||||
"Language-Team: Nesh <nesh@studioquatro.co.yu> & Petar <petar.maric@gmail.com> <sr@li.org>\n"
|
"Language-Team: Nesh <djnesh@gmail.com> & Petar <petar.maric@gmail.com> <sr@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Country: YUGOSLAVIA\n"
|
"X-Poedit-Country: YUGOSLAVIA\n"
|
||||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
|
"X-Poedit-Language: Serbian\n"
|
||||||
|
"X-Poedit-SourceCharset: utf-8\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
#, perl-format
|
#, perl-format
|
||||||
@ -47,63 +49,72 @@ msgstr "Izaberite potrebno i kliknite"
|
|||||||
msgid "Clear all"
|
msgid "Clear all"
|
||||||
msgstr "Obrišite sve"
|
msgstr "Obrišite sve"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:26
|
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
|
#: contrib/admin/media/js/dateparse.js:32
|
||||||
msgid "January February March April May June July August September October November December"
|
msgid "January February March April May June July August September October November December"
|
||||||
msgstr "Januar Februar Mart April Maj Jun Jul Avgust Septembar Oktobar Novembar Decembar"
|
msgstr "Januar Februar Mart April Maj Jun Jul Avgust Septembar Oktobar Novembar Decembar"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:27
|
|
||||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
|
||||||
msgstr "Nedelja Ponedeljak Utorak Sreda Četvrtak Petak Subota"
|
|
||||||
|
|
||||||
#: contrib/admin/media/js/calendar.js:25
|
#: contrib/admin/media/js/calendar.js:25
|
||||||
msgid "S M T W T F S"
|
msgid "S M T W T F S"
|
||||||
msgstr "N P U S Č P S"
|
msgstr "N P U S Č P S"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
#: contrib/admin/media/js/dateparse.js:33
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||||
|
msgstr "Nedelja Ponedeljak Utorak Sreda Četvrtak Petak Subota"
|
||||||
|
|
||||||
|
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||||
|
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||||
|
msgid "Show"
|
||||||
|
msgstr "Prikaži"
|
||||||
|
|
||||||
|
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||||
|
msgid "Hide"
|
||||||
|
msgstr "Sakrij"
|
||||||
|
|
||||||
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||||
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||||
msgid "Now"
|
msgid "Now"
|
||||||
msgstr "Sada"
|
msgstr "Sada"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||||
msgid "Clock"
|
msgid "Clock"
|
||||||
msgstr "Sat"
|
msgstr "Sat"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||||
msgid "Choose a time"
|
msgid "Choose a time"
|
||||||
msgstr "Izaberite vreme"
|
msgstr "Izaberite vreme"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||||
msgid "Midnight"
|
msgid "Midnight"
|
||||||
msgstr "Ponoć"
|
msgstr "Ponoć"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||||
msgid "6 a.m."
|
msgid "6 a.m."
|
||||||
msgstr "6 sati"
|
msgstr "6 sati"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||||
msgid "Noon"
|
msgid "Noon"
|
||||||
msgstr "Podne"
|
msgstr "Podne"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Poništi"
|
msgstr "Poništi"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||||
msgid "Today"
|
msgid "Today"
|
||||||
msgstr "Danas"
|
msgstr "Danas"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||||
msgid "Calendar"
|
msgid "Calendar"
|
||||||
msgstr "Kalendar"
|
msgstr "Kalendar"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Juče"
|
msgstr "Juče"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||||
msgid "Tomorrow"
|
msgid "Tomorrow"
|
||||||
msgstr "Sutra"
|
msgstr "Sutra"
|
||||||
|
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,16 @@
|
|||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
# Uncomment this for admin:
|
# Uncomment the next two lines to enable the admin:
|
||||||
# from django.contrib import admin
|
# from django.contrib import admin
|
||||||
|
# admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# Example:
|
# Example:
|
||||||
# (r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
|
# (r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
|
||||||
|
|
||||||
# Uncomment this for admin docs:
|
# Uncomment the next line to enable admin documentation:
|
||||||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
|
|
||||||
# Uncomment this for admin:
|
# Uncomment the next line for to enable the admin:
|
||||||
#('^admin/(.*)', admin.site.root),
|
# (r'^admin/(.*)', admin.site.root),
|
||||||
)
|
)
|
||||||
|
@ -8,9 +8,12 @@ def autodiscover():
|
|||||||
not present. This forces an import on them to register any admin bits they
|
not present. This forces an import on them to register any admin bits they
|
||||||
may want.
|
may want.
|
||||||
"""
|
"""
|
||||||
|
import imp
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
for app in settings.INSTALLED_APPS:
|
for app in settings.INSTALLED_APPS:
|
||||||
try:
|
try:
|
||||||
__import__("%s.admin" % app)
|
imp.find_module("admin", __import__(app, {}, {}, [app.split(".")[-1]]).__path__)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
# there is no app admin.py, skip it
|
||||||
|
continue
|
||||||
|
__import__("%s.admin" % app)
|
||||||
|
@ -44,3 +44,6 @@ div.breadcrumbs { text-align:right; }
|
|||||||
|
|
||||||
.selector { float: right;}
|
.selector { float: right;}
|
||||||
.selector .selector-filter { text-align: right;}
|
.selector .selector-filter { text-align: right;}
|
||||||
|
|
||||||
|
/* x unsorted */
|
||||||
|
.inline-related h2 { text-align:right }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from django import oldforms, template
|
from django import forms, template
|
||||||
from django import forms
|
|
||||||
from django.forms.formsets import all_valid
|
from django.forms.formsets import all_valid
|
||||||
from django.forms.models import modelform_factory, inlineformset_factory
|
from django.forms.models import modelform_factory, inlineformset_factory
|
||||||
from django.forms.models import BaseInlineFormset
|
from django.forms.models import BaseInlineFormset
|
||||||
@ -15,7 +14,10 @@ from django.utils.safestring import mark_safe
|
|||||||
from django.utils.text import capfirst, get_text_list
|
from django.utils.text import capfirst, get_text_list
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
import sets
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # Python 2.3 fallback
|
||||||
|
|
||||||
HORIZONTAL, VERTICAL = 1, 2
|
HORIZONTAL, VERTICAL = 1, 2
|
||||||
# returns the <ul> class for a given radio_admin field
|
# returns the <ul> class for a given radio_admin field
|
||||||
@ -90,7 +92,7 @@ class Fieldline(object):
|
|||||||
yield AdminField(self.form, field, is_first=(i == 0))
|
yield AdminField(self.form, field, is_first=(i == 0))
|
||||||
|
|
||||||
def errors(self):
|
def errors(self):
|
||||||
return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]))
|
return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
|
||||||
|
|
||||||
class AdminField(object):
|
class AdminField(object):
|
||||||
def __init__(self, form, field, is_first):
|
def __init__(self, form, field, is_first):
|
||||||
@ -130,6 +132,23 @@ class BaseModelAdmin(object):
|
|||||||
|
|
||||||
If kwargs are given, they're passed to the form Field's constructor.
|
If kwargs are given, they're passed to the form Field's constructor.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# If the field specifies choices, we don't need to look for special
|
||||||
|
# admin widgets - we just need to use a select widget of some kind.
|
||||||
|
if db_field.choices:
|
||||||
|
if db_field.name in self.radio_fields:
|
||||||
|
# If the field is named as a radio_field, use a RadioSelect
|
||||||
|
kwargs['widget'] = widgets.AdminRadioSelect(
|
||||||
|
choices=db_field.get_choices(include_blank=db_field.blank,
|
||||||
|
blank_choice=[('', _('None'))]),
|
||||||
|
attrs={
|
||||||
|
'class': get_ul_class(self.radio_fields[db_field.name]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Otherwise, use the default select widget.
|
||||||
|
return db_field.formfield(**kwargs)
|
||||||
|
|
||||||
# For DateTimeFields, use a special field and widget.
|
# For DateTimeFields, use a special field and widget.
|
||||||
if isinstance(db_field, models.DateTimeField):
|
if isinstance(db_field, models.DateTimeField):
|
||||||
kwargs['form_class'] = forms.SplitDateTimeField
|
kwargs['form_class'] = forms.SplitDateTimeField
|
||||||
@ -162,10 +181,13 @@ class BaseModelAdmin(object):
|
|||||||
kwargs['empty_label'] = db_field.blank and _('None') or None
|
kwargs['empty_label'] = db_field.blank and _('None') or None
|
||||||
else:
|
else:
|
||||||
if isinstance(db_field, models.ManyToManyField):
|
if isinstance(db_field, models.ManyToManyField):
|
||||||
if db_field.name in self.raw_id_fields:
|
# If it uses an intermediary model, don't show field in admin.
|
||||||
|
if db_field.rel.through is not None:
|
||||||
|
return None
|
||||||
|
elif db_field.name in self.raw_id_fields:
|
||||||
kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
|
kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
|
||||||
kwargs['help_text'] = ''
|
kwargs['help_text'] = ''
|
||||||
elif db_field.name in (self.filter_vertical + self.filter_horizontal):
|
elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
|
||||||
kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
|
kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
|
||||||
# Wrap the widget's render() method with a method that adds
|
# Wrap the widget's render() method with a method that adds
|
||||||
# extra HTML to the end of the rendered output.
|
# extra HTML to the end of the rendered output.
|
||||||
@ -175,15 +197,6 @@ class BaseModelAdmin(object):
|
|||||||
formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
|
formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
|
||||||
return formfield
|
return formfield
|
||||||
|
|
||||||
if db_field.choices and db_field.name in self.radio_fields:
|
|
||||||
kwargs['widget'] = widgets.AdminRadioSelect(
|
|
||||||
choices=db_field.get_choices(include_blank=db_field.blank,
|
|
||||||
blank_choice=[('', _('None'))]),
|
|
||||||
attrs={
|
|
||||||
'class': get_ul_class(self.radio_fields[db_field.name]),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# For any other type of field, just call its formfield() method.
|
# For any other type of field, just call its formfield() method.
|
||||||
return db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
|
|
||||||
@ -345,7 +358,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
|
|
||||||
pk_value = new_object._get_pk_val()
|
pk_value = new_object._get_pk_val()
|
||||||
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), ADDITION)
|
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), ADDITION)
|
||||||
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object}
|
||||||
# Here, we distinguish between different save types by checking for
|
# Here, we distinguish between different save types by checking for
|
||||||
# the presence of keys in request.POST.
|
# the presence of keys in request.POST.
|
||||||
if request.POST.has_key("_continue"):
|
if request.POST.has_key("_continue"):
|
||||||
@ -359,7 +372,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
# escape() calls force_unicode.
|
# escape() calls force_unicode.
|
||||||
(escape(pk_value), escape(new_object)))
|
(escape(pk_value), escape(new_object)))
|
||||||
elif request.POST.has_key("_addanother"):
|
elif request.POST.has_key("_addanother"):
|
||||||
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
|
||||||
return HttpResponseRedirect(request.path)
|
return HttpResponseRedirect(request.path)
|
||||||
else:
|
else:
|
||||||
request.user.message_set.create(message=msg)
|
request.user.message_set.create(message=msg)
|
||||||
@ -415,7 +428,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
change_message = _('No fields changed.')
|
change_message = _('No fields changed.')
|
||||||
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
|
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
|
||||||
|
|
||||||
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object}
|
||||||
if request.POST.has_key("_continue"):
|
if request.POST.has_key("_continue"):
|
||||||
request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
|
request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
|
||||||
if request.REQUEST.has_key('_popup'):
|
if request.REQUEST.has_key('_popup'):
|
||||||
@ -423,10 +436,10 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(request.path)
|
return HttpResponseRedirect(request.path)
|
||||||
elif request.POST.has_key("_saveasnew"):
|
elif request.POST.has_key("_saveasnew"):
|
||||||
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
|
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': new_object})
|
||||||
return HttpResponseRedirect("../%s/" % pk_value)
|
return HttpResponseRedirect("../%s/" % pk_value)
|
||||||
elif request.POST.has_key("_addanother"):
|
elif request.POST.has_key("_addanother"):
|
||||||
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
|
||||||
return HttpResponseRedirect("../add/")
|
return HttpResponseRedirect("../add/")
|
||||||
else:
|
else:
|
||||||
request.user.message_set.create(message=msg)
|
request.user.message_set.create(message=msg)
|
||||||
@ -504,7 +517,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
inline_admin_formsets.append(inline_admin_formset)
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'title': _('Add %s') % opts.verbose_name,
|
'title': _('Add %s') % force_unicode(opts.verbose_name),
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
'is_popup': request.REQUEST.has_key('_popup'),
|
'is_popup': request.REQUEST.has_key('_popup'),
|
||||||
'show_delete': False,
|
'show_delete': False,
|
||||||
@ -534,7 +547,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
|
raise Http404('%s object with primary key %r does not exist.' % (force_unicode(opts.verbose_name), escape(object_id)))
|
||||||
|
|
||||||
if request.POST and request.POST.has_key("_saveasnew"):
|
if request.POST and request.POST.has_key("_saveasnew"):
|
||||||
return self.add_view(request, form_url='../../add/')
|
return self.add_view(request, form_url='../../add/')
|
||||||
@ -557,17 +570,16 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
|
|
||||||
adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
|
adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
|
||||||
media = self.media + adminForm.media
|
media = self.media + adminForm.media
|
||||||
for fs in inline_formsets:
|
|
||||||
media = media + fs.media
|
|
||||||
|
|
||||||
inline_admin_formsets = []
|
inline_admin_formsets = []
|
||||||
for inline, formset in zip(self.inline_instances, inline_formsets):
|
for inline, formset in zip(self.inline_instances, inline_formsets):
|
||||||
fieldsets = list(inline.get_fieldsets(request, obj))
|
fieldsets = list(inline.get_fieldsets(request, obj))
|
||||||
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
|
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
|
||||||
inline_admin_formsets.append(inline_admin_formset)
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
|
media = media + inline_admin_formset.media
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'title': _('Change %s') % opts.verbose_name,
|
'title': _('Change %s') % force_unicode(opts.verbose_name),
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
'object_id': object_id,
|
'object_id': object_id,
|
||||||
'original': obj,
|
'original': obj,
|
||||||
@ -632,12 +644,12 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
|
raise Http404('%s object with primary key %r does not exist.' % (force_unicode(opts.verbose_name), escape(object_id)))
|
||||||
|
|
||||||
# Populate deleted_objects, a data structure of all related objects that
|
# Populate deleted_objects, a data structure of all related objects that
|
||||||
# will also be deleted.
|
# will also be deleted.
|
||||||
deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
|
deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
|
||||||
perms_needed = sets.Set()
|
perms_needed = set()
|
||||||
get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
|
get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
|
||||||
|
|
||||||
if request.POST: # The user has already confirmed the deletion.
|
if request.POST: # The user has already confirmed the deletion.
|
||||||
@ -653,7 +665,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
"title": _("Are you sure?"),
|
"title": _("Are you sure?"),
|
||||||
"object_name": opts.verbose_name,
|
"object_name": force_unicode(opts.verbose_name),
|
||||||
"object": obj,
|
"object": obj,
|
||||||
"deleted_objects": deleted_objects,
|
"deleted_objects": deleted_objects,
|
||||||
"perms_lacking": perms_needed,
|
"perms_lacking": perms_needed,
|
||||||
@ -681,7 +693,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
context = {
|
context = {
|
||||||
'title': _('Change history: %s') % force_unicode(obj),
|
'title': _('Change history: %s') % force_unicode(obj),
|
||||||
'action_list': action_list,
|
'action_list': action_list,
|
||||||
'module_name': capfirst(opts.verbose_name_plural),
|
'module_name': capfirst(force_unicode(opts.verbose_name_plural)),
|
||||||
'object': obj,
|
'object': obj,
|
||||||
'root_path': self.admin_site.root_path,
|
'root_path': self.admin_site.root_path,
|
||||||
}
|
}
|
||||||
@ -761,6 +773,13 @@ class InlineAdminFormSet(object):
|
|||||||
for field_name in flatten_fieldsets(self.fieldsets):
|
for field_name in flatten_fieldsets(self.fieldsets):
|
||||||
yield self.formset.form.base_fields[field_name]
|
yield self.formset.form.base_fields[field_name]
|
||||||
|
|
||||||
|
def _media(self):
|
||||||
|
media = self.formset.media
|
||||||
|
for fs in self:
|
||||||
|
media = media + fs.media
|
||||||
|
return media
|
||||||
|
media = property(_media)
|
||||||
|
|
||||||
class InlineAdminForm(AdminForm):
|
class InlineAdminForm(AdminForm):
|
||||||
"""
|
"""
|
||||||
A wrapper around an inline form for use in the admin system.
|
A wrapper around an inline form for use in the admin system.
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
import base64
|
||||||
|
import cPickle as pickle
|
||||||
|
import re
|
||||||
|
|
||||||
from django import http, template
|
from django import http, template
|
||||||
from django.contrib.admin import ModelAdmin
|
from django.contrib.admin import ModelAdmin
|
||||||
from django.contrib.auth import authenticate, login
|
from django.contrib.auth import authenticate, login
|
||||||
@ -8,11 +12,7 @@ from django.utils.text import capfirst
|
|||||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import base64
|
from django.utils.hashcompat import md5_constructor
|
||||||
import cPickle as pickle
|
|
||||||
import datetime
|
|
||||||
import md5
|
|
||||||
import re
|
|
||||||
|
|
||||||
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
|
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
|
||||||
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
||||||
@ -26,16 +26,14 @@ class NotRegistered(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _encode_post_data(post_data):
|
def _encode_post_data(post_data):
|
||||||
from django.conf import settings
|
|
||||||
pickled = pickle.dumps(post_data)
|
pickled = pickle.dumps(post_data)
|
||||||
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
|
pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
|
||||||
return base64.encodestring(pickled + pickled_md5)
|
return base64.encodestring(pickled + pickled_md5)
|
||||||
|
|
||||||
def _decode_post_data(encoded_data):
|
def _decode_post_data(encoded_data):
|
||||||
from django.conf import settings
|
|
||||||
encoded_data = base64.decodestring(encoded_data)
|
encoded_data = base64.decodestring(encoded_data)
|
||||||
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
||||||
if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
raise SuspiciousOperation, "User may have tampered with session cookie."
|
raise SuspiciousOperation, "User may have tampered with session cookie."
|
||||||
return pickle.loads(pickled)
|
return pickle.loads(pickled)
|
||||||
@ -66,19 +64,33 @@ class AdminSite(object):
|
|||||||
|
|
||||||
If a model is already registered, this will raise AlreadyRegistered.
|
If a model is already registered, this will raise AlreadyRegistered.
|
||||||
"""
|
"""
|
||||||
do_validate = admin_class and settings.DEBUG
|
# Don't import the humongous validation code unless required
|
||||||
if do_validate:
|
if admin_class and settings.DEBUG:
|
||||||
# don't import the humongous validation code unless required
|
|
||||||
from django.contrib.admin.validation import validate
|
from django.contrib.admin.validation import validate
|
||||||
admin_class = admin_class or ModelAdmin
|
else:
|
||||||
# TODO: Handle options
|
validate = lambda model, adminclass: None
|
||||||
|
|
||||||
|
if not admin_class:
|
||||||
|
admin_class = ModelAdmin
|
||||||
if isinstance(model_or_iterable, ModelBase):
|
if isinstance(model_or_iterable, ModelBase):
|
||||||
model_or_iterable = [model_or_iterable]
|
model_or_iterable = [model_or_iterable]
|
||||||
for model in model_or_iterable:
|
for model in model_or_iterable:
|
||||||
if model in self._registry:
|
if model in self._registry:
|
||||||
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
|
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
|
||||||
if do_validate:
|
|
||||||
|
# If we got **options then dynamically construct a subclass of
|
||||||
|
# admin_class with those **options.
|
||||||
|
if options:
|
||||||
|
# For reasons I don't quite understand, without a __module__
|
||||||
|
# the created class appears to "live" in the wrong place,
|
||||||
|
# which causes issues later on.
|
||||||
|
options['__module__'] = __name__
|
||||||
|
admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
|
||||||
|
|
||||||
|
# Validate (which might be a no-op)
|
||||||
validate(admin_class, model)
|
validate(admin_class, model)
|
||||||
|
|
||||||
|
# Instantiate the admin class to save in the registry
|
||||||
self._registry[model] = admin_class(model, self)
|
self._registry[model] = admin_class(model, self)
|
||||||
|
|
||||||
def unregister(self, model_or_iterable):
|
def unregister(self, model_or_iterable):
|
||||||
@ -189,7 +201,6 @@ class AdminSite(object):
|
|||||||
This takes into account the USE_I18N setting. If it's set to False, the
|
This takes into account the USE_I18N setting. If it's set to False, the
|
||||||
generated JavaScript will be leaner and faster.
|
generated JavaScript will be leaner and faster.
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
|
||||||
if settings.USE_I18N:
|
if settings.USE_I18N:
|
||||||
from django.views.i18n import javascript_catalog
|
from django.views.i18n import javascript_catalog
|
||||||
else:
|
else:
|
||||||
@ -249,9 +260,6 @@ class AdminSite(object):
|
|||||||
else:
|
else:
|
||||||
if user.is_active and user.is_staff:
|
if user.is_active and user.is_staff:
|
||||||
login(request, user)
|
login(request, user)
|
||||||
# TODO: set last_login with an event.
|
|
||||||
user.last_login = datetime.datetime.now()
|
|
||||||
user.save()
|
|
||||||
if request.POST.has_key('post_data'):
|
if request.POST.has_key('post_data'):
|
||||||
post_data = _decode_post_data(request.POST['post_data'])
|
post_data = _decode_post_data(request.POST['post_data'])
|
||||||
if post_data and not post_data.has_key(LOGIN_FORM_KEY):
|
if post_data and not post_data.has_key(LOGIN_FORM_KEY):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<fieldset class="module aligned {{ fieldset.classes }}">
|
<fieldset class="module aligned {{ fieldset.classes }}">
|
||||||
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
|
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
|
||||||
{% if fieldset.description %}<div class="description">{{ fieldset.description }}</div>{% endif %}
|
{% if fieldset.description %}<div class="description">{{ fieldset.description|safe }}</div>{% endif %}
|
||||||
{% for line in fieldset %}
|
{% for line in fieldset %}
|
||||||
<div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
|
<div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
|
||||||
{{ line.errors }}
|
{{ line.errors }}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ field.name }}</td>
|
<td>{{ field.name }}</td>
|
||||||
<td>{{ field.data_type }}</td>
|
<td>{{ field.data_type }}</td>
|
||||||
<td>{% if field.verbose %}{{ field.verbose }}{% endif %}{% if field.help_text %} - {{ field.help_text }}{% endif %}</td>
|
<td>{% if field.verbose %}{{ field.verbose }}{% endif %}{% if field.help_text %} - {{ field.help_text|safe }}{% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {% trans 'Password reset' %}</div>{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{% trans 'Password reset complete' %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{% trans 'Password reset complete' %}</h1>
|
||||||
|
|
||||||
|
<p>{% trans "Your password has been set. You may go ahead and log in now." %}</p>
|
||||||
|
|
||||||
|
<p><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,32 @@
|
|||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password reset confirmation' %}</div>{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{% trans 'Password reset' %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if validlink %}
|
||||||
|
|
||||||
|
<h1>{% trans 'Enter new password' %}</h1>
|
||||||
|
|
||||||
|
<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
{% if form.new_password1.errors %}{{ form.new_password1.errors }}{% endif %}
|
||||||
|
<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
|
||||||
|
{% if form.new_password2.errors %}{{ form.new_password2.errors }}{% endif %}
|
||||||
|
<p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
|
||||||
|
<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<h1>{% trans 'Password reset unsuccessful' %}</h1>
|
||||||
|
|
||||||
|
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -9,6 +9,6 @@
|
|||||||
|
|
||||||
<h1>{% trans 'Password reset successful' %}</h1>
|
<h1>{% trans 'Password reset successful' %}</h1>
|
||||||
|
|
||||||
<p>{% trans "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly." %}</p>
|
<p>{% trans "We've e-mailed you instructions for setting your password to the e-mail address you submitted. You should be receiving it shortly." %}</p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}{% autoescape off %}
|
||||||
{% trans "You're receiving this e-mail because you requested a password reset" %}
|
{% trans "You're receiving this e-mail because you requested a password reset" %}
|
||||||
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
|
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
|
||||||
|
|
||||||
{% blocktrans %}Your new password is: {{ new_password }}{% endblocktrans %}
|
{% trans "Please go to the following page and choose a new password:" %}
|
||||||
|
{% block reset_link %}
|
||||||
{% trans "Feel free to change this password by going to this page:" %}
|
{{ protocol }}://{{ domain }}/reset/{{ uid }}-{{ token }}/
|
||||||
|
{% endblock %}
|
||||||
http://{{ domain }}/password_change/
|
|
||||||
|
|
||||||
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
|
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
|
||||||
|
|
||||||
{% trans "Thanks for using our site!" %}
|
{% trans "Thanks for using our site!" %}
|
||||||
|
|
||||||
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
||||||
|
|
||||||
|
{% endautoescape %}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<h1>{% trans "Password reset" %}</h1>
|
<h1>{% trans "Password reset" %}</h1>
|
||||||
|
|
||||||
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you." %}</p>
|
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
|
||||||
|
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% if form.email.errors %}{{ form.email.errors }}{% endif %}
|
{% if form.email.errors %}{{ form.email.errors }}{% endif %}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # Python 2.3 fallback
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@ -165,6 +169,8 @@ def _validate_base(cls, model):
|
|||||||
_check_form_field_existsw('fields', field)
|
_check_form_field_existsw('fields', field)
|
||||||
if cls.fieldsets:
|
if cls.fieldsets:
|
||||||
raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__)
|
raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__)
|
||||||
|
if len(cls.fields) > len(set(cls.fields)):
|
||||||
|
raise ImproperlyConfigured('There are duplicate field(s) in %s.fields' % cls.__name__)
|
||||||
|
|
||||||
# fieldsets
|
# fieldsets
|
||||||
if cls.fieldsets: # default value is None
|
if cls.fieldsets: # default value is None
|
||||||
@ -179,7 +185,10 @@ def _validate_base(cls, model):
|
|||||||
raise ImproperlyConfigured("`fields` key is required in "
|
raise ImproperlyConfigured("`fields` key is required in "
|
||||||
"%s.fieldsets[%d][1] field options dict."
|
"%s.fieldsets[%d][1] field options dict."
|
||||||
% (cls.__name__, idx))
|
% (cls.__name__, idx))
|
||||||
for field in flatten_fieldsets(cls.fieldsets):
|
flattened_fieldsets = flatten_fieldsets(cls.fieldsets)
|
||||||
|
if len(flattened_fieldsets) > len(set(flattened_fieldsets)):
|
||||||
|
raise ImproperlyConfigured('There are duplicate field(s) in %s.fieldsets' % cls.__name__)
|
||||||
|
for field in flattened_fieldsets:
|
||||||
_check_form_field_existsw("fieldsets[%d][1]['fields']" % idx, field)
|
_check_form_field_existsw("fieldsets[%d][1]['fields']" % idx, field)
|
||||||
|
|
||||||
# form
|
# form
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import base64
|
import base64
|
||||||
import md5
|
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
try:
|
try:
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
@ -12,6 +11,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.contrib.auth import authenticate, login
|
from django.contrib.auth import authenticate, login
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
|
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
|
||||||
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
||||||
@ -35,13 +35,13 @@ def _display_login_form(request, error_message=''):
|
|||||||
|
|
||||||
def _encode_post_data(post_data):
|
def _encode_post_data(post_data):
|
||||||
pickled = pickle.dumps(post_data)
|
pickled = pickle.dumps(post_data)
|
||||||
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
|
pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
|
||||||
return base64.encodestring(pickled + pickled_md5)
|
return base64.encodestring(pickled + pickled_md5)
|
||||||
|
|
||||||
def _decode_post_data(encoded_data):
|
def _decode_post_data(encoded_data):
|
||||||
encoded_data = base64.decodestring(encoded_data)
|
encoded_data = base64.decodestring(encoded_data)
|
||||||
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
||||||
if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
raise SuspiciousOperation, "User may have tampered with session cookie."
|
raise SuspiciousOperation, "User may have tampered with session cookie."
|
||||||
return pickle.loads(pickled)
|
return pickle.loads(pickled)
|
||||||
|
@ -6,7 +6,6 @@ from django.db import models
|
|||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.utils.encoding import force_unicode, smart_str
|
from django.utils.encoding import force_unicode, smart_str
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ import copy
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.forms.widgets import RadioFieldRenderer
|
from django.forms.widgets import RadioFieldRenderer
|
||||||
from django.forms.util import flatatt
|
from django.forms.util import flatatt
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.text import truncate_words
|
||||||
from django.utils.text import capfirst, truncate_words
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
@ -5,7 +5,7 @@ from django.contrib.admin.views.decorators import staff_member_required
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||||
from django.http import Http404, get_host
|
from django.http import Http404
|
||||||
from django.core import urlresolvers
|
from django.core import urlresolvers
|
||||||
from django.contrib.admindocs import utils
|
from django.contrib.admindocs import utils
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django import oldforms, template
|
from django import template
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
try:
|
try:
|
||||||
from functools import wraps, update_wrapper
|
from functools import update_wrapper
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from django.utils.functional import wraps, update_wrapper # Python 2.3, 2.4 fallback.
|
from django.utils.functional import update_wrapper # Python 2.3, 2.4 fallback.
|
||||||
|
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.template import Context, loader
|
from django.template import Context, loader
|
||||||
from django.core import validators
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.http import int_to_base36
|
||||||
|
|
||||||
class UserCreationForm(forms.ModelForm):
|
class UserCreationForm(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
@ -13,8 +14,8 @@ class UserCreationForm(forms.ModelForm):
|
|||||||
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^\w+$',
|
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^\w+$',
|
||||||
help_text = _("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."),
|
help_text = _("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."),
|
||||||
error_message = _("This value must contain only letters, numbers and underscores."))
|
error_message = _("This value must contain only letters, numbers and underscores."))
|
||||||
password1 = forms.CharField(label=_("Password"), max_length=60, widget=forms.PasswordInput)
|
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||||
password2 = forms.CharField(label=_("Password confirmation"), max_length=60, widget=forms.PasswordInput)
|
password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
@ -48,7 +49,7 @@ class AuthenticationForm(forms.Form):
|
|||||||
username/password logins.
|
username/password logins.
|
||||||
"""
|
"""
|
||||||
username = forms.CharField(label=_("Username"), max_length=30)
|
username = forms.CharField(label=_("Username"), max_length=30)
|
||||||
password = forms.CharField(label=_("Password"), max_length=30, widget=forms.PasswordInput)
|
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||||
|
|
||||||
def __init__(self, request=None, *args, **kwargs):
|
def __init__(self, request=None, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -88,7 +89,7 @@ class AuthenticationForm(forms.Form):
|
|||||||
return self.user_cache
|
return self.user_cache
|
||||||
|
|
||||||
class PasswordResetForm(forms.Form):
|
class PasswordResetForm(forms.Form):
|
||||||
email = forms.EmailField(label=_("E-mail"), max_length=40)
|
email = forms.EmailField(label=_("E-mail"), max_length=75)
|
||||||
|
|
||||||
def clean_email(self):
|
def clean_email(self):
|
||||||
"""
|
"""
|
||||||
@ -99,15 +100,13 @@ class PasswordResetForm(forms.Form):
|
|||||||
if len(self.users_cache) == 0:
|
if len(self.users_cache) == 0:
|
||||||
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
||||||
|
|
||||||
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html'):
|
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
|
||||||
|
use_https=False, token_generator=default_token_generator):
|
||||||
"""
|
"""
|
||||||
Calculates a new password randomly and sends it to the user.
|
Generates a one-use only link for resetting password and sends to the user
|
||||||
"""
|
"""
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
for user in self.users_cache:
|
for user in self.users_cache:
|
||||||
new_pass = User.objects.make_random_password()
|
|
||||||
user.set_password(new_pass)
|
|
||||||
user.save()
|
|
||||||
if not domain_override:
|
if not domain_override:
|
||||||
current_site = Site.objects.get_current()
|
current_site = Site.objects.get_current()
|
||||||
site_name = current_site.name
|
site_name = current_site.name
|
||||||
@ -116,35 +115,28 @@ class PasswordResetForm(forms.Form):
|
|||||||
site_name = domain = domain_override
|
site_name = domain = domain_override
|
||||||
t = loader.get_template(email_template_name)
|
t = loader.get_template(email_template_name)
|
||||||
c = {
|
c = {
|
||||||
'new_password': new_pass,
|
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'domain': domain,
|
'domain': domain,
|
||||||
'site_name': site_name,
|
'site_name': site_name,
|
||||||
|
'uid': int_to_base36(user.id),
|
||||||
'user': user,
|
'user': user,
|
||||||
|
'token': token_generator.make_token(user),
|
||||||
|
'protocol': use_https and 'https' or 'http',
|
||||||
}
|
}
|
||||||
send_mail(_("Password reset on %s") % site_name,
|
send_mail(_("Password reset on %s") % site_name,
|
||||||
t.render(Context(c)), None, [user.email])
|
t.render(Context(c)), None, [user.email])
|
||||||
|
|
||||||
class PasswordChangeForm(forms.Form):
|
class SetPasswordForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
A form that lets a user change his/her password.
|
A form that lets a user change set his/her password without
|
||||||
|
entering the old password
|
||||||
"""
|
"""
|
||||||
old_password = forms.CharField(label=_("Old password"), max_length=30, widget=forms.PasswordInput)
|
new_password1 = forms.CharField(label=_("New password"), widget=forms.PasswordInput)
|
||||||
new_password1 = forms.CharField(label=_("New password"), max_length=30, widget=forms.PasswordInput)
|
new_password2 = forms.CharField(label=_("New password confirmation"), widget=forms.PasswordInput)
|
||||||
new_password2 = forms.CharField(label=_("New password confirmation"), max_length=30, widget=forms.PasswordInput)
|
|
||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
self.user = user
|
self.user = user
|
||||||
super(PasswordChangeForm, self).__init__(*args, **kwargs)
|
super(SetPasswordForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean_old_password(self):
|
|
||||||
"""
|
|
||||||
Validates that the old_password field is correct.
|
|
||||||
"""
|
|
||||||
old_password = self.cleaned_data["old_password"]
|
|
||||||
if not self.user.check_password(old_password):
|
|
||||||
raise forms.ValidationError(_("Your old password was entered incorrectly. Please enter it again."))
|
|
||||||
return old_password
|
|
||||||
|
|
||||||
def clean_new_password2(self):
|
def clean_new_password2(self):
|
||||||
password1 = self.cleaned_data.get('new_password1')
|
password1 = self.cleaned_data.get('new_password1')
|
||||||
@ -160,12 +152,29 @@ class PasswordChangeForm(forms.Form):
|
|||||||
self.user.save()
|
self.user.save()
|
||||||
return self.user
|
return self.user
|
||||||
|
|
||||||
|
class PasswordChangeForm(SetPasswordForm):
|
||||||
|
"""
|
||||||
|
A form that lets a user change his/her password by entering
|
||||||
|
their old password.
|
||||||
|
"""
|
||||||
|
old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput)
|
||||||
|
|
||||||
|
def clean_old_password(self):
|
||||||
|
"""
|
||||||
|
Validates that the old_password field is correct.
|
||||||
|
"""
|
||||||
|
old_password = self.cleaned_data["old_password"]
|
||||||
|
if not self.user.check_password(old_password):
|
||||||
|
raise forms.ValidationError(_("Your old password was entered incorrectly. Please enter it again."))
|
||||||
|
return old_password
|
||||||
|
PasswordChangeForm.base_fields.keyOrder = ['old_password', 'new_password1', 'new_password2']
|
||||||
|
|
||||||
class AdminPasswordChangeForm(forms.Form):
|
class AdminPasswordChangeForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
A form used to change the password of a user in the admin interface.
|
A form used to change the password of a user in the admin interface.
|
||||||
"""
|
"""
|
||||||
password1 = forms.CharField(label=_("Password"), max_length=60, widget=forms.PasswordInput)
|
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||||
password2 = forms.CharField(label=_("Password (again)"), max_length=60, widget=forms.PasswordInput)
|
password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)
|
||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
self.user = user
|
self.user = user
|
||||||
|
@ -7,7 +7,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
from django.contrib.auth.models import User, UNUSABLE_PASSWORD
|
from django.contrib.auth.models import User
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
|
@ -358,6 +358,9 @@ class AnonymousUser(object):
|
|||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def has_perms(self, perm_list):
|
||||||
|
return False
|
||||||
|
|
||||||
def has_module_perms(self, module):
|
def has_module_perms(self, module):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
from django.contrib.auth.tests.basic import BASIC_TESTS, PasswordResetTest
|
from django.contrib.auth.tests.basic import BASIC_TESTS
|
||||||
|
from django.contrib.auth.tests.views import PasswordResetTest
|
||||||
from django.contrib.auth.tests.forms import FORM_TESTS
|
from django.contrib.auth.tests.forms import FORM_TESTS
|
||||||
|
from django.contrib.auth.tests.tokens import TOKEN_GENERATOR_TESTS
|
||||||
|
|
||||||
__test__ = {
|
__test__ = {
|
||||||
'BASIC_TESTS': BASIC_TESTS,
|
'BASIC_TESTS': BASIC_TESTS,
|
||||||
'PASSWORDRESET_TESTS': PasswordResetTest,
|
'PASSWORDRESET_TESTS': PasswordResetTest,
|
||||||
'FORM_TESTS': FORM_TESTS,
|
'FORM_TESTS': FORM_TESTS,
|
||||||
|
'TOKEN_GENERATOR_TESTS': TOKEN_GENERATOR_TESTS
|
||||||
}
|
}
|
||||||
|
@ -54,24 +54,3 @@ u'joe@somewhere.org'
|
|||||||
>>> u.password
|
>>> u.password
|
||||||
u'!'
|
u'!'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
from django.core import mail
|
|
||||||
|
|
||||||
class PasswordResetTest(TestCase):
|
|
||||||
fixtures = ['authtestdata.json']
|
|
||||||
urls = 'django.contrib.auth.urls'
|
|
||||||
|
|
||||||
def test_email_not_found(self):
|
|
||||||
"Error is raised if the provided email address isn't currently registered"
|
|
||||||
response = self.client.get('/password_reset/')
|
|
||||||
self.assertEquals(response.status_code, 200)
|
|
||||||
response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
|
|
||||||
self.assertContains(response, "That e-mail address doesn't have an associated user account")
|
|
||||||
self.assertEquals(len(mail.outbox), 0)
|
|
||||||
|
|
||||||
def test_email_found(self):
|
|
||||||
"Email is sent if a valid email address is provided for password reset"
|
|
||||||
response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
|
|
||||||
self.assertEquals(response.status_code, 302)
|
|
||||||
self.assertEquals(len(mail.outbox), 1)
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
FORM_TESTS = """
|
FORM_TESTS = """
|
||||||
>>> from django.contrib.auth.models import User
|
>>> from django.contrib.auth.models import User
|
||||||
>>> from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
>>> from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
||||||
>>> from django.contrib.auth.forms import PasswordChangeForm
|
>>> from django.contrib.auth.forms import PasswordChangeForm, SetPasswordForm
|
||||||
|
|
||||||
The user already exists.
|
The user already exists.
|
||||||
|
|
||||||
@ -95,6 +95,32 @@ True
|
|||||||
>>> form.non_field_errors()
|
>>> form.non_field_errors()
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
SetPasswordForm:
|
||||||
|
|
||||||
|
The two new passwords do not match.
|
||||||
|
|
||||||
|
>>> data = {
|
||||||
|
... 'new_password1': 'abc123',
|
||||||
|
... 'new_password2': 'abc',
|
||||||
|
... }
|
||||||
|
>>> form = SetPasswordForm(user, data)
|
||||||
|
>>> form.is_valid()
|
||||||
|
False
|
||||||
|
>>> form["new_password2"].errors
|
||||||
|
[u"The two password fields didn't match."]
|
||||||
|
|
||||||
|
The success case.
|
||||||
|
|
||||||
|
>>> data = {
|
||||||
|
... 'new_password1': 'abc123',
|
||||||
|
... 'new_password2': 'abc123',
|
||||||
|
... }
|
||||||
|
>>> form = SetPasswordForm(user, data)
|
||||||
|
>>> form.is_valid()
|
||||||
|
True
|
||||||
|
|
||||||
|
PasswordChangeForm:
|
||||||
|
|
||||||
The old password is incorrect.
|
The old password is incorrect.
|
||||||
|
|
||||||
>>> data = {
|
>>> data = {
|
||||||
@ -132,4 +158,9 @@ The success case.
|
|||||||
>>> form.is_valid()
|
>>> form.is_valid()
|
||||||
True
|
True
|
||||||
|
|
||||||
|
Regression test - check the order of fields:
|
||||||
|
|
||||||
|
>>> PasswordChangeForm(user, {}).fields.keys()
|
||||||
|
['old_password', 'new_password1', 'new_password2']
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
29
django/contrib/auth/tests/tokens.py
Normal file
29
django/contrib/auth/tests/tokens.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
TOKEN_GENERATOR_TESTS = """
|
||||||
|
>>> from django.contrib.auth.models import User, AnonymousUser
|
||||||
|
>>> from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
|
>>> from django.conf import settings
|
||||||
|
>>> u = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw')
|
||||||
|
>>> p0 = PasswordResetTokenGenerator()
|
||||||
|
>>> tk1 = p0.make_token(u)
|
||||||
|
>>> p0.check_token(u, tk1)
|
||||||
|
True
|
||||||
|
|
||||||
|
Tests to ensure we can use the token after n days, but no greater.
|
||||||
|
Use a mocked version of PasswordResetTokenGenerator so we can change
|
||||||
|
the value of 'today'
|
||||||
|
|
||||||
|
>>> class Mocked(PasswordResetTokenGenerator):
|
||||||
|
... def __init__(self, today):
|
||||||
|
... self._today_val = today
|
||||||
|
... def _today(self):
|
||||||
|
... return self._today_val
|
||||||
|
|
||||||
|
>>> from datetime import date, timedelta
|
||||||
|
>>> p1 = Mocked(date.today() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS))
|
||||||
|
>>> p1.check_token(u, tk1)
|
||||||
|
True
|
||||||
|
>>> p2 = Mocked(date.today() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
|
||||||
|
>>> p2.check_token(u, tk1)
|
||||||
|
False
|
||||||
|
|
||||||
|
"""
|
88
django/contrib/auth/tests/views.py
Normal file
88
django/contrib/auth/tests/views.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
|
||||||
|
import re
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.core import mail
|
||||||
|
|
||||||
|
class PasswordResetTest(TestCase):
|
||||||
|
fixtures = ['authtestdata.json']
|
||||||
|
urls = 'django.contrib.auth.urls'
|
||||||
|
|
||||||
|
def test_email_not_found(self):
|
||||||
|
"Error is raised if the provided email address isn't currently registered"
|
||||||
|
response = self.client.get('/password_reset/')
|
||||||
|
self.assertEquals(response.status_code, 200)
|
||||||
|
response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
|
||||||
|
self.assertContains(response, "That e-mail address doesn't have an associated user account")
|
||||||
|
self.assertEquals(len(mail.outbox), 0)
|
||||||
|
|
||||||
|
def test_email_found(self):
|
||||||
|
"Email is sent if a valid email address is provided for password reset"
|
||||||
|
response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
|
||||||
|
self.assertEquals(response.status_code, 302)
|
||||||
|
self.assertEquals(len(mail.outbox), 1)
|
||||||
|
self.assert_("http://" in mail.outbox[0].body)
|
||||||
|
|
||||||
|
def _test_confirm_start(self):
|
||||||
|
# Start by creating the email
|
||||||
|
response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
|
||||||
|
self.assertEquals(response.status_code, 302)
|
||||||
|
self.assertEquals(len(mail.outbox), 1)
|
||||||
|
return self._read_signup_email(mail.outbox[0])
|
||||||
|
|
||||||
|
def _read_signup_email(self, email):
|
||||||
|
urlmatch = re.search(r"https?://[^/]*(/.*reset/\S*)", email.body)
|
||||||
|
self.assert_(urlmatch is not None, "No URL found in sent email")
|
||||||
|
return urlmatch.group(), urlmatch.groups()[0]
|
||||||
|
|
||||||
|
def test_confirm_valid(self):
|
||||||
|
url, path = self._test_confirm_start()
|
||||||
|
response = self.client.get(path)
|
||||||
|
# redirect to a 'complete' page:
|
||||||
|
self.assertEquals(response.status_code, 200)
|
||||||
|
self.assert_("Please enter your new password" in response.content)
|
||||||
|
|
||||||
|
def test_confirm_invalid(self):
|
||||||
|
url, path = self._test_confirm_start()
|
||||||
|
# Lets munge the token in the path, but keep the same length,
|
||||||
|
# in case the URL conf will reject a different length
|
||||||
|
path = path[:-5] + ("0"*4) + path[-1]
|
||||||
|
|
||||||
|
response = self.client.get(path)
|
||||||
|
self.assertEquals(response.status_code, 200)
|
||||||
|
self.assert_("The password reset link was invalid" in response.content)
|
||||||
|
|
||||||
|
def test_confirm_invalid_post(self):
|
||||||
|
# Same as test_confirm_invalid, but trying
|
||||||
|
# to do a POST instead.
|
||||||
|
url, path = self._test_confirm_start()
|
||||||
|
path = path[:-5] + ("0"*4) + path[-1]
|
||||||
|
|
||||||
|
response = self.client.post(path, {'new_password1': 'anewpassword',
|
||||||
|
'new_password2':' anewpassword'})
|
||||||
|
# Check the password has not been changed
|
||||||
|
u = User.objects.get(email='staffmember@example.com')
|
||||||
|
self.assert_(not u.check_password("anewpassword"))
|
||||||
|
|
||||||
|
def test_confirm_complete(self):
|
||||||
|
url, path = self._test_confirm_start()
|
||||||
|
response = self.client.post(path, {'new_password1': 'anewpassword',
|
||||||
|
'new_password2': 'anewpassword'})
|
||||||
|
# It redirects us to a 'complete' page:
|
||||||
|
self.assertEquals(response.status_code, 302)
|
||||||
|
# Check the password has been changed
|
||||||
|
u = User.objects.get(email='staffmember@example.com')
|
||||||
|
self.assert_(u.check_password("anewpassword"))
|
||||||
|
|
||||||
|
# Check we can't use the link again
|
||||||
|
response = self.client.get(path)
|
||||||
|
self.assertEquals(response.status_code, 200)
|
||||||
|
self.assert_("The password reset link was invalid" in response.content)
|
||||||
|
|
||||||
|
def test_confirm_different_passwords(self):
|
||||||
|
url, path = self._test_confirm_start()
|
||||||
|
response = self.client.post(path, {'new_password1': 'anewpassword',
|
||||||
|
'new_password2':' x'})
|
||||||
|
self.assertEquals(response.status_code, 200)
|
||||||
|
self.assert_("The two password fields didn't match" in response.content)
|
||||||
|
|
66
django/contrib/auth/tokens.py
Normal file
66
django/contrib/auth/tokens.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
from datetime import date
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.http import int_to_base36, base36_to_int
|
||||||
|
|
||||||
|
class PasswordResetTokenGenerator(object):
|
||||||
|
"""
|
||||||
|
Stratgy object used to generate and check tokens for the password
|
||||||
|
reset mechanism.
|
||||||
|
"""
|
||||||
|
def make_token(self, user):
|
||||||
|
"""
|
||||||
|
Returns a token that can be used once to do a password reset
|
||||||
|
for the given user.
|
||||||
|
"""
|
||||||
|
return self._make_token_with_timestamp(user, self._num_days(self._today()))
|
||||||
|
|
||||||
|
def check_token(self, user, token):
|
||||||
|
"""
|
||||||
|
Check that a password reset token is correct for a given user.
|
||||||
|
"""
|
||||||
|
# Parse the tokem
|
||||||
|
try:
|
||||||
|
ts_b36, hash = token.split("-")
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
ts = base36_to_int(ts_b36)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check that the timestamp/uid has not been tampered with
|
||||||
|
if self._make_token_with_timestamp(user, ts) != token:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check the timestamp is within limit
|
||||||
|
if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _make_token_with_timestamp(self, user, timestamp):
|
||||||
|
# timestamp is number of days since 2001-1-1. Converted to
|
||||||
|
# base 36, this gives us a 3 digit string until about 2121
|
||||||
|
ts_b36 = int_to_base36(timestamp)
|
||||||
|
|
||||||
|
# By hashing on the internal state of the user and using state
|
||||||
|
# that is sure to change (the password salt will change as soon as
|
||||||
|
# the password is set, at least for current Django auth, and
|
||||||
|
# last_login will also change), we produce a hash that will be
|
||||||
|
# invalid as soon as it is used.
|
||||||
|
# We limit the hash to 20 chars to keep URL short
|
||||||
|
from django.utils.hashcompat import sha_constructor
|
||||||
|
hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
|
||||||
|
user.password + unicode(user.last_login) +
|
||||||
|
unicode(timestamp)).hexdigest()[::2]
|
||||||
|
return "%s-%s" % (ts_b36, hash)
|
||||||
|
|
||||||
|
def _num_days(self, dt):
|
||||||
|
return (dt - date(2001,1,1)).days
|
||||||
|
|
||||||
|
def _today(self):
|
||||||
|
# Used for mocking in tests
|
||||||
|
return date.today()
|
||||||
|
|
||||||
|
default_token_generator = PasswordResetTokenGenerator()
|
@ -5,9 +5,12 @@
|
|||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
('^logout/$', 'django.contrib.auth.views.logout'),
|
(r'^logout/$', 'django.contrib.auth.views.logout'),
|
||||||
('^password_change/$', 'django.contrib.auth.views.password_change'),
|
(r'^password_change/$', 'django.contrib.auth.views.password_change'),
|
||||||
('^password_change/done/$', 'django.contrib.auth.views.password_change_done'),
|
(r'^password_change/done/$', 'django.contrib.auth.views.password_change_done'),
|
||||||
('^password_reset/$', 'django.contrib.auth.views.password_reset')
|
(r'^password_reset/$', 'django.contrib.auth.views.password_reset'),
|
||||||
|
(r'^password_reset/done/$', 'django.contrib.auth.views.password_reset_done'),
|
||||||
|
(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm'),
|
||||||
|
(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm, AdminPasswordChangeForm
|
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm, PasswordChangeForm, AdminPasswordChangeForm
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.shortcuts import render_to_response, get_object_or_404
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
from django.contrib.sites.models import Site, RequestSite
|
from django.contrib.sites.models import Site, RequestSite
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect, Http404
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote, base36_to_int
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -65,19 +67,29 @@ def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_N
|
|||||||
login_url = settings.LOGIN_URL
|
login_url = settings.LOGIN_URL
|
||||||
return HttpResponseRedirect('%s?%s=%s' % (login_url, urlquote(redirect_field_name), urlquote(next)))
|
return HttpResponseRedirect('%s?%s=%s' % (login_url, urlquote(redirect_field_name), urlquote(next)))
|
||||||
|
|
||||||
|
# 4 views for password reset:
|
||||||
|
# - password_reset sends the mail
|
||||||
|
# - password_reset_done shows a success message for the above
|
||||||
|
# - password_reset_confirm checks the link the user clicked and
|
||||||
|
# prompts for a new password
|
||||||
|
# - password_reset_complete shows a success message for the above
|
||||||
|
|
||||||
def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html',
|
def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html',
|
||||||
email_template_name='registration/password_reset_email.html',
|
email_template_name='registration/password_reset_email.html',
|
||||||
password_reset_form=PasswordResetForm):
|
password_reset_form=PasswordResetForm, token_generator=default_token_generator):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = password_reset_form(request.POST)
|
form = password_reset_form(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
opts = {}
|
||||||
|
opts['use_https'] = request.is_secure()
|
||||||
|
opts['token_generator'] = token_generator
|
||||||
if is_admin_site:
|
if is_admin_site:
|
||||||
form.save(domain_override=request.META['HTTP_HOST'])
|
opts['domain_override'] = request.META['HTTP_HOST']
|
||||||
else:
|
else:
|
||||||
if Site._meta.installed:
|
opts['email_template_name'] = email_template_name
|
||||||
form.save(email_template_name=email_template_name)
|
if not Site._meta.installed:
|
||||||
else:
|
opts['domain_override'] = RequestSite(request).domain
|
||||||
form.save(domain_override=RequestSite(request).domain, email_template_name=email_template_name)
|
form.save(**opts)
|
||||||
return HttpResponseRedirect('%sdone/' % request.path)
|
return HttpResponseRedirect('%sdone/' % request.path)
|
||||||
else:
|
else:
|
||||||
form = password_reset_form()
|
form = password_reset_form()
|
||||||
@ -88,6 +100,40 @@ def password_reset(request, is_admin_site=False, template_name='registration/pas
|
|||||||
def password_reset_done(request, template_name='registration/password_reset_done.html'):
|
def password_reset_done(request, template_name='registration/password_reset_done.html'):
|
||||||
return render_to_response(template_name, context_instance=RequestContext(request))
|
return render_to_response(template_name, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
def password_reset_confirm(request, uidb36=None, token=None, template_name='registration/password_reset_confirm.html',
|
||||||
|
token_generator=default_token_generator, set_password_form=SetPasswordForm):
|
||||||
|
"""
|
||||||
|
View that checks the hash in a password reset link and presents a
|
||||||
|
form for entering a new password.
|
||||||
|
"""
|
||||||
|
assert uidb36 is not None and token is not None # checked by URLconf
|
||||||
|
try:
|
||||||
|
uid_int = base36_to_int(uidb36)
|
||||||
|
except ValueError:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
user = get_object_or_404(User, id=uid_int)
|
||||||
|
context_instance = RequestContext(request)
|
||||||
|
|
||||||
|
if token_generator.check_token(user, token):
|
||||||
|
context_instance['validlink'] = True
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = set_password_form(user, request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return HttpResponseRedirect("../done/")
|
||||||
|
else:
|
||||||
|
form = set_password_form(None)
|
||||||
|
else:
|
||||||
|
context_instance['validlink'] = False
|
||||||
|
form = None
|
||||||
|
context_instance['form'] = form
|
||||||
|
return render_to_response(template_name, context_instance=context_instance)
|
||||||
|
|
||||||
|
def password_reset_complete(request, template_name='registration/password_reset_complete.html'):
|
||||||
|
return render_to_response(template_name, context_instance=RequestContext(request,
|
||||||
|
{'login_url': settings.LOGIN_URL}))
|
||||||
|
|
||||||
def password_change(request, template_name='registration/password_change_form.html'):
|
def password_change(request, template_name='registration/password_change_form.html'):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = PasswordChangeForm(request.user, request.POST)
|
form = PasswordChangeForm(request.user, request.POST)
|
||||||
|
@ -29,8 +29,8 @@ class CommentManager(models.Manager):
|
|||||||
'pa,ra') and target (something like 'lcom.eventtimes:5157'). Used to
|
'pa,ra') and target (something like 'lcom.eventtimes:5157'). Used to
|
||||||
validate that submitted form options have not been tampered-with.
|
validate that submitted form options have not been tampered-with.
|
||||||
"""
|
"""
|
||||||
import md5
|
from django.utils.hashcompat import md5_constructor
|
||||||
return md5.new(options + photo_options + rating_options + target + settings.SECRET_KEY).hexdigest()
|
return md5_constructor(options + photo_options + rating_options + target + settings.SECRET_KEY).hexdigest()
|
||||||
|
|
||||||
def get_rating_options(self, rating_string):
|
def get_rating_options(self, rating_string):
|
||||||
"""
|
"""
|
||||||
|
@ -95,7 +95,7 @@ class GenericForeignKey(object):
|
|||||||
setattr(instance, self.cache_attr, value)
|
setattr(instance, self.cache_attr, value)
|
||||||
|
|
||||||
class GenericRelation(RelatedField, Field):
|
class GenericRelation(RelatedField, Field):
|
||||||
"""Provides an accessor to generic related objects (i.e. comments)"""
|
"""Provides an accessor to generic related objects (e.g. comments)"""
|
||||||
|
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
@ -104,6 +104,9 @@ class GenericRelation(RelatedField, Field):
|
|||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
symmetrical=kwargs.pop('symmetrical', True))
|
symmetrical=kwargs.pop('symmetrical', True))
|
||||||
|
|
||||||
|
# By its very nature, a GenericRelation doesn't create a table.
|
||||||
|
self.creates_table = False
|
||||||
|
|
||||||
# Override content-type/object-id field names on the related class
|
# Override content-type/object-id field names on the related class
|
||||||
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
|
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
|
||||||
self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
|
self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
|
||||||
|
@ -3,15 +3,16 @@ Cross Site Request Forgery Middleware.
|
|||||||
|
|
||||||
This module provides a middleware that implements protection
|
This module provides a middleware that implements protection
|
||||||
against request forgeries from other sites.
|
against request forgeries from other sites.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
|
||||||
from django.http import HttpResponseForbidden
|
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
import md5
|
|
||||||
import re
|
import re
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
_ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
|
_ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
|
||||||
|
|
||||||
_POST_FORM_RE = \
|
_POST_FORM_RE = \
|
||||||
@ -20,7 +21,7 @@ _POST_FORM_RE = \
|
|||||||
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
|
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
|
||||||
|
|
||||||
def _make_token(session_id):
|
def _make_token(session_id):
|
||||||
return md5.new(settings.SECRET_KEY + session_id).hexdigest()
|
return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
|
||||||
|
|
||||||
class CsrfMiddleware(object):
|
class CsrfMiddleware(object):
|
||||||
"""Django middleware that adds protection against Cross Site
|
"""Django middleware that adds protection against Cross Site
|
||||||
|
@ -4,7 +4,6 @@ from django.contrib.databrowse.datastructures import EasyModel
|
|||||||
from django.contrib.databrowse.sites import DatabrowsePlugin
|
from django.contrib.databrowse.sites import DatabrowsePlugin
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import get_date_formats
|
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import date_based
|
from django.views.generic import date_based
|
||||||
|
@ -6,7 +6,6 @@ from django.shortcuts import render_to_response
|
|||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.encoding import smart_str, force_unicode
|
from django.utils.encoding import smart_str, force_unicode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import date_based
|
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
class FieldChoicePlugin(DatabrowsePlugin):
|
class FieldChoicePlugin(DatabrowsePlugin):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django import http
|
from django import http
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
|
from django.contrib.databrowse.datastructures import EasyModel
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from django.db.models import FieldDoesNotExist, DateTimeField
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
|
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# CHOICES #
|
# CHOICES #
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
Formtools Preview application.
|
Formtools Preview application.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import cPickle as pickle
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template.context import RequestContext
|
from django.template.context import RequestContext
|
||||||
import cPickle as pickle
|
from django.utils.hashcompat import md5_constructor
|
||||||
import md5
|
|
||||||
|
|
||||||
AUTO_ID = 'formtools_%s' # Each form here uses this as its auto_id parameter.
|
AUTO_ID = 'formtools_%s' # Each form here uses this as its auto_id parameter.
|
||||||
|
|
||||||
@ -109,7 +110,7 @@ class FormPreview(object):
|
|||||||
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
|
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
|
||||||
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
|
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
|
||||||
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
|
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
|
||||||
return md5.new(pickled).hexdigest()
|
return md5_constructor(pickled).hexdigest()
|
||||||
|
|
||||||
def failed_hash(self, request):
|
def failed_hash(self, request):
|
||||||
"Returns an HttpResponse in the case of an invalid security hash."
|
"Returns an HttpResponse in the case of an invalid security hash."
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.formtools import preview
|
from django.contrib.formtools import preview
|
||||||
from django import http
|
from django import http
|
||||||
from django.conf import settings
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
success_string = "Done was called!"
|
success_string = "Done was called!"
|
||||||
|
@ -4,13 +4,14 @@ step and storing the form's state as HTML hidden fields so that no state is
|
|||||||
stored on the server side.
|
stored on the server side.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import cPickle as pickle
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template.context import RequestContext
|
from django.template.context import RequestContext
|
||||||
import cPickle as pickle
|
from django.utils.hashcompat import md5_constructor
|
||||||
import md5
|
|
||||||
|
|
||||||
class FormWizard(object):
|
class FormWizard(object):
|
||||||
# Dictionary of extra template context variables.
|
# Dictionary of extra template context variables.
|
||||||
@ -150,7 +151,7 @@ class FormWizard(object):
|
|||||||
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
|
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
|
||||||
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
|
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
|
||||||
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
|
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
|
||||||
return md5.new(pickled).hexdigest()
|
return md5_constructor(pickled).hexdigest()
|
||||||
|
|
||||||
def determine_step(self, request, *args, **kwargs):
|
def determine_step(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -70,7 +70,7 @@ class OracleSpatialField(Field):
|
|||||||
style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';'
|
style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';'
|
||||||
return sql
|
return sql
|
||||||
|
|
||||||
def _post_create_sql(self, style, db_table):
|
def post_create_sql(self, style, db_table):
|
||||||
"""
|
"""
|
||||||
Returns SQL that will be executed after the model has been
|
Returns SQL that will be executed after the model has been
|
||||||
created.
|
created.
|
||||||
|
@ -50,7 +50,7 @@ class PostGISField(Field):
|
|||||||
style.SQL_KEYWORD(index_opts) + ' );'
|
style.SQL_KEYWORD(index_opts) + ' );'
|
||||||
return sql
|
return sql
|
||||||
|
|
||||||
def _post_create_sql(self, style, db_table):
|
def post_create_sql(self, style, db_table):
|
||||||
"""
|
"""
|
||||||
Returns SQL that will be executed after the model has been
|
Returns SQL that will be executed after the model has been
|
||||||
created. Geometry columns must be added after creation with the
|
created. Geometry columns must be added after creation with the
|
||||||
|
@ -4,6 +4,11 @@ from django.contrib.gis.db.models.query import GeoQuerySet
|
|||||||
class GeoManager(Manager):
|
class GeoManager(Manager):
|
||||||
"Overrides Manager to return Geographic QuerySets."
|
"Overrides Manager to return Geographic QuerySets."
|
||||||
|
|
||||||
|
# This manager should be used for queries on related fields
|
||||||
|
# so that geometry columns on Oracle and MySQL are selected
|
||||||
|
# properly.
|
||||||
|
use_for_related_fields = True
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return GeoQuerySet(model=self.model)
|
return GeoQuerySet(model=self.model)
|
||||||
|
|
||||||
|
14
django/contrib/localflavor/at/at_states.py
Normal file
14
django/contrib/localflavor/at/at_states.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# -*- coding: utf-8 -*
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
STATE_CHOICES = (
|
||||||
|
('BL', _('Burgenland')),
|
||||||
|
('KA', _('Carinthia')),
|
||||||
|
('NO', _('Lower Austria')),
|
||||||
|
('OO', _('Upper Austria')),
|
||||||
|
('SA', _('Salzburg')),
|
||||||
|
('ST', _('Styria')),
|
||||||
|
('TI', _('Tyrol')),
|
||||||
|
('VO', _('Vorarlberg')),
|
||||||
|
('WI', _('Vienna')),
|
||||||
|
)
|
65
django/contrib/localflavor/at/forms.py
Normal file
65
django/contrib/localflavor/at/forms.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"""
|
||||||
|
AT-specific Form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.forms.fields import Field, RegexField, Select
|
||||||
|
from django.forms import ValidationError
|
||||||
|
|
||||||
|
re_ssn = re.compile(r'^\d{4} \d{6}')
|
||||||
|
|
||||||
|
class ATZipCodeField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validates its input is an Austrian postcode.
|
||||||
|
|
||||||
|
Accepts 4 digits.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a zip code in the format XXXX.'),
|
||||||
|
}
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ATZipCodeField, self).__init__(r'^\d{4}$',
|
||||||
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
|
|
||||||
|
class ATStateSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of AT states as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from django.contrib.localflavor.at.at_states import STATE_CHOICES
|
||||||
|
super(ATStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
|
||||||
|
|
||||||
|
class ATSocialSecurityNumberField(Field):
|
||||||
|
"""
|
||||||
|
Austrian Social Security numbers are composed of a 4 digits and 6 digits
|
||||||
|
field. The latter represents in most cases the person's birthdate while
|
||||||
|
the first 4 digits represent a 3-digits counter and a one-digit checksum.
|
||||||
|
|
||||||
|
The 6-digits field can also differ from the person's birthdate if the
|
||||||
|
3-digits counter suffered an overflow.
|
||||||
|
|
||||||
|
This code is based on information available on
|
||||||
|
http://de.wikipedia.org/wiki/Sozialversicherungsnummer#.C3.96sterreich
|
||||||
|
"""
|
||||||
|
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _(u'Enter a valid Austrian Social Security Number in XXXX XXXXXX format.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
if not re_ssn.search(value):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
sqnr, date = value.split(" ")
|
||||||
|
sqnr, check = (sqnr[:3], (sqnr[3]))
|
||||||
|
if int(sqnr) < 100:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
res = int(sqnr[0])*3 + int(sqnr[1])*7 + int(sqnr[2])*9 \
|
||||||
|
+ int(date[0])*5 + int(date[1])*8 + int(date[2])*4 \
|
||||||
|
+ int(date[3])*2 + int(date[4])*1 + int(date[5])*6
|
||||||
|
res = res % 11
|
||||||
|
if res != int(check):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
return u'%s%s %s'%(sqnr, check, date,)
|
||||||
|
|
200
django/contrib/localflavor/ro/forms.py
Normal file
200
django/contrib/localflavor/ro/forms.py
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Romanian specific form helpers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.forms import ValidationError, Field, RegexField, Select
|
||||||
|
from django.forms.fields import EMPTY_VALUES
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
class ROCIFField(RegexField):
|
||||||
|
"""
|
||||||
|
A Romanian fiscal identity code (CIF) field
|
||||||
|
|
||||||
|
For CIF validation algorithm see http://www.validari.ro/cui.html
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _("Enter a valid CIF."),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ROCIFField, self).__init__(r'^[0-9]{2,10}', max_length=10,
|
||||||
|
min_length=2, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
CIF validation
|
||||||
|
"""
|
||||||
|
value = super(ROCIFField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
# strip RO part
|
||||||
|
if value[0:2] == 'RO':
|
||||||
|
value = value[2:]
|
||||||
|
key = '753217532'[::-1]
|
||||||
|
value = value[::-1]
|
||||||
|
key_iter = iter(key)
|
||||||
|
checksum = 0
|
||||||
|
for digit in value[1:]:
|
||||||
|
checksum += int(digit) * int(key_iter.next())
|
||||||
|
checksum = checksum * 10 % 11
|
||||||
|
if checksum == 10:
|
||||||
|
checksum = 0
|
||||||
|
if checksum != int(value[0]):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
return value[::-1]
|
||||||
|
|
||||||
|
class ROCNPField(RegexField):
|
||||||
|
"""
|
||||||
|
A Romanian personal identity code (CNP) field
|
||||||
|
|
||||||
|
For CNP validation algorithm see http://www.validari.ro/cnp.html
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _("Enter a valid CNP."),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ROCNPField, self).__init__(r'^[1-9][0-9]{12}', max_length=13,
|
||||||
|
min_length=13, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
CNP validations
|
||||||
|
"""
|
||||||
|
value = super(ROCNPField, self).clean(value)
|
||||||
|
# check birthdate digits
|
||||||
|
import datetime
|
||||||
|
try:
|
||||||
|
datetime.date(int(value[1:3]),int(value[3:5]),int(value[5:7]))
|
||||||
|
except:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
# checksum
|
||||||
|
key = '279146358279'
|
||||||
|
checksum = 0
|
||||||
|
value_iter = iter(value)
|
||||||
|
for digit in key:
|
||||||
|
checksum += int(digit) * int(value_iter.next())
|
||||||
|
checksum %= 11
|
||||||
|
if checksum == 10:
|
||||||
|
checksum = 1
|
||||||
|
if checksum != int(value[12]):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
return value
|
||||||
|
|
||||||
|
class ROCountyField(Field):
|
||||||
|
"""
|
||||||
|
A form field that validates its input is a Romanian county name or
|
||||||
|
abbreviation. It normalizes the input to the standard vehicle registration
|
||||||
|
abbreviation for the given county
|
||||||
|
|
||||||
|
WARNING: This field will only accept names written with diacritics; consider
|
||||||
|
using ROCountySelect if this behavior is unnaceptable for you
|
||||||
|
Example:
|
||||||
|
Argeş => valid
|
||||||
|
Arges => invalid
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Enter a Romanian county code or name.',
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
from ro_counties import COUNTIES_CHOICES
|
||||||
|
super(ROCountyField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
try:
|
||||||
|
value = value.strip().upper()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
# search for county code
|
||||||
|
for entry in COUNTIES_CHOICES:
|
||||||
|
if value in entry:
|
||||||
|
return value
|
||||||
|
# search for county name
|
||||||
|
normalized_CC = []
|
||||||
|
for entry in COUNTIES_CHOICES:
|
||||||
|
normalized_CC.append((entry[0],entry[1].upper()))
|
||||||
|
for entry in normalized_CC:
|
||||||
|
if entry[1] == value:
|
||||||
|
return entry[0]
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
class ROCountySelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of Romanian counties (judete) as its
|
||||||
|
choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from ro_counties import COUNTIES_CHOICES
|
||||||
|
super(ROCountySelect, self).__init__(attrs, choices=COUNTIES_CHOICES)
|
||||||
|
|
||||||
|
class ROIBANField(RegexField):
|
||||||
|
"""
|
||||||
|
Romanian International Bank Account Number (IBAN) field
|
||||||
|
|
||||||
|
For Romanian IBAN validation algorithm see http://validari.ro/iban.html
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid IBAN in ROXX-XXXX-XXXX-XXXX-XXXX-XXXX format'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ROIBANField, self).__init__(r'^[0-9A-Za-z\-\s]{24,40}$',
|
||||||
|
max_length=40, min_length=24, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Strips - and spaces, performs country code and checksum validation
|
||||||
|
"""
|
||||||
|
value = super(ROIBANField, self).clean(value)
|
||||||
|
value = value.replace('-','')
|
||||||
|
value = value.replace(' ','')
|
||||||
|
value = value.upper()
|
||||||
|
if value[0:2] != 'RO':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
numeric_format = ''
|
||||||
|
for char in value[4:] + value[0:4]:
|
||||||
|
if char.isalpha():
|
||||||
|
numeric_format += str(ord(char) - 55)
|
||||||
|
else:
|
||||||
|
numeric_format += char
|
||||||
|
if int(numeric_format) % 97 != 1:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
return value
|
||||||
|
|
||||||
|
class ROPhoneNumberField(RegexField):
|
||||||
|
"""Romanian phone number field"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Phone numbers must be in XXXX-XXXXXX format.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ROPhoneNumberField, self).__init__(r'^[0-9\-\(\)\s]{10,20}$',
|
||||||
|
max_length=20, min_length=10, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Strips -, (, ) and spaces. Checks the final length.
|
||||||
|
"""
|
||||||
|
value = super(ROPhoneNumberField, self).clean(value)
|
||||||
|
value = value.replace('-','')
|
||||||
|
value = value.replace('(','')
|
||||||
|
value = value.replace(')','')
|
||||||
|
value = value.replace(' ','')
|
||||||
|
if len(value) != 10:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
return value
|
||||||
|
|
||||||
|
class ROPostalCodeField(RegexField):
|
||||||
|
"""Romanian postal code field."""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid postal code in the format XXXXXX'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ROPostalCodeField, self).__init__(r'^[0-9][0-8][0-9]{4}$',
|
||||||
|
max_length=6, min_length=6, *args, **kwargs)
|
||||||
|
|
52
django/contrib/localflavor/ro/ro_counties.py
Normal file
52
django/contrib/localflavor/ro/ro_counties.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
A list of Romanian counties as `choices` in a formfield.
|
||||||
|
|
||||||
|
This exists as a standalone file so that it's only imported into memory when
|
||||||
|
explicitly needed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
COUNTIES_CHOICES = (
|
||||||
|
('AB', u'Alba'),
|
||||||
|
('AR', u'Arad'),
|
||||||
|
('AG', u'Argeş'),
|
||||||
|
('BC', u'Bacău'),
|
||||||
|
('BH', u'Bihor'),
|
||||||
|
('BN', u'Bistriţa-Năsăud'),
|
||||||
|
('BT', u'Botoşani'),
|
||||||
|
('BV', u'Braşov'),
|
||||||
|
('BR', u'Brăila'),
|
||||||
|
('B', u'Bucureşti'),
|
||||||
|
('BZ', u'Buzău'),
|
||||||
|
('CS', u'Caraş-Severin'),
|
||||||
|
('CL', u'Călăraşi'),
|
||||||
|
('CJ', u'Cluj'),
|
||||||
|
('CT', u'Constanţa'),
|
||||||
|
('CV', u'Covasna'),
|
||||||
|
('DB', u'Dâmboviţa'),
|
||||||
|
('DJ', u'Dolj'),
|
||||||
|
('GL', u'Galaţi'),
|
||||||
|
('GR', u'Giurgiu'),
|
||||||
|
('GJ', u'Gorj'),
|
||||||
|
('HR', u'Harghita'),
|
||||||
|
('HD', u'Hunedoara'),
|
||||||
|
('IL', u'Ialomiţa'),
|
||||||
|
('IS', u'Iaşi'),
|
||||||
|
('IF', u'Ilfov'),
|
||||||
|
('MM', u'Maramureş'),
|
||||||
|
('MH', u'Mehedinţi'),
|
||||||
|
('MS', u'Mureş'),
|
||||||
|
('NT', u'Neamţ'),
|
||||||
|
('OT', u'Olt'),
|
||||||
|
('PH', u'Prahova'),
|
||||||
|
('SM', u'Satu Mare'),
|
||||||
|
('SJ', u'Sălaj'),
|
||||||
|
('SB', u'Sibiu'),
|
||||||
|
('SV', u'Suceava'),
|
||||||
|
('TR', u'Teleorman'),
|
||||||
|
('TM', u'Timiş'),
|
||||||
|
('TL', u'Tulcea'),
|
||||||
|
('VS', u'Vaslui'),
|
||||||
|
('VL', u'Vâlcea'),
|
||||||
|
('VN', u'Vrancea'),
|
||||||
|
)
|
11
django/contrib/redirects/admin.py
Normal file
11
django/contrib/redirects/admin.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.contrib.redirects.models import Redirect
|
||||||
|
|
||||||
|
class RedirectAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('old_path', 'new_path')
|
||||||
|
list_filter = ('site',)
|
||||||
|
search_fields = ('old_path', 'new_path')
|
||||||
|
radio_fields = {'site': admin.VERTICAL}
|
||||||
|
|
||||||
|
admin.site.register(Redirect, RedirectAdmin)
|
@ -18,18 +18,3 @@ class Redirect(models.Model):
|
|||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s ---> %s" % (self.old_path, self.new_path)
|
return "%s ---> %s" % (self.old_path, self.new_path)
|
||||||
|
|
||||||
# Register the admin options for these models.
|
|
||||||
# TODO: Maybe this should live in a separate module admin.py, but how would we
|
|
||||||
# ensure that module was loaded?
|
|
||||||
|
|
||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
class RedirectAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('old_path', 'new_path')
|
|
||||||
list_filter = ('site',)
|
|
||||||
search_fields = ('old_path', 'new_path')
|
|
||||||
radio_fields = {'site': admin.VERTICAL}
|
|
||||||
|
|
||||||
admin.site.register(Redirect, RedirectAdmin)
|
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import base64
|
import base64
|
||||||
import md5
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
@ -12,6 +11,7 @@ except ImportError:
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
|
|
||||||
class SessionBase(object):
|
class SessionBase(object):
|
||||||
@ -73,13 +73,13 @@ class SessionBase(object):
|
|||||||
def encode(self, session_dict):
|
def encode(self, session_dict):
|
||||||
"Returns the given session dictionary pickled and encoded as a string."
|
"Returns the given session dictionary pickled and encoded as a string."
|
||||||
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
|
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
|
||||||
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
|
pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
|
||||||
return base64.encodestring(pickled + pickled_md5)
|
return base64.encodestring(pickled + pickled_md5)
|
||||||
|
|
||||||
def decode(self, session_data):
|
def decode(self, session_data):
|
||||||
encoded_data = base64.decodestring(session_data)
|
encoded_data = base64.decodestring(session_data)
|
||||||
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
||||||
if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
||||||
raise SuspiciousOperation("User tampered with session cookie.")
|
raise SuspiciousOperation("User tampered with session cookie.")
|
||||||
try:
|
try:
|
||||||
return pickle.loads(pickled)
|
return pickle.loads(pickled)
|
||||||
@ -117,7 +117,7 @@ class SessionBase(object):
|
|||||||
# No getpid() in Jython, for example
|
# No getpid() in Jython, for example
|
||||||
pid = 1
|
pid = 1
|
||||||
while 1:
|
while 1:
|
||||||
session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
|
session_key = md5_constructor("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
|
||||||
pid, time.time(), settings.SECRET_KEY)).hexdigest()
|
pid, time.time(), settings.SECRET_KEY)).hexdigest()
|
||||||
if not self.exists(session_key):
|
if not self.exists(session_key):
|
||||||
break
|
break
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.contrib.sessions.backends.base import SessionBase
|
from django.contrib.sessions.backends.base import SessionBase
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
class SessionStore(SessionBase):
|
class SessionStore(SessionBase):
|
||||||
"""
|
"""
|
||||||
A cache-based session store.
|
A cache-based session store.
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.sessions.models import Session
|
from django.contrib.sessions.models import Session
|
||||||
from django.contrib.sessions.backends.base import SessionBase
|
from django.contrib.sessions.backends.base import SessionBase
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
|
|
||||||
|
|
||||||
class SessionStore(SessionBase):
|
class SessionStore(SessionBase):
|
||||||
"""
|
"""
|
||||||
Implements database session store.
|
Implements database session store.
|
||||||
|
@ -4,12 +4,7 @@ from django.conf import settings
|
|||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.http import cookie_date
|
from django.utils.http import cookie_date
|
||||||
|
|
||||||
TEST_COOKIE_NAME = 'testcookie'
|
|
||||||
TEST_COOKIE_VALUE = 'worked'
|
|
||||||
|
|
||||||
|
|
||||||
class SessionMiddleware(object):
|
class SessionMiddleware(object):
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||||
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
|
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import base64
|
import base64
|
||||||
import md5
|
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
|
|
||||||
class SessionManager(models.Manager):
|
class SessionManager(models.Manager):
|
||||||
@ -13,7 +13,7 @@ class SessionManager(models.Manager):
|
|||||||
Returns the given session dictionary pickled and encoded as a string.
|
Returns the given session dictionary pickled and encoded as a string.
|
||||||
"""
|
"""
|
||||||
pickled = pickle.dumps(session_dict)
|
pickled = pickle.dumps(session_dict)
|
||||||
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
|
pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
|
||||||
return base64.encodestring(pickled + pickled_md5)
|
return base64.encodestring(pickled + pickled_md5)
|
||||||
|
|
||||||
def save(self, session_key, session_dict, expire_date):
|
def save(self, session_key, session_dict, expire_date):
|
||||||
@ -56,7 +56,7 @@ class Session(models.Model):
|
|||||||
def get_decoded(self):
|
def get_decoded(self):
|
||||||
encoded_data = base64.decodestring(self.session_data)
|
encoded_data = base64.decodestring(self.session_data)
|
||||||
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
||||||
if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
raise SuspiciousOperation, "User tampered with session cookie."
|
raise SuspiciousOperation, "User tampered with session cookie."
|
||||||
try:
|
try:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from django.core import urlresolvers
|
from django.core import urlresolvers, paginator
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
PING_URL = "http://www.google.com/webmasters/tools/ping"
|
PING_URL = "http://www.google.com/webmasters/tools/ping"
|
||||||
@ -34,6 +34,10 @@ def ping_google(sitemap_url=None, ping_url=PING_URL):
|
|||||||
urllib.urlopen("%s?%s" % (ping_url, params))
|
urllib.urlopen("%s?%s" % (ping_url, params))
|
||||||
|
|
||||||
class Sitemap:
|
class Sitemap:
|
||||||
|
# This limit is defined by Google. See the index documentation at
|
||||||
|
# http://sitemaps.org/protocol.php#index.
|
||||||
|
limit = 50000
|
||||||
|
|
||||||
def __get(self, name, obj, default=None):
|
def __get(self, name, obj, default=None):
|
||||||
try:
|
try:
|
||||||
attr = getattr(self, name)
|
attr = getattr(self, name)
|
||||||
@ -49,11 +53,17 @@ class Sitemap:
|
|||||||
def location(self, obj):
|
def location(self, obj):
|
||||||
return obj.get_absolute_url()
|
return obj.get_absolute_url()
|
||||||
|
|
||||||
def get_urls(self):
|
def _get_paginator(self):
|
||||||
|
if not hasattr(self, "paginator"):
|
||||||
|
self.paginator = paginator.Paginator(self.items(), self.limit)
|
||||||
|
return self.paginator
|
||||||
|
paginator = property(_get_paginator)
|
||||||
|
|
||||||
|
def get_urls(self, page=1):
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
current_site = Site.objects.get_current()
|
current_site = Site.objects.get_current()
|
||||||
urls = []
|
urls = []
|
||||||
for item in self.items():
|
for item in self.paginator.page(page).object_list:
|
||||||
loc = "http://%s%s" % (current_site.domain, self.__get('location', item))
|
loc = "http://%s%s" % (current_site.domain, self.__get('location', item))
|
||||||
url_info = {
|
url_info = {
|
||||||
'location': loc,
|
'location': loc,
|
||||||
|
0
django/contrib/sitemaps/management/__init__.py
Normal file
0
django/contrib/sitemaps/management/__init__.py
Normal file
@ -3,14 +3,22 @@ from django.template import loader
|
|||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core import urlresolvers
|
from django.core import urlresolvers
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
|
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
|
|
||||||
def index(request, sitemaps):
|
def index(request, sitemaps):
|
||||||
current_site = Site.objects.get_current()
|
current_site = Site.objects.get_current()
|
||||||
sites = []
|
sites = []
|
||||||
protocol = request.is_secure() and 'https' or 'http'
|
protocol = request.is_secure() and 'https' or 'http'
|
||||||
for section in sitemaps.keys():
|
for section, site in sitemaps.items():
|
||||||
|
if callable(site):
|
||||||
|
pages = site().paginator.num_pages
|
||||||
|
else:
|
||||||
|
pages = site.paginator.num_pages
|
||||||
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap', kwargs={'section': section})
|
sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap', kwargs={'section': section})
|
||||||
sites.append('%s://%s%s' % (protocol, current_site.domain, sitemap_url))
|
sites.append('%s://%s%s' % (protocol, current_site.domain, sitemap_url))
|
||||||
|
if pages > 1:
|
||||||
|
for page in range(2, pages+1):
|
||||||
|
sites.append('%s://%s%s?p=%s' % (protocol, current_site.domain, sitemap_url, page))
|
||||||
xml = loader.render_to_string('sitemap_index.xml', {'sitemaps': sites})
|
xml = loader.render_to_string('sitemap_index.xml', {'sitemaps': sites})
|
||||||
return HttpResponse(xml, mimetype='application/xml')
|
return HttpResponse(xml, mimetype='application/xml')
|
||||||
|
|
||||||
@ -22,10 +30,16 @@ def sitemap(request, sitemaps, section=None):
|
|||||||
maps.append(sitemaps[section])
|
maps.append(sitemaps[section])
|
||||||
else:
|
else:
|
||||||
maps = sitemaps.values()
|
maps = sitemaps.values()
|
||||||
|
page = request.GET.get("p", 1)
|
||||||
for site in maps:
|
for site in maps:
|
||||||
|
try:
|
||||||
if callable(site):
|
if callable(site):
|
||||||
urls.extend(site().get_urls())
|
urls.extend(site().get_urls(page))
|
||||||
else:
|
else:
|
||||||
urls.extend(site.get_urls())
|
urls.extend(site.get_urls(page))
|
||||||
|
except EmptyPage:
|
||||||
|
raise Http404("Page %s empty" % page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
raise Http404("No page '%s'" % page)
|
||||||
xml = smart_str(loader.render_to_string('sitemap.xml', {'urlset': urls}))
|
xml = smart_str(loader.render_to_string('sitemap.xml', {'urlset': urls}))
|
||||||
return HttpResponse(xml, mimetype='application/xml')
|
return HttpResponse(xml, mimetype='application/xml')
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
>>> # Make sure that get_current() does not return a deleted Site object.
|
|
||||||
>>> from django.contrib.sites.models import Site
|
>>> from django.contrib.sites.models import Site
|
||||||
|
>>> from django.conf import settings
|
||||||
|
>>> Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
|
||||||
|
|
||||||
|
>>> # Make sure that get_current() does not return a deleted Site object.
|
||||||
>>> s = Site.objects.get_current()
|
>>> s = Site.objects.get_current()
|
||||||
>>> isinstance(s, Site)
|
>>> isinstance(s, Site)
|
||||||
True
|
True
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||||
from django.template import Context, loader, Template, TemplateDoesNotExist
|
from django.template import loader, Template, TemplateDoesNotExist
|
||||||
from django.contrib.sites.models import Site, RequestSite
|
from django.contrib.sites.models import Site, RequestSite
|
||||||
from django.utils import feedgenerator
|
from django.utils import feedgenerator
|
||||||
from django.utils.encoding import smart_unicode, iri_to_uri
|
from django.utils.encoding import smart_unicode, iri_to_uri
|
||||||
|
23
django/core/cache/__init__.py
vendored
23
django/core/cache/__init__.py
vendored
@ -19,8 +19,10 @@ from cgi import parse_qsl
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache.backends.base import InvalidCacheBackendError
|
from django.core.cache.backends.base import InvalidCacheBackendError
|
||||||
|
|
||||||
|
# Name for use in settings file --> name of module in "backends" directory.
|
||||||
|
# Any backend scheme that is not in this dictionary is treated as a Python
|
||||||
|
# import path to a custom backend.
|
||||||
BACKENDS = {
|
BACKENDS = {
|
||||||
# name for use in settings file --> name of module in "backends" directory
|
|
||||||
'memcached': 'memcached',
|
'memcached': 'memcached',
|
||||||
'locmem': 'locmem',
|
'locmem': 'locmem',
|
||||||
'file': 'filebased',
|
'file': 'filebased',
|
||||||
@ -28,24 +30,12 @@ BACKENDS = {
|
|||||||
'dummy': 'dummy',
|
'dummy': 'dummy',
|
||||||
}
|
}
|
||||||
|
|
||||||
DEPRECATED_BACKENDS = {
|
|
||||||
# deprecated backend --> replacement module
|
|
||||||
'simple': 'locmem',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_cache(backend_uri):
|
def get_cache(backend_uri):
|
||||||
if backend_uri.find(':') == -1:
|
if backend_uri.find(':') == -1:
|
||||||
raise InvalidCacheBackendError, "Backend URI must start with scheme://"
|
raise InvalidCacheBackendError, "Backend URI must start with scheme://"
|
||||||
scheme, rest = backend_uri.split(':', 1)
|
scheme, rest = backend_uri.split(':', 1)
|
||||||
if not rest.startswith('//'):
|
if not rest.startswith('//'):
|
||||||
raise InvalidCacheBackendError, "Backend URI must start with scheme://"
|
raise InvalidCacheBackendError, "Backend URI must start with scheme://"
|
||||||
if scheme in DEPRECATED_BACKENDS:
|
|
||||||
import warnings
|
|
||||||
warnings.warn("'%s' backend is deprecated. Use '%s' instead." %
|
|
||||||
(scheme, DEPRECATED_BACKENDS[scheme]), DeprecationWarning)
|
|
||||||
scheme = DEPRECATED_BACKENDS[scheme]
|
|
||||||
if scheme not in BACKENDS:
|
|
||||||
raise InvalidCacheBackendError, "%r is not a valid cache backend" % scheme
|
|
||||||
|
|
||||||
host = rest[2:]
|
host = rest[2:]
|
||||||
qpos = rest.find('?')
|
qpos = rest.find('?')
|
||||||
@ -57,7 +47,10 @@ def get_cache(backend_uri):
|
|||||||
if host.endswith('/'):
|
if host.endswith('/'):
|
||||||
host = host[:-1]
|
host = host[:-1]
|
||||||
|
|
||||||
cache_class = getattr(__import__('django.core.cache.backends.%s' % BACKENDS[scheme], {}, {}, ['']), 'CacheClass')
|
if scheme in BACKENDS:
|
||||||
return cache_class(host, params)
|
module = __import__('django.core.cache.backends.%s' % BACKENDS[scheme], {}, {}, [''])
|
||||||
|
else:
|
||||||
|
module = __import__(scheme, {}, {}, [''])
|
||||||
|
return getattr(module, 'CacheClass')(host, params)
|
||||||
|
|
||||||
cache = get_cache(settings.CACHE_BACKEND)
|
cache = get_cache(settings.CACHE_BACKEND)
|
||||||
|
9
django/core/cache/backends/base.py
vendored
9
django/core/cache/backends/base.py
vendored
@ -63,4 +63,11 @@ class BaseCache(object):
|
|||||||
"""
|
"""
|
||||||
return self.get(key) is not None
|
return self.get(key) is not None
|
||||||
|
|
||||||
__contains__ = has_key
|
def __contains__(self, key):
|
||||||
|
"""
|
||||||
|
Returns True if the key is in the cache and has not expired.
|
||||||
|
"""
|
||||||
|
# This is a separate method, rather than just a copy of has_key(),
|
||||||
|
# so that it always has the same functionality as has_key(), even
|
||||||
|
# if a subclass overrides it.
|
||||||
|
return self.has_key(key)
|
||||||
|
9
django/core/cache/backends/filebased.py
vendored
9
django/core/cache/backends/filebased.py
vendored
@ -1,12 +1,14 @@
|
|||||||
"File-based cache backend"
|
"File-based cache backend"
|
||||||
|
|
||||||
import md5
|
import os
|
||||||
import os, time
|
import time
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
from django.core.cache.backends.base import BaseCache
|
from django.core.cache.backends.base import BaseCache
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
class CacheClass(BaseCache):
|
class CacheClass(BaseCache):
|
||||||
def __init__(self, dir, params):
|
def __init__(self, dir, params):
|
||||||
@ -137,7 +139,7 @@ class CacheClass(BaseCache):
|
|||||||
Thus, a cache key of "foo" gets turnned into a file named
|
Thus, a cache key of "foo" gets turnned into a file named
|
||||||
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
|
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
|
||||||
"""
|
"""
|
||||||
path = md5.new(key.encode('utf-8')).hexdigest()
|
path = md5_constructor(key.encode('utf-8')).hexdigest()
|
||||||
path = os.path.join(path[:2], path[2:4], path[4:])
|
path = os.path.join(path[:2], path[2:4], path[4:])
|
||||||
return os.path.join(self._dir, path)
|
return os.path.join(self._dir, path)
|
||||||
|
|
||||||
@ -147,4 +149,3 @@ class CacheClass(BaseCache):
|
|||||||
count += len(files)
|
count += len(files)
|
||||||
return count
|
return count
|
||||||
_num_entries = property(_get_num_entries)
|
_num_entries = property(_get_num_entries)
|
||||||
|
|
||||||
|
2
django/core/cache/backends/locmem.py
vendored
2
django/core/cache/backends/locmem.py
vendored
@ -107,7 +107,7 @@ class CacheClass(BaseCache):
|
|||||||
else:
|
else:
|
||||||
doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
|
doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
|
||||||
for k in doomed:
|
for k in doomed:
|
||||||
self.delete(k)
|
self._delete(k)
|
||||||
|
|
||||||
def _delete(self, key):
|
def _delete(self, key):
|
||||||
try:
|
try:
|
||||||
|
58
django/core/files/temp.py
Normal file
58
django/core/files/temp.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
"""
|
||||||
|
The temp module provides a NamedTemporaryFile that can be re-opened on any
|
||||||
|
platform. Most platforms use the standard Python tempfile.TemporaryFile class,
|
||||||
|
but MS Windows users are given a custom class.
|
||||||
|
|
||||||
|
This is needed because in Windows NT, the default implementation of
|
||||||
|
NamedTemporaryFile uses the O_TEMPORARY flag, and thus cannot be reopened [1].
|
||||||
|
|
||||||
|
1: http://mail.python.org/pipermail/python-list/2005-December/359474.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
__all__ = ('NamedTemporaryFile', 'gettempdir',)
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
class TemporaryFile(object):
|
||||||
|
"""
|
||||||
|
Temporary file object constructor that works in Windows and supports
|
||||||
|
reopening of the temporary file in windows.
|
||||||
|
"""
|
||||||
|
def __init__(self, mode='w+b', bufsize=-1, suffix='', prefix='',
|
||||||
|
dir=None):
|
||||||
|
fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix,
|
||||||
|
dir=dir)
|
||||||
|
self.name = name
|
||||||
|
self._file = os.fdopen(fd, mode, bufsize)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
try:
|
||||||
|
self._file.close()
|
||||||
|
except (OSError, IOError):
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
os.unlink(self.name)
|
||||||
|
except (OSError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
super(TemporaryFile, self).__del__()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def read(self, *args): return self._file.read(*args)
|
||||||
|
def seek(self, offset): return self._file.seek(offset)
|
||||||
|
def write(self, s): return self._file.write(s)
|
||||||
|
def close(self): return self._file.close()
|
||||||
|
def __iter__(self): return iter(self._file)
|
||||||
|
def readlines(self, size=None): return self._file.readlines(size)
|
||||||
|
def xreadlines(self): return self._file.xreadlines()
|
||||||
|
|
||||||
|
NamedTemporaryFile = TemporaryFile
|
||||||
|
else:
|
||||||
|
NamedTemporaryFile = tempfile.NamedTemporaryFile
|
||||||
|
|
||||||
|
gettempdir = tempfile.gettempdir
|
@ -3,7 +3,6 @@ Classes representing uploaded files.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
|
||||||
import warnings
|
import warnings
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@ -12,6 +11,8 @@ except ImportError:
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
from django.core.files import temp as tempfile
|
||||||
|
|
||||||
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile')
|
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile')
|
||||||
|
|
||||||
# Because we fooled around with it a bunch, UploadedFile has a bunch
|
# Because we fooled around with it a bunch, UploadedFile has a bunch
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Base file upload handler classes, and the built-in concrete subclasses
|
Base file upload handler classes, and the built-in concrete subclasses
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -3,6 +3,7 @@ import sys
|
|||||||
from django import http
|
from django import http
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
class BaseHandler(object):
|
class BaseHandler(object):
|
||||||
# Changes that are always applied to a response (in this order).
|
# Changes that are always applied to a response (in this order).
|
||||||
@ -73,7 +74,8 @@ class BaseHandler(object):
|
|||||||
|
|
||||||
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
|
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
|
||||||
try:
|
try:
|
||||||
callback, callback_args, callback_kwargs = resolver.resolve(request.path)
|
callback, callback_args, callback_kwargs = resolver.resolve(
|
||||||
|
request.path_info)
|
||||||
|
|
||||||
# Apply view middleware
|
# Apply view middleware
|
||||||
for middleware_method in self._view_middleware:
|
for middleware_method in self._view_middleware:
|
||||||
@ -107,8 +109,11 @@ class BaseHandler(object):
|
|||||||
from django.views import debug
|
from django.views import debug
|
||||||
return debug.technical_404_response(request, e)
|
return debug.technical_404_response(request, e)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
callback, param_dict = resolver.resolve404()
|
callback, param_dict = resolver.resolve404()
|
||||||
return callback(request, **param_dict)
|
return callback(request, **param_dict)
|
||||||
|
except:
|
||||||
|
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
|
||||||
except exceptions.PermissionDenied:
|
except exceptions.PermissionDenied:
|
||||||
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
|
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
@ -118,9 +123,6 @@ class BaseHandler(object):
|
|||||||
# Get the exception info now, in case another exception is thrown later.
|
# Get the exception info now, in case another exception is thrown later.
|
||||||
exc_info = sys.exc_info()
|
exc_info = sys.exc_info()
|
||||||
receivers = dispatcher.send(signal=signals.got_request_exception, request=request)
|
receivers = dispatcher.send(signal=signals.got_request_exception, request=request)
|
||||||
|
|
||||||
if settings.DEBUG_PROPAGATE_EXCEPTIONS:
|
|
||||||
raise
|
|
||||||
return self.handle_uncaught_exception(request, resolver, exc_info)
|
return self.handle_uncaught_exception(request, resolver, exc_info)
|
||||||
|
|
||||||
def handle_uncaught_exception(self, request, resolver, exc_info):
|
def handle_uncaught_exception(self, request, resolver, exc_info):
|
||||||
@ -136,6 +138,9 @@ class BaseHandler(object):
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import mail_admins
|
from django.core.mail import mail_admins
|
||||||
|
|
||||||
|
if settings.DEBUG_PROPAGATE_EXCEPTIONS:
|
||||||
|
raise
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
from django.views import debug
|
from django.views import debug
|
||||||
return debug.technical_500_response(request, *exc_info)
|
return debug.technical_500_response(request, *exc_info)
|
||||||
@ -167,3 +172,27 @@ class BaseHandler(object):
|
|||||||
response = func(request, response)
|
response = func(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def get_script_name(environ):
|
||||||
|
"""
|
||||||
|
Returns the equivalent of the HTTP request's SCRIPT_NAME environment
|
||||||
|
variable. If Apache mod_rewrite has been used, returns what would have been
|
||||||
|
the script name prior to any rewriting (so it's the script name as seen
|
||||||
|
from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to
|
||||||
|
anything).
|
||||||
|
"""
|
||||||
|
from django.conf import settings
|
||||||
|
if settings.FORCE_SCRIPT_NAME is not None:
|
||||||
|
return force_unicode(settings.FORCE_SCRIPT_NAME)
|
||||||
|
|
||||||
|
# If Apache's mod_rewrite had a whack at the URL, Apache set either
|
||||||
|
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
|
||||||
|
# rewrites. Unfortunately not every webserver (lighttpd!) passes this
|
||||||
|
# information through all the time, so FORCE_SCRIPT_NAME, above, is still
|
||||||
|
# needed.
|
||||||
|
script_url = environ.get('SCRIPT_URL', u'')
|
||||||
|
if not script_url:
|
||||||
|
script_url = environ.get('REDIRECT_URL', u'')
|
||||||
|
if script_url:
|
||||||
|
return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
|
||||||
|
return force_unicode(environ.get('SCRIPT_NAME', u''))
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from pprint import pformat
|
|||||||
from django import http
|
from django import http
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
from django.core.handlers.base import BaseHandler
|
from django.core.handlers.base import BaseHandler
|
||||||
|
from django.core.urlresolvers import set_script_prefix
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.utils import datastructures
|
from django.utils import datastructures
|
||||||
from django.utils.encoding import force_unicode, smart_str
|
from django.utils.encoding import force_unicode, smart_str
|
||||||
@ -15,7 +16,26 @@ from django.utils.encoding import force_unicode, smart_str
|
|||||||
class ModPythonRequest(http.HttpRequest):
|
class ModPythonRequest(http.HttpRequest):
|
||||||
def __init__(self, req):
|
def __init__(self, req):
|
||||||
self._req = req
|
self._req = req
|
||||||
|
# FIXME: This isn't ideal. The request URI may be encoded (it's
|
||||||
|
# non-normalized) slightly differently to the "real" SCRIPT_NAME
|
||||||
|
# and PATH_INFO values. This causes problems when we compute path_info,
|
||||||
|
# below. For now, don't use script names that will be subject to
|
||||||
|
# encoding/decoding.
|
||||||
self.path = force_unicode(req.uri)
|
self.path = force_unicode(req.uri)
|
||||||
|
root = req.get_options().get('django.root', '')
|
||||||
|
self.django_root = root
|
||||||
|
# req.path_info isn't necessarily computed correctly in all
|
||||||
|
# circumstances (it's out of mod_python's control a bit), so we use
|
||||||
|
# req.uri and some string manipulations to get the right value.
|
||||||
|
if root and req.uri.startswith(root):
|
||||||
|
self.path_info = force_unicode(req.uri[len(root):])
|
||||||
|
else:
|
||||||
|
self.path_info = self.path
|
||||||
|
if not self.path_info:
|
||||||
|
# Django prefers empty paths to be '/', rather than '', to give us
|
||||||
|
# a common start character for URL patterns. So this is a little
|
||||||
|
# naughty, but also pretty harmless.
|
||||||
|
self.path_info = u'/'
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# Since this is called as part of error handling, we need to be very
|
# Since this is called as part of error handling, we need to be very
|
||||||
@ -100,7 +120,7 @@ class ModPythonRequest(http.HttpRequest):
|
|||||||
'CONTENT_LENGTH': self._req.clength, # This may be wrong
|
'CONTENT_LENGTH': self._req.clength, # This may be wrong
|
||||||
'CONTENT_TYPE': self._req.content_type, # This may be wrong
|
'CONTENT_TYPE': self._req.content_type, # This may be wrong
|
||||||
'GATEWAY_INTERFACE': 'CGI/1.1',
|
'GATEWAY_INTERFACE': 'CGI/1.1',
|
||||||
'PATH_INFO': self._req.path_info,
|
'PATH_INFO': self.path_info,
|
||||||
'PATH_TRANSLATED': None, # Not supported
|
'PATH_TRANSLATED': None, # Not supported
|
||||||
'QUERY_STRING': self._req.args,
|
'QUERY_STRING': self._req.args,
|
||||||
'REMOTE_ADDR': self._req.connection.remote_ip,
|
'REMOTE_ADDR': self._req.connection.remote_ip,
|
||||||
@ -108,7 +128,7 @@ class ModPythonRequest(http.HttpRequest):
|
|||||||
'REMOTE_IDENT': self._req.connection.remote_logname,
|
'REMOTE_IDENT': self._req.connection.remote_logname,
|
||||||
'REMOTE_USER': self._req.user,
|
'REMOTE_USER': self._req.user,
|
||||||
'REQUEST_METHOD': self._req.method,
|
'REQUEST_METHOD': self._req.method,
|
||||||
'SCRIPT_NAME': None, # Not supported
|
'SCRIPT_NAME': self.django_root,
|
||||||
'SERVER_NAME': self._req.server.server_hostname,
|
'SERVER_NAME': self._req.server.server_hostname,
|
||||||
'SERVER_PORT': self._req.server.port,
|
'SERVER_PORT': self._req.server.port,
|
||||||
'SERVER_PROTOCOL': self._req.protocol,
|
'SERVER_PROTOCOL': self._req.protocol,
|
||||||
@ -153,6 +173,7 @@ class ModPythonHandler(BaseHandler):
|
|||||||
if self._request_middleware is None:
|
if self._request_middleware is None:
|
||||||
self.load_middleware()
|
self.load_middleware()
|
||||||
|
|
||||||
|
set_script_prefix(req.get_options().get('django.root', ''))
|
||||||
dispatcher.send(signal=signals.request_started)
|
dispatcher.send(signal=signals.request_started)
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user