1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

newforms-admin: Merged from trunk up to [7232]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7233 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2008-03-13 06:14:26 +00:00
parent 304642769c
commit bfc5660c47
92 changed files with 11782 additions and 3146 deletions

View File

@ -56,6 +56,7 @@ answer newbie questions, and generally made Django that much better:
David Ascher <http://ascher.ca/> David Ascher <http://ascher.ca/>
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com> Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
Arthur <avandorp@gmail.com> Arthur <avandorp@gmail.com>
David Avsajanishvili <avsd05@gmail.com>
axiak@mit.edu axiak@mit.edu
Jiri Barton Jiri Barton
Ned Batchelder <http://www.nedbatchelder.com/> Ned Batchelder <http://www.nedbatchelder.com/>
@ -71,6 +72,7 @@ answer newbie questions, and generally made Django that much better:
boobsd@gmail.com boobsd@gmail.com
Andrew Brehaut <http://brehaut.net/blog> Andrew Brehaut <http://brehaut.net/blog>
brut.alll@gmail.com brut.alll@gmail.com
btoll@bestweb.net
Jonathan Buchanan <jonathan.buchanan@gmail.com> Jonathan Buchanan <jonathan.buchanan@gmail.com>
Can Burak Çilingir <canburak@cs.bilgi.edu.tr> Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
Trevor Caira <trevor@caira.com> Trevor Caira <trevor@caira.com>
@ -111,6 +113,7 @@ answer newbie questions, and generally made Django that much better:
Sander Dijkhuis <sander.dijkhuis@gmail.com> Sander Dijkhuis <sander.dijkhuis@gmail.com>
Jordan Dimov <s3x3y1@gmail.com> Jordan Dimov <s3x3y1@gmail.com>
dne@mayonnaise.net dne@mayonnaise.net
dready <wil@mojipage.com>
Maximillian Dornseif <md@hudora.de> Maximillian Dornseif <md@hudora.de>
Jeremy Dunck <http://dunck.us/> Jeremy Dunck <http://dunck.us/>
Andrew Durdin <adurdin@gmail.com> Andrew Durdin <adurdin@gmail.com>

View File

@ -52,7 +52,7 @@ LANGUAGES = (
('fa', gettext_noop('Persian')), ('fa', gettext_noop('Persian')),
('fi', gettext_noop('Finnish')), ('fi', gettext_noop('Finnish')),
('fr', gettext_noop('French')), ('fr', gettext_noop('French')),
('ga', gettext_noop('Gaeilge')), ('ga', gettext_noop('Irish')),
('gl', gettext_noop('Galician')), ('gl', gettext_noop('Galician')),
('hu', gettext_noop('Hungarian')), ('hu', gettext_noop('Hungarian')),
('he', gettext_noop('Hebrew')), ('he', gettext_noop('Hebrew')),
@ -60,6 +60,7 @@ LANGUAGES = (
('is', gettext_noop('Icelandic')), ('is', gettext_noop('Icelandic')),
('it', gettext_noop('Italian')), ('it', gettext_noop('Italian')),
('ja', gettext_noop('Japanese')), ('ja', gettext_noop('Japanese')),
('ka', gettext_noop('Georgian')),
('ko', gettext_noop('Korean')), ('ko', gettext_noop('Korean')),
('km', gettext_noop('Khmer')), ('km', gettext_noop('Khmer')),
('kn', gettext_noop('Kannada')), ('kn', gettext_noop('Kannada')),
@ -90,8 +91,8 @@ LANGUAGES_BIDI = ("he", "ar", "fa")
# If you set this to False, Django will make some optimizations so as not # If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery. # to load the internationalization machinery.
USE_I18N = True USE_I18N = True
LOCALE_PATHS = () LOCALE_PATHS = ()
LANGUAGE_COOKIE_NAME = 'django_language'
# Not-necessarily-technical managers of the site. They get broken link # Not-necessarily-technical managers of the site. They get broken link
# notifications and other various e-mails. # notifications and other various e-mails.

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,12 @@
# Italian translation of Django. # Italian translation of Django.
# Copyright (C) 2006 the Lawrence Journal-World # Copyright (C) 2006 the Lawrence Journal-World
# This file is distributed under the same license as the Django package. # This file is distributed under the same license as the Django package.
#
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django\n" "Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-02-02 18:31+0100\n" "POT-Creation-Date: 2008-02-02 18:31+0100\n"
"PO-Revision-Date: 2008-02-02 19:40+0100\n" "PO-Revision-Date: 2008-03-02 11:40+0100\n"
"Last-Translator: Nicola Larosa <nico@tekNico.net>\n" "Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
"Language-Team: Italiano\n" "Language-Team: Italiano\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -79,7 +78,7 @@ msgstr "Francese"
#: conf/global_settings.py:54 #: conf/global_settings.py:54
msgid "Gaeilge" msgid "Gaeilge"
msgstr "" msgstr "Gaelico"
#: conf/global_settings.py:55 #: conf/global_settings.py:55
msgid "Galician" msgid "Galician"

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,118 @@
# Translation of Django Java-script part to Georgian.
# Copyright (C) 2008
# This file is distributed under the same license as the PACKAGE package.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django 0.97\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-02-16 22:31+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: David Avsajanishvili <avsd05@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "მისაწვდომი %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "ავირჩიოთ ყველა"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "დავამატოთ"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "წავშალოთ"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "არჩეული %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "აირჩიეთ და დააწკაპეთ "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "გავასუფთავოთ ყველა"
#: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/dateparse.js:32
msgid ""
"January February March April May June July August September October November "
"December"
msgstr "იანვარი თებერვალი მარტი აპრილი მაისი ივნისი ივლისი აგვისტო სექტემბერი "
"ოქტომბერი ნოემბერი დეკემბერი"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "კ ო ს ო ხ პ შ"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "კვირა ორშაბათი სამშაბათი ოთხშაბათი ხუთშაბათი პარასკევი შაბათი"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "ვაჩვენოთ"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "დავმალოთ"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "ახლა"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "საათი"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "ავირჩიოთ დრო"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "შუაღამე"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "დილის 6 სთ"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "შუადღე"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "უარი"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "დღეს"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "კალენდარი"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "გუშინ"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "ხვალ"

File diff suppressed because it is too large Load Diff

View File

@ -5,33 +5,16 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 17:39+0200\n" "POT-Creation-Date: 2008-02-27 10:34+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2008-02-27 11:22+0100\n"
"Last-Translator: Rudolph Froger <rfroger@estrate.nl>\n" "Last-Translator: jdetaeye <jdetaeye@frepple.com>\n"
"Language-Team: nl <LL@li.org>\n" "Language-Team: nl <LL@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/dateparse.js:32
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"januari februari maart april mei juni juli augustus september oktober "
"november december"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "Z M D W D V Z"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "zondag maandag dinsdag woensdag donderdag vrijdag zaterdag"
#: contrib/admin/media/js/SelectFilter2.js:33 #: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format #, perl-format
msgid "Available %s" msgid "Available %s"
@ -62,49 +45,72 @@ msgstr "Selecteer uw keuze(s) en klik "
msgid "Clear all" msgid "Clear all"
msgstr "Allemaal verwijderen" msgstr "Allemaal verwijderen"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 #: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 #: contrib/admin/media/js/dateparse.js:32
msgid "January February March April May June July August September October November December"
msgstr "januari februari maart april mei juni juli augustus september oktober november december"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "Z M D W D V Z"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "zondag maandag dinsdag woensdag donderdag vrijdag zaterdag"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "Tonen"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "Verbergen"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now" msgid "Now"
msgstr "Nu" msgstr "Nu"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock" msgid "Clock"
msgstr "Klok" msgstr "Klok"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time" msgid "Choose a time"
msgstr "Kies een tijd" msgstr "Kies een tijd"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight" msgid "Midnight"
msgstr "Middernacht" msgstr "Middernacht"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m." msgid "6 a.m."
msgstr "6 uur" msgstr "6 uur"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon" msgid "Noon"
msgstr "12 uur" msgstr "12 uur"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel" msgid "Cancel"
msgstr "Annuleren" msgstr "Annuleren"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today" msgid "Today"
msgstr "Vandaag" msgstr "Vandaag"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar" msgid "Calendar"
msgstr "Kalender" msgstr "Kalender"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday" msgid "Yesterday"
msgstr "Gisteren" msgstr "Gisteren"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow" msgid "Tomorrow"
msgstr "Morgen" msgstr "Morgen"

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,11 @@
import base64
import md5
import cPickle as pickle
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django import http, template from django import http, template
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -5,8 +13,6 @@ from django.contrib.auth import authenticate, login
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.utils.translation import ugettext_lazy, ugettext as _ from django.utils.translation import ugettext_lazy, ugettext as _
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
import base64, datetime, md5
import cPickle as pickle
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form' LOGIN_FORM_KEY = 'this_is_the_login_form'
@ -104,4 +110,4 @@ def staff_member_required(view_func):
else: else:
return _display_login_form(request, ERROR_MESSAGE) return _display_login_form(request, ERROR_MESSAGE)
return _checklogin return wraps(view_func)(_checklogin)

View File

@ -6,7 +6,7 @@ try:
except NameError: except NameError:
from sets import Set as set # Python 2.3 fallback from sets import Set as set # Python 2.3 fallback
class ModelBackend: class ModelBackend(object):
""" """
Authenticate against django.contrib.auth.models.User Authenticate against django.contrib.auth.models.User
""" """

View File

@ -1,3 +1,8 @@
try:
from functools import wraps, update_wrapper
except ImportError:
from django.utils.functional import wraps, update_wrapper # Python 2.3, 2.4 fallback.
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.utils.http import urlquote from django.utils.http import urlquote
@ -51,7 +56,7 @@ class _CheckLogin(object):
self.test_func = test_func self.test_func = test_func
self.login_url = login_url self.login_url = login_url
self.redirect_field_name = redirect_field_name self.redirect_field_name = redirect_field_name
self.__name__ = view_func.__name__ update_wrapper(self, view_func)
def __get__(self, obj, cls=None): def __get__(self, obj, cls=None):
view_func = self.view_func.__get__(obj, cls) view_func = self.view_func.__get__(obj, cls)

View File

@ -39,13 +39,19 @@ class GenericForeignKey(object):
# content-type/object-id fields. # content-type/object-id fields.
if self.name in kwargs: if self.name in kwargs:
value = kwargs.pop(self.name) value = kwargs.pop(self.name)
kwargs[self.ct_field] = self.get_content_type(value) kwargs[self.ct_field] = self.get_content_type(obj=value)
kwargs[self.fk_field] = value._get_pk_val() kwargs[self.fk_field] = value._get_pk_val()
def get_content_type(self, obj): def get_content_type(self, obj=None, id=None):
# Convenience function using get_model avoids a circular import when using this model # Convenience function using get_model avoids a circular import when using this model
ContentType = get_model("contenttypes", "contenttype") ContentType = get_model("contenttypes", "contenttype")
return ContentType.objects.get_for_model(obj) if obj:
return ContentType.objects.get_for_model(obj)
elif id:
return ContentType.objects.get_for_id(id)
else:
# This should never happen. I love comments like this, don't you?
raise Exception("Impossible arguments to GFK.get_content_type!")
def __get__(self, instance, instance_type=None): def __get__(self, instance, instance_type=None):
if instance is None: if instance is None:
@ -55,8 +61,15 @@ class GenericForeignKey(object):
return getattr(instance, self.cache_attr) return getattr(instance, self.cache_attr)
except AttributeError: except AttributeError:
rel_obj = None rel_obj = None
ct = getattr(instance, self.ct_field)
if ct: # Make sure to use ContentType.objects.get_for_id() to ensure that
# lookups are cached (see ticket #5570). This takes more code than
# the naive ``getattr(instance, self.ct_field)``, but has better
# performance when dealing with GFKs in loops and such.
f = self.model._meta.get_field(self.ct_field)
ct_id = getattr(instance, f.get_attname(), None)
if ct_id:
ct = self.get_content_type(id=ct_id)
try: try:
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field)) rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
except ObjectDoesNotExist: except ObjectDoesNotExist:
@ -71,7 +84,7 @@ class GenericForeignKey(object):
ct = None ct = None
fk = None fk = None
if value is not None: if value is not None:
ct = self.get_content_type(value) ct = self.get_content_type(obj=value)
fk = value._get_pk_val() fk = value._get_pk_val()
setattr(instance, self.ct_field, ct) setattr(instance, self.ct_field, ct)

View File

