1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

multi-auth: Merged to [2964]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@2965 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2006-05-22 15:19:32 +00:00
parent d659956cf5
commit 681763a29c
36 changed files with 2777 additions and 1840 deletions

View File

@ -12,10 +12,63 @@ from django.conf import global_settings
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings:
"""
A lazy proxy for either global Django settings or a custom settings object.
The user can manually configure settings prior to using them. Otherwise,
Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
"""
def __init__(self):
# _target must be either None or something that supports attribute
# access (getattr, hasattr, etc).
self._target = None
def __getattr__(self, name):
if self._target is None:
self._import_settings()
if name == '__members__':
# Used to implement dir(obj), for example.
return self._target.get_all_members()
return getattr(self._target, name)
def __setattr__(self, name, value):
if name == '_target':
# Assign directly to self.__dict__, because otherwise we'd call
# __setattr__(), which would be an infinite loop.
self.__dict__['_target'] = value
else:
setattr(self._target, name, value)
def _import_settings(self):
"""
Load the settings module pointed to by the environment variable. This
is used the first time we need any settings at all, if the user has not
previously configured the settings manually.
"""
try:
settings_module = os.environ[ENVIRONMENT_VARIABLE]
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE
self._target = Settings(settings_module)
def configure(self, default_settings=global_settings, **options):
"""
Called to manually configure the settings. The 'default_settings'
parameter sets where to retrieve any unspecified values from (its
argument must support attribute access (__getattr__)).
"""
if self._target != None:
raise EnvironmentError, 'Settings already configured.'
holder = UserSettingsHolder(default_settings)
for name, value in options.items():
setattr(holder, name, value)
self._target = holder
class Settings:
def __init__(self, settings_module):
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings):
if setting == setting.upper():
@ -27,7 +80,7 @@ class Settings:
try:
mod = __import__(self.SETTINGS_MODULE, '', '', [''])
except ImportError, e:
raise EnvironmentError, "Could not import settings '%s' (is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)
raise EnvironmentError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e)
# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
@ -56,18 +109,32 @@ class Settings:
# move the time zone info into os.environ
os.environ['TZ'] = self.TIME_ZONE
# try to load DJANGO_SETTINGS_MODULE
try:
settings_module = os.environ[ENVIRONMENT_VARIABLE]
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE
def get_all_members(self):
return dir(self)
# instantiate the configuration object
settings = Settings(settings_module)
class UserSettingsHolder:
"""
Holder for user configured settings.
"""
# SETTINGS_MODULE does not really make sense in the manually configured
# (standalone) case.
SETTINGS_MODULE = None
def __init__(self, default_settings):
"""
Requests for configuration variables not in this class are satisfied
from the module specified in default_settings (if possible).
"""
self.default_settings = default_settings
def __getattr__(self, name):
return getattr(self.default_settings, name)
def get_all_members(self):
return dir(self) + dir(self.default_settings)
settings = LazySettings()
# install the translation machinery so that it is available
from django.utils import translation
translation.install()

View File