@ -2,25 +2,49 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
CONTENT_TYPE_CACHE = {}
class ContentTypeManager(models.Manager): class ContentTypeManager(models.Manager):
# Cache to avoid re-looking up ContentType objects all over the place.
# This cache is shared by all the get_for_* methods.
_cache = {}
def get_for_model(self, model): def get_for_model(self, model):
""" """
Returns the ContentType object for the given model, creating the Returns the ContentType object for a given model, creating the
ContentType if necessary. ContentType if necessary. Lookups are cached so that subsequent lookups
for the same model don't hit the database.
""" """
opts = model._meta opts = model._meta
key = (opts.app_label, opts.object_name.lower()) key = (opts.app_label, opts.object_name.lower())
try: try:
ct = CONTENT_TYPE_CACHE[key] ct = self.__class__._cache[key]
except KeyError: except KeyError:
# The smart_unicode() is needed around opts.verbose_name_raw because it might # Load or create the ContentType entry. The smart_unicode() is
# be a django.utils.functional.__proxy__ object. # needed around opts.verbose_name_raw because name_raw might be a
ct, created = self.model._default_manager.get_or_create(app_label=key[0], # django.utils.functional.__proxy__ object.
model=key[1], defaults={'name': smart_unicode(opts.verbose_name_raw)}) ct, created = self.get_or_create(
CONTENT_TYPE_CACHE[key] = ct app_label = opts.app_label,
model = opts.object_name.lower(),
defaults = {'name': smart_unicode(opts.verbose_name_raw)},
)
self._add_to_cache(ct)
return ct return ct
def get_for_id(self, id):
"""
Lookup a ContentType by ID. Uses the same shared cache as get_for_model
(though ContentTypes are obviously not created on-the-fly by get_by_id).
"""
try:
ct = self.__class__._cache[id]
except KeyError:
# This could raise a DoesNotExist; that's correct behavior and will
# make sure that only correct ctypes get stored in the cache dict.
ct = self.get(pk=id)
self._add_to_cache(ct)
return ct
def clear_cache(self): def clear_cache(self):
""" """
Clear out the content-type cache. This needs to happen during database Clear out the content-type cache. This needs to happen during database
@ -28,14 +52,21 @@ class ContentTypeManager(models.Manager):
django.contrib.contenttypes.management.update_contenttypes for where django.contrib.contenttypes.management.update_contenttypes for where
this gets called). this gets called).
""" """
global CONTENT_TYPE_CACHE self.__class__._cache.clear()
CONTENT_TYPE_CACHE = {}
def _add_to_cache(self, ct):
"""Insert a ContentType into the cache."""
model = ct.model_class()
key = (model._meta.app_label, model._meta.object_name.lower())
self.__class__._cache[key] = ct
self.__class__._cache[ct.id] = ct
class ContentType(models.Model): class ContentType(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
app_label = models.CharField(max_length=100) app_label = models.CharField(max_length=100)
model = models.CharField(_('python model class name'), max_length=100) model = models.CharField(_('python model class name'), max_length=100)
objects = ContentTypeManager() objects = ContentTypeManager()
class Meta: class Meta:
verbose_name = _('content type') verbose_name = _('content type')
verbose_name_plural = _('content types') verbose_name_plural = _('content types')

View File

@ -0,0 +1,47 @@
"""
Make sure that the content type cache (see ContentTypeManager) works correctly.
Lookups for a particular content type -- by model or by ID -- should hit the
database only on the first lookup.
First, let's make sure we're dealing with a blank slate (and that DEBUG is on so
that queries get logged)::
>>> from django.conf import settings
>>> settings.DEBUG = True
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.clear_cache()
>>> from django import db
>>> db.reset_queries()
At this point, a lookup for a ContentType should hit the DB::
>>> ContentType.objects.get_for_model(ContentType)
<ContentType: content type>
>>> len(db.connection.queries)
1
A second hit, though, won't hit the DB, nor will a lookup by ID::
>>> ct = ContentType.objects.get_for_model(ContentType)
>>> len(db.connection.queries)
1
>>> ContentType.objects.get_for_id(ct.id)
<ContentType: content type>
>>> len(db.connection.queries)
1
Once we clear the cache, another lookup will again hit the DB::
>>> ContentType.objects.clear_cache()
>>> ContentType.objects.get_for_model(ContentType)
<ContentType: content type>
>>> len(db.connection.queries)
2
Don't forget to reset DEBUG!
>>> settings.DEBUG = False
"""

View File

@ -8,8 +8,6 @@ from django.utils.translation import get_date_formats
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.views.generic import date_based from django.views.generic import date_based
import datetime
import time
class CalendarPlugin(DatabrowsePlugin): class CalendarPlugin(DatabrowsePlugin):
def __init__(self, field_names=None): def __init__(self, field_names=None):

View File

@ -7,8 +7,6 @@ from django.utils.text import capfirst
from django.utils.encoding import smart_str, force_unicode from django.utils.encoding import smart_str, force_unicode
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.views.generic import date_based from django.views.generic import date_based
import datetime
import time
import urllib import urllib
class FieldChoicePlugin(DatabrowsePlugin): class FieldChoicePlugin(DatabrowsePlugin):

View File

@ -2,8 +2,6 @@ from django.db.models import FieldDoesNotExist, DateTimeField
from django.http import Http404 from django.http import Http404
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.contrib.databrowse.datastructures import EasyModel, EasyChoice from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
import datetime
import time
########### ###########
# CHOICES # # CHOICES #

View File

@ -3,7 +3,6 @@ Formtools Preview application.
""" """
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404 from django.http import Http404
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.template.context import RequestContext from django.template.context import RequestContext

View File

@ -3,8 +3,6 @@ from django.contrib.formtools import preview
from django import http from django import http
from django.conf import settings from django.conf import settings
from django.test import TestCase from django.test import TestCase
from django.test.client import Client
success_string = "Done was called!" success_string = "Done was called!"
test_data = {'field1': u'foo', test_data = {'field1': u'foo',
@ -88,6 +86,3 @@ class PreviewTests(TestCase):
response = self.client.post('/test1/', test_data) response = self.client.post('/test1/', test_data)
self.assertEqual(response.content, success_string) self.assertEqual(response.content, success_string)
if __name__ == '__main__':
unittest.main()

View File

@ -2,8 +2,7 @@ from django.utils.translation import ungettext, ugettext as _
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from django import template from django import template
from django.template import defaultfilters from django.template import defaultfilters
from django.conf import settings from datetime import date
from datetime import date, timedelta
import re import re
register = template.Library() register = template.Library()

View File

@ -7,7 +7,6 @@ from django.newforms import ValidationError
from django.newforms.fields import RegexField, CharField, Select, EMPTY_VALUES from django.newforms.fields import RegexField, CharField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext from django.utils.translation import ugettext
import re
class ARProvinceSelect(Select): class ARProvinceSelect(Select):
""" """

View File

@ -1,38 +1,38 @@
from django import newforms as forms from django import newforms as forms
DEFAULT_DATE_INPUT_FORMATS = ( DEFAULT_DATE_INPUT_FORMATS = (
'%Y-%m-%d', '%d/%m/%Y', '%d/%m/%y', # '2006-10-25', '25/10/2006', '25/10/06' '%Y-%m-%d', '%d/%m/%Y', '%d/%m/%y', # '2006-10-25', '25/10/2006', '25/10/06'
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
'%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
'%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
'%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
) )
DEFAULT_DATETIME_INPUT_FORMATS = ( DEFAULT_DATETIME_INPUT_FORMATS = (
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30' '%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25' '%Y-%m-%d', # '2006-10-25'
'%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59' '%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59'
'%d/%m/%Y %H:%M', # '25/10/2006 14:30' '%d/%m/%Y %H:%M', # '25/10/2006 14:30'
'%d/%m/%Y', # '25/10/2006' '%d/%m/%Y', # '25/10/2006'
'%d/%m/%y %H:%M:%S', # '25/10/06 14:30:59' '%d/%m/%y %H:%M:%S', # '25/10/06 14:30:59'
'%d/%m/%y %H:%M', # '25/10/06 14:30' '%d/%m/%y %H:%M', # '25/10/06 14:30'
'%d/%m/%y', # '25/10/06' '%d/%m/%y', # '25/10/06'
) )
class DateField(forms.DateField): class DateField(forms.DateField):
""" """
A date input field which uses non-US date input formats by default. A date input field which uses non-US date input formats by default.
""" """
def __init__(self, input_formats=None, *args, **kwargs): def __init__(self, input_formats=None, *args, **kwargs):
input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
super(DateField, self).__init__(input_formats=input_formats, *args, **kwargs) super(DateField, self).__init__(input_formats=input_formats, *args, **kwargs)
class DateTimeField(forms.DateTimeField): class DateTimeField(forms.DateTimeField):
""" """
A date and time input field which uses non-US date and time input formats A date and time input field which uses non-US date and time input formats
by default. by default.
""" """
def __init__(self, input_formats=None, *args, **kwargs): def __init__(self, input_formats=None, *args, **kwargs):
input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
super(DateTimeField, self).__init__(input_formats=input_formats, *args, **kwargs) super(DateTimeField, self).__init__(input_formats=input_formats, *args, **kwargs)

View File

@ -7,8 +7,6 @@ from django.newforms import ValidationError
from django.utils.translation import ugettext from django.utils.translation import ugettext
from django.newforms.fields import RegexField, Select from django.newforms.fields import RegexField, Select
import re
class JPPostalCodeField(RegexField): class JPPostalCodeField(RegexField):
""" """
A form field that validates its input is a Japanese postcode. A form field that validates its input is a Japanese postcode.

View File

@ -1,10 +1,5 @@
import os
import sys
import time
import datetime
import base64 import base64
import md5 import md5
import random
import cPickle as pickle import cPickle as pickle
from django.db import models from django.db import models

View File

@ -14,7 +14,6 @@ u'lorem ipsum dolor'
""" """
from django.contrib.webdesign.lorem_ipsum import * from django.contrib.webdesign.lorem_ipsum import *
import datetime
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest

View File

@ -109,7 +109,8 @@ class BaseHandler(object):
except exceptions.PermissionDenied: except exceptions.PermissionDenied:
return http.HttpResponseForbidden('<h1>Permission denied</h1>') return http.HttpResponseForbidden('<h1>Permission denied</h1>')
except SystemExit: except SystemExit:
pass # See http://code.djangoproject.com/ticket/1023 # Allow sys.exit() to actually exit. See tickets #1023 and #4701
raise
except: # Handle everything else, including SuspiciousOperation, etc. except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later. # Get the exception info now, in case another exception is thrown later.
exc_info = sys.exc_info() exc_info = sys.exc_info()

View File

@ -6,7 +6,7 @@ from django.core import signals
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.utils import datastructures from django.utils import datastructures
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode, smart_str
# NOTE: do *not* import settings (or any module which eventually imports # NOTE: do *not* import settings (or any module which eventually imports
# settings) until after ModPythonHandler has been called; otherwise os.environ # settings) until after ModPythonHandler has been called; otherwise os.environ
@ -36,8 +36,9 @@ class ModPythonRequest(http.HttpRequest):
meta = pformat(self.META) meta = pformat(self.META)
except: except:
meta = '<could not parse>' meta = '<could not parse>'
return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ return smart_str(u'<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' %
(self.path, get, post, cookies, meta) (self.path, unicode(get), unicode(post),
unicode(cookies), unicode(meta)))
def get_full_path(self): def get_full_path(self):
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '') return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')

View File

@ -318,8 +318,8 @@ def send_mail(subject, message, from_email, recipient_list, fail_silently=False,
If auth_user is None, the EMAIL_HOST_USER setting is used. If auth_user is None, the EMAIL_HOST_USER setting is used.
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used. If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
NOTE: This method is deprecated. It exists for backwards compatibility. Note: The API for this method is frozen. New code wanting to extend the
New code should use the EmailMessage class directly. functionality should use the EmailMessage class directly.
""" """
connection = SMTPConnection(username=auth_user, password=auth_password, connection = SMTPConnection(username=auth_user, password=auth_password,
fail_silently=fail_silently) fail_silently=fail_silently)
@ -335,8 +335,8 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password
If auth_user is None, the EMAIL_HOST_USER setting is used. If auth_user is None, the EMAIL_HOST_USER setting is used.
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used. If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
NOTE: This method is deprecated. It exists for backwards compatibility. Note: The API for this method is frozen. New code wanting to extend the
New code should use the EmailMessage class directly. functionality should use the EmailMessage class directly.
""" """
connection = SMTPConnection(username=auth_user, password=auth_password, connection = SMTPConnection(username=auth_user, password=auth_password,
fail_silently=fail_silently) fail_silently=fail_silently)

View File

@ -6,10 +6,22 @@ import sys
from django.utils import termcolors from django.utils import termcolors
def supports_color():
"""
Returns True if the running system's terminal supports color, and False
otherwise.
"""
unsupported_platform = (sys.platform in ('win32', 'Pocket PC')
or sys.platform.startswith('java'))
# isatty is not always implemented, #6223.
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
if unsupported_platform or not is_a_tty:
return False
return True
def color_style(): def color_style():
"""Returns a Style object with the Django color scheme.""" """Returns a Style object with the Django color scheme."""
if (sys.platform == 'win32' or sys.platform == 'Pocket PC' if not supports_color():
or sys.platform.startswith('java') or not sys.stdout.isatty()):
return no_style() return no_style()
class dummy: pass class dummy: pass
style = dummy() style = dummy()

View File

@ -30,7 +30,8 @@ class Command(BaseCommand):
show_traceback = options.get('traceback', False) show_traceback = options.get('traceback', False)
# Keep a count of the installed objects and fixtures # Keep a count of the installed objects and fixtures
count = [0, 0] fixture_count = 0
object_count = 0
models = set() models = set()
humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path' humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
@ -65,7 +66,12 @@ class Command(BaseCommand):
else: else:
print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format) print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']: if os.path.isabs(fixture_name):
fixture_dirs = [fixture_name]
else:
fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + ['']
for fixture_dir in fixture_dirs:
if verbosity > 1: if verbosity > 1:
print "Checking %s for fixtures..." % humanize(fixture_dir) print "Checking %s for fixtures..." % humanize(fixture_dir)
@ -86,14 +92,14 @@ class Command(BaseCommand):
transaction.leave_transaction_management() transaction.leave_transaction_management()
return return
else: else:
count[1] += 1 fixture_count += 1
if verbosity > 0: if verbosity > 0:
print "Installing %s fixture '%s' from %s." % \ print "Installing %s fixture '%s' from %s." % \
(format, fixture_name, humanize(fixture_dir)) (format, fixture_name, humanize(fixture_dir))
try: try:
objects = serializers.deserialize(format, fixture) objects = serializers.deserialize(format, fixture)
for obj in objects: for obj in objects:
count[0] += 1 object_count += 1
models.add(obj.object.__class__) models.add(obj.object.__class__)
obj.save() obj.save()
label_found = True label_found = True
@ -102,10 +108,12 @@ class Command(BaseCommand):
transaction.rollback() transaction.rollback()
transaction.leave_transaction_management() transaction.leave_transaction_management()
if show_traceback: if show_traceback:
raise import traceback
sys.stderr.write( traceback.print_exc()
self.style.ERROR("Problem installing fixture '%s': %s\n" % else:
(full_path, str(e)))) sys.stderr.write(
self.style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, str(e))))
return return
fixture.close() fixture.close()
except: except:
@ -113,7 +121,7 @@ class Command(BaseCommand):
print "No %s fixture '%s' in %s." % \ print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir)) (format, fixture_name, humanize(fixture_dir))
if count[0] > 0: if object_count > 0:
sequence_sql = connection.ops.sequence_reset_sql(self.style, models) sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
if sequence_sql: if sequence_sql:
if verbosity > 1: if verbosity > 1:
@ -124,9 +132,9 @@ class Command(BaseCommand):
transaction.commit() transaction.commit()
transaction.leave_transaction_management() transaction.leave_transaction_management()
if count[0] == 0: if object_count == 0:
if verbosity >= 2: if verbosity >= 2:
print "No fixtures found." print "No fixtures found."
else: else:
if verbosity > 0: if verbosity > 0:
print "Installed %d object(s) from %d fixture(s)" % tuple(count) print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)

View File

@ -67,6 +67,8 @@ class Command(NoArgsCommand):
created_models.add(model) created_models.add(model)
for refto, refs in references.items(): for refto, refs in references.items():
pending_references.setdefault(refto, []).extend(refs) pending_references.setdefault(refto, []).extend(refs)
if refto in seen_models:
sql.extend(sql_for_pending_references(refto, self.style, pending_references))
sql.extend(sql_for_pending_references(model, self.style, pending_references)) sql.extend(sql_for_pending_references(model, self.style, pending_references))
if verbosity >= 1: if verbosity >= 1:
print "Creating table %s" % model._meta.db_table print "Creating table %s" % model._meta.db_table

View File

@ -90,6 +90,8 @@ def sql_create(app, style):
final_output.extend(output) final_output.extend(output)
for refto, refs in references.items(): for refto, refs in references.items():
pending_references.setdefault(refto, []).extend(refs) pending_references.setdefault(refto, []).extend(refs)
if refto in known_models:
final_output.extend(sql_for_pending_references(refto, style, pending_references))
final_output.extend(sql_for_pending_references(model, style, pending_references)) final_output.extend(sql_for_pending_references(model, style, pending_references))
# Keep track of the fact that we've created the table for this model. # Keep track of the fact that we've created the table for this model.
known_models.add(model) known_models.add(model)

View File

@ -4,7 +4,6 @@ Serialize data to/from JSON
import datetime import datetime
from django.utils import simplejson from django.utils import simplejson
from django.utils.simplejson import decoder
from django.core.serializers.python import Serializer as PythonSerializer from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer from django.core.serializers.python import Deserializer as PythonDeserializer
try: try:

View File

@ -4,7 +4,6 @@ YAML serializer.
Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__. Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
""" """
import datetime
from django.db import models from django.db import models
from django.core.serializers.python import Serializer as PythonSerializer from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer from django.core.serializers.python import Deserializer as PythonDeserializer

View File

@ -21,7 +21,6 @@ if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
from MySQLdb.converters import conversions from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE from MySQLdb.constants import FIELD_TYPE
import types
import re import re
# Raise exceptions for database warnings if DEBUG is on # Raise exceptions for database warnings if DEBUG is on

View File

@ -27,6 +27,11 @@ class DatabaseOperations(BaseDatabaseOperations):
def deferrable_sql(self): def deferrable_sql(self):
return " DEFERRABLE INITIALLY DEFERRED" return " DEFERRABLE INITIALLY DEFERRED"
def field_cast_sql(self, db_type):
if db_type == 'inet':
return 'HOST(%s)'
return '%s'
def last_insert_id(self, cursor, table_name, pk_name): def last_insert_id(self, cursor, table_name, pk_name):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]

View File

@ -132,6 +132,9 @@ class Model(object):
def __ne__(self, other): def __ne__(self, other):
return not self.__eq__(other) return not self.__eq__(other)
def __hash__(self):
return hash(self._get_pk_val())
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)

View File

@ -226,7 +226,11 @@ class Field(object):
value = int(value) value = int(value)
except ValueError: except ValueError:
raise ValueError("The __year lookup type requires an integer argument") raise ValueError("The __year lookup type requires an integer argument")
return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value] if settings.DATABASE_ENGINE == 'sqlite3':
first = '%s-01-01'
else:
first = '%s-01-01 00:00:00'
return [first % value, '%s-12-31 23:59:59.999999' % value]
raise TypeError("Field has invalid lookup: %s" % lookup_type) raise TypeError("Field has invalid lookup: %s" % lookup_type)
def has_default(self): def has_default(self):
@ -445,6 +449,9 @@ class BooleanField(Field):
kwargs['blank'] = True kwargs['blank'] = True
Field.__init__(self, *args, **kwargs) Field.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "BooleanField"
def to_python(self, value): def to_python(self, value):
if value in (True, False): return value if value in (True, False): return value
if value in ('t', 'True', '1'): return True if value in ('t', 'True', '1'): return True
@ -463,6 +470,9 @@ class CharField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.TextField] return [oldforms.TextField]
def get_internal_type(self):
return "CharField"
def to_python(self, value): def to_python(self, value):
if isinstance(value, basestring): if isinstance(value, basestring):
return value return value
@ -493,6 +503,9 @@ class DateField(Field):
kwargs['blank'] = True kwargs['blank'] = True
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "DateField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -562,6 +575,9 @@ class DateField(Field):
return super(DateField, self).formfield(**defaults) return super(DateField, self).formfield(**defaults)
class DateTimeField(DateField): class DateTimeField(DateField):
def get_internal_type(self):
return "DateTimeField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -632,6 +648,9 @@ class DecimalField(Field):
self.max_digits, self.decimal_places = max_digits, decimal_places self.max_digits, self.decimal_places = max_digits, decimal_places
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "DecimalField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -691,9 +710,6 @@ class EmailField(CharField):
kwargs['max_length'] = kwargs.get('max_length', 75) kwargs['max_length'] = kwargs.get('max_length', 75)
CharField.__init__(self, *args, **kwargs) CharField.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "CharField"
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.EmailField] return [oldforms.EmailField]
@ -711,6 +727,9 @@ class FileField(Field):
kwargs['max_length'] = kwargs.get('max_length', 100) kwargs['max_length'] = kwargs.get('max_length', 100)
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "FileField"
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
"Returns field's value prepared for saving into a database." "Returns field's value prepared for saving into a database."
# Need to convert UploadedFile objects provided via a form to unicode for database insertion # Need to convert UploadedFile objects provided via a form to unicode for database insertion
@ -820,12 +839,18 @@ class FilePathField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)] return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
def get_internal_type(self):
return "FilePathField"
class FloatField(Field): class FloatField(Field):
empty_strings_allowed = False empty_strings_allowed = False
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.FloatField] return [oldforms.FloatField]
def get_internal_type(self):
return "FloatField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.FloatField} defaults = {'form_class': forms.FloatField}
defaults.update(kwargs) defaults.update(kwargs)
@ -848,6 +873,9 @@ class ImageField(FileField):
if not self.height_field: if not self.height_field:
setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self)) setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
def get_internal_type(self):
return "ImageField"
def save_file(self, new_data, new_object, original_object, change, rel, save=True): def save_file(self, new_data, new_object, original_object, change, rel, save=True):
FileField.save_file(self, new_data, new_object, original_object, change, rel, save) FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
# If the image has height and/or width field(s) and they haven't # If the image has height and/or width field(s) and they haven't
@ -870,6 +898,9 @@ class IntegerField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.IntegerField] return [oldforms.IntegerField]
def get_internal_type(self):
return "IntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.IntegerField} defaults = {'form_class': forms.IntegerField}
defaults.update(kwargs) defaults.update(kwargs)
@ -884,6 +915,9 @@ class IPAddressField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.IPAddressField] return [oldforms.IPAddressField]
def get_internal_type(self):
return "IPAddressField"
def validate(self, field_data, all_data): def validate(self, field_data, all_data):
validators.isValidIPAddress4(field_data, None) validators.isValidIPAddress4(field_data, None)
@ -898,6 +932,9 @@ class NullBooleanField(Field):
kwargs['null'] = True kwargs['null'] = True
Field.__init__(self, *args, **kwargs) Field.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "NullBooleanField"
def to_python(self, value): def to_python(self, value):
if value in (None, True, False): return value if value in (None, True, False): return value
if value in ('None'): return None if value in ('None'): return None
@ -921,6 +958,9 @@ class PhoneNumberField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PhoneNumberField] return [oldforms.PhoneNumberField]
def get_internal_type(self):
return "PhoneNumberField"
def validate(self, field_data, all_data): def validate(self, field_data, all_data):
validators.isValidPhone(field_data, all_data) validators.isValidPhone(field_data, all_data)
@ -934,6 +974,9 @@ class PositiveIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PositiveIntegerField] return [oldforms.PositiveIntegerField]
def get_internal_type(self):
return "PositiveIntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'min_value': 0} defaults = {'min_value': 0}
defaults.update(kwargs) defaults.update(kwargs)
@ -943,6 +986,9 @@ class PositiveSmallIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PositiveSmallIntegerField] return [oldforms.PositiveSmallIntegerField]
def get_internal_type(self):
return "PositiveSmallIntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'min_value': 0} defaults = {'min_value': 0}
defaults.update(kwargs) defaults.update(kwargs)
@ -957,14 +1003,23 @@ class SlugField(CharField):
kwargs['db_index'] = True kwargs['db_index'] = True
super(SlugField, self).__init__(*args, **kwargs) super(SlugField, self).__init__(*args, **kwargs)
def get_internal_type(self):
return "SlugField"
class SmallIntegerField(IntegerField): class SmallIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.SmallIntegerField] return [oldforms.SmallIntegerField]
def get_internal_type(self):
return "SmallIntegerField"
class TextField(Field): class TextField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.LargeTextField] return [oldforms.LargeTextField]
def get_internal_type(self):
return "TextField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'widget': forms.Textarea} defaults = {'widget': forms.Textarea}
defaults.update(kwargs) defaults.update(kwargs)
@ -978,6 +1033,9 @@ class TimeField(Field):
kwargs['editable'] = False kwargs['editable'] = False
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "TimeField"
def get_db_prep_lookup(self, lookup_type, value): def get_db_prep_lookup(self, lookup_type, value):
if settings.DATABASE_ENGINE == 'oracle': if settings.DATABASE_ENGINE == 'oracle':
# Oracle requires a date in order to parse. # Oracle requires a date in order to parse.
@ -1042,9 +1100,6 @@ class URLField(CharField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.URLField] return [oldforms.URLField]
def get_internal_type(self):
return "CharField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists}
defaults.update(kwargs) defaults.update(kwargs)
@ -1054,6 +1109,9 @@ class USStateField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.USStateField] return [oldforms.USStateField]
def get_internal_type(self):
return "USStateField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
from django.contrib.localflavor.us.forms import USStateSelect from django.contrib.localflavor.us.forms import USStateSelect
defaults = {'widget': USStateSelect} defaults = {'widget': USStateSelect}
@ -1065,9 +1123,6 @@ class XMLField(TextField):
self.schema_path = schema_path self.schema_path = schema_path
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "TextField"
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)] return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
@ -1078,8 +1133,5 @@ class OrderingField(IntegerField):
kwargs['null'] = True kwargs['null'] = True
IntegerField.__init__(self, **kwargs ) IntegerField.__init__(self, **kwargs )
def get_internal_type(self):
return "IntegerField"
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
return [oldforms.HiddenField(name_prefix + self.name)] return [oldforms.HiddenField(name_prefix + self.name)]