@ -1,22 +1,19 @@
# translation of Django.
# Copyright (C) 2006 THE Django'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Django package.
# <>, 2006.
# , fuzzy
# <>, 2006.
#
#
msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
"Project-Id-Version: Django 0.95\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 10:14+0200\n"
"PO-Revision-Date: 2006-04-04 14:29+0300\n"
"PO-Revision-Date: 2006-05-16 15:48+0300\n"
"Last-Translator: Meir Kriheli <meir@mksoft.co.il>\n"
"Language-Team: Hebrew\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: 8bit"
#: contrib/comments/models.py:67 contrib/comments/models.py:166
msgid "object ID"
@ -88,12 +85,11 @@ msgid ""
"Check this box if the comment is inappropriate. A \"This comment has been "
"removed\" message will be displayed instead."
msgstr ""
"יש לסמן תיבה זו עבור תגובה לא נאותה. הודעת \"תגובה זונמחקה\" תוצג במקום."
"יש לסמן תיבה זו עבור תגובה לא נאותה. הודעת \"תגובה זו נמחקה\" תוצג במקום."
#: contrib/comments/models.py:91
#, fuzzy
msgid "comments"
msgstr "תגובה"
msgstr "תגובות"
#: contrib/comments/models.py:131 contrib/comments/models.py:207
msgid "Content object"
@ -127,12 +123,10 @@ msgid "approved by staff"
msgstr "אושר ע\"י הצוות"
#: contrib/comments/models.py:176
#, fuzzy
msgid "free comment"
msgstr "הערה אנונימית"
#: contrib/comments/models.py:177
#, fuzzy
msgid "free comments"
msgstr "הערות אנונימיות"
@ -145,14 +139,12 @@ msgid "score date"
msgstr "תאריך ציון"
#: contrib/comments/models.py:237
#, fuzzy
msgid "karma score"
msgstr "ציון קארמה"
msgstr "ניקוד קארמה"
#: contrib/comments/models.py:238
#, fuzzy
msgid "karma scores"
msgstr "ציוני קארמה"
msgstr "ניקודי קארמה"
#: contrib/comments/models.py:242
#, python-format
@ -175,14 +167,12 @@ msgid "flag date"
msgstr "תאריך סימון"
#: contrib/comments/models.py:268
#, fuzzy
msgid "user flag"
msgstr "סימן משתמש"
msgstr "סימון ע\"י משתמש"
#: contrib/comments/models.py:269
#, fuzzy
msgid "user flags"
msgstr "סימני משתמש"
msgstr "סימונים ע\"י משתמש"
#: contrib/comments/models.py:273
#, python-format
@ -194,14 +184,12 @@ msgid "deletion date"
msgstr "תאריך מחיקה"
#: contrib/comments/models.py:280
#, fuzzy
msgid "moderator deletion"
msgstr "מחיקת מודרציה"
msgstr "מחיקת מודרטור"
#: contrib/comments/models.py:281
#, fuzzy
msgid "moderator deletions"
msgstr "מחיקות מודרציה"
msgstr "מחיקות מודרטור"
#: contrib/comments/models.py:285
#, python-format
@ -226,23 +214,23 @@ msgid ""
msgstr "הדירוג נדרש מאחר והזנת לפחות דרוג אחד אחר."
#: contrib/comments/views/comments.py:112
#, fuzzy, python-format
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
"comment:\n"
"\n"
"%(text)s"
msgid_plural ""
"This comment was posted by a user who has posted fewer than %(count)s "
"comments:\n"
"\n"
"%(text)s"
msgstr[0] ""
"ההודעה נשלחה ע\"י משתמש מפוקפק:\n"
msgstr ""
"תגובה זו נשלחה ע\"י משתמש אשר שלח פחות מ %(count)s "
"תגובה:\n"
"\n"
"%(text)s"
msgstr[1] ""
"ההודעה נשלחה ע\"י משתמש מפוקפק:\n"
"תגובה זו נשלחה ע\"י משתמש אשר שלח פחות מ %(count)s "
"תגובות:\n"
"\n"
"%(text)s"
@ -296,9 +284,8 @@ msgid "Password:"
msgstr "סיסמה:"
#: contrib/comments/templates/comments/form.html:6
#, fuzzy
msgid "Forgotten your password?"
msgstr "שנה את סיסמתי"
msgstr "שכחת את סיסמתך ?"
#: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/object_history.html:3
@ -322,40 +309,36 @@ msgid "Log out"
msgstr "יציאה"
#: contrib/comments/templates/comments/form.html:12
#, fuzzy
msgid "Ratings"
msgstr "דירוג #1"
msgstr "דירוג"
#: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23
msgid "Required"
msgstr ""
msgstr "נדרש"
#: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23
msgid "Optional"
msgstr ""
msgstr "אופציונלי"
#: contrib/comments/templates/comments/form.html:23
msgid "Post a photo"
msgstr ""
msgstr "שליחת תמונה"
#: contrib/comments/templates/comments/form.html:27
#: contrib/comments/templates/comments/freeform.html:5
#, fuzzy
msgid "Comment:"
msgstr "תגובה"
msgstr "תגובה:"
#: contrib/comments/templates/comments/form.html:32
#: contrib/comments/templates/comments/freeform.html:9
#, fuzzy
msgid "Preview comment"
msgstr "הערה אנונימית"
msgstr "תצוגה מקדימה של התגובה"
#: contrib/comments/templates/comments/freeform.html:4
#, fuzzy
msgid "Your name:"
msgstr "שם משתמש"
msgstr "שמך:"
#: contrib/admin/filterspecs.py:40
#, python-format
@ -752,7 +735,7 @@ msgstr "אנו מצטערים, לא ניתן למצוא את הדף המבוקש
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
msgstr ""
msgstr "מודלים זמינים ביישום %(name)s."
#: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15
@ -834,11 +817,8 @@ msgid "View on site"
msgstr "צפיה באתר"
#: contrib/admin/templates/admin/change_form.html:30
#, fuzzy
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] "נא לתקן את השגיאה הבאה:"
msgstr[1] "נא לתקן את השגיאה הבאה:"
msgstr "נא לתקן את השגיאה המופיעה מתחת."
#: contrib/admin/templates/admin/change_form.html:48
msgid "Ordering"
@ -1139,22 +1119,18 @@ msgid "codename"
msgstr "שם קוד"
#: contrib/auth/models.py:17
#, fuzzy
msgid "permission"
msgstr "הרשאה"
#: contrib/auth/models.py:18 contrib/auth/models.py:27
#, fuzzy
msgid "permissions"
msgstr "הרשאות"
#: contrib/auth/models.py:29
#, fuzzy
msgid "group"
msgstr "קבוצה"
#: contrib/auth/models.py:30 contrib/auth/models.py:65
#, fuzzy
msgid "groups"
msgstr "קבוצות"
@ -1215,17 +1191,14 @@ msgstr ""
"המשוייכת אליו/ה."
#: contrib/auth/models.py:67
#, fuzzy
msgid "user permissions"
msgstr "הרשאות"
msgstr "הרשאות משתמש"
#: contrib/auth/models.py:70
#, fuzzy
msgid "user"
msgstr "משתמש"
#: contrib/auth/models.py:71
#, fuzzy
msgid "users"
msgstr "משתמשים"
@ -1246,7 +1219,6 @@ msgid "Groups"
msgstr "קבוצות"
#: contrib/auth/models.py:219
#, fuzzy
msgid "message"
msgstr "הודעה"
@ -1257,9 +1229,8 @@ msgid ""
msgstr "נראה שעוגיות לא מאופשרות בדפדפן שלך.הן נדרשות כדי להתחבר."
#: contrib/contenttypes/models.py:25
#, fuzzy
msgid "python model class name"
msgstr "שם מודל פייתון"
msgstr "שם ה-class של מודל פייתון"
#: contrib/contenttypes/models.py:28
msgid "content type"
@ -1394,54 +1365,52 @@ msgid "December"
msgstr "תצבר"
#: utils/dates.py:19
#, fuzzy
msgid "jan"
msgstr "ו"
msgstr "יאנ"
#: utils/dates.py:19
msgid "feb"
msgstr ""
msgstr "פבר"
#: utils/dates.py:19
msgid "mar"
msgstr ""
msgstr "מרץ"
#: utils/dates.py:19
msgid "apr"
msgstr ""
msgstr "אפר"
#: utils/dates.py:19
#, fuzzy
msgid "may"
msgstr "יום"
msgstr "מאי"
#: utils/dates.py:19
msgid "jun"
msgstr ""
msgstr "יונ"
#: utils/dates.py:20
msgid "jul"
msgstr ""
msgstr "יול"
#: utils/dates.py:20
msgid "aug"
msgstr ""
msgstr "אוג"
#: utils/dates.py:20
msgid "sep"
msgstr ""
msgstr "ספט"
#: utils/dates.py:20
msgid "oct"
msgstr ""
msgstr "אוק"
#: utils/dates.py:20
msgid "nov"
msgstr ""
msgstr "נוב"
#: utils/dates.py:20
msgid "dec"
msgstr ""
msgstr "דצמ"
#: utils/dates.py:27
msgid "Jan."
@ -1472,46 +1441,28 @@ msgid "Dec."
msgstr "דצמ'"
#: utils/timesince.py:12
#, fuzzy
msgid "year"
msgid_plural "years"
msgstr[0] "שנה"
msgstr[1] "שנה"
msgstr "שנה"
#: utils/timesince.py:13
#, fuzzy
msgid "month"
msgid_plural "months"
msgstr[0] "חודש"
msgstr[1] "חודש"
msgstr "חודש"
#: utils/timesince.py:14
#, fuzzy
msgid "week"
msgid_plural "weeks"
msgstr[0] "יוונית - Greek"
msgstr[1] "יוונית - Greek"
msgstr "שבוע"
#: utils/timesince.py:15
#, fuzzy
msgid "day"
msgid_plural "days"
msgstr[0] "יום"
msgstr[1] "יום"
msgstr "יום"
#: utils/timesince.py:16
#, fuzzy
msgid "hour"
msgid_plural "hours"
msgstr[0] "שעה"
msgstr[1] "שעה"
msgstr "שעה"
#: utils/timesince.py:17
#, fuzzy
msgid "minute"
msgid_plural "minutes"
msgstr[0] "דקה"
msgstr[1] "דקה"
msgstr "דקה"
#: conf/global_settings.py:37
msgid "Bengali"
@ -1555,7 +1506,7 @@ msgstr "גאליצית - Galician"
#: conf/global_settings.py:47
msgid "Hungarian"
msgstr ""
msgstr "הונגרית (Hungarian)"
#: conf/global_settings.py:48
msgid "Hebrew"
@ -1610,9 +1561,8 @@ msgid "Swedish"
msgstr "שוודית - Swedish"
#: conf/global_settings.py:61
#, fuzzy
msgid "Ukrainian"
msgstr "ברזילאית - Brazilian"
msgstr "אוקראינית - Ukrainian"
#: conf/global_settings.py:62
msgid "Simplified Chinese"
@ -1742,11 +1692,9 @@ msgid "Enter a valid U.S. state abbreviation."
msgstr "יש להזין קיצור חוקי למדינה בארה\"ב."
#: core/validators.py:229
#, fuzzy, python-format
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "שמור על לשונך! המילה %s אינה מותרת לשימוש כאן."
msgstr[1] "שמור על לשונך! המילה %s אינה מותרת לשימוש כאן."
msgstr "שמור על לשונך! המילה %s אינה מותרת לשימוש כאן."
#: core/validators.py:236
#, python-format
@ -1785,20 +1733,18 @@ msgid "Please enter a valid decimal number."
msgstr "יש להזין מספר עשרוני חוקי."
#: core/validators.py:349
#, fuzzy, python-format
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
msgstr[0] "יש להזין מספר עשרוני חוקי."
msgstr[1] "יש להזין מספר עשרוני חוקי."
msgstr "נא להזין מספר שלם המכיל %s ספרה לכל היותר."
"נא להזין מספר שלם המכיל %s ספרות לכל היותר."
#: core/validators.py:352
#, fuzzy, python-format
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "יש להזין מספר עשרוני חוקי."
msgstr[1] "יש להזין מספר עשרוני חוקי."
msgstr "נא·להזין·מספר·עשרוני·חוקי·המכיל·%s·ספרה·אחרי·הנקודה·לכל·היותר."
"נא להזין מספר עשרוני חוקי המכיל %s ספרות אחרי הנקודה לכל היותר."
#: core/validators.py:362
#, python-format
@ -1895,19 +1841,16 @@ msgid "This field is required."
msgstr "יש להזין תוכן בשדה זה."
#: db/models/fields/__init__.py:337
#, fuzzy
msgid "This value must be an integer."
msgstr "ערך זה חייב להיות חזקה של %s."
msgstr "ערך זה חייב להיות מספר שלם."
#: db/models/fields/__init__.py:369
#, fuzzy
msgid "This value must be either True or False."
msgstr "ערך זה חייב להיות חזקה של %s."
msgstr "ערך זה חייב להיות אמת או שקר."
#: db/models/fields/__init__.py:385
#, fuzzy
msgid "This field cannot be null."
msgstr "שדה זה אינו חוקי."
msgstr "שדה זה אינו יכול להכיל null."
#: db/models/fields/__init__.py:562
msgid "Enter a valid filename."
@ -1919,35 +1862,26 @@ msgid "Please enter a valid %s."
msgstr "יש להזין %s חוקי."
#: db/models/fields/related.py:579
#, fuzzy
msgid "Separate multiple IDs with commas."
msgstr "יש להפריד מזהים מרובים בפסיקים."
#: db/models/fields/related.py:581
#, fuzzy
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
" יש להחזיק לחוץ את \"Control\" או \"Command\" על מק, כדי לבחור יותר מאחד."
"החזק את \"Control\", או \"Command\" על מק, לחוץ כדי לבחור יותר מאחד."
#: db/models/fields/related.py:625
#, fuzzy, python-format
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
"Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgstr[0] ""
"נא להזין זיהוי·%(self)s·חוקי.·הערך·%(value)r·אינו חוקי.נא להזין זיהויי·%"
"(self)s·חוקיים.·הערכים·%(value)r·אינם חוקיים."
msgstr[1] ""
"נא להזין זיהוי·%(self)s·חוקי.·הערך·%(value)r·אינו חוקי.נא להזין זיהויי·%"
"(self)s·חוקיים.·הערכים·%(value)r·אינם חוקיים."
msgstr "נא להזין זיהוי %(self)s חוקי. הערך %(value)r אינו חוקי."
"נא להזין זיהויי %(self)s חוקיים. הערכים %(value)r אינם חוקיים."
#: forms/__init__.py:380
#, fuzzy, python-format
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "יש לוודא שהטקסט שלך מכיל פחות מ %s תו."
msgstr[1] "יש לוודא שהטקסט שלך מכיל פחות מ %s תו."
msgstr "נא לוודא שהטקסט שלך מכיל פחות מ %s תו."
#: forms/__init__.py:385
msgid "Line breaks are not allowed here."
@ -1978,61 +1912,3 @@ msgstr "יש להזין מספר שלם בין 0 ל- 32,767."
msgid "yes,no,maybe"
msgstr "כן,לא,אולי"
#~ msgid "label"
#~ msgstr "תווית"
#~ msgid "package"
#~ msgstr "חבילה"
#~ msgid "packages"
#~ msgstr "חבילות"
#, fuzzy
#~ msgid ""
#~ "Please enter a valid decimal number with at most %s total digit.Please "
#~ "enter a valid decimal number with at most %s total digits."
#~ msgstr ""
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "יש להזין מספר עשרוני חוקי עם %s ספרה לכל היותר.יש להזין מספר עשרוני חוקי "
#~ "עם %s ספרות לכל היותר.\n"
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "יש להזין מספר עשרוני הכולל %s ספרה לכל היותר.יש להזין מספר עשרוני הכולל %"
#~ "s ספרות לכל היותר."
#, fuzzy
#~ msgid ""
#~ "Please enter a valid decimal number with at most %s decimal place.Please "
#~ "enter a valid decimal number with at most %s decimal places."
#~ msgstr ""
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "יש להזין מספר עשרוני חוקי עם %s ספרה אחרי הנקודה לכל היותר."
#~ "יש·להזין·מספר·עשרוני·חוקי·עם·%s·ספרות·אחרי·הנקודה·לכל·היותר.\n"
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "יש להזין מספר עשרוני עם %s ספרה אחרי הנקודה העשרונית לכל היותר.יש להזין "
#~ "מספר עשרוני עם %s ספרות אחרי הנקודה העשרונית לכל היותר."
#~ msgid "Comments"
#~ msgstr "תגובות"
#, fuzzy
#~ msgid ""
#~ "This comment was posted by a user who has posted fewer than %(count)s "
#~ "comment:\n"
#~ "\n"
#~ "%(text)sThis comment was posted by a user who has posted fewer than %"
#~ "(count)s comments:\n"
#~ "\n"
#~ "%(text)s"
#~ msgstr ""
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "התגובה נשלחה ע\"י משתמש בעל פחות מ %(count)s תגובה:\n"
#~ "\n"
#~ "%(text)sהתגובה·נשלחה·ע\"י·משתמש·בעל·פחות·מ·%(count)s·תגובות:\n"
#~ "\n"
#~ "%(text)s\n"
#~ "#-#-#-#-# django.po (Django 1.0) #-#-#-#-#\n"
#~ "התגובה נשלח ע\"י משתמש ששלח פחות מ %(count)s·תגובה:\n"
#~ "\n"
#~ "%(text)sהתגובה נשלח ע\"י משתמש ששלח פחות מ %(count)s·תגובות:\n"
#~ "\n"
#~ "%(text)s"

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: django v1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 10:10+0200\n"
"PO-Revision-Date: 2006-01-05 13:46+0800\n"
"PO-Revision-Date: 2006-05-17 13:47+0800\n"
"Last-Translator: limodou <limodou@gmail.com>\n"
"Language-Team: Simplified Chinese <limodou@gmail.com>\n"
"MIME-Version: 1.0\n"
@ -19,7 +19,8 @@ msgstr ""
"X-Poedit-SourceCharset: utf-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: contrib/comments/models.py:67 contrib/comments/models.py:166
#: contrib/comments/models.py:67
#: contrib/comments/models.py:166
msgid "object ID"
msgstr "对象ID"
@ -27,7 +28,8 @@ msgstr "对象ID"
msgid "headline"
msgstr "大字标题"
#: contrib/comments/models.py:69 contrib/comments/models.py:90
#: contrib/comments/models.py:69
#: contrib/comments/models.py:90
#: contrib/comments/models.py:167
msgid "comment"
msgstr "评论"
@ -68,15 +70,18 @@ msgstr "等级 #8"
msgid "is valid rating"
msgstr "是无效等级"
#: contrib/comments/models.py:83 contrib/comments/models.py:169
#: contrib/comments/models.py:83
#: contrib/comments/models.py:169
msgid "date/time submitted"
msgstr "日期/时间已提交"
#: contrib/comments/models.py:84 contrib/comments/models.py:170
#: contrib/comments/models.py:84
#: contrib/comments/models.py:170
msgid "is public"
msgstr "公开"
#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289
#: contrib/comments/models.py:85
#: contrib/admin/views/doc.py:289
msgid "IP address"
msgstr "IP地址"
@ -85,18 +90,15 @@ msgid "is removed"
msgstr "被删除"
#: contrib/comments/models.py:86
msgid ""
"Check this box if the comment is inappropriate. A \"This comment has been "
"removed\" message will be displayed instead."
msgstr ""
"如果评论不适合选中这个检查框。评论将被一条\"此评论已经被删除\"的消息所替换。"
msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead."
msgstr "如果评论不适合选中这个检查框。评论将被一条\"此评论已经被删除\"的消息所替换。"
#: contrib/comments/models.py:91
#, fuzzy
msgid "comments"
msgstr "评论"
#: contrib/comments/models.py:131 contrib/comments/models.py:207
#: contrib/comments/models.py:131
#: contrib/comments/models.py:207
msgid "Content object"
msgstr "内容对象"
@ -128,12 +130,10 @@ msgid "approved by staff"
msgstr "由团队批准"
#: contrib/comments/models.py:176
#, fuzzy
msgid "free comment"
msgstr "自由评论"
#: contrib/comments/models.py:177
#, fuzzy
msgid "free comments"
msgstr "自由评论"
@ -146,12 +146,10 @@ msgid "score date"
msgstr "得分日期"
#: contrib/comments/models.py:237
#, fuzzy
msgid "karma score"
msgstr "Karma得分"
#: contrib/comments/models.py:238
#, fuzzy
msgid "karma scores"
msgstr "Karma得分"
@ -176,12 +174,10 @@ msgid "flag date"
msgstr "标记日期"
#: contrib/comments/models.py:268
#, fuzzy
msgid "user flag"
msgstr "用户标志"
#: contrib/comments/models.py:269
#, fuzzy
msgid "user flags"
msgstr "用户标志"
@ -195,14 +191,12 @@ msgid "deletion date"
msgstr "删除日期"
#: contrib/comments/models.py:280
#, fuzzy
msgid "moderator deletion"
msgstr "仲裁删除"
msgstr "删除仲裁"
#: contrib/comments/models.py:281
#, fuzzy
msgid "moderator deletions"
msgstr "仲裁删除"
msgstr "删除仲裁"
#: contrib/comments/models.py:285
#, python-format
@ -222,20 +216,17 @@ msgid "No voting for yourself"
msgstr "不能给自已投票"
#: contrib/comments/views/comments.py:28
msgid ""
"This rating is required because you've entered at least one other rating."
msgid "This rating is required because you've entered at least one other rating."
msgstr "要求此等级,因为你已经输入了至少一个等级。"
#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
"This comment was posted by a user who has posted fewer than %(count)s "
"comment:\n"
"This comment was posted by a user who has posted fewer than %(count)s comment:\n"
"\n"
"%(text)s"
msgid_plural ""
"This comment was posted by a user who has posted fewer than %(count)s "
"comments:\n"
"This comment was posted by a user who has posted fewer than %(count)s comments:\n"
"\n"
"%(text)s"
msgstr[0] ""
@ -271,9 +262,7 @@ msgstr "有人篡改了评论表格(安全侵害)"
#: contrib/comments/views/comments.py:207
#: contrib/comments/views/comments.py:292
msgid ""
"The comment form had an invalid 'target' parameter -- the object ID was "
"invalid"
msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
msgstr "评论表格有一个无效的 'target' 参数 -- 对象 ID 无效"
#: contrib/comments/views/comments.py:257
@ -293,9 +282,8 @@ msgid "Password:"
msgstr "口令:"
#: contrib/comments/templates/comments/form.html:6
#, fuzzy
msgid "Forgotten your password?"
msgstr "修改我的口令"
msgstr "忘记你的口令?"
#: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/object_history.html:3
@ -319,40 +307,36 @@ msgid "Log out"
msgstr "注销"
#: contrib/comments/templates/comments/form.html:12
#, fuzzy
msgid "Ratings"
msgstr "等级 #1"
msgstr "等级"
#: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23
msgid "Required"
msgstr ""
msgstr "必须的"
#: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23
msgid "Optional"
msgstr ""
msgstr "可选的"
#: contrib/comments/templates/comments/form.html:23
msgid "Post a photo"
msgstr ""
msgstr "上传一张照片"
#: contrib/comments/templates/comments/form.html:27
#: contrib/comments/templates/comments/freeform.html:5
#, fuzzy
msgid "Comment:"
msgstr "评论"
msgstr "评论"
#: contrib/comments/templates/comments/form.html:32
#: contrib/comments/templates/comments/freeform.html:9
#, fuzzy
msgid "Preview comment"
msgstr "自由评论"
msgstr "预览评论"
#: contrib/comments/templates/comments/freeform.html:4
#, fuzzy
msgid "Your name:"
msgstr "用户名"
msgstr "你的名字:"
#: contrib/admin/filterspecs.py:40
#, python-format
@ -363,7 +347,8 @@ msgstr ""
"<h3>由 %s:</h3>\n"
"<ul>\n"
#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
#: contrib/admin/filterspecs.py:70
#: contrib/admin/filterspecs.py:88
#: contrib/admin/filterspecs.py:143
msgid "All"
msgstr "全部"
@ -432,11 +417,10 @@ msgstr "日志记录"
msgid "All dates"
msgstr "全有日期"
#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36
#: contrib/admin/views/decorators.py:9
#: contrib/auth/forms.py:36
#: contrib/auth/forms.py:41
msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
msgstr "请输入正确的用户名和口令。请注意两个域都是大小写敏感的。"
#: contrib/admin/views/decorators.py:23
@ -445,18 +429,12 @@ msgid "Log in"
msgstr "登录"
#: contrib/admin/views/decorators.py:61
msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
msgstr "请重新登录,因为你的会话已经过期。不用担心:你的提交已经被保存。"
#: contrib/admin/views/decorators.py:68
msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
msgstr ""
"看上去你的浏览器没有配置成接受 cookie 。请允许 cookie重新装入本页面再试一"
"次。"
msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
msgstr "看上去你的浏览器没有配置成接受 cookie 。请允许 cookie重新装入本页面再试一次。"
#: contrib/admin/views/decorators.py:82
msgid "Usernames cannot contain the '@' character."
@ -476,11 +454,13 @@ msgstr "站点管理员"
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" 添加成功。"
#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348
#: contrib/admin/views/main.py:264
#: contrib/admin/views/main.py:348
msgid "You may edit it again below."
msgstr "你可以在下面再次编辑它。"
#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357
#: contrib/admin/views/main.py:272
#: contrib/admin/views/main.py:357
#, python-format
msgid "You may add another %s below."
msgstr "你可以在下面增加另一个 %s 。"
@ -495,7 +475,8 @@ msgstr "增加 %s"
msgid "Added %s."
msgstr "%s 已增加。"
#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338
#: contrib/admin/views/main.py:336
#: contrib/admin/views/main.py:338
#: contrib/admin/views/main.py:340
msgid "and"
msgstr "和"
@ -521,8 +502,7 @@ msgstr "%(name)s \"%(obj)s\" 修改成功。"
#: contrib/admin/views/main.py:354
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr "%(name)s \"%(obj)s\" 添加成功。你可以在下面再次编辑它。"
#: contrib/admin/views/main.py:392
@ -564,9 +544,12 @@ msgstr "选择 %s"
msgid "Select %s to change"
msgstr "选择 %s 来修改"
#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286
#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294
#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297
#: contrib/admin/views/doc.py:277
#: contrib/admin/views/doc.py:286
#: contrib/admin/views/doc.py:288
#: contrib/admin/views/doc.py:294
#: contrib/admin/views/doc.py:295
#: contrib/admin/views/doc.py:297
msgid "Integer"
msgstr "整数"
@ -574,7 +557,8 @@ msgstr "整数"
msgid "Boolean (Either True or False)"
msgstr "布尔(True或False)"
#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296
#: contrib/admin/views/doc.py:279
#: contrib/admin/views/doc.py:296
#, python-format
msgid "String (up to %(maxlength)s)"
msgstr "字符串(最长 %(maxlength)s)"
@ -595,7 +579,8 @@ msgstr "日期(带时间)"
msgid "E-mail address"
msgstr "邮箱地址"
#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287
#: contrib/admin/views/doc.py:284
#: contrib/admin/views/doc.py:287
msgid "File path"
msgstr "文件路径"
@ -623,7 +608,8 @@ msgstr "文本"
msgid "Time"
msgstr "时间"
#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7
#: contrib/admin/views/doc.py:300
#: contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
@ -703,9 +689,7 @@ msgid "DATE_WITH_TIME_FULL"
msgstr "N j, Y, P"
#: contrib/admin/templates/admin/object_history.html:36
msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
msgstr "此对象没有修改历史。可能不能通过这个管理站点来增加。"
#: contrib/admin/templates/admin/base_site.html:4
@ -729,12 +713,8 @@ msgid "Server Error <em>(500)</em>"
msgstr "服务器错误 <em>(500)</em>"
#: contrib/admin/templates/admin/500.html:10
msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
"存在一个错误。它已经通过电子邮件被报告给站点管理员了,并且应该很快被改正。谢"
"谢你的关心。"
msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
msgstr "存在一个错误。它已经通过电子邮件被报告给站点管理员了,并且应该很快被改正。谢谢你的关心。"
#: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8
@ -748,7 +728,7 @@ msgstr "很报歉,请求页面无法找到。"
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
msgstr ""
msgstr "在 %(name)s 应用中模块有效。"
#: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15
@ -795,21 +775,13 @@ msgstr "删除"
#: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format
msgid ""
"Deleting the %(object_name)s '%(object)s' would result in deleting related "
"objects, but your account doesn't have permission to delete the following "
"types of objects:"
msgstr ""
"删除 %(object_name)s '%(object)s' 会导致删除相关的对象,但你的帐号无权删除下"
"列类型的对象:"
msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
msgstr "删除 %(object_name)s '%(object)s' 会导致删除相关的对象,但你的帐号无权删除下列类型的对象:"
#: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format
msgid ""
"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of "
"the following related items will be deleted:"
msgstr ""
"你确信相要删除 %(object_name)s \"%(object)s\"?所有相关的项目都将被删除:"
msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:"
msgstr "你确信相要删除 %(object_name)s \"%(object)s\"?所有相关的项目都将被删除:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
@ -881,12 +853,8 @@ msgid "Password reset"
msgstr "口令重设"
#: contrib/admin/templates/registration/password_reset_form.html:12
msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you."
msgstr ""
"忘记你的口令?在下面输入你的邮箱地址,我们将重设你的口令并且将新的口令通过邮"
"件发送给你。"
msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
msgstr "忘记你的口令?在下面输入你的邮箱地址,我们将重设你的口令并且将新的口令通过邮件发送给你。"
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
@ -910,19 +878,12 @@ msgid "Password reset successful"
msgstr "口令重设成功"
#: contrib/admin/templates/registration/password_reset_done.html:12
msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly."
msgstr ""
"我们已经按你所提交的邮箱地址发送了一个新的口令给你。你应该很会收到这封邮件。"
msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
msgstr "我们已经按你所提交的邮箱地址发送了一个新的口令给你。你应该很会收到这封邮件。"
#: contrib/admin/templates/registration/password_change_form.html:12
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
"请输入你的旧口令,为了安全起见,接着要输入你的新口令两遍,这样我们可以校验你"
"输入的是否正确。"
msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
msgstr "请输入你的旧口令,为了安全起见,接着要输入你的新口令两遍,这样我们可以校验你输入的是否正确。"
#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
@ -1002,9 +963,7 @@ msgid "Documentation for this page"
msgstr "本页面的文档"
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
msgid ""
"Jumps you from any page to the documentation for the view that generates "
"that page."
msgid "Jumps you from any page to the documentation for the view that generates that page."
msgstr "对于任何页面跳转到生成这个页面的view所在的文件。"
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
@ -1012,9 +971,7 @@ msgid "Show object ID"
msgstr "显示对象ID"
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
msgid ""
"Shows the content-type and unique ID for pages that represent a single "
"object."
msgid "Shows the content-type and unique ID for pages that represent a single object."
msgstr "用于那些表现单个对象的页面显示 content-type 和唯一ID。"
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
@ -1054,9 +1011,7 @@ msgid "redirect from"
msgstr "重定向自"
#: contrib/redirects/models.py:8
msgid ""
"This should be an absolute path, excluding the domain name. Example: '/"
"events/search/'."
msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
msgstr "应该是一个绝对路径,不包括域名。例如:'/events/search/'。"
#: contrib/redirects/models.py:9
@ -1064,9 +1019,7 @@ msgid "redirect to"
msgstr "重定向到"
#: contrib/redirects/models.py:10
msgid ""
"This can be either an absolute path (as above) or a full URL starting with "
"'http://'."
msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
msgstr "可以是绝对路径(同上)或以'http://'开始的全URL。"
#: contrib/redirects/models.py:12
@ -1078,8 +1031,7 @@ msgid "redirects"
msgstr "重定向"
#: contrib/flatpages/models.py:8
msgid ""
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr "例如:'/about/contact/'。请确保前导和结尾的除号。"
#: contrib/flatpages/models.py:9
@ -1099,11 +1051,8 @@ msgid "template name"
msgstr "模板名称"
#: contrib/flatpages/models.py:13
msgid ""
"Example: 'flatpages/contact_page'. If this isn't provided, the system will "
"use 'flatpages/default'."
msgstr ""
"例如:'flatfiles/contact_page'。如果未提供,系统将使用'flatfiles/default'。"
msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'."
msgstr "例如:'flatfiles/contact_page'。如果未提供,系统将使用'flatfiles/default'。"
#: contrib/flatpages/models.py:14
msgid "registration required"
@ -1121,7 +1070,8 @@ msgstr "简单页面"
msgid "flat pages"
msgstr "简单页面"
#: contrib/auth/models.py:13 contrib/auth/models.py:26
#: contrib/auth/models.py:13
#: contrib/auth/models.py:26
msgid "name"
msgstr "名称"
@ -1130,22 +1080,20 @@ msgid "codename"
msgstr "代码名称"
#: contrib/auth/models.py:17
#, fuzzy
msgid "permission"
msgstr "许可"
msgstr "权限"
#: contrib/auth/models.py:18 contrib/auth/models.py:27
#, fuzzy
#: contrib/auth/models.py:18
#: contrib/auth/models.py:27
msgid "permissions"
msgstr "许可"
msgstr "权限"
#: contrib/auth/models.py:29
#, fuzzy
msgid "group"
msgstr "组"
#: contrib/auth/models.py:30 contrib/auth/models.py:65
#, fuzzy
#: contrib/auth/models.py:30
#: contrib/auth/models.py:65
msgid "groups"
msgstr "组"
@ -1198,24 +1146,18 @@ msgid "date joined"
msgstr "加入日期"
#: contrib/auth/models.py:66
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
msgstr ""
"除了手动设置权限以外,用户也会从他(她)所在的小组获得所赋组小组的所有权限。"
msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
msgstr "除了手动设置权限以外,用户也会从他(她)所在的小组获得所赋组小组的所有权限。"
#: contrib/auth/models.py:67
#, fuzzy
msgid "user permissions"
msgstr "许可"
msgstr "用户权限"
#: contrib/auth/models.py:70
#, fuzzy
msgid "user"
msgstr "用户"
#: contrib/auth/models.py:71
#, fuzzy
msgid "users"
msgstr "用户"
@ -1236,20 +1178,16 @@ msgid "Groups"
msgstr "组"
#: contrib/auth/models.py:219
#, fuzzy
msgid "message"
msgstr "消息"
#: contrib/auth/forms.py:30
msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
msgstr "你的Web浏览器好象不允许使用cookie。登录需要使用cookie。"
#: contrib/contenttypes/models.py:25
#, fuzzy
msgid "python model class name"
msgstr "python模块名"
msgstr "python模块名"
#: contrib/contenttypes/models.py:28
msgid "content type"
@ -1343,23 +1281,28 @@ msgstr "一月"
msgid "February"
msgstr "二月"
#: utils/dates.py:14 utils/dates.py:27
#: utils/dates.py:14
#: utils/dates.py:27
msgid "March"
msgstr "三月"
#: utils/dates.py:14 utils/dates.py:27
#: utils/dates.py:14
#: utils/dates.py:27
msgid "April"
msgstr "四月"
#: utils/dates.py:14 utils/dates.py:27
#: utils/dates.py:14
#: utils/dates.py:27
msgid "May"
msgstr "五月"
#: utils/dates.py:14 utils/dates.py:27
#: utils/dates.py:14
#: utils/dates.py:27
msgid "June"
msgstr "六月"
#: utils/dates.py:15 utils/dates.py:27
#: utils/dates.py:15
#: utils/dates.py:27
msgid "July"
msgstr "七月"
@ -1384,54 +1327,52 @@ msgid "December"
msgstr "十二月"
#: utils/dates.py:19
#, fuzzy
msgid "jan"
msgstr ""
msgstr "一月"
#: utils/dates.py:19
msgid "feb"
msgstr ""
msgstr "二月"
#: utils/dates.py:19
msgid "mar"
msgstr ""
msgstr "三月"
#: utils/dates.py:19
msgid "apr"
msgstr ""
msgstr "四月"
#: utils/dates.py:19
#, fuzzy
msgid "may"
msgstr ""
msgstr "三月"
#: utils/dates.py:19
msgid "jun"
msgstr ""
msgstr "六月"
#: utils/dates.py:20
msgid "jul"
msgstr ""
msgstr "七月"
#: utils/dates.py:20
msgid "aug"
msgstr ""
msgstr "八月"
#: utils/dates.py:20
msgid "sep"
msgstr ""
msgstr "九月"
#: utils/dates.py:20
msgid "oct"
msgstr ""
msgstr "十月"
#: utils/dates.py:20
msgid "nov"
msgstr ""
msgstr "十一月"
#: utils/dates.py:20
msgid "dec"
msgstr ""
msgstr "十二月"
#: utils/dates.py:27
msgid "Jan."
@ -1474,7 +1415,7 @@ msgstr[0] "月"
#: utils/timesince.py:14
msgid "week"
msgid_plural "weeks"
msgstr[0] ""
msgstr[0] ""
#: utils/timesince.py:15
msgid "day"
@ -1513,7 +1454,7 @@ msgstr "德语"
#: conf/global_settings.py:42
msgid "Greek"
msgstr ""
msgstr "希腊语"
#: conf/global_settings.py:43
msgid "English"
@ -1533,11 +1474,11 @@ msgstr "加利西亚语"
#: conf/global_settings.py:47
msgid "Hungarian"
msgstr ""
msgstr "匈牙利语"
#: conf/global_settings.py:48
msgid "Hebrew"
msgstr ""
msgstr "希伯来语"
#: conf/global_settings.py:49
msgid "Icelandic"
@ -1553,7 +1494,7 @@ msgstr "日语"
#: conf/global_settings.py:52
msgid "Dutch"
msgstr ""
msgstr "荷兰语"
#: conf/global_settings.py:53
msgid "Norwegian"
@ -1576,9 +1517,8 @@ msgid "Slovak"
msgstr "斯洛伐克语"
#: conf/global_settings.py:58
#, fuzzy
msgid "Slovenian"
msgstr "斯洛伐克语"
msgstr "斯洛文尼亚语"
#: conf/global_settings.py:59
msgid "Serbian"
@ -1589,9 +1529,8 @@ msgid "Swedish"
msgstr "瑞典语"
#: conf/global_settings.py:61
#, fuzzy
msgid "Ukrainian"
msgstr "巴西语"
msgstr "乌克兰语"
#: conf/global_settings.py:62
msgid "Simplified Chinese"
@ -1606,11 +1545,8 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "此值只能包含字母、数字和下划线。"
#: core/validators.py:64
#, fuzzy
msgid ""
"This value must contain only letters, numbers, underscores, dashes or "
"slashes."
msgstr "此值只能包含字母、数字、下划线和斜线。"
msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
msgstr "此值只能包含字母、数字、下划线、反斜线和斜线。"
#: core/validators.py:72
msgid "Uppercase letters are not allowed here."
@ -1660,7 +1596,8 @@ msgstr "输入一个 YYYY-MM-DD 格式的有效日期。"
msgid "Enter a valid time in HH:MM format."
msgstr "输入一个 HH:MM 格式的有效时间。"
#: core/validators.py:132 db/models/fields/__init__.py:468
#: core/validators.py:132
#: db/models/fields/__init__.py:468
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "输入一个 YYYY-MM-DD HH:MM 格式的有效日期/时间。"
@ -1669,9 +1606,7 @@ msgid "Enter a valid e-mail address."
msgstr "输入一个有效的邮件地址。"
#: core/validators.py:148
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
msgstr "上传一个有效的图片。您所上传的文件或者不是图片或是一个破坏的图片。"
#: core/validators.py:155
@ -1712,7 +1647,8 @@ msgstr "格式错误的 XML: %s"
msgid "Invalid URL: %s"
msgstr "无效 URL: %s"
#: core/validators.py:206 core/validators.py:208
#: core/validators.py:206
#: core/validators.py:208
#, python-format
msgid "The URL %s is a broken link."
msgstr "URL %s 是一个断开的链接。"
@ -1736,7 +1672,8 @@ msgstr "这个字段必须与 '%s' 字段相匹配。"
msgid "Please enter something for at least one field."
msgstr "请至少在一个字段上输入些什么。"
#: core/validators.py:264 core/validators.py:275
#: core/validators.py:264
#: core/validators.py:275
msgid "Please enter both fields or leave them both empty."
msgstr "请要么两个字段都输入或者两个字段都空着。"
@ -1766,15 +1703,13 @@ msgstr "请输入一个有效的小数。"
#: core/validators.py:349
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural ""
"Please enter a valid decimal number with at most %s total digits."
msgid_plural "Please enter a valid decimal number with at most %s total digits."
msgstr[0] "请输入一个有效的小数,最多 %s 个数字。 "
#: core/validators.py:352
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places."
msgid_plural "Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "请输入一个有效的小数,最多 %s 个小数位。 "
#: core/validators.py:362
@ -1802,57 +1737,38 @@ msgstr "不能从 %s 得到任何东西。"
#: core/validators.py:429
#, python-format
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "URL %(url)s 返回了无效的 Content-Type 头 '%(contenttype)s'。"
#: core/validators.py:462
#, python-format
msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
"\"%(start)s\".)"
msgstr ""
"请关闭未关闭的 %(tag)s 标签从第 %(line)s 行。(行开始于 \"%(start)s\"。)"
msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
msgstr "请关闭未关闭的 %(tag)s 标签从第 %(line)s 行。(行开始于 \"%(start)s\"。)"
#: core/validators.py:466
#, python-format
msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line "
"starts with \"%(start)s\".)"
msgstr ""
"在 %(line)s 行开始的一些文本不允许在那个上下文中。(行开始于 \"%(start)s\"。)"
msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行开始的一些文本不允许在那个上下文中。(行开始于 \"%(start)s\"。)"
#: core/validators.py:471
#, python-format
msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
"(start)s\".)"
msgstr ""
"在 %(line)s 行的\"%(attr)s\"不是一个有效的属性。(行开始于 \"%(start)s\"。)"
msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行的\"%(attr)s\"不是一个有效的属性。(行开始于 \"%(start)s\"。)"
#: core/validators.py:476
#, python-format
msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
"(start)s\".)"
msgstr ""
"在 %(line)s 行的\"<%(tag)s>\"不是一个有效的标签。(行开始于 \"%(start)s\"。)"
msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
msgstr "在 %(line)s 行的\"<%(tag)s>\"不是一个有效的标签。(行开始于 \"%(start)s\"。)"
#: core/validators.py:480
#, python-format
msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line "
"starts with \"%(start)s\".)"
msgstr ""
"在行 %(line)s 的标签少了一个或多个必须的属性。(行开始于 \"%(start)s\"。)"
msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
msgstr "在行 %(line)s 的标签少了一个或多个必须的属性。(行开始于 \"%(start)s\"。)"
#: core/validators.py:485
#, python-format
msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
"starts with \"%(start)s\".)"
msgstr ""
"在行 %(line)s 的\"%(attr)s\"属性有一个无效的值。(行开始于 \"%(start)s\"。)"
msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
msgstr "在行 %(line)s 的\"%(attr)s\"属性有一个无效的值。(行开始于 \"%(start)s\"。)"
#: db/models/manipulators.py:302
#, python-format
@ -1864,26 +1780,25 @@ msgstr "带有这个 %(type)s 的 %(object)s 对于给定的 %(field)s 已经存
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(optname)s 带有 %(fieldname)s 已经存在。"
#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265
#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553
#: db/models/fields/__init__.py:114
#: db/models/fields/__init__.py:265
#: db/models/fields/__init__.py:542
#: db/models/fields/__init__.py:553
#: forms/__init__.py:346
msgid "This field is required."
msgstr "这个字段是必输项。"
#: db/models/fields/__init__.py:337
#, fuzzy
msgid "This value must be an integer."
msgstr "这个值必须是 %s 的乘方。"
msgstr "这个值必须是一个整数。"
#: db/models/fields/__init__.py:369
#, fuzzy
msgid "This value must be either True or False."
msgstr "这个值必须是 %s 的乘方。"
msgstr "这个值必须是 True 或 False。"
#: db/models/fields/__init__.py:385
#, fuzzy
msgid "This field cannot be null."
msgstr "这个字段无效。"
msgstr "这个值不能为 null。"
#: db/models/fields/__init__.py:562
msgid "Enter a valid filename."
@ -1895,21 +1810,17 @@ msgid "Please enter a valid %s."
msgstr "请输入一个有效的 %s 。"
#: db/models/fields/related.py:579
#, fuzzy
msgid "Separate multiple IDs with commas."
msgstr " 用逗号分隔多个ID。"
msgstr "用逗号分隔多个ID。"
#: db/models/fields/related.py:581
#, fuzzy
msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr " 按下 \"Control\"或者在Mac上按 \"Command\" 来选择一个或多个值。"
msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "按下 \"Control\"或者在Mac上按 \"Command\" 来选择多个值。"
#: db/models/fields/related.py:625
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural ""
"Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgstr[0] "请输入有效的 %(self)s ID。值 %(value)r 无效。"
#: forms/__init__.py:380
@ -1922,7 +1833,9 @@ msgstr[0] "确定你输入的文本少于 %s 个字符。"
msgid "Line breaks are not allowed here."
msgstr "这里不允许换行符。"
#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589
#: forms/__init__.py:480
#: forms/__init__.py:551
#: forms/__init__.py:589
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "选择一个有效的选项: '%(data)s' 不在 %(choices)s 中。"
@ -1949,22 +1862,18 @@ msgstr "是、否、也许"
#~ msgid "Comment"
#~ msgstr "评论"
#~ msgid "Comments"
#~ msgstr "评论"
#~ msgid "String (up to 50)"
#~ msgstr "整数(最长50)"
#~ msgid "label"
#~ msgstr "标签"
#~ msgid "package"
#~ msgstr "包"
#~ msgid "packages"
#~ msgstr "包"
#, fuzzy
#~ msgid "count"
#~ msgstr "内容"

View File

@ -5,6 +5,7 @@
{{ block.super }}
<style type="text/css">
.module table { width:100%; }
.module table p { padding: 0; margin: 0; }
</style>
{% endblock %}

View File

@ -207,10 +207,12 @@ def model_detail(request, app_label, model_name):
accessor = rel.get_accessor_name()
fields.append({
'name' : "%s.all" % accessor,
'data_type' : 'List',
'verbose' : utils.parse_rst("all " + verbose , 'model', 'model:' + opts.module_name),
})
fields.append({
'name' : "%s.count" % accessor,
'data_type' : 'Integer',
'verbose' : utils.parse_rst("number of " + verbose , 'model', 'model:' + opts.module_name),
})
@ -282,6 +284,7 @@ DATA_TYPE_MAPPING = {
'DateTimeField' : _('Date (with time)'),
'EmailField' : _('E-mail address'),
'FileField' : _('File path'),
'FilePathField' : _('File path'),
'FloatField' : _('Decimal number'),
'ForeignKey' : _('Integer'),
'ImageField' : _('File path'),

View File

@ -1,5 +1,6 @@
from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
from urllib import quote
def user_passes_test(test_func, login_url=LOGIN_URL):
"""
@ -11,7 +12,7 @@ def user_passes_test(test_func, login_url=LOGIN_URL):
def _checklogin(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.path))
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
return _checklogin
return _dec

View File

@ -0,0 +1,26 @@
from django.conf import settings
from django.db import models
from django.db.models.fields import FieldDoesNotExist
class CurrentSiteManager(models.Manager):
"Use this to limit objects to those associated with the current site."
def __init__(self, field_name='site'):
super(CurrentSiteManager, self).__init__()
self.__field_name = field_name
def contribute_to_class(self, *args, **kwargs):
# This method is overridden purely to check for errors in
# self.field_name. We can't do this in __init__() because of
# how Managers are implemented -- self.model isn't available
# until after contribute_to_class() is called.
super(CurrentSiteManager, self).contribute_to_class(*args, **kwargs)
try:
self.model._meta.get_field(self.__field_name)
except FieldDoesNotExist:
raise ValueError, "%s couldn't find a field named %s in %s." % \
(self.__class__.__name__, self.__field_name, self.model._meta.object_name)
self.__lookup = self.__field_name + '__id__exact'
del self.__field_name
def get_query_set(self):
return super(SiteLimitManager, self).get_query_set().filter(**{self.__lookup: settings.SITE_ID})

View File

@ -665,6 +665,9 @@ def startapp(app_name, directory):
# the parent directory.
project_dir = os.path.normpath(os.path.join(directory, '..'))
project_name = os.path.basename(project_dir)
if app_name == os.path.basename(directory):
sys.stderr.write(style.ERROR("Error: You cannot create an app with the same name (%r) as your project.\n" % app_name))
sys.exit(1)
_start_helper('app', app_name, directory, project_name)
startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
startapp.args = "[appname]"

View File

@ -0,0 +1,123 @@
"""
PostgreSQL database backend for Django.
Requires psycopg 2: http://initd.org/projects/psycopg2
"""
from django.db.backends import util
import psycopg2 as Database
DatabaseError = Database.DatabaseError
try:
# Only exists in Python 2.4+
from threading import local
except ImportError:
# Import copy of _thread_local.py from Python 2.4
from django.utils._threading_local import local
class DatabaseWrapper(local):
def __init__(self):
self.connection = None
self.queries = []
def cursor(self):
from django.conf import settings
if self.connection is None:
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
conn_string = "dbname=%s" % settings.DATABASE_NAME
if settings.DATABASE_USER:
conn_string = "user=%s %s" % (settings.DATABASE_USER, conn_string)
if settings.DATABASE_PASSWORD:
conn_string += " password='%s'" % settings.DATABASE_PASSWORD
if settings.DATABASE_HOST:
conn_string += " host=%s" % settings.DATABASE_HOST
if settings.DATABASE_PORT:
conn_string += " port=%s" % settings.DATABASE_PORT
self.connection = Database.connect(conn_string)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor()
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
if settings.DEBUG:
return util.CursorDebugWrapper(cursor, self)
return cursor
def _commit(self):
return self.connection.commit()
def _rollback(self):
if self.connection:
return self.connection.rollback()
def close(self):
if self.connection is not None:
self.connection.close()
self.connection = None
supports_constraints = True
def quote_name(name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def dictfetchone(cursor):
"Returns a row from the cursor as a dict"
# TODO: cursor.dictfetchone() doesn't exist in psycopg2,
# but no Django code uses this. Safe to remove?
return cursor.dictfetchone()
def dictfetchmany(cursor, number):
"Returns a certain number of rows from a cursor as a dict"
# TODO: cursor.dictfetchmany() doesn't exist in psycopg2,
# but no Django code uses this. Safe to remove?
return cursor.dictfetchmany(number)
def dictfetchall(cursor):
"Returns all rows from a cursor as a dict"
# TODO: cursor.dictfetchall() doesn't exist in psycopg2,
# but no Django code uses this. Safe to remove?
return cursor.dictfetchall()
def get_last_insert_id(cursor, table_name, pk_name):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0]
def get_date_extract_sql(lookup_type, table_name):
# lookup_type is 'year', 'month', 'day'
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
return "EXTRACT('%s' FROM %s)" % (lookup_type, table_name)
def get_date_trunc_sql(lookup_type, field_name):
# lookup_type is 'year', 'month', 'day'
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
def get_limit_offset_sql(limit, offset=None):
sql = "LIMIT %s" % limit
if offset and offset != 0:
sql += " OFFSET %s" % offset
return sql
def get_random_function_sql():
return "RANDOM()"
def get_drop_foreignkey_sql():
return "DROP CONSTRAINT"
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'ILIKE %s',
'contains': 'LIKE %s',
'icontains': 'ILIKE %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',
'lte': '<= %s',
'startswith': 'LIKE %s',
'endswith': 'LIKE %s',
'istartswith': 'ILIKE %s',
'iendswith': 'ILIKE %s',
}

View File

@ -0,0 +1 @@
from django.db.backends.postgresql.client import *

View File

@ -0,0 +1 @@
from django.db.backends.postgresql.creation import *

View File

@ -0,0 +1,85 @@
from django.db import transaction
from django.db.backends.postgresql_psycopg2.base import quote_name
def get_table_list(cursor):
"Returns a list of table names in the current database."
cursor.execute("""
SELECT c.relname
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'v', '')
AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
AND pg_catalog.pg_table_is_visible(c.oid)""")
return [row[0] for row in cursor.fetchall()]
def get_table_description(cursor, table_name):
"Returns a description of the table, with the DB-API cursor.description interface."
cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name))
return cursor.description
def get_relations(cursor, table_name):
"""
Returns a dictionary of {field_index: (field_index_other_table, other_table)}
representing all relationships to the given table. Indexes are 0-based.
"""
cursor.execute("""
SELECT con.conkey, con.confkey, c2.relname
FROM pg_constraint con, pg_class c1, pg_class c2
WHERE c1.oid = con.conrelid
AND c2.oid = con.confrelid
AND c1.relname = %s
AND con.contype = 'f'""", [table_name])
relations = {}
for row in cursor.fetchall():
try:
# row[0] and row[1] are like "{2}", so strip the curly braces.
relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
except ValueError:
continue
return relations
def get_indexes(cursor, table_name):
"""
Returns a dictionary of fieldname -> infodict for the given table,
where each infodict is in the format:
{'primary_key': boolean representing whether it's the primary key,
'unique': boolean representing whether it's a unique index}
"""
# Get the table description because we only have the column indexes, and we
# need the column names.
desc = get_table_description(cursor, table_name)
# This query retrieves each index on the given table.
cursor.execute("""
SELECT idx.indkey, idx.indisunique, idx.indisprimary
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
pg_catalog.pg_index idx
WHERE c.oid = idx.indrelid
AND idx.indexrelid = c2.oid
AND c.relname = %s""", [table_name])
indexes = {}
for row in cursor.fetchall():
# row[0] (idx.indkey) is stored in the DB as an array. It comes out as
# a string of space-separated integers. This designates the field
# indexes (1-based) of the fields that have indexes on the table.
# Here, we skip any indexes across multiple fields.
if ' ' in row[0]:
continue
col_name = desc[int(row[0])-1][0]
indexes[col_name] = {'primary_key': row[2], 'unique': row[1]}
return indexes
# Maps type codes to Django Field types.
DATA_TYPES_REVERSE = {
16: 'BooleanField',
21: 'SmallIntegerField',
23: 'IntegerField',
25: 'TextField',
869: 'IPAddressField',
1043: 'CharField',
1082: 'DateField',
1083: 'TimeField',
1114: 'DateTimeField',
1184: 'DateTimeField',
1266: 'TimeField',
1700: 'FloatField',
}

View File

@ -341,16 +341,16 @@ class Model(object):
_save_FIELD_file.alters_data = True
def _get_FIELD_width(self, field):
return self.__get_image_dimensions(field)[0]
return self._get_image_dimensions(field)[0]
def _get_FIELD_height(self, field):
return self.__get_image_dimensions(field)[1]
return self._get_image_dimensions(field)[1]
def _get_image_dimensions(self, field):
cachename = "__%s_dimensions_cache" % field.name
if not hasattr(self, cachename):
from django.utils.images import get_image_dimensions
filename = self.__get_FIELD_filename(field)()
filename = self._get_FIELD_filename(field)()
setattr(self, cachename, get_image_dimensions(filename))
return getattr(self, cachename)

View File

@ -327,14 +327,18 @@ def get_digit(value, arg):
# DATES #
###################
def date(value, arg=settings.DATE_FORMAT):
def date(value, arg=None):
"Formats a date according to the given format"
from django.utils.dateformat import format
if arg is None:
arg = settings.DATE_FORMAT
return format(value, arg)
def time(value, arg=settings.TIME_FORMAT):
def time(value, arg=None):
"Formats a time according to the given format"
from django.utils.dateformat import time_format
if arg is None:
arg = settings.TIME_FORMAT
return time_format(value, arg)
def timesince(value):

View File

@ -117,9 +117,12 @@ def translation(language):
globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
if settings.SETTINGS_MODULE is not None:
parts = settings.SETTINGS_MODULE.split('.')
project = __import__(parts[0], {}, {}, [])
projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
else:
projectpath = None
def _fetch(lang, fallback=None):
@ -155,7 +158,7 @@ def translation(language):
if os.path.isdir(localepath):
res = _merge(localepath)
if os.path.isdir(projectpath):
if projectpath and os.path.isdir(projectpath):
res = _merge(projectpath)
for appname in settings.INSTALLED_APPS:

View File

@ -107,7 +107,7 @@ def update_object(request, model, object_id=None, slug=None,
errors = manipulator.get_validation_errors(new_data)
manipulator.do_html2python(new_data)
if not errors:
manipulator.save(new_data)
object = manipulator.save(new_data)
if not request.user.is_anonymous():
request.user.message_set.create(message="The %s was updated successfully." % model._meta.verbose_name)

View File

@ -16,11 +16,35 @@ The automatic Django administrative interface. For more information, see
.. _Tutorial 2: http://www.djangoproject.com/documentation/tutorial2/
auth
====
Django's authentication framework.
See the `authentication documentation`_.
.. _authentication documentation: http://www.djangoproject.com/documentation/authentication/
comments
========
A simple yet flexible comments system. This is not yet documented.
contenttypes
============
A light framework for hooking into "types" of content, where each installed
Django model is a separate content type. This is not yet documented.
csrf
====
A middleware for preventing Cross Site Request Forgeries
See the `csrf documentation`_.
.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
flatpages
=========
@ -48,6 +72,17 @@ See the `redirects documentation`_.
.. _redirects documentation: http://www.djangoproject.com/documentation/redirects/
sites
=====
A light framework that lets you operate multiple Web sites off of the same
database and Django installation. It gives you hooks for associating objects to
one or more sites.
See the `sites documentation`_.
.. _sites documentation: http://www.djangoproject.com/documentation/sites/
syndication
===========
@ -57,16 +92,6 @@ See the `syndication documentation`_.
.. _syndication documentation: http://www.djangoproject.com/documentation/syndication/
csrf
====
A middleware for preventing Cross Site Request Forgeries
See the `csrf documentation`_.
.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
Other add-ons
=============

View File

@ -338,6 +338,60 @@ introduced in Python 2.4::
* If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
Note that you'll need to map the appropriate Django view to ``/accounts/login/``.
To do this, add the following line to your URLconf::
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
Here's what ``django.contrib.auth.views.login`` does::
* If called via ``GET``, it displays a login form that POSTs to the same
URL. More on this in a bit.
* If called via ``POST``, it tries to log the user in. If login is
successful, the view redirects to the URL specified in ``next``. If
``next`` isn't provided, it redirects to ``/accounts/profile/`` (which is
currently hard-coded). If login isn't successful, it redisplays the login
form.
It's your responsibility to provide the login form in a template called
``registration/login.html``. This template gets passed three template context
variables:
* ``form``: A ``FormWrapper`` object representing the login form. See the
`forms documentation`_ for more on ``FormWrapper`` objects.
* ``next``: The URL to redirect to after successful login. This may contain
a query string, too.
* ``site_name``: The name of the current ``Site``, according to the
``SITE_ID`` setting. See the `site framework docs`_.
Here's a sample ``registration/login.html`` template you can use as a starting
point. It assumes you have a ``base.html`` template that defines a ``content``
block::
{% extends "base.html" %}
{% block content %}
{% if form.has_errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">
<table>
<tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr>
<tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{% endblock %}
.. _forms documentation: http://www.djangoproject.com/documentation/forms/
.. _site framework docs: http://www.djangoproject.com/documentation/sites/
Limiting access to logged-in users that pass a test
---------------------------------------------------

View File

@ -177,6 +177,16 @@ Port 7000 on IP address 1.2.3.4::
django-admin.py runserver 1.2.3.4:7000
Serving static files with the development server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, the development server doesn't serve any static files for your site
(such as CSS files, images, things under ``MEDIA_ROOT_URL`` and so forth). If
you want to configure Django to serve static media, read the `serving static files`_
documentation.
.. _serving static files: http://www.djangoproject.com/documentation/static_files/
shell
-----
@ -200,6 +210,9 @@ sqlall [appname appname ...]
Prints the CREATE TABLE and initial-data SQL statements for the given appnames.
Refer to the description of ``sqlinitialdata`` for an explanation of how to
specify initial data.
sqlclear [appname appname ...]
--------------------------------------
@ -215,6 +228,18 @@ sqlinitialdata [appname appname ...]
Prints the initial INSERT SQL statements for the given appnames.
For each model in each specified app, this command looks for the file
``<appname>/sql/<modelname>.sql``, where ``<appname>`` is the given appname and
``<modelname>`` is the model's name in lowercase. For example, if you have an
app ``news`` that includes a ``Story`` model, ``sqlinitialdata`` will attempt
to read a file ``news/sql/story.sql`` and append it to the output of this
command.
Each of the SQL files, if given, is expected to contain valid SQL. The SQL
files are piped directly into the database after all of the models'
table-creation statements have been executed. Use this SQL hook to populate
tables with any necessary initial records, SQL functions or test data.
sqlreset [appname appname ...]
--------------------------------------
@ -240,6 +265,20 @@ startproject [projectname]
Creates a Django project directory structure for the given project name in the
current directory.
syncdb
------
Creates the database tables for all apps in ``INSTALLED_APPS`` whose tables
have not already been created.
Use this command when you've added new applications to your project and want to
install them in the database. This includes any apps shipped with Django that
might be in ``INSTALLED_APPS`` by default. When you start a new project, run
this command to install the default apps.
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
give you the option of creating a superuser immediately.
validate
--------
@ -286,6 +325,16 @@ setting the Python path for you.
Displays a help message that includes a terse list of all available actions and
options.
--version
---------
Displays the current Django version.
Example output::
0.9.1
0.9.1 (SVN)
Extra niceties
==============

View File

@ -62,6 +62,15 @@ Most generic views require the ``queryset`` key, which is a ``QuerySet``
instance; see the `database API docs`_ for more information about ``Queryset``
objects.
Most views also take an optional ``extra_context`` dictionary that you can use
to pass any auxiliary information you wish to the view. The values in the
``extra_context`` dictionary can be either functions (or other callables) or
other objects. Functions are evaluated just before they are passed to the
template. However, note that QuerySets retrieve and cache their data when they
are first evaluated, so if you want to pass in a QuerySet via
``extra_context`` that is always fresh you need to wrap it in a function or
lambda that returns the QuerySet.
.. _database API docs: http://www.djangoproject.com/documentation/db_api/
"Simple" generic views
@ -160,10 +169,10 @@ a date in the *future* are not included.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary.
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -225,10 +234,10 @@ with a date in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -287,10 +296,10 @@ date in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -360,10 +369,10 @@ in the *future* are not displayed.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -436,10 +445,10 @@ a 404 error, regardless of whether any objects exist for future days.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -543,10 +552,10 @@ A page representing an individual object.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@ -600,10 +609,10 @@ A page representing a list of objects.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available,
@ -697,10 +706,10 @@ A page representing an individual object.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@ -764,10 +773,10 @@ automatic manipulators that come with Django models.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@ -843,10 +852,10 @@ object. This uses the automatic manipulators that come with Django models.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
@ -924,10 +933,10 @@ contain a form that POSTs to the same URL.
* ``template_loader``: The template loader to use when loading the
template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template context.
If a value in the dictionary is callable, the generic view will call it
just before rendering the template. By default, this is an empty
dictionary.
* ``extra_context``: A dictionary of values to add to the template
context. By default, this is an empty dictionary. If a value in the
dictionary is callable, the generic view will call it
just before rendering the template.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.

View File

@ -540,6 +540,17 @@ you can override base translations in your project path. Or, you can just build
a big project out of several apps and put all translations into one big project
message file. The choice is yours.
.. note::
If you're using manually configured settings, as described in the
`settings documentation`_, the ``locale`` directory in the project
directory will not be examined, since Django loses the ability to work out
the location of the project directory. (Django normally uses the location
of the settings file to determine this, and a settings file doesn't exist
if you're manually configuring your settings.)
.. _settings documentation: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
All message file repositories are structured the same way. They are:
* ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``

View File

@ -77,9 +77,9 @@ It's easy either way.
Installing the official version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Download Django-0.92.tar.gz from our `download page`_.
2. ``tar xzvf Django-0.92.tar.gz``
3. ``cd Django-0.92``
1. Download Django-0.91.tar.gz from our `download page`_.
2. ``tar xzvf Django-0.91.tar.gz``
3. ``cd Django-0.91``
4. ``sudo python setup.py install``
Note that the last command will automatically download and install setuptools_
@ -89,6 +89,14 @@ connection.
This will install Django in your Python installation's ``site-packages``
directory.
.. note::
Due to recent backwards-incompatible changes, it is strongly recommended
that you use the development version (below) for any new applications or
if you are just starting to work with Django. The 0.91 release is a
dead-end branch that is primarily of use for supporting legacy Django
applications.
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
Installing the development version

View File

@ -59,8 +59,12 @@ Adds a few conveniences for perfectionists:
* Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW``
settings. If ``APPEND_SLASH`` is ``True``, URLs that lack a trailing
slash will be redirected to the same URL with a trailing slash. If
``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
slash will be redirected to the same URL with a trailing slash, unless the
last component in the path contains a period. So ``foo.com/bar`` is
redirected to ``foo.com/bar/``, but ``foo.com/bar/file.txt`` is passed
through unchanged.
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
redirected to the same URL with a leading "www."
Both of these options are meant to normalize URLs. The philosophy is that

View File

@ -1599,6 +1599,39 @@ API. See `Other lookup options`_.
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
.. _Other lookup options: http://www.djangoproject.com/documentation/db_api/#extra-params-select-where-tables
Overriding default model methods
--------------------------------
As explained in the `database API docs`_, each model gets a few methods
automatically -- most notably, ``save()`` and ``delete()``. You can override
these methods to alter behavior.
A classic use-case for overriding the built-in methods is if you want something
to happen whenever you save an object. For example::
class Blog(models.Model):
name = models.CharField(maxlength=100)
tagline = models.TextField()
def save(self):
do_something()
super(Blog, self).save() # Call the "real" save() method.
do_something_else()
You can also prevent saving::
class Blog(models.Model):
name = models.CharField(maxlength=100)
tagline = models.TextField()
def save(self):
if self.name == "Yoko Ono's blog":
return # Yoko shall never have her own blog!
else:
super(Blog, self).save() # Call the "real" save() method.
.. _database API docs: http://www.djangoproject.com/documentation/db_api/
Models across files
===================
@ -1631,3 +1664,52 @@ read, in part::
'mysite.myapp',
#...
)
Providing initial SQL data
==========================
Django provides a hook for passing the database arbitrary SQL that's executed
just after the CREATE TABLE statements. Use this hook, for example, if you want
to populate default records, or create SQL functions, automatically.
The hook is simple: Django just looks for a file called
``<appname>/sql/<modelname>.sql``, where ``<appname>`` is your app directory and
``<modelname>`` is the model's name in lowercase.
In the ``Person`` example model at the top of this document, assuming it lives
in an app called ``myapp``, you could add arbitrary SQL to the file
``myapp/sql/person.sql``. Here's an example of what the file might contain::
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
Each SQL file, if given, is expected to contain valid SQL. The SQL files are
piped directly into the database after all of the models' table-creation
statements have been executed.
The SQL files are read by the ``sqlinitialdata``, ``sqlreset``, ``sqlall`` and
``reset`` commands in ``manage.py``. Refer to the `manage.py documentation`_
for more information.
Note that if you have multiple SQL data files, there's no guarantee of the
order in which they're executed. The only thing you can assume is that, by the
time your custom data files are executed, all the database tables already will
have been created.
.. _`manage.py documentation`: http://www.djangoproject.com/documentation/django_admin/#sqlinitialdata-appname-appname
Database-backend-specific SQL data
----------------------------------
There's also a hook for backend-specific SQL data. For example, you can have
separate initial-data files for PostgreSQL and MySQL. For each app, Django
looks for a file called ``<appname>/sql/<modelname>.<backend>.sql``, where
``<appname>`` is your app directory, ``<modelname>`` is the model's name in
lowercase and ``<backend>`` is the value of ``DATABASE_ENGINE`` in your
settings file (e.g., ``postgresql``, ``mysql``).
Backend-specific SQL data is executed before non-backend-specific SQL data. For
example, if your app contains the files ``sql/person.sql`` and
``sql/person.postgresql.sql`` and you're installing the app on PostgreSQL,
Django will execute the contents of ``sql/person.postgresql.sql`` first, then
``sql/person.sql``.

View File

@ -619,6 +619,10 @@ The ID, as an integer, of the current site in the ``django_site`` database
table. This is used so that application data can hook into specific site(s)
and a single database can manage content for multiple sites.
See the `site framework docs`_.
.. _site framework docs: http://www.djangoproject.com/documentation/sites/
TEMPLATE_CONTEXT_PROCESSORS
---------------------------
@ -724,3 +728,77 @@ Django apps. Just follow these conventions:
* For settings that are sequences, use tuples instead of lists. This is
purely for performance.
* Don't reinvent an already-existing setting.
Using settings without setting DJANGO_SETTINGS_MODULE
=====================================================
In some cases, you might want to bypass the ``DJANGO_SETTINGS_MODULE``
environment variable. For example, if you're using the template system by
itself, you likely don't want to have to set up an environment variable
pointing to a settings module.
In these cases, you can configure Django's settings manually. Do this by
calling ``django.conf.settings.configure()``.
Example::
from django.conf import settings
settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base'))
Pass ``configure()`` as many keyword arguments as you'd like, with each keyword
argument representing a setting and its value. Each argument name should be all
uppercase, with the same name as the settings described above. If a particular
setting is not passed to ``configure()`` and is needed at some later point,
Django will use the default setting value.
Custom default settings
-----------------------
If you'd like default values to come from somewhere other than
``django.conf.global_settings``, you can pass in a module or class that
provides the default settings as the ``default_settings`` argument (or as the
first positional argument) in the call to ``configure()``.
In this example, default settings are taken from ``myapp_defaults``, and the
``DEBUG`` setting is set to ``True``, regardless of its value in
``myapp_defaults``::
from django.conf import settings
from myapp import myapp_defaults
settings.configure(default_settings=myapp_defaults, DEBUG=True)
The following example, which uses ``myapp_defaults`` as a positional argument,
is equivalent::
settings.configure(myapp_defaults, DEBUG = True)
Normally, you will not need to override the defaults in this fashion. The
Django defaults are sufficiently tame that you can safely use them. Be aware
that if you do pass in a new default module, it entirely *replaces* the Django
defaults, so you must specify a value for every possible setting that might be
used in that code you are importing. Check in
``django.conf.settings.global_settings`` for the full list.
Either configure() or DJANGO_SETTINGS_MODULE is required
--------------------------------------------------------
If you're not setting the ``DJANGO_SETTINGS_MODULE`` environment variable, you
*must* call ``configure()`` at some point before using any code that reads
settings.
If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``,
Django will raise an ``EnvironmentError`` exception the first time a setting
is accessed.
If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then*
call ``configure()``, Django will raise an ``EnvironmentError`` saying settings
have already been configured.
Also, it's an error to call ``configure()`` more than once, or to call
``configure()`` after any setting has been accessed.
It boils down to this: Use exactly one of either ``configure()`` or
``DJANGO_SETTINGS_MODULE``. Not both, and not neither.

311
docs/sites.txt Normal file
View File

@ -0,0 +1,311 @@
=====================
The "sites" framework
=====================
Django comes with an optional "sites" framework. It's a hook for associating
objects and functionality to particular Web sites, and it's a holding place for
the domain names and "verbose" names of your Django-powered sites.
Use it if your single Django installation powers more than one site and you
need to differentiate between those sites in some way.
The whole sites framework is based on two simple concepts:
* The ``Site`` model, found in ``django.contrib.sites``, has ``domain`` and
``name`` fields.
* The ``SITE_ID`` setting specifies the database ID of the ``Site`` object
associated with that particular settings file.
How you use this is up to you, but Django uses it in a couple of ways
automatically via simple conventions.
Example usage
=============
Why would you use sites? It's best explained through examples.
Associating content with multiple sites
---------------------------------------
The Django-powered sites LJWorld.com_ and Lawrence.com_ are operated by the
same news organization -- the Lawrence Journal-World newspaper in Lawrence,
Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local
entertainment. But sometimes editors want to publish an article on *both*
sites.
The brain-dead way of solving the problem would be to require site producers to
publish the same story twice: once for LJWorld.com and again for Lawrence.com.
But that's inefficient for site producers, and it's redundant to store
multiple copies of the same story in the database.
The better solution is simple: Both sites use the same article database, and an
article is associated with one or more sites. In Django model terminology,
that's represented by a ``ManyToManyField`` in the ``Article`` model::
from django.db import models
from django.contrib.sites.models import Site
class Article(models.Model):
headline = models.CharField(maxlength=200)
# ...
sites = models.ManyToManyField(Site)
This accomplishes several things quite nicely:
* It lets the site producers edit all content -- on both sites -- in a
single interface (the Django admin).
* It means the same story doesn't have to be published twice in the
database; it only has a single record in the database.
* It lets the site developers use the same Django view code for both sites.
The view code that displays a given story just checks to make sure the
requested story is on the current site. It looks something like this::
from django.conf import settings
def article_detail(request, article_id):
try:
a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID)
except Article.DoesNotExist:
raise Http404
# ...
.. _ljworld.com: http://www.ljworld.com/
.. _lawrence.com: http://www.lawrence.com/
Associating content with a single site
--------------------------------------
Similarly, you can associate a model to the ``Site`` model in a many-to-one
relationship, using ``ForeignKey``.
For example, if an article is only allowed on a single site, you'd use a model
like this::
from django.db import models
from django.contrib.sites.models import Site
class Article(models.Model):
headline = models.CharField(maxlength=200)
# ...
site = models.ForeignKey(Site)
This has the same benefits as described in the last section.
Hooking into the current site from views
----------------------------------------
On a lower level, you can use the sites framework in your Django views to do
particular things based on what site in which the view is being called.
For example::
from django.conf import settings
def my_view(request):
if settings.SITE_ID == 3:
# Do something.
else:
# Do something else.
Of course, it's ugly to hard-code the site IDs like that. This sort of
hard-coding is best for hackish fixes that you need done quickly. A slightly
cleaner way of accomplishing the same thing is to check the current site's
domain::
from django.conf import settings
from django.contrib.sites.models import Site
def my_view(request):
current_site = Site.objects.get(id=settings.SITE_ID)
if current_site.domain == 'foo.com':
# Do something
else:
# Do something else.
The idiom of retrieving the ``Site`` object for the value of
``settings.SITE_ID`` is quite common, so the ``Site`` model's manager has a
``get_current()`` method. This example is equivalent to the previous one::
from django.contrib.sites.models import Site
def my_view(request):
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
# Do something
else:
# Do something else.
Getting the current domain for display
--------------------------------------
LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets
readers sign up to get notifications when news happens. It's pretty basic: A
reader signs up on a Web form, and he immediately gets an e-mail saying,
"Thanks for your subscription."
It'd be inefficient and redundant to implement this signup-processing code
twice, so the sites use the same code behind the scenes. But the "thank you for
signing up" notice needs to be different for each site. By using ``Site``
objects, we can abstract the "thank you" notice to use the values of the
current site's ``name`` and ``domain``.
Here's an example of what the form-handling view looks like::
from django.contrib.sites.models import Site
from django.core.mail import send_mail
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
current_site = Site.objects.get_current()
send_mail('Thanks for subscribing to %s alerts' % current_site.name,
'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
'editor@%s' % current_site.domain,
[user.email])
# ...
On Lawrence.com, this e-mail has the subject line "Thanks for subscribing to
lawrence.com alerts." On LJWorld.com, the e-mail has the subject "Thanks for
subscribing to LJWorld.com alerts." Same goes for the e-mail's message body.
Note that an even more flexible (but more heavyweight) way of doing this would
be to use Django's template system. Assuming Lawrence.com and LJWorld.com have
different template directories (``TEMPLATE_DIRS``), you could simply farm out
to the template system like so::
from django.core.mail import send_mail
from django.template import loader, Context
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
subject = loader.get_template('alerts/subject.txt').render(Context({}))
message = loader.get_template('alerts/message.txt').render(Context({}))
send_mail(subject, message, 'editor@ljworld.com', [user.email])
# ...
In this case, you'd have to create ``subject.txt`` and ``message.txt`` template
files for both the LJWorld.com and Lawrence.com template directories. That
gives you more flexibility, but it's also more complex.
It's a good idea to exploit the ``Site`` objects as much as possible, to remove
unneeded complexity and redundancy.
Getting the current domain for full URLs
----------------------------------------
Django's ``get_absolute_url()`` convention is nice for getting your objects'
URL without the domain name, but in some cases you might want to display the
full URL -- with ``http://`` and the domain and everything -- for an object.
To do this, you can use the sites framework. A simple example::
>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
'http://example.com/mymodel/objects/3/'
The ``CurrentSiteManager``
==========================
If ``Site``\s play a key role in your application, consider using the helpful
``CurrentSiteManager`` in your model(s). It's a model manager_ that
automatically filters its queries to include only objects associated with the
current ``Site``.
Use ``CurrentSiteManager`` by adding it to your model explicitly. For example::
from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
class Photo(models.Model):
photo = models.FileField(upload_to='/home/photos')
photographer_name = models.CharField(maxlength=100)
pub_date = models.DateField()
site = models.ForeignKey(Site)
objects = models.Manager()
on_site = CurrentSiteManager()
With this model, ``Photo.objects.all()`` will return all ``Photo`` objects in
the database, but ``Photo.on_site.all()`` will return only the ``Photo``
objects associated with the current site, according to the ``SITE_ID`` setting.
Put another way, these two statements are equivalent::
Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()
How did ``CurrentSiteManager`` know which field of ``Photo`` was the ``Site``?
It defaults to looking for a field called ``site``. If your model has a
``ForeignKey`` or ``ManyToManyField`` called something *other* than ``site``,
you need to explicitly pass that as the parameter to ``CurrentSiteManager``.
The following model, which has a field called ``publish_on``, demonstrates
this::
from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
class Photo(models.Model):
photo = models.FileField(upload_to='/home/photos')
photographer_name = models.CharField(maxlength=100)
pub_date = models.DateField()
publish_on = models.ForeignKey(Site)
objects = models.Manager()
on_site = CurrentSiteManager('publish_on')
If you attempt to use ``CurrentSiteManager`` and pass a field name that doesn't
exist, Django will raise a ``ValueError``.
.. _manager: http://www.djangoproject.com/documentation/model_api/#managers
How Django uses the sites framework
===================================
Although it's not required that you use the sites framework, it's strongly
encouraged, because Django takes advantage of it in a few places. Even if your
Django installation is powering only a single site, you should take the two
seconds to create the site object with your ``domain`` and ``name``, and point
to its ID in your ``SITE_ID`` setting.
Here's how Django uses the sites framework:
* In the `redirects framework`_, each redirect object is associated with a
particular site. When Django searches for a redirect, it takes into
account the current ``SITE_ID``.
* In the comments framework, each comment is associated with a particular
site. When a comment is posted, its ``site`` is set to the current
``SITE_ID``, and when comments are listed via the appropriate template
tag, only the comments for the current site are displayed.
* In the `flatpages framework`_, each flatpage is associated with a
particular site. When a flatpage is created, you specify its ``site``,
and the ``FlatpageFallbackMiddleware`` checks the current ``SITE_ID`` in
retrieving flatpages to display.
* In the `syndication framework`_, the templates for ``title`` and
``description`` automatically have access to a variable ``{{{ site }}}``,
which is the ``Site`` object representing the current site. Also, the
hook for providing item URLs will use the ``domain`` from the current
``Site`` object if you don't specify a fully-qualified domain.
* In the `authentication framework`_, the ``django.contrib.auth.views.login``
view passes the current ``Site`` name to the template as ``{{{ site_name }}}``.
* The shortcut view (``django.views.defaults.shortcut``) uses the domain of
the current ``Site`` object when calculating an object's URL.
.. _redirects framework: http://www.djangoproject.com/documentation/redirects/
.. _flatpages framework: http://www.djangoproject.com/documentation/flatpages/
.. _syndication framework: http://www.djangoproject.com/documentation/syndication/
.. _authentication framework: http://www.djangoproject.com/documentation/syndication/

View File

@ -7,6 +7,10 @@ perspective -- how it works and how to extend it. If you're just looking for
reference on the language syntax, see
`The Django template language: For template authors`_.
If you're looking to use the Django template system as part of another
application -- i.e., without the rest of the framework -- make sure to read
the `configuration`_ section later in this document.
.. _`The Django template language: For template authors`: http://www.djangoproject.com/documentation/templates/
Basics
@ -739,6 +743,164 @@ Python 2.4 and above::
If you leave off the ``name`` argument, as in the second example above, Django
will use the function's name as the tag name.
Shortcut for simple tags
~~~~~~~~~~~~~~~~~~~~~~~~
Many template tags take a single argument -- a string or a template variable
reference -- and return a string after doing some processing based solely on
the input argument and some external information. For example, the
``current_time`` tag we wrote above is of this variety: we give it a format
string, it returns the time as a string.
To ease the creation of the types of tags, Django provides a helper function,
``simple_tag``. This function, which is a method of
``django.template.Library``, takes a function that accepts one argument, wraps
it in a ``render`` function and the other necessary bits mentioned above and
registers it with the template system.
Our earlier ``current_time`` function could thus be written like this::
# This version of do_current_time takes only a single argument and returns
# a string.
def do_current_time(token):
try:
# Splitting by None == splitting by spaces.
tag_name, format_string = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0]
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
return datetime.datetime.now().strftime(self.format_string[1:-1])
register.simple_tag(do_current_time)
In Python 2.4, the decorator syntax also works::
@simple_tag
def do_current_time(token):
...
Inclusion tags
~~~~~~~~~~~~~~
Another type of template tag that is sometimes useful is when you want to
display some data that is computed at render time in a template fragment. For
example, in Django's admin interface, there is a line of buttons along the
bottom of the `create/edit record` screen. These buttons always look the same,
but the link targets change depending upon the object being edited. So they
are a perfect example for using a small template that is filled in with
details from the current object. To save typing, it would also be nice if we
could wrap this whole display up in a single tag (in the admin templates this
is the ``submit_row`` tag).
We call these sorts of tags `inclusion tags`. In your template, you pass in
any appropriate arguments and the tag uses those arguments, together with the
current context to render a template and include the result in the output.
Writing inclusion tags is probably best demonstrated by example. We will write
a tag that outputs a list of choices for a Poll object, such as was created in
the tutorials_. We will use this tag like this::
{{ show_results poll }}
and the output will be something like this::
<ul>
<li>First choice</li>
<li>Second choice</li>
<li>Third choice</li>
</ul>
First, we define the function which takes the argument and produces a
dictionary of data for the result. The important point here is we only need to
return a dictionary, not anything more complex. This will be used to substitue
for values in the template fragment, just as when templates are used
elsewhere.
::
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
We also need to create the template that is used to render the output. This
template is a fixed feature of the tag: the tag writer specifies it, not the
template designer. In our case, the template is very simple::
<ul>
{% for choice in choices %}
<li> {{ choice }} </li>
{% endfor %}
</ul>
Now we can create the inclusion tag. Suppose the above template is in a file
called ``results.html`` in a directory that is searched by the template
loader. We register our new tag similarly to a normal tag.
::
# Here, register is a django.template.Library instance, as before
register.inclusion_tag('results.html')(show_results)
As always, Python 2.4 decorator syntax works as well, so we could have
written
::
@inclusion_tag('results.html')
def show_results(poll):
...
when first creating the function.
In some cases, an inclusion tag might require a large number of arguments to
display itself properly. In essence, it would depend largely on the current
context it was being rendered with. We can make these sorts of tags easier to
write by telling the ``inclusion_tag`` function that the whole context
should be passed in as an argument to the function. This will be done
invisibly as far as the template tag user is concerned: they will not need to
do anything to pass in the context.
For example, suppose we are writing an inclusion tag that will always be used
in a context that contains ``home_link`` and ``home_title`` variables that
point back to the main page. We can write a tag that is used like this::
{{ jump_link }}
and renders this::
Jump directly to <a href="http://example.com/home">Home</a>
The tag function is almost as simple as before. This time it takes no
arguments except the ``context`` (and the parameter `must` be called
``context`` in this case; the special parameter named is used internally by
Django to fill in the values correctly).
::
# The first argument *must* be called "context" here.
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
Our template is very simple again::
Jump directly to <a href="{{ link }}">{{ title }}</a>.
Assuming the template is in a file called ``link.html``, we register this new
tag as follows::
register.inclusion_tag('link.html', takes_context = True)(jump_link)
The ``takes_context`` parameter here defaults to *False*. When it is set to
*True*, our tag is passed the implicit context as in this example. That is the
only difference between this case and our previous use of ``inclusion_tag``.
.. _tutorials: http://www.djangoproject.com/documentation/tutorial1/#creating-models
Setting a variable in the context
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -876,3 +1038,37 @@ The only new concept here is the ``self.nodelist.render(context)`` in
For more examples of complex rendering, see the source code for ``{% if %}``,
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
``django/template/defaulttags.py``.
.. _configuration:
Configuring the template system in standalone mode
==================================================
.. note::
This section is only of interest to people trying to use the template
system as an output component in another application. If you are using the
template system as part of a Django application, nothing here applies to
you.
Normally, Django will load all the configuration information it needs from its
own default configuration file, combined with the settings in the module given
in the ``DJANGO_SETTINGS_MODULE`` environment variable. But if you're using the
template system independently of the rest of Django, the environment variable
approach isn't very convenient, because you probably want to configure the
template system in line with the rest of your application rather than dealing
with settings files and pointing to them via environment variables.
To solve this problem, you need to use the manual configuration option
described in the `settings file`_ documentation. Simply import the appropriate
pieces of the templating system and then, *before* you call any of the
templating functions, call ``django.conf.settings.configure()`` with any
settings you wish to specify. You might want to consider setting at least
``TEMPLATE_DIRS`` (if you are going to use template loaders),
``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
``TEMPLATE_DEBUG``. All available settings are described in the
`settings documentation`_, and any setting starting with *TEMPLATE_*
is of obvious interest.
.. _settings file: http://www.djangoproject.com/documentation/settings/#using-settings-without-the-django-settings-module-environment-variable
.. _settings documentation: http://www.djangoproject.com/documentation/settings/

View File

@ -445,13 +445,13 @@ Once you're in the shell, explore the database API::
# objects.all() displays all the polls in the database.
>>> Poll.objects.all()
[<Poll object>]
[<Poll: Poll object>]
Wait a minute. ``<Poll object>`` is, utterly, an unhelpful representation of
this object. Let's fix that by editing the polls model
(in the ``polls/models.py`` file) and adding a ``__str__()`` method to
both ``Poll`` and ``Choice``::
Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful
representation of this object. Let's fix that by editing the polls model (in
the ``polls/models.py`` file) and adding a ``__str__()`` method to both
``Poll`` and ``Choice``::
class Poll(models.Model):
# ...
@ -487,30 +487,30 @@ Let's jump back into the Python interactive shell by running
# Make sure our __str__() addition worked.
>>> Poll.objects.all()
[What's up?]
[<Poll: What's up?>]
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Poll.objects.filter(id=1)
[What's up?]
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[What's up?]
[<Poll: What's up?>]
# Get the poll whose year is 2005. Of course, if you're going through this
# tutorial in another year, change as appropriate.
>>> Poll.objects.get(pub_date__year=2005)
What's up?
<Poll: What's up?>
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Poll does not exist for {'id': 2}
DoesNotExist: Poll matching query does not exist.
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
What's up?
<Poll: What's up?>
# Make sure our custom method worked.
>>> p = Poll.objects.get(pk=1)
@ -522,18 +522,18 @@ Let's jump back into the Python interactive shell by running
# of available choices and returns the new Choice object.
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.create(choice='Not much', votes=0)
Not much
<Choice: Not much>
>>> p.choice_set.create(choice='The sky', votes=0)
The sky
<Choice: The sky>
>>> c = p.choice_set.create(choice='Just hacking again', votes=0)
# Choice objects have API access to their related Poll objects.
>>> c.poll
What's up?
<Poll: What's up?>
# And vice versa: Poll objects get access to Choice objects.
>>> p.choice_set.all()
[Not much, The sky, Just hacking again]
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3
@ -542,7 +542,7 @@ Let's jump back into the Python interactive shell by running
# This works as many levels deep as you want. There's no limit.
# Find all Choices for any poll whose pub_date is in 2005.
>>> Choice.objects.filter(poll__pub_date__year=2005)
[Not much, The sky, Just hacking again]
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Let's delete one of the choices. Use delete() for that.
>>> c = p.choice_set.filter(choice__startswith='Just hacking')

View File

@ -507,4 +507,5 @@ def run_tests(verbosity=0, standalone=False):
raise Exception, msg
if __name__ == "__main__":
settings.configure()
run_tests(1, True)

View File

@ -73,6 +73,10 @@ class TestRunner:
def run_tests(self):
from django.conf import settings
# An empty access of the settings to force the default options to be
# installed prior to assigning to them.
settings.INSTALLED_APPS
# Manually set INSTALLED_APPS to point to the test models.
settings.INSTALLED_APPS = [MODEL_TESTS_DIR_NAME + '.' + a for a in get_test_models()]
@ -110,14 +114,11 @@ class TestRunner:
global TEST_DATABASE_NAME
TEST_DATABASE_NAME = ":memory:"
else:
# Create the test database and connect to it. We need autocommit()
# because PostgreSQL doesn't allow CREATE DATABASE statements
# within transactions.
# Create the test database and connect to it. We need to autocommit
# if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions.
cursor = connection.cursor()
try:
connection.connection.autocommit(1)
except AttributeError:
pass
self._set_autocommit(connection)
self.output(1, "Creating test database")
try:
cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME)
@ -220,11 +221,7 @@ class TestRunner:
settings.DATABASE_NAME = old_database_name
cursor = connection.cursor()
self.output(1, "Deleting test database")
try:
connection.connection.autocommit(1)
except AttributeError:
pass
else:
self._set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.
cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)
@ -239,6 +236,15 @@ class TestRunner:
else:
print "All tests passed."
def _set_autocommit(self, connection):
"""
Make sure a connection is in autocommit mode.
"""
if hasattr(connection.connection, "autocommit"):
connection.connection.autocommit(True)
elif hasattr(connection.connection, "set_isolation_level"):
connection.connection.set_isolation_level(0)
if __name__ == "__main__":
from optparse import OptionParser
usage = "%prog [options] [model model model ...]"