View File

@ -23,26 +23,64 @@ RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
pending_lookups = {} pending_lookups = {}
def add_lookup(rel_cls, field): def add_lazy_relation(cls, field, relation):
name = field.rel.to """
module = rel_cls.__module__ Adds a lookup on ``cls`` when a related field is defined using a string,
key = (module, name) i.e.::
# Has the model already been loaded?
# If so, resolve the string reference right away class MyModel(Model):
model = get_model(rel_cls._meta.app_label, field.rel.to, False) fk = ForeignKey("AnotherModel")
This string can be:
* RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
relation.
* The name of a model (i.e "AnotherModel") to indicate another model in
the same app.
* An app-label and model name (i.e. "someapp.AnotherModel") to indicate
another model in a different app.
If the other model hasn't yet been loaded -- almost a given if you're using
lazy relationships -- then the relation won't be set up until the
class_prepared signal fires at the end of model initialization.
"""
# Check for recursive relations
if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
app_label = cls._meta.app_label
model_name = cls.__name__
else:
# Look for an "app.Model" relation
try:
app_label, model_name = relation.split(".")
except ValueError:
# If we can't split, assume a model in current app
app_label = cls._meta.app_label
model_name = relation
# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
# model isn't loaded yet, so we need to pend the relation until the class
# is prepared.
model = get_model(app_label, model_name, False)
if model: if model:
field.rel.to = model field.rel.to = model
field.do_related_class(model, rel_cls) field.do_related_class(model, cls)
else: else:
# Mark the related field for later lookup key = (app_label, model_name)
pending_lookups.setdefault(key, []).append((rel_cls, field)) value = (cls, field)
pending_lookups.setdefault(key, []).append(value)
def do_pending_lookups(sender): def do_pending_lookups(sender):
other_cls = sender """
key = (other_cls.__module__, other_cls.__name__) Handle any pending relations to the sending model. Sent from class_prepared.
for rel_cls, field in pending_lookups.setdefault(key, []): """
field.rel.to = other_cls key = (sender._meta.app_label, sender.__name__)
field.do_related_class(other_cls, rel_cls) for cls, field in pending_lookups.pop(key, []):
field.rel.to = sender
field.do_related_class(sender, cls)
dispatcher.connect(do_pending_lookups, signal=signals.class_prepared) dispatcher.connect(do_pending_lookups, signal=signals.class_prepared)
@ -66,9 +104,7 @@ class RelatedField(object):
sup.contribute_to_class(cls, name) sup.contribute_to_class(cls, name)
other = self.rel.to other = self.rel.to
if isinstance(other, basestring): if isinstance(other, basestring):
if other == RECURSIVE_RELATIONSHIP_CONSTANT: add_lazy_relation(cls, self, other)
self.rel.to = cls.__name__
add_lookup(cls, self)
else: else:
self.do_related_class(other, cls) self.do_related_class(other, cls)

View File

@ -3,23 +3,25 @@ from Cookie import SimpleCookie
from pprint import pformat from pprint import pformat
from urllib import urlencode from urllib import urlencode
from urlparse import urljoin from urlparse import urljoin
from django.utils.datastructures import MultiValueDict, FileDict
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
from utils import *
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
try: try:
# The mod_python version is more efficient, so try importing it first. # The mod_python version is more efficient, so try importing it first.
from mod_python.util import parse_qsl from mod_python.util import parse_qsl
except ImportError: except ImportError:
from cgi import parse_qsl from cgi import parse_qsl
from django.utils.datastructures import MultiValueDict, FileDict
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
from utils import *
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
class Http404(Exception): class Http404(Exception):
pass pass
class HttpRequest(object): class HttpRequest(object):
"A basic HTTP request" """A basic HTTP request."""
# The encoding used in GET/POST dicts. None means use default setting. # The encoding used in GET/POST dicts. None means use default setting.
_encoding = None _encoding = None
@ -46,7 +48,7 @@ class HttpRequest(object):
__contains__ = has_key __contains__ = has_key
def get_host(self): def get_host(self):
"Returns the HTTP host using the environment or request headers." """Returns the HTTP host using the environment or request headers."""
# We try three options, in order of decreasing preference. # We try three options, in order of decreasing preference.
if 'HTTP_X_FORWARDED_HOST' in self.META: if 'HTTP_X_FORWARDED_HOST' in self.META:
host = self.META['HTTP_X_FORWARDED_HOST'] host = self.META['HTTP_X_FORWARDED_HOST']
@ -98,7 +100,7 @@ class HttpRequest(object):
encoding = property(_get_encoding, _set_encoding) encoding = property(_get_encoding, _set_encoding)
def parse_file_upload(header_dict, post_data): def parse_file_upload(header_dict, post_data):
"Returns a tuple of (POST QueryDict, FILES MultiValueDict)" """Returns a tuple of (POST QueryDict, FILES MultiValueDict)."""
import email, email.Message import email, email.Message
from cgi import parse_header from cgi import parse_header
raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()]) raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()])
@ -130,6 +132,7 @@ def parse_file_upload(header_dict, post_data):
POST.appendlist(name_dict['name'], submessage.get_payload()) POST.appendlist(name_dict['name'], submessage.get_payload())
return POST, FILES return POST, FILES
class QueryDict(MultiValueDict): class QueryDict(MultiValueDict):
""" """
A specialized MultiValueDict that takes a query string when initialized. A specialized MultiValueDict that takes a query string when initialized.
@ -148,12 +151,13 @@ class QueryDict(MultiValueDict):
self.encoding = encoding self.encoding = encoding
self._mutable = True self._mutable = True
for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True
self.appendlist(force_unicode(key, encoding, errors='replace'), force_unicode(value, encoding, errors='replace')) self.appendlist(force_unicode(key, encoding, errors='replace'),
force_unicode(value, encoding, errors='replace'))
self._mutable = mutable self._mutable = mutable
def _assert_mutable(self): def _assert_mutable(self):
if not self._mutable: if not self._mutable:
raise AttributeError, "This QueryDict instance is immutable" raise AttributeError("This QueryDict instance is immutable")
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._assert_mutable() self._assert_mutable()
@ -171,7 +175,7 @@ class QueryDict(MultiValueDict):
dict.__setitem__(result, key, value) dict.__setitem__(result, key, value)
return result return result
def __deepcopy__(self, memo={}): def __deepcopy__(self, memo):
import copy import copy
result = self.__class__('', mutable=True) result = self.__class__('', mutable=True)
memo[id(self)] = result memo[id(self)] = result
@ -222,8 +226,8 @@ class QueryDict(MultiValueDict):
return MultiValueDict.setdefault(self, key, default) return MultiValueDict.setdefault(self, key, default)
def copy(self): def copy(self):
"Returns a mutable copy of this object." """Returns a mutable copy of this object."""
return self.__deepcopy__() return self.__deepcopy__({})
def urlencode(self): def urlencode(self):
output = [] output = []
@ -243,7 +247,7 @@ def parse_cookie(cookie):
return cookiedict return cookiedict
class HttpResponse(object): class HttpResponse(object):
"A basic HTTP response, with content and dictionary-accessed headers" """A basic HTTP response, with content and dictionary-accessed headers."""
status_code = 200 status_code = 200
@ -272,13 +276,13 @@ class HttpResponse(object):
self._headers = {'content-type': ('Content-Type', content_type)} self._headers = {'content-type': ('Content-Type', content_type)}
def __str__(self): def __str__(self):
"Full HTTP message, including headers" """Full HTTP message, including headers."""
return '\n'.join(['%s: %s' % (key, value) return '\n'.join(['%s: %s' % (key, value)
for key, value in self._headers.values()]) \ for key, value in self._headers.values()]) \
+ '\n\n' + self.content + '\n\n' + self.content
def _convert_to_ascii(self, *values): def _convert_to_ascii(self, *values):
"Convert all values to ascii strings" """Converts all values to ascii strings."""
for value in values: for value in values:
if isinstance(value, unicode): if isinstance(value, unicode):
try: try:
@ -303,7 +307,7 @@ class HttpResponse(object):
return self._headers[header.lower()][1] return self._headers[header.lower()][1]
def has_header(self, header): def has_header(self, header):
"Case-insensitive check for a header" """Case-insensitive check for a header."""
return self._headers.has_key(header.lower()) return self._headers.has_key(header.lower())
__contains__ = has_header __contains__ = has_header
@ -314,16 +318,23 @@ class HttpResponse(object):
def get(self, header, alternate): def get(self, header, alternate):
return self._headers.get(header.lower(), (None, alternate))[1] return self._headers.get(header.lower(), (None, alternate))[1]
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
domain=None, secure=False):
self.cookies[key] = value self.cookies[key] = value
for var in ('max_age', 'path', 'domain', 'secure', 'expires'): if max_age is not None:
val = locals()[var] self.cookies[key]['max-age'] = max_age
if val is not None: if expires is not None:
self.cookies[key][var.replace('_', '-')] = val self.cookies[key]['expires'] = expires
if path is not None:
self.cookies[key]['path'] = path
if domain is not None:
self.cookies[key]['domain'] = domain
if secure:
self.cookies[key]['secure'] = True
def delete_cookie(self, key, path='/', domain=None): def delete_cookie(self, key, path='/', domain=None):
self.set_cookie(key, max_age=0, path=path, domain=domain, self.set_cookie(key, max_age=0, path=path, domain=domain,
expires='Thu, 01-Jan-1970 00:00:00 GMT') expires='Thu, 01-Jan-1970 00:00:00 GMT')
def _get_content(self): def _get_content(self):
if self.has_header('Content-Encoding'): if self.has_header('Content-Encoding'):
@ -354,7 +365,7 @@ class HttpResponse(object):
# See http://docs.python.org/lib/bltin-file-objects.html # See http://docs.python.org/lib/bltin-file-objects.html
def write(self, content): def write(self, content):
if not self._is_string: if not self._is_string:
raise Exception, "This %s instance is not writable" % self.__class__ raise Exception("This %s instance is not writable" % self.__class__)
self._container.append(content) self._container.append(content)
def flush(self): def flush(self):
@ -362,7 +373,7 @@ class HttpResponse(object):
def tell(self): def tell(self):
if not self._is_string: if not self._is_string:
raise Exception, "This %s instance cannot tell its position" % self.__class__ raise Exception("This %s instance cannot tell its position" % self.__class__)
return sum([len(chunk) for chunk in self._container]) return sum([len(chunk) for chunk in self._container])
class HttpResponseRedirect(HttpResponse): class HttpResponseRedirect(HttpResponse):
@ -419,7 +430,7 @@ def get_host(request):
# this slightly more restricted function. # this slightly more restricted function.
def str_to_unicode(s, encoding): def str_to_unicode(s, encoding):
""" """
Convert basestring objects to unicode, using the given encoding. Illegaly Converts basestring objects to unicode, using the given encoding. Illegally
encoded input characters are replaced with Unicode "unknown" codepoint encoded input characters are replaced with Unicode "unknown" codepoint
(\ufffd). (\ufffd).
@ -429,4 +440,3 @@ def str_to_unicode(s, encoding):
return unicode(s, encoding, 'replace') return unicode(s, encoding, 'replace')
else: else:
return s return s

View File

@ -134,7 +134,7 @@ class BaseForm(StrAndUnicode):
bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable. bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
if bf.is_hidden: if bf.is_hidden:
if bf_errors: if bf_errors:
top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors]) top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
hidden_fields.append(unicode(bf)) hidden_fields.append(unicode(bf))
else: else:
if errors_on_separate_row and bf_errors: if errors_on_separate_row and bf_errors:
@ -155,7 +155,7 @@ class BaseForm(StrAndUnicode):
help_text = u'' help_text = u''
output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text}) output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text})
if top_errors: if top_errors:
output.insert(0, error_row % top_errors) output.insert(0, error_row % force_unicode(top_errors))
if hidden_fields: # Insert any hidden fields in the last row. if hidden_fields: # Insert any hidden fields in the last row.
str_hidden = u''.join(hidden_fields) str_hidden = u''.join(hidden_fields)
if output: if output:

View File

@ -2,6 +2,10 @@
import re import re
import random as random_module import random as random_module
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.template import Variable, Library from django.template import Variable, Library
from django.conf import settings from django.conf import settings
@ -35,7 +39,7 @@ def stringfilter(func):
for attr in ('is_safe', 'needs_autoescape'): for attr in ('is_safe', 'needs_autoescape'):
if hasattr(func, attr): if hasattr(func, attr):
setattr(_dec, attr, getattr(func, attr)) setattr(_dec, attr, getattr(func, attr))
return _dec return wraps(func)(_dec)
################### ###################
# STRINGS # # STRINGS #

View File

@ -100,7 +100,7 @@ __all__ = [
import __future__ import __future__
import sys, traceback, inspect, linecache, os, re, types import sys, traceback, inspect, linecache, os, re
import unittest, difflib, pdb, tempfile import unittest, difflib, pdb, tempfile
import warnings import warnings
from StringIO import StringIO from StringIO import StringIO

View File

@ -1,7 +1,5 @@
import datetime
import sys import sys
from cStringIO import StringIO from cStringIO import StringIO
from urlparse import urlparse
from django.conf import settings from django.conf import settings
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler

View File

@ -146,4 +146,3 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
teardown_test_environment() teardown_test_environment()
return len(result.failures) + len(result.errors) return len(result.failures) + len(result.errors)

View File

@ -3,7 +3,7 @@ class MergeDict(object):
A simple class for creating new "virtual" dictionaries that actually look A simple class for creating new "virtual" dictionaries that actually look
up values in more than one dictionary, passed in the constructor. up values in more than one dictionary, passed in the constructor.
If a key appears in more than one of the passed in dictionaries, only the If a key appears in more than one of the given dictionaries, only the
first occurrence will be used. first occurrence will be used.
""" """
def __init__(self, *dicts): def __init__(self, *dicts):
@ -145,7 +145,7 @@ class SortedDict(dict):
"""Returns a copy of this object.""" """Returns a copy of this object."""
# This way of initializing the copy means it works for subclasses, too. # This way of initializing the copy means it works for subclasses, too.
obj = self.__class__(self) obj = self.__class__(self)
obj.keyOrder = self.keyOrder obj.keyOrder = self.keyOrder[:]
return obj return obj
def __repr__(self): def __repr__(self):
@ -155,6 +155,10 @@ class SortedDict(dict):
""" """
return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()]) return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
def clear(self):
super(SortedDict, self).clear()
self.keyOrder = []
class MultiValueDictKeyError(KeyError): class MultiValueDictKeyError(KeyError):
pass pass

View File

@ -1,6 +1,10 @@
"Functions that help with dynamically creating decorators for views." "Functions that help with dynamically creating decorators for views."
import types import types
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
def decorator_from_middleware(middleware_class): def decorator_from_middleware(middleware_class):
""" """
@ -53,5 +57,5 @@ def decorator_from_middleware(middleware_class):
if result is not None: if result is not None:
return result return result
return response return response
return _wrapped_view return wraps(view_func)(_wrapped_view)
return _decorator_from_middleware return _decorator_from_middleware

View File

@ -1,8 +1,120 @@
# License for code in this file that was taken from Python 2.5.
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
# --------------------------------------------
#
# 1. This LICENSE AGREEMENT is between the Python Software Foundation
# ("PSF"), and the Individual or Organization ("Licensee") accessing and
# otherwise using this software ("Python") in source or binary form and
# its associated documentation.
#
# 2. Subject to the terms and conditions of this License Agreement, PSF
# hereby grants Licensee a nonexclusive, royalty-free, world-wide
# license to reproduce, analyze, test, perform and/or display publicly,
# prepare derivative works, distribute, and otherwise use Python
# alone or in any derivative version, provided, however, that PSF's
# License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
# 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
# All Rights Reserved" are retained in Python alone or in any derivative
# version prepared by Licensee.
#
# 3. In the event Licensee prepares a derivative work that is based on
# or incorporates Python or any part thereof, and wants to make
# the derivative work available to others as provided herein, then
# Licensee hereby agrees to include in any such work a brief summary of
# the changes made to Python.
#
# 4. PSF is making Python available to Licensee on an "AS IS"
# basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
# IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
# DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
# FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
# INFRINGE ANY THIRD PARTY RIGHTS.
#
# 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
# FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
# A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
# OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
#
# 6. This License Agreement will automatically terminate upon a material
# breach of its terms and conditions.
#
# 7. Nothing in this License Agreement shall be deemed to create any
# relationship of agency, partnership, or joint venture between PSF and
# Licensee. This License Agreement does not grant permission to use PSF
# trademarks or trade name in a trademark sense to endorse or promote
# products or services of Licensee, or any third party.
#
# 8. By copying, installing or otherwise using Python, Licensee
# agrees to be bound by the terms and conditions of this License
# Agreement.
def curry(_curried_func, *args, **kwargs): def curry(_curried_func, *args, **kwargs):
def _curried(*moreargs, **morekwargs): def _curried(*moreargs, **morekwargs):
return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
return _curried return _curried
### Begin from Python 2.5 functools.py ########################################
# Summary of changes made to the Python 2.5 code below:
# * swapped ``partial`` for ``curry`` to maintain backwards-compatibility
# in Django.
# * Wrapped the ``setattr`` call in ``update_wrapper`` with a try-except
# block to make it compatible with Python 2.3, which doesn't allow
# assigning to ``__name__``.
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation.
# All Rights Reserved.
###############################################################################
# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes off the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
try:
setattr(wrapper, attr, getattr(wrapped, attr))
except TypeError: # Python 2.3 doesn't allow assigning to __name__.
pass
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr))
# Return the wrapper so this can be used as a decorator via curry()
return wrapper
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Decorator factory to apply update_wrapper() to a wrapper function
Returns a decorator that invokes update_wrapper() with the decorated
function as the wrapper argument and the arguments to wraps() as the
remaining arguments. Default arguments are as for update_wrapper().
This is a convenience function to simplify applying curry() to
update_wrapper().
"""
return curry(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
### End from Python 2.5 functools.py ##########################################
def memoize(func, cache, num_args): def memoize(func, cache, num_args):
""" """
Wrap a function so that results for any argument tuple are stored in Wrap a function so that results for any argument tuple are stored in
@ -18,7 +130,7 @@ def memoize(func, cache, num_args):
result = func(*args) result = func(*args)
cache[mem_args] = result cache[mem_args] = result
return result return result
return wrapper return wraps(func)(wrapper)
class Promise(object): class Promise(object):
""" """
@ -110,7 +222,7 @@ def lazy(func, *resultclasses):
# Creates the proxy object, instead of the actual value. # Creates the proxy object, instead of the actual value.
return __proxy__(args, kw) return __proxy__(args, kw)
return __wrapper__ return wraps(func)(__wrapper__)
def allow_lazy(func, *resultclasses): def allow_lazy(func, *resultclasses):
""" """
@ -126,4 +238,4 @@ def allow_lazy(func, *resultclasses):
else: else:
return func(*args, **kwargs) return func(*args, **kwargs)
return lazy(func, *resultclasses)(*args, **kwargs) return lazy(func, *resultclasses)(*args, **kwargs)
return wrapper return wraps(func)(wrapper)

View File

@ -1,4 +1,4 @@
"Translation helper functions" """Translation helper functions."""
import locale import locale
import os import os
@ -7,7 +7,6 @@ import sys
import gettext as gettext_module import gettext as gettext_module
from cStringIO import StringIO from cStringIO import StringIO
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe, SafeData from django.utils.safestring import mark_safe, SafeData
try: try:
@ -30,7 +29,7 @@ _active = {}
# The default translation is based on the settings file. # The default translation is based on the settings file.
_default = None _default = None
# This is a cache for normalised accept-header languages to prevent multiple # This is a cache for normalized accept-header languages to prevent multiple
# file lookups when checking the same locale on repeated requests. # file lookups when checking the same locale on repeated requests.
_accepted = {} _accepted = {}
@ -56,7 +55,7 @@ def to_locale(language, to_lower=False):
return language.lower() return language.lower()
def to_language(locale): def to_language(locale):
"Turns a locale name (en_US) into a language name (en-us)." """Turns a locale name (en_US) into a language name (en-us)."""
p = locale.find('_') p = locale.find('_')
if p >= 0: if p >= 0:
return locale[:p].lower()+'-'+locale[p+1:].lower() return locale[:p].lower()+'-'+locale[p+1:].lower()
@ -229,7 +228,7 @@ def deactivate_all():
_active[currentThread()] = gettext_module.NullTranslations() _active[currentThread()] = gettext_module.NullTranslations()
def get_language(): def get_language():
"Returns the currently selected language." """Returns the currently selected language."""
t = _active.get(currentThread(), None) t = _active.get(currentThread(), None)
if t is not None: if t is not None:
try: try:
@ -251,7 +250,7 @@ def get_language_bidi():
def catalog(): def catalog():
""" """
This function returns the current active catalog for further processing. Returns the current active catalog for further processing.
This can be used if you need to modify the catalog or want to access the This can be used if you need to modify the catalog or want to access the
whole message catalog instead of just translating one string. whole message catalog instead of just translating one string.
""" """
@ -355,7 +354,7 @@ def get_language_from_request(request):
if lang_code in supported and lang_code is not None and check_for_language(lang_code): if lang_code in supported and lang_code is not None and check_for_language(lang_code):
return lang_code return lang_code
lang_code = request.COOKIES.get('django_language') lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
if lang_code and lang_code in supported and check_for_language(lang_code): if lang_code and lang_code in supported and check_for_language(lang_code):
return lang_code return lang_code
@ -374,7 +373,7 @@ def get_language_from_request(request):
normalized = locale.locale_alias.get(to_locale(accept_lang, True)) normalized = locale.locale_alias.get(to_locale(accept_lang, True))
if not normalized: if not normalized:
continue continue
# Remove the default encoding from locale_alias # Remove the default encoding from locale_alias.
normalized = normalized.split('.')[0] normalized = normalized.split('.')[0]
if normalized in _accepted: if normalized in _accepted:
@ -396,9 +395,9 @@ def get_language_from_request(request):
def get_date_formats(): def get_date_formats():
""" """
This function checks whether translation files provide a translation for some Checks whether translation files provide a translation for some technical
technical message ID to store date and time formats. If it doesn't contain message ID to store date and time formats. If it doesn't contain one, the
one, the formats provided in the settings will be used. formats provided in the settings will be used.
""" """
from django.conf import settings from django.conf import settings
date_format = ugettext('DATE_FORMAT') date_format = ugettext('DATE_FORMAT')
@ -414,9 +413,9 @@ def get_date_formats():
def get_partial_date_formats(): def get_partial_date_formats():
""" """
This function checks whether translation files provide a translation for some Checks whether translation files provide a translation for some technical
technical message ID to store partial date formats. If it doesn't contain message ID to store partial date formats. If it doesn't contain one, the
one, the formats provided in the settings will be used. formats provided in the settings will be used.
""" """
from django.conf import settings from django.conf import settings
year_month_format = ugettext('YEAR_MONTH_FORMAT') year_month_format = ugettext('YEAR_MONTH_FORMAT')
@ -440,6 +439,7 @@ block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""")
endblock_re = re.compile(r"""^\s*endblocktrans$""") endblock_re = re.compile(r"""^\s*endblocktrans$""")
plural_re = re.compile(r"""^\s*plural$""") plural_re = re.compile(r"""^\s*plural$""")
constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""") constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
def templatize(src): def templatize(src):
""" """
Turns a Django template into something that is understood by xgettext. It Turns a Django template into something that is understood by xgettext. It
@ -475,7 +475,7 @@ def templatize(src):
elif pluralmatch: elif pluralmatch:
inplural = True inplural = True
else: else:
raise SyntaxError, "Translation blocks must not include other block tags: %s" % t.contents raise SyntaxError("Translation blocks must not include other block tags: %s" % t.contents)
elif t.token_type == TOKEN_VAR: elif t.token_type == TOKEN_VAR:
if inplural: if inplural:
plural.append('%%(%s)s' % t.contents) plural.append('%%(%s)s' % t.contents)
@ -541,4 +541,3 @@ def parse_accept_lang_header(lang_string):
result.append((lang, priority)) result.append((lang, priority))
result.sort(lambda x, y: -cmp(x[1], y[1])) result.sort(lambda x, y: -cmp(x[1], y[1]))
return result return result

View File

@ -5,7 +5,11 @@ import time
from datetime import timedelta, tzinfo from datetime import timedelta, tzinfo
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
DEFAULT_ENCODING = locale.getdefaultlocale()[1] or 'ascii' try:
DEFAULT_ENCODING = locale.getdefaultlocale()[1] or 'ascii'
except:
# Any problems at all determining the locale and we fallback. See #5846.
DEFAULT_ENCODING = 'ascii'
class FixedOffset(tzinfo): class FixedOffset(tzinfo):
"Fixed offset in minutes east from UTC." "Fixed offset in minutes east from UTC."

View File

@ -11,6 +11,11 @@ Additionally, all headers from the response's Vary header will be taken into
account on caching -- just like the middleware does. account on caching -- just like the middleware does.
""" """
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.utils.decorators import decorator_from_middleware from django.utils.decorators import decorator_from_middleware
from django.utils.cache import patch_cache_control, add_never_cache_headers from django.utils.cache import patch_cache_control, add_never_cache_headers
from django.middleware.cache import CacheMiddleware from django.middleware.cache import CacheMiddleware
@ -26,7 +31,7 @@ def cache_control(**kwargs):
patch_cache_control(response, **kwargs) patch_cache_control(response, **kwargs)
return response return response
return _cache_controlled return wraps(viewfunc)(_cache_controlled)
return _cache_controller return _cache_controller
@ -39,4 +44,4 @@ def never_cache(view_func):
response = view_func(request, *args, **kwargs) response = view_func(request, *args, **kwargs)
add_never_cache_headers(response) add_never_cache_headers(response)
return response return response
return _wrapped_view_func return wraps(view_func)(_wrapped_view_func)

View File

@ -2,6 +2,11 @@
Decorators for views based on HTTP headers. Decorators for views based on HTTP headers.
""" """
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.utils.decorators import decorator_from_middleware from django.utils.decorators import decorator_from_middleware
from django.middleware.http import ConditionalGetMiddleware from django.middleware.http import ConditionalGetMiddleware
from django.http import HttpResponseNotAllowed from django.http import HttpResponseNotAllowed
@ -24,7 +29,7 @@ def require_http_methods(request_method_list):
if request.method not in request_method_list: if request.method not in request_method_list:
return HttpResponseNotAllowed(request_method_list) return HttpResponseNotAllowed(request_method_list)
return func(request, *args, **kwargs) return func(request, *args, **kwargs)
return inner return wraps(func)(inner)
return decorator return decorator
require_GET = require_http_methods(["GET"]) require_GET = require_http_methods(["GET"])

View File

@ -1,3 +1,8 @@
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
def vary_on_headers(*headers): def vary_on_headers(*headers):
@ -16,7 +21,7 @@ def vary_on_headers(*headers):
response = func(*args, **kwargs) response = func(*args, **kwargs)
patch_vary_headers(response, headers) patch_vary_headers(response, headers)
return response return response
return inner_func return wraps(func)(inner_func)
return decorator return decorator
def vary_on_cookie(func): def vary_on_cookie(func):
@ -32,4 +37,4 @@ def vary_on_cookie(func):
response = func(*args, **kwargs) response = func(*args, **kwargs)
patch_vary_headers(response, ('Cookie',)) patch_vary_headers(response, ('Cookie',))
return response return response
return inner_func return wraps(func)(inner_func)

View File

@ -28,7 +28,7 @@ def set_language(request):
if hasattr(request, 'session'): if hasattr(request, 'session'):
request.session['django_language'] = lang_code request.session['django_language'] = lang_code
else: else:
response.set_cookie('django_language', lang_code) response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
return response return response
NullSource = """ NullSource = """

View File

@ -83,12 +83,12 @@ Methods
objects in the same way as any other `Django model`_:: objects in the same way as any other `Django model`_::
myuser.groups = [group_list] myuser.groups = [group_list]
myuser.groups.add(group, group,...) myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group,...) myuser.groups.remove(group, group, ...)
myuser.groups.clear() myuser.groups.clear()
myuser.user_permissions = [permission_list] myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...) myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...] myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear() myuser.user_permissions.clear()
In addition to those automatic API methods, ``User`` objects have the following In addition to those automatic API methods, ``User`` objects have the following
@ -380,14 +380,14 @@ This example shows how you might use both ``authenticate()`` and ``login()``::
# Return an 'invalid login' error message. # Return an 'invalid login' error message.
.. admonition:: Calling ``authenticate()`` first .. admonition:: Calling ``authenticate()`` first
When you're manually logging a user in, you *must* call When you're manually logging a user in, you *must* call
``authenticate()`` before you call ``login()``. ``authenticate()`` ``authenticate()`` before you call ``login()``. ``authenticate()``
sets an attribute on the ``User`` noting which authentication sets an attribute on the ``User`` noting which authentication
backend successfully authenticated that user (see the `backends backend successfully authenticated that user (see the `backends
documentation`_ for details), and this information is needed later documentation`_ for details), and this information is needed later
during the login process. during the login process.
.. _backends documentation: #other-authentication-sources .. _backends documentation: #other-authentication-sources
Manually checking a user's password Manually checking a user's password
@ -460,7 +460,7 @@ introduced in Python 2.4::
In the Django development version, ``login_required`` also takes an optional In the Django development version, ``login_required`` also takes an optional
``redirect_field_name`` parameter. Example:: ``redirect_field_name`` parameter. Example::
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
def my_view(request): def my_view(request):
@ -468,7 +468,7 @@ In the Django development version, ``login_required`` also takes an optional
my_view = login_required(redirect_field_name='redirect_to')(my_view) my_view = login_required(redirect_field_name='redirect_to')(my_view)
Again, an equivalent example of the more compact decorator syntax introduced in Python 2.4:: Again, an equivalent example of the more compact decorator syntax introduced in Python 2.4::
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='redirect_to') @login_required(redirect_field_name='redirect_to')
@ -479,7 +479,7 @@ Again, an equivalent example of the more compact decorator syntax introduced in
* If the user isn't logged in, redirect to ``settings.LOGIN_URL`` * If the user isn't logged in, redirect to ``settings.LOGIN_URL``
(``/accounts/login/`` by default), passing the current absolute URL (``/accounts/login/`` by default), passing the current absolute URL
in the query string as ``next`` or the value of ``redirect_field_name``. in the query string as ``next`` or the value of ``redirect_field_name``.
For example: For example:
``/accounts/login/?next=/polls/3/``. ``/accounts/login/?next=/polls/3/``.
* If the user is logged in, execute the view normally. The view code is * If the user is logged in, execute the view normally. The view code is
@ -1119,7 +1119,7 @@ object the first time a user authenticates::
Handling authorization in custom backends Handling authorization in custom backends
----------------------------------------- -----------------------------------------
Custom auth backends can provide their own permissions. Custom auth backends can provide their own permissions.
The user model will delegate permission lookup functions The user model will delegate permission lookup functions
(``get_group_permissions()``, ``get_all_permissions()``, ``has_perm()``, and (``get_group_permissions()``, ``get_all_permissions()``, ``has_perm()``, and
@ -1132,9 +1132,9 @@ one backend grants.
The simple backend above could implement permissions for the magic admin fairly The simple backend above could implement permissions for the magic admin fairly
simply:: simply::
class SettingsBackend: class SettingsBackend:
# ... # ...
def has_perm(self, user_obj, perm): def has_perm(self, user_obj, perm):
@ -1142,7 +1142,7 @@ simply::
return True return True
else: else:
return False return False
This gives full permissions to the user granted access in the above example. Notice This gives full permissions to the user granted access in the above example. Notice
that the backend auth functions all take the user object as an argument, and that the backend auth functions all take the user object as an argument, and
they also accept the same arguments given to the associated ``User`` functions. they also accept the same arguments given to the associated ``User`` functions.

View File

@ -1605,8 +1605,7 @@ the cache of all one-to-many relationships ahead of time. Example::
print e.blog # Doesn't hit the database; uses cached version. print e.blog # Doesn't hit the database; uses cached version.
print e.blog # Doesn't hit the database; uses cached version. print e.blog # Doesn't hit the database; uses cached version.
``select_related()`` is documented in the "QuerySet methods that return new ``select_related()`` is documented in the `QuerySet methods that return new QuerySets`_ section above.
QuerySets" section above.
Backward Backward
~~~~~~~~ ~~~~~~~~

View File

@ -166,7 +166,7 @@ logical to us.
We're well aware that there are other awesome Web frameworks out there, and We're well aware that there are other awesome Web frameworks out there, and
we're not averse to borrowing ideas where appropriate. However, Django was we're not averse to borrowing ideas where appropriate. However, Django was
developed precisely because we were unhappy with the status quo, so please be developed precisely because we were unhappy with the status quo, so please be
aware that "because <Framework X>" does it is not going to be sufficient reason aware that "because <Framework X> does it" is not going to be sufficient reason
to add a given feature to Django. to add a given feature to Django.
Why did you write all of Django from scratch, instead of using other Python libraries? Why did you write all of Django from scratch, instead of using other Python libraries?
@ -353,7 +353,7 @@ How do I install mod_python on Windows?
working`_. working`_.
.. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24 .. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24
.. _`Django on Windows howto`: http://thinkhole.org/wp/2006/04/03/django-on-windows-howto/ .. _`Django on Windows howto`: http://thinkhole.org/wp/django-on-windows/
.. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f .. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html .. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html

View File

@ -24,11 +24,14 @@ Installation
To install the flatpages app, follow these steps: To install the flatpages app, follow these steps:
1. Add ``'django.contrib.flatpages'`` to your INSTALLED_APPS_ setting. 1. Install the `sites framework`_ by adding ``'django.contrib.sites'`` to
2. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'`` your INSTALLED_APPS_ setting, if it's not already in there.
2. Add ``'django.contrib.flatpages'`` to your INSTALLED_APPS_ setting.
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
to your MIDDLEWARE_CLASSES_ setting. to your MIDDLEWARE_CLASSES_ setting.
3. Run the command ``manage.py syncdb``. 4. Run the command ``manage.py syncdb``.
.. _sites framework: ../sites/
.. _INSTALLED_APPS: ../settings/#installed-apps .. _INSTALLED_APPS: ../settings/#installed-apps
.. _MIDDLEWARE_CLASSES: ../settings/#middleware-classes .. _MIDDLEWARE_CLASSES: ../settings/#middleware-classes

View File

@ -547,7 +547,7 @@ following this algorithm:
* First, it looks for a ``django_language`` key in the the current user's * First, it looks for a ``django_language`` key in the the current user's
`session`_. `session`_.
* Failing that, it looks for a cookie called ``django_language``. * Failing that, it looks for a cookie that is named according to your ``LANGUAGE_COOKIE_NAME`` setting (the default name is: ``django_language``).
* Failing that, it looks at the ``Accept-Language`` HTTP header. This * Failing that, it looks at the ``Accept-Language`` HTTP header. This
header is sent by your browser and tells the server which language(s) you header is sent by your browser and tells the server which language(s) you
prefer, in order by priority. Django tries each language in the header prefer, in order by priority. Django tries each language in the header
@ -719,7 +719,8 @@ Activate this view by adding the following line to your URLconf::
The view expects to be called via the ``POST`` method, with a ``language`` The view expects to be called via the ``POST`` method, with a ``language``
parameter set in request. If session support is enabled, the view parameter set in request. If session support is enabled, the view
saves the language choice in the user's session. Otherwise, it saves the saves the language choice in the user's session. Otherwise, it saves the
language choice in a ``django_language`` cookie. language choice in a cookie that is by default named ``django_language``
(the name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting).
After setting the language choice, Django redirects the user, following this After setting the language choice, Django redirects the user, following this
algorithm: algorithm:

View File

@ -784,9 +784,17 @@ you can use the name of the model, rather than the model object itself::
class Manufacturer(models.Model): class Manufacturer(models.Model):
# ... # ...
Note, however, that you can only use strings to refer to models in the same Note, however, that this only refers to models in the same models.py file -- you
models.py file -- you cannot use a string to reference a model in a different cannot use a string to reference a model defined in another application or
application, or to reference a model that has been imported from elsewhere. imported from elsewhere.
**New in Django development version:** to refer to models defined in another
application, you must instead explicitially specify the application label. That
is, if the ``Manufacturer`` model above is defined in another application called
``production``, you'd need to use::
class Car(models.Model):
manufacturer = models.ForeignKey('production.Manufacturer')
Behind the scenes, Django appends ``"_id"`` to the field name to create its Behind the scenes, Django appends ``"_id"`` to the field name to create its
database column name. In the above example, the database table for the ``Car`` database column name. In the above example, the database table for the ``Car``

View File

@ -226,7 +226,7 @@ For example::
# Create a form instance with POST data. # Create a form instance with POST data.
>>> a = Author() >>> a = Author()
>>> f = AuthorForm(a, request.POST) >>> f = AuthorForm(request.POST, instance=a)
# Create and save the new author instance. There's no need to do anything else. # Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save() >>> new_author = f.save()
@ -238,34 +238,34 @@ In some cases, you may not want all the model fields to appear on the generated
form. There are three ways of telling ``ModelForm`` to use only a subset of the form. There are three ways of telling ``ModelForm`` to use only a subset of the
model fields: model fields:
1. Set ``editable=False`` on the model field. As a result, *any* form 1. Set ``editable=False`` on the model field. As a result, *any* form
created from the model via ``ModelForm`` will not include that created from the model via ``ModelForm`` will not include that
field. field.
2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` class. 2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta``
This attribute, if given, should be a list of field names to include in class. This attribute, if given, should be a list of field names
the form. to include in the form.
3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` class. 3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta``
This attribute, if given, should be a list of field names to exclude class. This attribute, if given, should be a list of field names
the form. to exclude from the form.
For example, if you want a form for the ``Author`` model (defined above) For example, if you want a form for the ``Author`` model (defined
that includes only the ``name`` and ``title`` fields, you would specify above) that includes only the ``name`` and ``title`` fields, you would
``fields`` or ``exclude`` like this:: specify ``fields`` or ``exclude`` like this::
class PartialAuthorForm(ModelForm): class PartialAuthorForm(ModelForm):
class Meta: class Meta:
model = Author model = Author
fields = ('name', 'title') fields = ('name', 'title')
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
class PartialAuthorForm(ModelForm): Since the Author model has only 3 fields, 'name', 'title', and
class Meta: 'birth_date', the forms above will contain exactly the same fields.
model = Author
exclude = ('birth_date',)
Since the Author model has only 3 fields, 'name', 'title', and
'birth_date', the forms above will contain exactly the same fields.
.. note:: .. note::
@ -323,17 +323,18 @@ parameter when declaring the form field::
Form inheritance Form inheritance
---------------- ----------------
As with the basic forms, you can extend and reuse ``ModelForms`` by inheriting
them. Normally, this will be useful if you need to declare some extra fields As with basic forms, you can extend and reuse ``ModelForms`` by inheriting
or extra methods on a parent class for use in a number of forms derived from them. This is useful if you need to declare extra fields or extra methods on a
models. For example, using the previous ``ArticleForm`` class:: parent class for use in a number of forms derived from models. For example,
using the previous ``ArticleForm`` class::
>>> class EnhancedArticleForm(ArticleForm): >>> class EnhancedArticleForm(ArticleForm):
... def clean_pub_date(self): ... def clean_pub_date(self):
... ... ... ...
This creates a form that behaves identically to ``ArticleForm``, except there This creates a form that behaves identically to ``ArticleForm``, except there's
is some extra validation and cleaning for the ``pub_date`` field. some extra validation and cleaning for the ``pub_date`` field.
You can also subclass the parent's ``Meta`` inner class if you want to change You can also subclass the parent's ``Meta`` inner class if you want to change
the ``Meta.fields`` or ``Meta.excludes`` lists:: the ``Meta.fields`` or ``Meta.excludes`` lists::
@ -342,17 +343,18 @@ the ``Meta.fields`` or ``Meta.excludes`` lists::
... class Meta(ArticleForm.Meta): ... class Meta(ArticleForm.Meta):
... exclude = ['body'] ... exclude = ['body']
This adds in the extra method from the ``EnhancedArticleForm`` and modifies This adds the extra method from the ``EnhancedArticleForm`` and modifies
the original ``ArticleForm.Meta`` to remove one field. the original ``ArticleForm.Meta`` to remove one field.
There are a couple of things to note, however. Most of these won't normally be There are a couple of things to note, however.
of concern unless you are trying to do something tricky with subclassing.
* Normal Python name resolution rules apply. If you have multiple base * Normal Python name resolution rules apply. If you have multiple base
classes that declare a ``Meta`` inner class, only the first one will be classes that declare a ``Meta`` inner class, only the first one will be
used. This means the child's ``Meta``, if it exists, otherwise the used. This means the child's ``Meta``, if it exists, otherwise the
``Meta`` of the first parent, etc. ``Meta`` of the first parent, etc.
* For technical reasons, you cannot have a subclass that is inherited from * For technical reasons, a subclass cannot inherit from both a ``ModelForm``
both a ``ModelForm`` and a ``Form`` simultaneously. and a ``Form`` simultaneously.
Chances are these notes won't affect you unless you're trying to do something
tricky with subclassing.

View File

@ -246,6 +246,10 @@ object::
>>> f.cleaned_data >>> f.cleaned_data
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
.. note::
**New in Django development version** The ``cleaned_data`` attribute was
called ``clean_data`` in earlier releases.
Note that any text-based field -- such as ``CharField`` or ``EmailField`` -- Note that any text-based field -- such as ``CharField`` or ``EmailField`` --
always cleans the input into a Unicode string. We'll cover the encoding always cleans the input into a Unicode string. We'll cover the encoding
implications later in this document. implications later in this document.
@ -1563,7 +1567,7 @@ The three types of cleaning methods are:
Note that any errors raised by your ``Form.clean()`` override will not Note that any errors raised by your ``Form.clean()`` override will not
be associated with any field in particular. They go into a special be associated with any field in particular. They go into a special
"field" (called ``__all__``, which you can access via the "field" (called ``__all__``), which you can access via the
``non_field_errors()`` method if you need to. ``non_field_errors()`` method if you need to.
These methods are run in the order given above, one field at a time. That is, These methods are run in the order given above, one field at a time. That is,

View File

@ -576,7 +576,7 @@ Three things to note about 404 views:
in the 404. in the 404.
* The 404 view is passed a ``RequestContext`` and will have access to * The 404 view is passed a ``RequestContext`` and will have access to
variables supplied by your ``TEMPLATE_CONTEXT_PROCESSORS`` (e.g. variables supplied by your ``TEMPLATE_CONTEXT_PROCESSORS`` setting (e.g.,
``MEDIA_URL``). ``MEDIA_URL``).
* If ``DEBUG`` is set to ``True`` (in your settings module), then your 404 * If ``DEBUG`` is set to ``True`` (in your settings module), then your 404

View File

@ -88,7 +88,7 @@ something like::
for deserialized_object in serializers.deserialize("xml", data): for deserialized_object in serializers.deserialize("xml", data):
if object_should_be_saved(deserialized_object): if object_should_be_saved(deserialized_object):
obj.save() deserialized_object.save()
In other words, the usual use is to examine the deserialized objects to make In other words, the usual use is to examine the deserialized objects to make
sure that they are "appropriate" for saving before doing so. Of course, if you trust your data source you could just save the object and move on. sure that they are "appropriate" for saving before doing so. Of course, if you trust your data source you could just save the object and move on.

View File

@ -579,6 +579,16 @@ in standard language format. For example, U.S. English is ``"en-us"``. See the
.. _internationalization docs: ../i18n/ .. _internationalization docs: ../i18n/
LANGUAGE_COOKIE_NAME
--------------------
Default: ``'django_language'``
The name of the cookie to use for the language cookie. This can be whatever
you want (but should be different from SESSION_COOKIE_NAME). See the
`internationalization docs`_ for details.
LANGUAGES LANGUAGES
--------- ---------
@ -822,8 +832,8 @@ SESSION_COOKIE_NAME
Default: ``'sessionid'`` Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want. The name of the cookie to use for sessions. This can be whatever you want (but
See the `session docs`_. should be different from ``LANGUAGE_COOKIE_NAME``). See the `session docs`_.
SESSION_COOKIE_PATH SESSION_COOKIE_PATH
------------------- -------------------

View File

@ -30,9 +30,9 @@ Optional arguments
``context_instance`` ``context_instance``
The context instance to render the template with. By default, the template The context instance to render the template with. By default, the template
will be rendered with a ``Context`` instance (filled with values from will be rendered with a ``Context`` instance (filled with values from
``dictionary``). If you need to use `context processors`_, you will want to ``dictionary``). If you need to use `context processors`_, render the
render the template with a ``RequestContext`` instance instead. Your code template with a ``RequestContext`` instance instead. Your code might look
might look something like this:: something like this::
return render_to_response('my_template.html', return render_to_response('my_template.html',
my_data_dictionary, my_data_dictionary,

View File

@ -1406,6 +1406,8 @@ Joins a list with a string, like Python's ``str.join(list)``.
last last
~~~~ ~~~~
**New in Django development version.**
Returns the last item in a list. Returns the last item in a list.
length length

View File

@ -395,6 +395,8 @@ See the `internationalization docs`_ for more.
django.core.context_processors.media django.core.context_processors.media
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**New in Django development version**
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the ``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
value of the `MEDIA_URL setting`_. value of the `MEDIA_URL setting`_.
@ -627,9 +629,10 @@ the given Python module name, not the name of the app.
Once you've created that Python module, you'll just have to write a bit of Once you've created that Python module, you'll just have to write a bit of
Python code, depending on whether you're writing filters or tags. Python code, depending on whether you're writing filters or tags.
To be a valid tag library, the module contain a module-level variable named To be a valid tag library, the module must contain a module-level variable
``register`` that is a ``template.Library`` instance, in which all the tags and named ``register`` that is a ``template.Library`` instance, in which all the
filters are registered. So, near the top of your module, put the following:: tags and filters are registered. So, near the top of your module, put the
following::
from django import template from django import template
@ -981,7 +984,7 @@ Notes:
exception. It should fail silently, just as template filters should. exception. It should fail silently, just as template filters should.
Ultimately, this decoupling of compilation and rendering results in an Ultimately, this decoupling of compilation and rendering results in an
efficient template system, because a template can render multiple context efficient template system, because a template can render multiple contexts
without having to be parsed multiple times. without having to be parsed multiple times.
Auto-escaping considerations Auto-escaping considerations
@ -1014,7 +1017,7 @@ This is not a very common situation, but it's useful if you're rendering a
template yourself. For example:: template yourself. For example::
def render(self, context): def render(self, context):
t = template.load_template('small_fragment.html') t = template.loader.get_template('small_fragment.html')
return t.render(Context({'var': obj}, autoescape=context.autoescape)) return t.render(Context({'var': obj}, autoescape=context.autoescape))
If we had neglected to pass in the current ``context.autoescape`` value to our If we had neglected to pass in the current ``context.autoescape`` value to our

View File

@ -191,12 +191,12 @@ The remaining arguments should be tuples in this format::
`Passing extra options to view functions`_ below.) `Passing extra options to view functions`_ below.)
.. note:: .. note::
Since `patterns()` is a function call, it accepts a maximum of 255 Because `patterns()` is a function call, it accepts a maximum of 255
arguments (URL patterns, in this case). This is a limit for all Python arguments (URL patterns, in this case). This is a limit for all Python
function calls. This will rarely be problem in practice, since you'll function calls. This is rarely a problem in practice, because you'll
typically structure your URL patterns modularly by using `include()` typically structure your URL patterns modularly by using `include()`
sections. However, on the off-chance you do hit the 255-argument limit, sections. However, on the off-chance you do hit the 255-argument limit,
realise that `patterns()` returns a Python list, so you can split up the realize that `patterns()` returns a Python list, so you can split up the
construction of the list. construction of the list.
:: ::
@ -209,8 +209,8 @@ The remaining arguments should be tuples in this format::
) )
Python lists have unlimited size, so there's no limit to how many URL Python lists have unlimited size, so there's no limit to how many URL
patterns you can construct; merely that you may only create 254 at a time patterns you can construct. The only limit is that you can only create 254
(the 255-th argument is the initial prefix argument). at a time (the 255th argument is the initial prefix argument).
url url
--- ---

View File

@ -61,13 +61,13 @@ _django_completion()
|| ||
# python manage.py, /some/path/python manage.py (if manage.py exists) # python manage.py, /some/path/python manage.py (if manage.py exists)
( ${COMP_CWORD} -eq 2 && ( ${COMP_CWORD} -eq 2 &&
( $( basename ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) && ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
( $( basename ${COMP_WORDS[1]} ) == manage.py) && ( $( basename -- ${COMP_WORDS[1]} ) == manage.py) &&
( -r ${COMP_WORDS[1]} ) ) ( -r ${COMP_WORDS[1]} ) )
|| ||
( ${COMP_CWORD} -eq 2 && ( ${COMP_CWORD} -eq 2 &&
( $( basename ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) && ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
( $( basename ${COMP_WORDS[1]} ) == django-admin.py) && ( $( basename -- ${COMP_WORDS[1]} ) == django-admin.py) &&
( -r ${COMP_WORDS[1]} ) ) ]] ; then ( -r ${COMP_WORDS[1]} ) ) ]] ; then
case ${cur} in case ${cur} in
@ -149,7 +149,7 @@ unset pythons
if command -v whereis &>/dev/null; then if command -v whereis &>/dev/null; then
python_interpreters=$(whereis python | cut -d " " -f 2-) python_interpreters=$(whereis python | cut -d " " -f 2-)
for python in $python_interpreters; do for python in $python_interpreters; do
pythons="${pythons} $(basename $python)" pythons="${pythons} $(basename -- $python)"
done done
pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ") pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ")
else else

View File

@ -27,19 +27,16 @@ for scheme in INSTALL_SCHEMES.values():
# an easy way to do this. # an easy way to do this.
packages, data_files = [], [] packages, data_files = [], []
root_dir = os.path.dirname(__file__) root_dir = os.path.dirname(__file__)
django_dir = os.path.join(root_dir, 'django') if root_dir != '':
pieces = fullsplit(root_dir) os.chdir(root_dir)
if pieces[-1] == '': django_dir = 'django'
len_root_dir = len(pieces) - 1
else:
len_root_dir = len(pieces)
for dirpath, dirnames, filenames in os.walk(django_dir): for dirpath, dirnames, filenames in os.walk(django_dir):
# Ignore dirnames that start with '.' # Ignore dirnames that start with '.'
for i, dirname in enumerate(dirnames): for i, dirname in enumerate(dirnames):
if dirname.startswith('.'): del dirnames[i] if dirname.startswith('.'): del dirnames[i]
if '__init__.py' in filenames: if '__init__.py' in filenames:
packages.append('.'.join(fullsplit(dirpath)[len_root_dir:])) packages.append('.'.join(fullsplit(dirpath)))
elif filenames: elif filenames:
data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])

View File

@ -5,6 +5,11 @@
This is a basic model with only two non-primary-key fields. This is a basic model with only two non-primary-key fields.
""" """
try:
set
except NameError:
from sets import Set as set
from django.db import models from django.db import models
class Article(models.Model): class Article(models.Model):
@ -389,4 +394,10 @@ year, including Jan. 1 and Dec. 31.
>>> a.save() >>> a.save()
>>> Article.objects.get(pk=a.id).headline >>> Article.objects.get(pk=a.id).headline
u'\u6797\u539f \u3081\u3050\u307f' u'\u6797\u539f \u3081\u3050\u307f'
# Model instances have a hash function, so they can be used in sets or as
# dictionary keys. Two models compare as equal if their primary keys are equal.
>>> s = set([a10, a11, a12])
>>> Article.objects.get(headline='Article 11') in s
True
""" """

View File

@ -1,18 +1,22 @@
""" """
24. Mutually referential many-to-one relationships 24. Mutually referential many-to-one relationships
To define a many-to-one relationship, use ``ForeignKey()`` . Strings can be used instead of model literals to set up "lazy" relations.
""" """
from django.db.models import * from django.db.models import *
class Parent(Model): class Parent(Model):
name = CharField(max_length=100, core=True) name = CharField(max_length=100, core=True)
# Use a simple string for forward declarations.
bestchild = ForeignKey("Child", null=True, related_name="favoured_by") bestchild = ForeignKey("Child", null=True, related_name="favoured_by")
class Child(Model): class Child(Model):
name = CharField(max_length=100) name = CharField(max_length=100)
parent = ForeignKey(Parent)
# You can also explicitally specify the related app.
parent = ForeignKey("mutually_referential.Parent")
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
# Create a Parent # Create a Parent

View File

@ -77,6 +77,8 @@ MultiValueDictKeyError: "Key 'lastname' not found in <MultiValueDict: {'position
'not one' 'not one'
>>> d.keys() == d.copy().keys() >>> d.keys() == d.copy().keys()
True True
>>> d2 = d.copy()
>>> d2['four'] = 'four'
>>> print repr(d) >>> print repr(d)
{'one': 'not one', 'two': 'two', 'three': 'three'} {'one': 'not one', 'two': 'two', 'three': 'three'}
>>> d.pop('one', 'missing') >>> d.pop('one', 'missing')
@ -99,6 +101,12 @@ Init from sequence of tuples
>>> print repr(d) >>> print repr(d)
{1: 'one', 0: 'zero', 2: 'two'} {1: 'one', 0: 'zero', 2: 'two'}
>>> d.clear()
>>> d
{}
>>> d.keyOrder
[]
### DotExpandedDict ############################################################ ### DotExpandedDict ############################################################
>>> d = DotExpandedDict({'person.1.firstname': ['Simon'], 'person.1.lastname': ['Willison'], 'person.2.firstname': ['Adrian'], 'person.2.lastname': ['Holovaty']}) >>> d = DotExpandedDict({'person.1.firstname': ['Simon'], 'person.1.lastname': ['Willison'], 'person.2.firstname': ['Adrian'], 'person.2.lastname': ['Holovaty']})

View File

@ -56,4 +56,30 @@ datetime.date(1938, 6, 4)
datetime.time(5, 30) datetime.time(5, 30)
>>> d3.consumed_at >>> d3.consumed_at
datetime.datetime(2007, 4, 20, 16, 19, 59) datetime.datetime(2007, 4, 20, 16, 19, 59)
# Year boundary tests (ticket #3689)
>>> d = Donut(name='Date Test 2007', baked_date=datetime.datetime(year=2007, month=12, day=31), consumed_at=datetime.datetime(year=2007, month=12, day=31, hour=23, minute=59, second=59))
>>> d.save()
>>> d1 = Donut(name='Date Test 2006', baked_date=datetime.datetime(year=2006, month=1, day=1), consumed_at=datetime.datetime(year=2006, month=1, day=1))
>>> d1.save()
>>> Donut.objects.filter(baked_date__year=2007)
[<Donut: Date Test 2007>]
>>> Donut.objects.filter(baked_date__year=2006)
[<Donut: Date Test 2006>]
>>> Donut.objects.filter(consumed_at__year=2007).order_by('name')
[<Donut: Apple Fritter>, <Donut: Date Test 2007>]
>>> Donut.objects.filter(consumed_at__year=2006)
[<Donut: Date Test 2006>]
>>> Donut.objects.filter(consumed_at__year=2005)
[]
>>> Donut.objects.filter(consumed_at__year=2008)
[]
"""} """}

View File

@ -0,0 +1,2 @@
# A models.py so that tests run.

View File

@ -0,0 +1,56 @@
from unittest import TestCase
from sys import version_info
from django.http import HttpResponse
from django.utils.functional import allow_lazy, lazy, memoize
from django.views.decorators.http import require_http_methods, require_GET, require_POST
from django.views.decorators.vary import vary_on_headers, vary_on_cookie
from django.views.decorators.cache import cache_page, never_cache, cache_control
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.contrib.admin.views.decorators import staff_member_required
def fully_decorated(request):
"""Expected __doc__"""
return HttpResponse('<html><body>dummy</body></html>')
fully_decorated.anything = "Expected __dict__"
# django.views.decorators.http
fully_decorated = require_http_methods(["GET"])(fully_decorated)
fully_decorated = require_GET(fully_decorated)
fully_decorated = require_POST(fully_decorated)
# django.views.decorators.vary
fully_decorated = vary_on_headers('Accept-language')(fully_decorated)
fully_decorated = vary_on_cookie(fully_decorated)
# django.views.decorators.cache
fully_decorated = cache_page(60*15)(fully_decorated)
fully_decorated = cache_control(private=True)(fully_decorated)
fully_decorated = never_cache(fully_decorated)
# django.contrib.auth.decorators
fully_decorated = user_passes_test(lambda u:True)(fully_decorated)
fully_decorated = login_required(fully_decorated)
fully_decorated = permission_required('change_world')(fully_decorated)
# django.contrib.admin.views.decorators
fully_decorated = staff_member_required(fully_decorated)
# django.utils.functional
fully_decorated = memoize(fully_decorated, {}, 1)
fully_decorated = allow_lazy(fully_decorated)
fully_decorated = lazy(fully_decorated)
class DecoratorsTest(TestCase):
def test_attributes(self):
"""
Tests that django decorators set certain attributes of the wrapped
function.
"""
# Only check __name__ on Python 2.4 or later since __name__ can't be
# assigned to in earlier Python versions.
if version_info[0] >= 2 and version_info[1] >= 4:
self.assertEquals(fully_decorated.__name__, 'fully_decorated')
self.assertEquals(fully_decorated.__doc__, 'Expected __doc__')
self.assertEquals(fully_decorated.__dict__['anything'], 'Expected __dict__')

View File

@ -0,0 +1,9 @@
[
{
"pk": "1",
"model": "fixtures_regress.absolute",
"fields": {
"name": "Load Absolute Path Test"
}
}
]

View File

@ -1,6 +1,7 @@
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.conf import settings from django.conf import settings
import os
class Animal(models.Model): class Animal(models.Model):
name = models.CharField(max_length=150) name = models.CharField(max_length=150)
@ -28,6 +29,16 @@ class Stuff(models.Model):
name = None name = None
return unicode(name) + u' is owned by ' + unicode(self.owner) return unicode(name) + u' is owned by ' + unicode(self.owner)
class Absolute(models.Model):
name = models.CharField(max_length=40)
load_count = 0
def __init__(self, *args, **kwargs):
super(Absolute, self).__init__(*args, **kwargs)
Absolute.load_count += 1
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
>>> from django.core import management >>> from django.core import management
@ -49,4 +60,15 @@ __test__ = {'API_TESTS':"""
>>> Stuff.objects.all() >>> Stuff.objects.all()
[<Stuff: None is owned by None>] [<Stuff: None is owned by None>]
###############################################
# Regression test for ticket #6436 --
# os.path.join will throw away the initial parts of a path if it encounters
# an absolute path. This means that if a fixture is specified as an absolute path,
# we need to make sure we don't discover the absolute path in every fixture directory.
>>> load_absolute_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'absolute.json')
>>> management.call_command('loaddata', load_absolute_path, verbosity=0)
>>> Absolute.load_count
1
"""} """}

View File

@ -0,0 +1,3 @@
"""
Tests for Django's various Request objects.
"""

View File

@ -0,0 +1 @@
# Need a models module for the test runner.

View File

@ -0,0 +1,34 @@
"""
>>> from django.http import HttpRequest
>>> print repr(HttpRequest())
<HttpRequest
GET:{},
POST:{},
COOKIES:{},
META:{}>
>>> from django.core.handlers.wsgi import WSGIRequest
>>> print repr(WSGIRequest({'PATH_INFO': 'bogus', 'REQUEST_METHOD': 'bogus'}))
<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {}>,
COOKIES:{},
META:{...}>
>>> from django.core.handlers.modpython import ModPythonRequest
>>> class FakeModPythonRequest(ModPythonRequest):
... def __init__(self, *args, **kwargs):
... super(FakeModPythonRequest, self).__init__(*args, **kwargs)
... self._get = self._post = self._meta = self._cookies = {}
>>> class Dummy: pass
...
>>> req = Dummy()
>>> req.uri = 'bogus'
>>> print repr(FakeModPythonRequest(req))
<ModPythonRequest
path:bogus,
GET:{},
POST:{},
COOKIES:{},
META:{}>
"""

View File

@ -39,6 +39,7 @@ class Base(models.Model):
class Article(models.Model): class Article(models.Model):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
text = models.TextField() text = models.TextField()
submitted_from = models.IPAddressField(blank=True, null=True)
def __str__(self): def __str__(self):
return "Article %s" % self.name return "Article %s" % self.name
@ -98,4 +99,11 @@ __test__ = {'API_TESTS': ur"""
>>> Article.objects.get(text__contains='quick brown fox') >>> Article.objects.get(text__contains='quick brown fox')
<Article: Article Test> <Article: Article Test>
# Regression test for #708: "like" queries on IP address fields require casting
# to text (on PostgreSQL).
>>> Article(name='IP test', text='The body', submitted_from='192.0.2.100').save()
>>> Article.objects.filter(submitted_from__contains='192.0.2')
[<Article: Article IP test>]
"""} """}