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

newforms-admin: Merged changes from trunk up to [6863].

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6864 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2007-12-03 17:37:33 +00:00
parent 22aa9db4a2
commit c68f751f8c
96 changed files with 3135 additions and 1212 deletions

View File

@ -90,6 +90,7 @@ answer newbie questions, and generally made Django that much better:
Paul Collier <paul@paul-collier.com> Paul Collier <paul@paul-collier.com>
Pete Crosier <pete.crosier@gmail.com> Pete Crosier <pete.crosier@gmail.com>
Matt Croydon <http://www.postneo.com/> Matt Croydon <http://www.postneo.com/>
Leah Culver <leah@pownce.com>
flavio.curella@gmail.com flavio.curella@gmail.com
Jure Cuhalev <gandalf@owca.info> Jure Cuhalev <gandalf@owca.info>
John D'Agostino <john.dagostino@gmail.com> John D'Agostino <john.dagostino@gmail.com>
@ -133,6 +134,7 @@ answer newbie questions, and generally made Django that much better:
Jorge Gajon <gajon@gajon.org> Jorge Gajon <gajon@gajon.org>
gandalf@owca.info gandalf@owca.info
Marc Garcia <marc.garcia@accopensys.com> Marc Garcia <marc.garcia@accopensys.com>
Andy Gayton <andy-django@thecablelounge.com>
Baishampayan Ghose Baishampayan Ghose
Dimitris Glezos <dimitris@glezos.com> Dimitris Glezos <dimitris@glezos.com>
glin@seznam.cz glin@seznam.cz
@ -173,6 +175,7 @@ answer newbie questions, and generally made Django that much better:
junzhang.jn@gmail.com junzhang.jn@gmail.com
Antti Kaihola <http://akaihola.blogspot.com/> Antti Kaihola <http://akaihola.blogspot.com/>
Nagy Károly <charlie@rendszergazda.com> Nagy Károly <charlie@rendszergazda.com>
Erik Karulf <erik@karulf.com>
Ben Dean Kawamura <ben.dean.kawamura@gmail.com> Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
Ian G. Kelly <ian.g.kelly@gmail.com> Ian G. Kelly <ian.g.kelly@gmail.com>
Thomas Kerpe <thomas@kerpe.net> Thomas Kerpe <thomas@kerpe.net>
@ -192,6 +195,7 @@ answer newbie questions, and generally made Django that much better:
Joseph Kocherhans Joseph Kocherhans
konrad@gwu.edu konrad@gwu.edu
knox <christobzr@gmail.com> knox <christobzr@gmail.com>
David Krauth
kurtiss@meetro.com kurtiss@meetro.com
lakin.wecker@gmail.com lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com> Nick Lane <nick.lane.au@gmail.com>
@ -207,6 +211,7 @@ answer newbie questions, and generally made Django that much better:
limodou limodou
Philip Lindborg <philip.lindborg@gmail.com> Philip Lindborg <philip.lindborg@gmail.com>
Simon Litchfield <simon@quo.com.au> Simon Litchfield <simon@quo.com.au>
Trey Long <trey@ktrl.com>
msaelices <msaelices@gmail.com> msaelices <msaelices@gmail.com>
Matt McClanahan <http://mmcc.cx/> Matt McClanahan <http://mmcc.cx/>
Martin Maney <http://www.chipy.org/Martin_Maney> Martin Maney <http://www.chipy.org/Martin_Maney>
@ -256,6 +261,7 @@ answer newbie questions, and generally made Django that much better:
Gustavo Picon Gustavo Picon
Luke Plant <http://lukeplant.me.uk/> Luke Plant <http://lukeplant.me.uk/>
plisk plisk
Mihai Preda <mihai_preda@yahoo.com>
Daniel Poelzleithner <http://poelzi.org/> Daniel Poelzleithner <http://poelzi.org/>
polpak@yahoo.com polpak@yahoo.com
Matthias Pronk <django@masida.nl> Matthias Pronk <django@masida.nl>
@ -268,6 +274,7 @@ answer newbie questions, and generally made Django that much better:
Massimiliano Ravelli <massimiliano.ravelli@gmail.com> Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
Brian Ray <http://brianray.chipy.org/> Brian Ray <http://brianray.chipy.org/>
remco@diji.biz remco@diji.biz
David Reynolds <david@reynoldsfamily.org.uk>
rhettg@gmail.com rhettg@gmail.com
ricardojbarrios@gmail.com ricardojbarrios@gmail.com
Matt Riggott Matt Riggott
@ -287,6 +294,7 @@ answer newbie questions, and generally made Django that much better:
Pete Shinners <pete@shinners.org> Pete Shinners <pete@shinners.org>
jason.sidabras@gmail.com jason.sidabras@gmail.com
Jozko Skrablin <jozko.skrablin@gmail.com> Jozko Skrablin <jozko.skrablin@gmail.com>
Ben Slavin <benjamin.slavin@gmail.com>
SmileyChris <smileychris@gmail.com> SmileyChris <smileychris@gmail.com>
smurf@smurf.noris.de smurf@smurf.noris.de
Vsevolod Solovyov Vsevolod Solovyov

View File

@ -52,7 +52,7 @@ class LazySettings(object):
if not settings_module: # If it's set but is an empty string. if not settings_module: # If it's set but is an empty string.
raise KeyError raise KeyError
except KeyError: except KeyError:
raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE raise ImportError, "Environment variable %s is undefined so settings cannot be imported." % ENVIRONMENT_VARIABLE # NOTE: This is arguably an EnvironmentError, but that causes problems with Python's interactive help
self._target = Settings(settings_module) self._target = Settings(settings_module)
@ -63,7 +63,7 @@ class LazySettings(object):
argument must support attribute access (__getattr__)). argument must support attribute access (__getattr__)).
""" """
if self._target != None: if self._target != None:
raise EnvironmentError, 'Settings already configured.' raise RuntimeError, 'Settings already configured.'
holder = UserSettingsHolder(default_settings) holder = UserSettingsHolder(default_settings)
for name, value in options.items(): for name, value in options.items():
setattr(holder, name, value) setattr(holder, name, value)
@ -82,7 +82,7 @@ class Settings(object):
try: try:
mod = __import__(self.SETTINGS_MODULE, {}, {}, ['']) mod = __import__(self.SETTINGS_MODULE, {}, {}, [''])
except ImportError, e: except ImportError, e:
raise EnvironmentError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e) raise ImportError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e)
# Settings that should be converted into tuples if they're mistakenly entered # Settings that should be converted into tuples if they're mistakenly entered
# as strings. # as strings.

View File

@ -253,6 +253,10 @@ TRANSACTIONS_MANAGED = False
from django import get_version from django import get_version
URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version() URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version()
# The tablespaces to use for each model when not specified otherwise.
DEFAULT_TABLESPACE = ''
DEFAULT_INDEX_TABLESPACE = ''
############## ##############
# MIDDLEWARE # # MIDDLEWARE #
############## ##############
@ -289,7 +293,7 @@ SESSION_FILE_PATH = '/tmp/' # Directory to store ses
# The cache backend to use. See the docstring in django.core.cache for the # The cache backend to use. See the docstring in django.core.cache for the
# possible values. # possible values.
CACHE_BACKEND = 'simple://' CACHE_BACKEND = 'locmem://'
CACHE_MIDDLEWARE_KEY_PREFIX = '' CACHE_MIDDLEWARE_KEY_PREFIX = ''
CACHE_MIDDLEWARE_SECONDS = 600 CACHE_MIDDLEWARE_SECONDS = 600

View File

@ -1,19 +1,21 @@
# translation of djangojs.po to español
# translation of djangojs.po to # translation of djangojs.po to
# Catalan translation for the django-admin JS files. # Catalan translation for the django-admin JS files.
# This file is distributed under the same license as the Django package. # This file is distributed under the same license as the Django package.
# #
# Antoni Aloy <antoni.aloy@trespams.com>, 2007.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: djangojs\n" "Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-05-20 18:25+0200\n" "POT-Creation-Date: 2007-05-20 18:25+0200\n"
"PO-Revision-Date: 2007-06-25 17:47+0200\n" "PO-Revision-Date: 2007-12-01 12:06+0100\n"
"Last-Translator: Marc Fargas <telenieko@telenieko.com>\n" "Last-Translator: Antoni Aloy <antoni.aloy@trespams.com>\n"
"Language-Team: <es@li.org>\n" "Language-Team: español <ca@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: VIM 7.0\n" "X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: contrib/admin/media/js/SelectFilter2.js:33 #: contrib/admin/media/js/SelectFilter2.js:33
@ -51,8 +53,7 @@ msgstr "Deseleccionar tots"
msgid "" msgid ""
"January February March April May June July August September October November " "January February March April May June July August September October November "
"December" "December"
msgstr "" msgstr "Gener Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
"Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
#: contrib/admin/media/js/dateparse.js:33 #: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
@ -117,3 +118,4 @@ msgstr "Mostrar"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63 #: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide" msgid "Hide"
msgstr "Ocultar" msgstr "Ocultar"

View File

@ -0,0 +1,14 @@
"""
Mexican-specific form helpers.
"""
from django.newforms.fields import Select
class MXStateSelect(Select):
"""
A Select widget that uses a list of Mexican states as its choices.
"""
def __init__(self, attrs=None):
from mx_states import STATE_CHOICES
super(MXStateSelect, self).__init__(attrs, choices=STATE_CHOICES)

View File

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""
A list of Mexican states for use as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
from django.utils.translation import ugettext_lazy as _
STATE_CHOICES = (
('AGU', _(u'Aguascalientes')),
('BCN', _(u'Baja California')),
('BCS', _(u'Baja California Sur')),
('CAM', _(u'Campeche')),
('CHH', _(u'Chihuahua')),
('CHP', _(u'Chiapas')),
('COA', _(u'Coahuila')),
('COL', _(u'Colima')),
('DIF', _(u'Distrito Federal')),
('DUR', _(u'Durango')),
('GRO', _(u'Guerrero')),
('GUA', _(u'Guanajuato')),
('HID', _(u'Hidalgo')),
('JAL', _(u'Jalisco')),
('MEX', _(u'Estado de México')),
('MIC', _(u'Michoacán')),
('MOR', _(u'Morelos')),
('NAY', _(u'Nayarit')),
('NLE', _(u'Nuevo León')),
('OAX', _(u'Oaxaca')),
('PUE', _(u'Puebla')),
('QUE', _(u'Querétaro')),
('ROO', _(u'Quintana Roo')),
('SIN', _(u'Sinaloa')),
('SLP', _(u'San Luis Potosí')),
('SON', _(u'Sonora')),
('TAB', _(u'Tabasco')),
('TAM', _(u'Tamaulipas')),
('TLA', _(u'Tlaxcala')),
('VER', _(u'Veracruz')),
('YUC', _(u'Yucatán')),
('ZAC', _(u'Zacatecas')),
)

View File

@ -2,7 +2,7 @@
UK-specific Form helpers UK-specific Form helpers
""" """
from django.newforms.fields import RegexField from django.newforms.fields import RegexField, Select
from django.utils.translation import ugettext from django.utils.translation import ugettext
class UKPostcodeField(RegexField): class UKPostcodeField(RegexField):
@ -17,3 +17,19 @@ class UKPostcodeField(RegexField):
max_length=None, min_length=None, max_length=None, min_length=None,
error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'), error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
*args, **kwargs) *args, **kwargs)
class UKCountySelect(Select):
"""
A Select widget that uses a list of UK Counties/Regions as its choices.
"""
def __init__(self, attrs=None):
from uk_regions import UK_REGION_CHOICES
super(UKCountySelect, self).__init__(attrs, choices=UK_REGION_CHOICES)
class UKNationSelect(Select):
"""
A Select widget that uses a list of UK Nations as its choices.
"""
def __init__(self, attrs=None):
from uk_regions import UK_NATIONS_CHOICES
super(UKNationSelect, self).__init__(attrs, choices=UK_NATIONS_CHOICES)

View File

@ -0,0 +1,97 @@
"""
Sources:
English regions: http://www.statistics.gov.uk/geography/downloads/31_10_01_REGION_names_and_codes_12_00.xls
Northern Ireland regions: http://en.wikipedia.org/wiki/List_of_Irish_counties_by_area
Welsh regions: http://en.wikipedia.org/wiki/Preserved_counties_of_Wales
Scottish regions: http://en.wikipedia.org/wiki/Regions_and_districts_of_Scotland
"""
from django.utils.translation import ugettext as _
ENGLAND_REGION_CHOICES = (
("Bedfordshire", _("Bedfordshire")),
("Buckinghamshire", _("Buckinghamshire")),
("Cambridgeshire", ("Cambridgeshire")),
("Cheshire", _("Cheshire")),
("Cornwall and Isles of Scilly", _("Cornwall and Isles of Scilly")),
("Cumbria", _("Cumbria")),
("Derbyshire", _("Derbyshire")),
("Devon", _("Devon")),
("Dorset", _("Dorset")),
("Durham", _("Durham")),
("East Sussex", _("East Sussex")),
("Essex", _("Essex")),
("Gloucestershire", _("Gloucestershire")),
("Greater London", _("Greater London")),
("Greater Manchester", _("Greater Manchester")),
("Hampshire", _("Hampshire")),
("Hertfordshire", _("Hertfordshire")),
("Kent", _("Kent")),
("Lancashire", _("Lancashire")),
("Leicestershire", _("Leicestershire")),
("Lincolnshire", _("Lincolnshire")),
("Merseyside", _("Merseyside")),
("Norfolk", _("Norfolk")),
("North Yorkshire", _("North Yorkshire")),
("Northamptonshire", _("Northamptonshire")),
("Northumberland", _("Northumberland")),
("Nottinghamshire", _("Nottinghamshire")),
("Oxfordshire", _("Oxfordshire")),
("Shropshire", _("Shropshire")),
("Somerset", _("Somerset")),
("South Yorkshire", _("South Yorkshire")),
("Staffordshire", _("Staffordshire")),
("Suffolk", _("Suffolk")),
("Surrey", _("Surrey")),
("Tyne and Wear", _("Tyne and Wear")),
("Warwickshire", _("Warwickshire")),
("West Midlands", _("West Midlands")),
("West Sussex", _("West Sussex")),
("West Yorkshire", _("West Yorkshire")),
("Wiltshire", _("Wiltshire")),
("Worcestershire", _("Worcestershire")),
)
NORTHERN_IRELAND_REGION_CHOICES = (
("County Antrim", _("County Antrim")),
("County Armagh", _("County Armagh")),
("County Down", _("County Down")),
("County Fermanagh", _("County Down")),
("County Londonderry", _("County Londonderry")),
("County Tyrone", _("County Tyrone")),
)
WALES_REGION_CHOICES = (
("Clwyd", _("Clwyd")),
("Dyfed", _("Dyfed")),
("Gwent", _("Gwent")),
("Gwynedd", _("Gwynedd")),
("Mid Glamorgan", _("Mid Glamorgan")),
("Powys", _("Powys")),
("South Glamorgan", _("South Glamorgan")),
("West Glamorgan", _("West Glamorgan")),
)
SCOTTISH_REGION_CHOICES = (
("Borders", _("Borders")),
("Central Scotland", _("Central Scotland")),
("Dumfries and Galloway", _("Dumfries and Galloway")),
("Fife", _("Fife")),
("Grampian", _("Grampian")),
("Highland", _("Highland")),
("Lothian", _("Lothian")),
("Orkney Islands", _("Orkney Islands")),
("Shetland Islands", _("Shetland Islands")),
("Strathclyde", _("Strathclyde")),
("Tayside", _("Tayside")),
("Western Isles", _("Western Isles")),
)
UK_NATIONS_CHOICES = (
("England", _("England")),
("Northern Ireland", _("Northern Ireland")),
("Scotland", _("Scotland")),
("Wales", _("Wales")),
)
UK_REGION_CHOICES = ENGLAND_REGION_CHOICES + NORTHERN_IRELAND_REGION_CHOICES + WALES_REGION_CHOICES + SCOTTISH_REGION_CHOICES

View File

@ -0,0 +1,57 @@
"""
South Africa-specific Form helpers
"""
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, EMPTY_VALUES
from django.utils.checksums import luhn
from django.utils.translation import gettext as _
import re
from datetime import date
id_re = re.compile(r'^(?P<yy>\d\d)(?P<mm>\d\d)(?P<dd>\d\d)(?P<mid>\d{4})(?P<end>\d{3})')
class ZAIDField(Field):
"""A form field for South African ID numbers -- the checksum is validated
using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
check for the birthdate
"""
def __init__(self, *args, **kwargs):
super(ZAIDField, self).__init__()
self.error_message = _(u'Enter a valid South African ID number')
def clean(self, value):
# strip spaces and dashes
value = value.strip().replace(' ', '').replace('-', '')
super(ZAIDField, self).clean(value)
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
if not match:
raise ValidationError(self.error_message)
g = match.groupdict()
try:
# The year 2000 is conveniently a leapyear.
# This algorithm will break in xx00 years which aren't leap years
# There is no way to guess the century of a ZA ID number
d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
except ValueError:
raise ValidationError(self.error_message)
if not luhn(value):
raise ValidationError(self.error_message)
return value
class ZAPostCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(ZAPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
error_message=_(u'Enter a valid South African postal code'))

View File

@ -0,0 +1,13 @@
from django.utils.translation import gettext_lazy as _
PROVINCE_CHOICES = (
('EC', _('Eastern Cape')),
('FS', _('Free State')),
('GP', _('Gauteng')),
('KN', _('KwaZulu-Natal')),
('LP', _('Limpopo')),
('MP', _('Mpumalanga')),
('NC', _('Northern Cape')),
('NW', _('North West')),
('WC', _('Western Cape')),
)

View File

@ -32,7 +32,23 @@ def textile(value):
return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8'))) return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8')))
textile.is_safe = True textile.is_safe = True
def markdown(value): def markdown(value, arg=''):
"""
Runs Markdown over a given value, optionally using various
extensions python-markdown supports.
Syntax::
{{ value|markdown:"extension1_name,extension2_name..." }}
To enable safe mode, which strips raw HTML and only returns HTML
generated by actual Markdown syntax, pass "safe" as the first
extension in the list.
If the version of Markdown in use does not support extensions,
they will be silently ignored.
"""
try: try:
import markdown import markdown
except ImportError: except ImportError:
@ -40,7 +56,18 @@ def markdown(value):
raise template.TemplateSyntaxError, "Error in {% markdown %} filter: The Python markdown library isn't installed." raise template.TemplateSyntaxError, "Error in {% markdown %} filter: The Python markdown library isn't installed."
return force_unicode(value) return force_unicode(value)
else: else:
return mark_safe(force_unicode(markdown.markdown(smart_str(value)))) # markdown.version was first added in 1.6b. The only version of markdown
# to fully support extensions before 1.6b was the shortlived 1.6a.
if hasattr(markdown, 'version'):
extensions = [e for e in arg.split(",") if e]
if len(extensions) > 0 and extensions[0] == "safe":
extensions = extensions[1:]
safe_mode = True
else:
safe_mode = False
return mark_safe(force_unicode(markdown.markdown(smart_str(value), extensions, safe_mode=safe_mode)))
else:
return mark_safe(force_unicode(markdown.markdown(smart_str(value))))
markdown.is_safe = True markdown.is_safe = True
def restructuredtext(value): def restructuredtext(value):

View File

@ -61,8 +61,15 @@ Paragraph 2 with a link_
t = Template("{{ rest_content|restructuredtext }}") t = Template("{{ rest_content|restructuredtext }}")
rendered = t.render(Context(locals())).strip() rendered = t.render(Context(locals())).strip()
if docutils: if docutils:
self.assertEqual(rendered, """<p>Paragraph 1</p> # Different versions of docutils return slightly different HTML
try:
# Docutils v0.4 and earlier
self.assertEqual(rendered, """<p>Paragraph 1</p>
<p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""") <p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""")
except AssertionError, e:
# Docutils from SVN (which will become 0.5)
self.assertEqual(rendered, """<p>Paragraph 1</p>
<p>Paragraph 2 with a <a class="reference external" href="http://www.example.com/">link</a></p>""")
else: else:
self.assertEqual(rendered, rest_content) self.assertEqual(rendered, rest_content)

View File

@ -51,6 +51,14 @@ class SessionBase(object):
self.modified = self.modified or key in self._session self.modified = self.modified or key in self._session
return self._session.pop(key, *args) return self._session.pop(key, *args)
def setdefault(self, key, value):
if key in self._session:
return self._session[key]
else:
self.modified = True
self._session[key] = value
return value
def set_test_cookie(self): def set_test_cookie(self):
self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE

View File

@ -18,40 +18,6 @@ class SessionManager(models.Manager):
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest() pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5) return base64.encodestring(pickled + pickled_md5)
def get_new_session_key(self):
"Returns session key that isn't being used."
# The random module is seeded when this Apache child is created.
# Use SECRET_KEY as added salt.
try:
pid = os.getpid()
except AttributeError:
# No getpid() in Jython, for example
pid = 1
while 1:
session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), pid, time.time(), settings.SECRET_KEY)).hexdigest()
try:
self.get(session_key=session_key)
except self.model.DoesNotExist:
break
return session_key
def get_new_session_object(self):
"""
Returns a new session object.
"""
# FIXME: There is a *small* chance of collision here, meaning we will
# return an existing object. That can be fixed when we add a way to
# validate (and guarantee) that non-auto primary keys are unique. For
# now, we save immediately in order to reduce the "window of
# misfortune" as much as possible.
created = False
while not created:
obj, created = self.get_or_create(session_key=self.get_new_session_key(),
expire_date = datetime.datetime.now())
# Collision in key generation, so re-seed the generator
random.seed()
return obj
def save(self, session_key, session_dict, expire_date): def save(self, session_key, session_dict, expire_date):
s = self.model(session_key, self.encode(session_dict), expire_date) s = self.model(session_key, self.encode(session_dict), expire_date)
if session_dict: if session_dict:

View File

@ -66,6 +66,11 @@ False
>>> s.accessed, s.modified >>> s.accessed, s.modified
(True, False) (True, False)
>>> s.setdefault('foo', 'bar')
'bar'
>>> s.setdefault('foo', 'baz')
'bar'
>>> s.accessed = False # Reset the accessed flag >>> s.accessed = False # Reset the accessed flag
>>> s.pop('some key') >>> s.pop('some key')

View File

@ -22,19 +22,28 @@ from django.core.cache.backends.base import InvalidCacheBackendError
BACKENDS = { BACKENDS = {
# name for use in settings file --> name of module in "backends" directory # name for use in settings file --> name of module in "backends" directory
'memcached': 'memcached', 'memcached': 'memcached',
'simple': 'simple',
'locmem': 'locmem', 'locmem': 'locmem',
'file': 'filebased', 'file': 'filebased',
'db': 'db', 'db': 'db',
'dummy': 'dummy', 'dummy': 'dummy',
} }
DEPRECATED_BACKENDS = {
# deprecated backend --> replacement module
'simple': 'locmem',
}
def get_cache(backend_uri): def get_cache(backend_uri):
if backend_uri.find(':') == -1: if backend_uri.find(':') == -1:
raise InvalidCacheBackendError, "Backend URI must start with scheme://" raise InvalidCacheBackendError, "Backend URI must start with scheme://"
scheme, rest = backend_uri.split(':', 1) scheme, rest = backend_uri.split(':', 1)
if not rest.startswith('//'): if not rest.startswith('//'):
raise InvalidCacheBackendError, "Backend URI must start with scheme://" raise InvalidCacheBackendError, "Backend URI must start with scheme://"
if scheme in DEPRECATED_BACKENDS:
import warnings
warnings.warn("'%s' backend is deprecated. Use '%s' instead." %
(scheme, DEPRECATED_BACKENDS[scheme]), DeprecationWarning)
scheme = DEPRECATED_BACKENDS[scheme]
if scheme not in BACKENDS: if scheme not in BACKENDS:
raise InvalidCacheBackendError, "%r is not a valid cache backend" % scheme raise InvalidCacheBackendError, "%r is not a valid cache backend" % scheme

View File

@ -1,21 +1,32 @@
"File-based cache backend" "File-based cache backend"
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
from django.utils.http import urlquote_plus
import os, time import os, time
try: try:
import cPickle as pickle import cPickle as pickle
except ImportError: except ImportError:
import pickle import pickle
from django.core.cache.backends.base import BaseCache
from django.utils.http import urlquote_plus
class CacheClass(SimpleCacheClass): class CacheClass(BaseCache):
def __init__(self, dir, params): def __init__(self, dir, params):
BaseCache.__init__(self, params)
max_entries = params.get('max_entries', 300)
try:
self._max_entries = int(max_entries)
except (ValueError, TypeError):
self._max_entries = 300
cull_frequency = params.get('cull_frequency', 3)
try:
self._cull_frequency = int(cull_frequency)
except (ValueError, TypeError):
self._cull_frequency = 3
self._dir = dir self._dir = dir
if not os.path.exists(self._dir): if not os.path.exists(self._dir):
self._createdir() self._createdir()
SimpleCacheClass.__init__(self, dir, params)
del self._cache
del self._expire_info
def add(self, key, value, timeout=None): def add(self, key, value, timeout=None):
fname = self._key_to_file(key) fname = self._key_to_file(key)

View File

@ -6,20 +6,44 @@ try:
except ImportError: except ImportError:
import pickle import pickle
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass from django.core.cache.backends.base import BaseCache
from django.utils.synch import RWLock from django.utils.synch import RWLock
class CacheClass(SimpleCacheClass): class CacheClass(BaseCache):
def __init__(self, host, params): def __init__(self, _, params):
SimpleCacheClass.__init__(self, host, params) BaseCache.__init__(self, params)
self._cache = {}
self._expire_info = {}
max_entries = params.get('max_entries', 300)
try:
self._max_entries = int(max_entries)
except (ValueError, TypeError):
self._max_entries = 300
cull_frequency = params.get('cull_frequency', 3)
try:
self._cull_frequency = int(cull_frequency)
except (ValueError, TypeError):
self._cull_frequency = 3
self._lock = RWLock() self._lock = RWLock()
def _add(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries:
self._cull()
if timeout is None:
timeout = self.default_timeout
if key not in self._cache.keys():
self._cache[key] = value
self._expire_info[key] = time.time() + timeout
def add(self, key, value, timeout=None): def add(self, key, value, timeout=None):
self._lock.writer_enters() self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks. # Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try: try:
try: try:
super(CacheClass, self).add(key, pickle.dumps(value), timeout) self._add(key, pickle.dumps(value), timeout)
except pickle.PickleError: except pickle.PickleError:
pass pass
finally: finally:
@ -51,20 +75,50 @@ class CacheClass(SimpleCacheClass):
finally: finally:
self._lock.writer_leaves() self._lock.writer_leaves()
def _set(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries:
self._cull()
if timeout is None:
timeout = self.default_timeout
self._cache[key] = value
self._expire_info[key] = time.time() + timeout
def set(self, key, value, timeout=None): def set(self, key, value, timeout=None):
self._lock.writer_enters() self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks. # Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try: try:
try: try:
super(CacheClass, self).set(key, pickle.dumps(value), timeout) self._set(key, pickle.dumps(value), timeout)
except pickle.PickleError: except pickle.PickleError:
pass pass
finally: finally:
self._lock.writer_leaves() self._lock.writer_leaves()
def has_key(self, key):
return key in self._cache
def _cull(self):
if self._cull_frequency == 0:
self._cache.clear()
self._expire_info.clear()
else:
doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
for k in doomed:
self.delete(k)
def _delete(self, key):
try:
del self._cache[key]
except KeyError:
pass
try:
del self._expire_info[key]
except KeyError:
pass
def delete(self, key): def delete(self, key):
self._lock.writer_enters() self._lock.writer_enters()
try: try:
SimpleCacheClass.delete(self, key) self._delete(key)
finally: finally:
self._lock.writer_leaves() self._lock.writer_leaves()

View File

@ -1,73 +0,0 @@
"Single-process in-memory cache backend."
from django.core.cache.backends.base import BaseCache
import time
class CacheClass(BaseCache):
def __init__(self, host, params):
BaseCache.__init__(self, params)
self._cache = {}
self._expire_info = {}
max_entries = params.get('max_entries', 300)
try:
self._max_entries = int(max_entries)
except (ValueError, TypeError):
self._max_entries = 300
cull_frequency = params.get('cull_frequency', 3)
try:
self._cull_frequency = int(cull_frequency)
except (ValueError, TypeError):
self._cull_frequency = 3
def add(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries:
self._cull()
if timeout is None:
timeout = self.default_timeout
if key not in self._cache.keys():
self._cache[key] = value
self._expire_info[key] = time.time() + timeout
def get(self, key, default=None):
now = time.time()
exp = self._expire_info.get(key)
if exp is None:
return default
elif exp < now:
del self._cache[key]
del self._expire_info[key]
return default
else:
return self._cache[key]
def set(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries:
self._cull()
if timeout is None:
timeout = self.default_timeout
self._cache[key] = value
self._expire_info[key] = time.time() + timeout
def delete(self, key):
try:
del self._cache[key]
except KeyError:
pass
try:
del self._expire_info[key]
except KeyError:
pass
def has_key(self, key):
return key in self._cache
def _cull(self):
if self._cull_frequency == 0:
self._cache.clear()
self._expire_info.clear()
else:
doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
for k in doomed:
self.delete(k)

View File

@ -4,6 +4,10 @@ class ObjectDoesNotExist(Exception):
"The requested object does not exist" "The requested object does not exist"
silent_variable_failure = True silent_variable_failure = True
class MultipleObjectsReturned(Exception):
"The query returned multiple objects when only one was expected."
pass
class SuspiciousOperation(Exception): class SuspiciousOperation(Exception):
"The user did something suspicious" "The user did something suspicious"
pass pass

View File

@ -1,7 +1,8 @@
import sys
from django import http
from django.core import signals from django.core import signals
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django import http
import sys
class BaseHandler(object): class BaseHandler(object):
# Changes that are always applied to a response (in this order). # Changes that are always applied to a response (in this order).

View File

@ -1,11 +1,12 @@
from django.core.handlers.base import BaseHandler import os
from pprint import pformat
from django import http
from django.core import signals from django.core import signals
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
from django import http
from pprint import pformat
import os
# 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

View File

@ -5,12 +5,12 @@ try:
except ImportError: except ImportError:
from StringIO import StringIO from StringIO import StringIO
from django.core.handlers.base import BaseHandler from django import http
from django.core import signals from django.core import signals
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
from django import http
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
STATUS_CODE_TEXT = { STATUS_CODE_TEXT = {

View File

@ -84,7 +84,7 @@ def get_commands():
try: try:
from django.conf import settings from django.conf import settings
apps = settings.INSTALLED_APPS apps = settings.INSTALLED_APPS
except (AttributeError, EnvironmentError): except (AttributeError, ImportError):
apps = [] apps = []
for app_name in apps: for app_name in apps:
@ -99,7 +99,7 @@ def get_commands():
try: try:
from django.conf import settings from django.conf import settings
project_directory = setup_environ(__import__(settings.SETTINGS_MODULE)) project_directory = setup_environ(__import__(settings.SETTINGS_MODULE))
except (AttributeError, EnvironmentError, ImportError): except (AttributeError, ImportError):
project_directory = None project_directory = None
if project_directory: if project_directory:
@ -254,6 +254,8 @@ def setup_environ(settings_mod):
# way. For example, if this file (manage.py) lives in a directory # way. For example, if this file (manage.py) lives in a directory
# "myproject", this code would add "/path/to/myproject" to sys.path. # "myproject", this code would add "/path/to/myproject" to sys.path.
project_directory, settings_filename = os.path.split(settings_mod.__file__) project_directory, settings_filename = os.path.split(settings_mod.__file__)
if not project_directory:
project_directory = os.getcwd()
project_name = os.path.basename(project_directory) project_name = os.path.basename(project_directory)
settings_name = os.path.splitext(settings_filename)[0] settings_name = os.path.splitext(settings_filename)[0]
sys.path.append(os.path.join(project_directory, os.pardir)) sys.path.append(os.path.join(project_directory, os.pardir))

View File

@ -33,8 +33,9 @@ class Command(NoArgsCommand):
for app_name in settings.INSTALLED_APPS: for app_name in settings.INSTALLED_APPS:
try: try:
__import__(app_name + '.management', {}, {}, ['']) __import__(app_name + '.management', {}, {}, [''])
except ImportError: except ImportError, exc:
pass if not exc.args[0].startswith('No module named management'):
raise
cursor = connection.cursor() cursor = connection.cursor()

View File

@ -70,10 +70,14 @@ def get_validation_errors(outfile, app=None):
# Check to see if the related field will clash with any # Check to see if the related field will clash with any
# existing fields, m2m fields, m2m related objects or related objects # existing fields, m2m fields, m2m related objects or related objects
if f.rel: if f.rel:
rel_opts = f.rel.to._meta
if f.rel.to not in models.get_models(): if f.rel.to not in models.get_models():
e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name)) e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, f.rel.to))
# it is a string and we could not find the model it refers to
# so skip the next section
if isinstance(f.rel.to, (str, unicode)):
continue
rel_opts = f.rel.to._meta
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
rel_query_name = f.related_query_name() rel_query_name = f.related_query_name()
for r in rel_opts.fields: for r in rel_opts.fields:
@ -101,10 +105,14 @@ def get_validation_errors(outfile, app=None):
for i, f in enumerate(opts.many_to_many): for i, f in enumerate(opts.many_to_many):
# Check to see if the related m2m field will clash with any # Check to see if the related m2m field will clash with any
# existing fields, m2m fields, m2m related objects or related objects # existing fields, m2m fields, m2m related objects or related objects
rel_opts = f.rel.to._meta
if f.rel.to not in models.get_models(): if f.rel.to not in models.get_models():
e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name)) e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to))
# it is a string and we could not find the model it refers to
# so skip the next section
if isinstance(f.rel.to, (str, unicode)):
continue
rel_opts = f.rel.to._meta
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
rel_query_name = f.related_query_name() rel_query_name = f.related_query_name()
# If rel_name is none, there is no reverse accessor. # If rel_name is none, there is no reverse accessor.

View File

@ -47,7 +47,8 @@ class DatabaseOperations(BaseDatabaseOperations):
BEGIN BEGIN
SELECT %(sq_name)s.nextval SELECT %(sq_name)s.nextval
INTO :new.%(col_name)s FROM dual; INTO :new.%(col_name)s FROM dual;
END;/""" % locals() END;
/""" % locals()
return sequence_sql, trigger_sql return sequence_sql, trigger_sql
def date_extract_sql(self, lookup_type, field_name): def date_extract_sql(self, lookup_type, field_name):

View File

@ -6,6 +6,7 @@ Requires psycopg 2: http://initd.org/projects/psycopg2
from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures
from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
from django.utils.safestring import SafeUnicode
try: try:
import psycopg2 as Database import psycopg2 as Database
import psycopg2.extensions import psycopg2.extensions
@ -17,6 +18,7 @@ DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError IntegrityError = Database.IntegrityError
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
class DatabaseFeatures(BaseDatabaseFeatures): class DatabaseFeatures(BaseDatabaseFeatures):
needs_datetime_string_cast = False needs_datetime_string_cast = False

View File

@ -1,7 +1,7 @@
import django.db.models.manipulators import django.db.models.manipulators
import django.db.models.manager import django.db.models.manager
from django.core import validators from django.core import validators
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
from django.db.models.fields.related import OneToOneRel, ManyToOneRel from django.db.models.fields.related import OneToOneRel, ManyToOneRel
from django.db.models.query import delete_objects from django.db.models.query import delete_objects
@ -35,6 +35,8 @@ class ModelBase(type):
new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')})
new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) new_class.add_to_class('_meta', Options(attrs.pop('Meta', None)))
new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {}))
new_class.add_to_class('MultipleObjectsReturned',
types.ClassType('MultipleObjectsReturned', (MultipleObjectsReturned, ), {}))
# Build complete list of parents # Build complete list of parents
for base in bases: for base in bases:

View File

@ -102,7 +102,7 @@ class Field(object):
self.radio_admin = radio_admin self.radio_admin = radio_admin
self.help_text = help_text self.help_text = help_text
self.db_column = db_column self.db_column = db_column
self.db_tablespace = db_tablespace self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index. # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
self.db_index = db_index self.db_index = db_index

View File

@ -28,7 +28,7 @@ class Options(object):
self.object_name, self.app_label = None, None self.object_name, self.app_label = None, None
self.get_latest_by = None self.get_latest_by = None
self.order_with_respect_to = None self.order_with_respect_to = None
self.db_tablespace = None self.db_tablespace = settings.DEFAULT_TABLESPACE
self.admin = None self.admin = None
self.meta = meta self.meta = meta
self.pk = None self.pk = None
@ -151,7 +151,7 @@ class Options(object):
rel_objs = [] rel_objs = []
for klass in get_models(): for klass in get_models():
for f in klass._meta.fields: for f in klass._meta.fields:
if f.rel and self == f.rel.to._meta: if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
rel_objs.append(RelatedObject(f.rel.to, klass, f)) rel_objs.append(RelatedObject(f.rel.to, klass, f))
self._all_related_objects = rel_objs self._all_related_objects = rel_objs
return rel_objs return rel_objs
@ -185,7 +185,7 @@ class Options(object):
rel_objs = [] rel_objs = []
for klass in get_models(): for klass in get_models():
for f in klass._meta.many_to_many: for f in klass._meta.many_to_many:
if f.rel and self == f.rel.to._meta: if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
rel_objs.append(RelatedObject(f.rel.to, klass, f)) rel_objs.append(RelatedObject(f.rel.to, klass, f))
if app_cache_ready(): if app_cache_ready():
self._all_related_many_to_many_objects = rel_objs self._all_related_many_to_many_objects = rel_objs

View File

@ -261,7 +261,8 @@ class _QuerySet(object):
obj_list = list(clone) obj_list = list(clone)
if len(obj_list) < 1: if len(obj_list) < 1:
raise self.model.DoesNotExist, "%s matching query does not exist." % self.model._meta.object_name raise self.model.DoesNotExist, "%s matching query does not exist." % self.model._meta.object_name
assert len(obj_list) == 1, "get() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.model._meta.object_name, len(obj_list), kwargs) elif len(obj_list) > 1:
raise self.model.MultipleObjectsReturned, "get() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.model._meta.object_name, len(obj_list), kwargs)
return obj_list[0] return obj_list[0]
def create(self, **kwargs): def create(self, **kwargs):

View File

@ -5,7 +5,7 @@ Functions that modify an HTTP request or response in some way.
# This group of functions are run as part of the response handling, after # This group of functions are run as part of the response handling, after
# everything else, including all response middleware. Think of them as # everything else, including all response middleware. Think of them as
# "compulsory response middleware". Be careful about what goes here, because # "compulsory response middleware". Be careful about what goes here, because
# it's a little fiddly to override this behaviour, so they should be truly # it's a little fiddly to override this behavior, so they should be truly
# universally applicable. # universally applicable.
def fix_location_header(request, response): def fix_location_header(request, response):
@ -13,7 +13,7 @@ def fix_location_header(request, response):
Ensures that we always use an absolute URI in any location header in the Ensures that we always use an absolute URI in any location header in the
response. This is required by RFC 2616, section 14.30. response. This is required by RFC 2616, section 14.30.
Code constructing response objects is free to insert relative paths and Code constructing response objects is free to insert relative paths, as
this function converts them to absolute paths. this function converts them to absolute paths.
""" """
if 'Location' in response and request.get_host(): if 'Location' in response and request.get_host():
@ -31,4 +31,3 @@ def conditional_content_removal(request, response):
if request.method == 'HEAD': if request.method == 'HEAD':
response.content = '' response.content = ''
return response return response

View File

@ -5,6 +5,7 @@ from django.conf import settings
from django import http from django import http
from django.core.mail import mail_managers from django.core.mail import mail_managers
from django.utils.http import urlquote from django.utils.http import urlquote
from django.core import urlresolvers
class CommonMiddleware(object): class CommonMiddleware(object):
""" """
@ -16,6 +17,12 @@ class CommonMiddleware(object):
this middleware appends missing slashes and/or prepends missing this middleware appends missing slashes and/or prepends missing
"www."s. "www."s.
- If APPEND_SLASH is set and the initial URL doesn't end with a
slash, and it is not found in urlpatterns, a new URL is formed by
appending a slash at the end. If this new URL is found in
urlpatterns, then an HTTP-redirect is returned to this new URL;
otherwise the initial URL is processed as usual.
- ETags: If the USE_ETAGS setting is set, ETags will be calculated from - ETags: If the USE_ETAGS setting is set, ETags will be calculated from
the entire page content and Not Modified responses will be returned the entire page content and Not Modified responses will be returned
appropriately. appropriately.
@ -33,27 +40,48 @@ class CommonMiddleware(object):
if user_agent_regex.search(request.META['HTTP_USER_AGENT']): if user_agent_regex.search(request.META['HTTP_USER_AGENT']):
return http.HttpResponseForbidden('<h1>Forbidden</h1>') return http.HttpResponseForbidden('<h1>Forbidden</h1>')
# Check for a redirect based on settings.APPEND_SLASH and settings.PREPEND_WWW # Check for a redirect based on settings.APPEND_SLASH
# and settings.PREPEND_WWW
host = request.get_host() host = request.get_host()
old_url = [host, request.path] old_url = [host, request.path]
new_url = old_url[:] new_url = old_url[:]
if settings.PREPEND_WWW and old_url[0] and not old_url[0].startswith('www.'):
if (settings.PREPEND_WWW and old_url[0] and
not old_url[0].startswith('www.')):
new_url[0] = 'www.' + old_url[0] new_url[0] = 'www.' + old_url[0]
# Append a slash if append_slash is set and the URL doesn't have a
# trailing slash or a file extension. # Append a slash if APPEND_SLASH is set and the URL doesn't have a
if settings.APPEND_SLASH and (not old_url[1].endswith('/')) and ('.' not in old_url[1].split('/')[-1]): # trailing slash and there is no pattern for the current path
new_url[1] = new_url[1] + '/' if settings.APPEND_SLASH and (not old_url[1].endswith('/')):
if settings.DEBUG and request.method == 'POST': try:
raise RuntimeError, "You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to %s%s (note the trailing slash), or set APPEND_SLASH=False in your Django settings." % (new_url[0], new_url[1]) urlresolvers.resolve(request.path)
except urlresolvers.Resolver404:
new_url[1] = new_url[1] + '/'
if settings.DEBUG and request.method == 'POST':
raise RuntimeError, (""
"You called this URL via POST, but the URL doesn't end "
"in a slash and you have APPEND_SLASH set. Django can't "
"redirect to the slash URL while maintaining POST data. "
"Change your form to point to %s%s (note the trailing "
"slash), or set APPEND_SLASH=False in your Django "
"settings.") % (new_url[0], new_url[1])
if new_url != old_url: if new_url != old_url:
# Redirect # Redirect if the target url exists
if new_url[0]: try:
newurl = "%s://%s%s" % (request.is_secure() and 'https' or 'http', new_url[0], urlquote(new_url[1])) urlresolvers.resolve(new_url[1])
except urlresolvers.Resolver404:
pass
else: else:
newurl = urlquote(new_url[1]) if new_url[0]:
if request.GET: newurl = "%s://%s%s" % (
newurl += '?' + request.GET.urlencode() request.is_secure() and 'https' or 'http',
return http.HttpResponsePermanentRedirect(newurl) new_url[0], urlquote(new_url[1]))
else:
newurl = urlquote(new_url[1])
if request.GET:
newurl += '?' + request.GET.urlencode()
return http.HttpResponsePermanentRedirect(newurl)
return None return None

View File

@ -83,21 +83,15 @@ class Field(object):
self.creation_counter = Field.creation_counter self.creation_counter = Field.creation_counter
Field.creation_counter += 1 Field.creation_counter += 1
self.error_messages = self._build_error_messages(error_messages) def set_class_error_messages(messages, klass):
def _build_error_messages(self, extra_error_messages):
error_messages = {}
def get_default_error_messages(klass):
for base_class in klass.__bases__: for base_class in klass.__bases__:
get_default_error_messages(base_class) set_class_error_messages(messages, base_class)
if hasattr(klass, 'default_error_messages'): messages.update(getattr(klass, 'default_error_messages', {}))
error_messages.update(klass.default_error_messages)
get_default_error_messages(self.__class__) messages = {}
if extra_error_messages: set_class_error_messages(messages, self.__class__)
error_messages.update(extra_error_messages) messages.update(error_messages or {})
return error_messages self.error_messages = messages
def clean(self, value): def clean(self, value):
""" """
@ -415,7 +409,7 @@ class EmailField(RegexField):
try: try:
from django.conf import settings from django.conf import settings
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
except (ImportError, EnvironmentError): except ImportError:
# It's OK if Django settings aren't configured. # It's OK if Django settings aren't configured.
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'

View File

@ -3,17 +3,21 @@ Helper functions for creating Form classes from Django models
and database field objects. and database field objects.
""" """
from warnings import warn
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
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from django.core.exceptions import ImproperlyConfigured
from util import ValidationError from util import ValidationError, ErrorList
from forms import BaseForm from forms import BaseForm
from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES
from formsets import BaseFormSet, formset_for_form, DELETION_FIELD_NAME from formsets import BaseFormSet, formset_for_form, DELETION_FIELD_NAME
from widgets import Select, SelectMultiple, HiddenInput, MultipleHiddenInput from widgets import Select, SelectMultiple, HiddenInput, MultipleHiddenInput
__all__ = ( __all__ = (
'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields', 'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
'formset_for_model', 'inline_formset', 'formset_for_model', 'inline_formset',
'ModelChoiceField', 'ModelMultipleChoiceField', 'ModelChoiceField', 'ModelMultipleChoiceField',
@ -82,6 +86,9 @@ def form_for_model(model, form=BaseForm, fields=None,
determining the formfield for a given database field. It's a callable that determining the formfield for a given database field. It's a callable that
takes a database Field instance and returns a form Field instance. takes a database Field instance and returns a form Field instance.
""" """
warn("form_for_model is deprecated, use ModelForm instead.",
PendingDeprecationWarning,
stacklevel=3)
opts = model._meta opts = model._meta
field_list = [] field_list = []
for f in opts.fields + opts.many_to_many: for f in opts.fields + opts.many_to_many:
@ -109,6 +116,9 @@ def form_for_instance(instance, form=BaseForm, fields=None,
takes a database Field instance, plus **kwargs, and returns a form Field takes a database Field instance, plus **kwargs, and returns a form Field
instance with the given kwargs (i.e. 'initial'). instance with the given kwargs (i.e. 'initial').
""" """
warn("form_for_instance is deprecated, use ModelForm instead.",
PendingDeprecationWarning,
stacklevel=3)
model = instance.__class__ model = instance.__class__
opts = model._meta opts = model._meta
field_list = [] field_list = []
@ -134,6 +144,155 @@ def form_for_fields(field_list):
for f in field_list if f.editable]) for f in field_list if f.editable])
return type('FormForFields', (BaseForm,), {'base_fields': fields}) return type('FormForFields', (BaseForm,), {'base_fields': fields})
# ModelForms #################################################################
def model_to_dict(instance, fields=None, exclude=None):
"""
Returns a dict containing the data in ``instance`` suitable for passing as
a Form's ``initial`` keyword argument.
``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned dict.
``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned dict, even if they are listed in
the ``fields`` argument.
"""
# avoid a circular import
from django.db.models.fields.related import ManyToManyField
opts = instance._meta
data = {}
for f in opts.fields + opts.many_to_many:
if not f.editable:
continue
if fields and not f.name in fields:
continue
if exclude and f.name in exclude:
continue
if isinstance(f, ManyToManyField):
# If the object doesn't have a primry key yet, just use an empty
# list for its m2m fields. Calling f.value_from_object will raise
# an exception.
if instance.pk is None:
data[f.name] = []
else:
# MultipleChoiceWidget needs a list of pks, not object instances.
data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
else:
data[f.name] = f.value_from_object(instance)
return data
def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
"""
Returns a ``SortedDict`` containing form fields for the given model.
``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned fields.
``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned fields, even if they are listed
in the ``fields`` argument.
"""
# TODO: if fields is provided, it would be nice to return fields in that order
field_list = []
opts = model._meta
for f in opts.fields + opts.many_to_many:
if not f.editable:
continue
if fields and not f.name in fields:
continue
if exclude and f.name in exclude:
continue
formfield = formfield_callback(f)
if formfield:
field_list.append((f.name, formfield))
return SortedDict(field_list)
class ModelFormOptions(object):
def __init__(self, options=None):
self.model = getattr(options, 'model', None)
self.fields = getattr(options, 'fields', None)
self.exclude = getattr(options, 'exclude', None)
class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs):
# TODO: no way to specify formfield_callback yet, do we need one, or
# should it be a special case for the admin?
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
# If this class is subclassing another Form, add that Form's fields.
# Note that we loop over the bases in *reverse*. This is necessary in
# order to preserve the correct order of fields.
for base in bases[::-1]:
if hasattr(base, 'base_fields'):
fields = base.base_fields.items() + fields
declared_fields = SortedDict(fields)
opts = ModelFormOptions(attrs.get('Meta', None))
attrs['_meta'] = opts
# Don't allow more than one Meta model defenition in bases. The fields
# would be generated correctly, but the save method won't deal with
# more than one object.
base_models = []
for base in bases:
base_opts = getattr(base, '_meta', None)
base_model = getattr(base_opts, 'model', None)
if base_model is not None:
base_models.append(base_model)
if len(base_models) > 1:
raise ImproperlyConfigured("%s's base classes define more than one model." % name)
# If a model is defined, extract form fields from it and add them to base_fields
if attrs['_meta'].model is not None:
# Don't allow a subclass to define a Meta model if a parent class has.
# Technically the right fields would be generated, but the save
# method will not deal with more than one model.
for base in bases:
base_opts = getattr(base, '_meta', None)
base_model = getattr(base_opts, 'model', None)
if base_model is not None:
raise ImproperlyConfigured('%s defines more than one model.' % name)
model_fields = fields_for_model(opts.model, opts.fields, opts.exclude)
# fields declared in base classes override fields from the model
model_fields.update(declared_fields)
attrs['base_fields'] = model_fields
else:
attrs['base_fields'] = declared_fields
return type.__new__(cls, name, bases, attrs)
class BaseModelForm(BaseForm):
def __init__(self, instance, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=':'):
self.instance = instance
opts = self._meta
object_data = model_to_dict(instance, opts.fields, opts.exclude)
# if initial was provided, it should override the values from instance
if initial is not None:
object_data.update(initial)
BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)
def save(self, commit=True):
"""
Saves this ``form``'s cleaned_data into model instance ``self.instance``.
If commit=True, then the changes to ``instance`` will be saved to the
database. Returns ``instance``.
"""
if self.instance.pk is None:
fail_message = 'created'
else:
fail_message = 'changed'
return save_instance(self, self.instance, self._meta.fields, fail_message, commit)
class ModelForm(BaseModelForm):
__metaclass__ = ModelFormMetaclass
# Fields #####################################################################
class QuerySetIterator(object): class QuerySetIterator(object):
def __init__(self, queryset, empty_label, cache_choices): def __init__(self, queryset, empty_label, cache_choices):
self.queryset = queryset self.queryset = queryset

View File

@ -38,7 +38,7 @@ def get_object_or_404(klass, *args, **kwargs):
klass may be a Model, Manager, or QuerySet object. All other passed klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the get() query. arguments and keyword arguments are used in the get() query.
Note: Like with get(), an AssertionError will be raised if more than one Note: Like with get(), an MultipleObjectsReturned will be raised if more than one
object is found. object is found.
""" """
queryset = _get_queryset(klass) queryset = _get_queryset(klass)

View File

@ -23,12 +23,14 @@ class Context(object):
yield d yield d
def push(self): def push(self):
self.dicts = [{}] + self.dicts d = {}
self.dicts = [d] + self.dicts
return d
def pop(self): def pop(self):
if len(self.dicts) == 1: if len(self.dicts) == 1:
raise ContextPopException raise ContextPopException
del self.dicts[0] return self.dicts.pop(0)
def __setitem__(self, key, value): def __setitem__(self, key, value):
"Set a variable in the current context" "Set a variable in the current context"
@ -62,6 +64,7 @@ class Context(object):
def update(self, other_dict): def update(self, other_dict):
"Like dict.update(). Pushes an entire dictionary's keys and values onto the context." "Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
self.dicts = [other_dict] + self.dicts self.dicts = [other_dict] + self.dicts
return other_dict
# This is a function rather than module-level procedural code because we only # This is a function rather than module-level procedural code because we only
# want it to execute if somebody uses RequestContext. # want it to execute if somebody uses RequestContext.

View File

@ -696,7 +696,7 @@ filesizeformat.is_safe = True
def pluralize(value, arg=u's'): def pluralize(value, arg=u's'):
""" """
Returns a plural suffix if the value is not 1. By default, 's' is used as Returns a plural suffix if the value is not 1. By default, 's' is used as
the suffix: the suffix:
* If value is 0, vote{{ value|pluralize }} displays "0 votes". * If value is 0, vote{{ value|pluralize }} displays "0 votes".

View File

@ -354,8 +354,19 @@ class _OutputRedirectingPdb(pdb.Pdb):
""" """
def __init__(self, out): def __init__(self, out):
self.__out = out self.__out = out
self.__debugger_used = False
pdb.Pdb.__init__(self) pdb.Pdb.__init__(self)
def set_trace(self):
self.__debugger_used = True
pdb.Pdb.set_trace(self)
def set_continue(self):
# Calling set_continue unconditionally would break unit test coverage
# reporting, as Bdb.set_continue calls sys.settrace(None).
if self.__debugger_used:
pdb.Pdb.set_continue(self)
def trace_dispatch(self, *args): def trace_dispatch(self, *args):
# Redirect stdout to the given stream. # Redirect stdout to the given stream.
save_stdout = sys.stdout save_stdout = sys.stdout

View File

@ -1,6 +1,6 @@
class MergeDict(object): class MergeDict(object):
""" """
A simple class for creating new "virtual" dictionaries that actualy 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.
""" """
def __init__(self, *dicts): def __init__(self, *dicts):
@ -215,7 +215,7 @@ class MultiValueDict(dict):
def get(self, key, default=None): def get(self, key, default=None):
""" """
Returns the last data value for the passed key. If key doesn't exist Returns the last data value for the passed key. If key doesn't exist
or value is an empty list, then default is returned. or value is an empty list, then default is returned.
""" """
try: try:
@ -228,7 +228,7 @@ class MultiValueDict(dict):
def getlist(self, key): def getlist(self, key):
""" """
Returns the list of values for the passed key. If key doesn't exist, Returns the list of values for the passed key. If key doesn't exist,
then an empty list is returned. then an empty list is returned.
""" """
try: try:

View File

@ -100,7 +100,7 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
if safe_input: if safe_input:
middle = mark_safe(middle) middle = mark_safe(middle)
if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \ if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \
len(middle) > 0 and middle[0] in string.letters + string.digits and \ len(middle) > 0 and middle[0] in string.ascii_letters + string.digits and \
(middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))): (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
middle = '<a href="http://%s"%s>%s</a>' % ( middle = '<a href="http://%s"%s>%s</a>' % (
urlquote(middle, safe='/&=:;#?+'), nofollow_attr, urlquote(middle, safe='/&=:;#?+'), nofollow_attr,

View File

@ -21,7 +21,7 @@ def legacy_maxlength(max_length, maxlength):
""" """
if maxlength is not None: if maxlength is not None:
warn("maxlength is deprecated, use max_length instead.", warn("maxlength is deprecated, use max_length instead.",
PendingDeprecationWarning, DeprecationWarning,
stacklevel=3) stacklevel=3)
if max_length is not None: if max_length is not None:
raise TypeError("field can not take both the max_length" raise TypeError("field can not take both the max_length"

View File

@ -34,15 +34,12 @@ class SafeString(str, SafeData):
Concatenating a safe string with another safe string or safe unicode Concatenating a safe string with another safe string or safe unicode
object is safe. Otherwise, the result is no longer safe. object is safe. Otherwise, the result is no longer safe.
""" """
t = super(SafeString, self).__add__(rhs)
if isinstance(rhs, SafeUnicode): if isinstance(rhs, SafeUnicode):
return SafeUnicode(self + rhs) return SafeUnicode(t)
elif isinstance(rhs, SafeString): elif isinstance(rhs, SafeString):
return SafeString(self + rhs) return SafeString(t)
else: return t
return super(SafeString, self).__add__(rhs)
def __str__(self):
return self
def _proxy_method(self, *args, **kwargs): def _proxy_method(self, *args, **kwargs):
""" """
@ -69,10 +66,10 @@ class SafeUnicode(unicode, SafeData):
Concatenating a safe unicode object with another safe string or safe Concatenating a safe unicode object with another safe string or safe
unicode object is safe. Otherwise, the result is no longer safe. unicode object is safe. Otherwise, the result is no longer safe.
""" """
t = super(SafeUnicode, self).__add__(rhs)
if isinstance(rhs, SafeData): if isinstance(rhs, SafeData):
return SafeUnicode(self + rhs) return SafeUnicode(t)
else: return t
return super(SafeUnicode, self).__add__(rhs)
def _proxy_method(self, *args, **kwargs): def _proxy_method(self, *args, **kwargs):
""" """

View File

@ -131,7 +131,7 @@ def technical_500_response(request, exc_type, exc_value, tb):
if start is not None and end is not None: if start is not None and end is not None:
unicode_str = exc_value.args[1] unicode_str = exc_value.args[1]
unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace')
from django import get_version
t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template')
c = Context({ c = Context({
'exception_type': exc_type.__name__, 'exception_type': exc_type.__name__,
@ -144,6 +144,7 @@ def technical_500_response(request, exc_type, exc_value, tb):
'settings': get_safe_settings(), 'settings': get_safe_settings(),
'sys_executable' : sys.executable, 'sys_executable' : sys.executable,
'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3], 'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3],
'django_version_info' : get_version(),
'template_info': template_info, 'template_info': template_info,
'template_does_not_exist': template_does_not_exist, 'template_does_not_exist': template_does_not_exist,
'loader_debug_info': loader_debug_info, 'loader_debug_info': loader_debug_info,
@ -275,6 +276,8 @@ TECHNICAL_500_TEMPLATE = """
#requestinfo h3 { margin-bottom:-1em; } #requestinfo h3 { margin-bottom:-1em; }
.error { background: #ffc; } .error { background: #ffc; }
.specific { color:#cc3300; font-weight:bold; } .specific { color:#cc3300; font-weight:bold; }
h2 span.commands { font-size:.7em;}
span.commands a:link {color:#5E5694;}
</style> </style>
<script type="text/javascript"> <script type="text/javascript">
//<!-- //<!--
@ -409,9 +412,7 @@ TECHNICAL_500_TEMPLATE = """
</div> </div>
{% endif %} {% endif %}
<div id="traceback"> <div id="traceback">
<h2>Traceback <span>(innermost last)</span></h2> <h2>Traceback <span class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></span></h2>
<div class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></div>
<br/>
{% autoescape off %} {% autoescape off %}
<div id="browserTraceback"> <div id="browserTraceback">
<ul class="traceback"> <ul class="traceback">
@ -456,27 +457,51 @@ TECHNICAL_500_TEMPLATE = """
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<div id="pastebinTraceback" class="pastebin">
<table>
<tbody>
<tr>
<td>
<code>
Traceback (most recent call last):<br/>
{% for frame in frames %}
File "{{ frame.filename }}" in {{ frame.function }}<br/>
{% if frame.context_line %}
&nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line|escape }}<br/>
{% endif %}
{% endfor %}<br/>
&nbsp;&nbsp;{{ exception_type }} at {{ request.path|escape }}<br/>
&nbsp;&nbsp;{{ exception_value|escape }}</code>
</td>
</tr>
</tbody>
</table>
</div>
{% endautoescape %} {% endautoescape %}
<form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post">
<div id="pastebinTraceback" class="pastebin">
<input type="hidden" name="language" value="PythonConsole" />
<input type="hidden" name="title" value="{{ exception_type|escape }} at {{ request.path|escape }}" />
<input type="hidden" name="source" value="Django Dpaste Agent" />
<input type="hidden" name="poster" value="Django" />
<textarea name="content" id="traceback_area" cols="140" rows="25">
Environment:
Request Method: {{ request.META.REQUEST_METHOD }}
Request URL: {{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
Django Version: {{ django_version_info }}
Python Version: {{ sys_version_info }}
Installed Applications:
{{ settings.INSTALLED_APPS|pprint }}
Installed Middleware:
{{ settings.MIDDLEWARE_CLASSES|pprint }}
{% if template_does_not_exist %}Template Loader Error:
{% if loader_debug_info %}Django tried loading these templates, in this order:
{% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
{% for t in loader.templates %}{{ t.name }} (File {% if t.exists %}exists{% else %}does not exist{% endif %})
{% endfor %}{% endfor %}
{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!
{% endif %}
{% endif %}{% if template_info %}
Template error:
In template {{ template_info.name }}, error at line {{ template_info.line }}
{{ template_info.message }}{% for source_line in template_info.source_lines %}{% ifequal source_line.0 template_info.line %}
{{ source_line.0 }} : {{ template_info.before }} {{ template_info.during }} {{ template_info.after }}
{% else %}
{{ source_line.0 }} : {{ source_line.1 }}
{% endifequal %}{% endfor %}{% endif %}
Traceback:
{% for frame in frames %}File "{{ frame.filename|escape }}" in {{ frame.function|escape }}
{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line|escape }}{% endif %}
{% endfor %}
Exception Type: {{ exception_type|escape }} at {{ request.path|escape }}
Exception Value: {{ exception_value|escape }}
</textarea>
<br/><br/>
</div>
<input type="submit" value="Send to DPaste">
</form>
</div> </div>
<div id="requestinfo"> <div id="requestinfo">

View File

@ -9,7 +9,7 @@ from django.http import Http404, HttpResponse
def archive_index(request, queryset, date_field, num_latest=15, def archive_index(request, queryset, date_field, num_latest=15,
template_name=None, template_loader=loader, template_name=None, template_loader=loader,
extra_context=None, allow_empty=False, context_processors=None, extra_context=None, allow_empty=True, context_processors=None,
mimetype=None, allow_future=False, template_object_name='latest'): mimetype=None, allow_future=False, template_object_name='latest'):
""" """
Generic top-level archive of date-based objects. Generic top-level archive of date-based objects.

View File

@ -5,7 +5,7 @@ from django.core.paginator import ObjectPaginator, InvalidPage
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
def object_list(request, queryset, paginate_by=None, page=None, def object_list(request, queryset, paginate_by=None, page=None,
allow_empty=False, template_name=None, template_loader=loader, allow_empty=True, template_name=None, template_loader=loader,
extra_context=None, context_processors=None, template_object_name='object', extra_context=None, context_processors=None, template_object_name='object',
mimetype=None): mimetype=None):
""" """

View File

@ -58,6 +58,17 @@ See the `csrf documentation`_.
.. _csrf documentation: ../csrf/ .. _csrf documentation: ../csrf/
flatpages
=========
A framework for managing simple "flat" HTML content in a database.
See the `flatpages documentation`_.
.. _flatpages documentation: ../flatpages/
Requires the sites_ contrib package to be installed as well.
formtools formtools
========= =========
@ -162,17 +173,6 @@ Examples (when 'today' is 17 Feb 2007):
.. _DATE_FORMAT: ../settings/#date_format .. _DATE_FORMAT: ../settings/#date_format
flatpages
=========
A framework for managing simple "flat" HTML content in a database.
See the `flatpages documentation`_.
.. _flatpages documentation: ../flatpages/
Requires the sites_ contrib package to be installed as well.
localflavor localflavor
=========== ===========
@ -211,6 +211,15 @@ See the `redirects documentation`_.
.. _redirects documentation: ../redirects/ .. _redirects documentation: ../redirects/
sessions
========
A framework for storing data in anonymous sessions.
See the `sessions documentation`_.
.. _sessions documentation: ../sessions/
sites sites
===== =====
@ -240,6 +249,16 @@ See the `syndication documentation`_.
.. _syndication documentation: ../syndication_feeds/ .. _syndication documentation: ../syndication_feeds/
webdesign
=========
Helpers and utilties targeted primarily at web designers rather than
web developers.
See the `web design helpers documentation`_.
.. _web design helpers documentation: ../webdesign/
Other add-ons Other add-ons
============= =============

View File

@ -154,10 +154,13 @@ custom methods:
* ``get_profile()`` -- Returns a site-specific profile for this user. * ``get_profile()`` -- Returns a site-specific profile for this user.
Raises ``django.contrib.auth.models.SiteProfileNotAvailable`` if the current site Raises ``django.contrib.auth.models.SiteProfileNotAvailable`` if the current site
doesn't allow profiles. doesn't allow profiles. For information on how to define a
site-specific user profile, see the section on `storing additional
user information`_ below.
.. _Django model: ../model-api/ .. _Django model: ../model-api/
.. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email .. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email
.. _storing additional user information: #storing-additional-information-about-users
Manager functions Manager functions
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -269,6 +272,45 @@ you need to create a superuser after that via the command line, you can use the
Make sure to substitute ``/path/to/`` with the path to the Django codebase on Make sure to substitute ``/path/to/`` with the path to the Django codebase on
your filesystem. your filesystem.
Storing additional information about users
------------------------------------------
If you'd like to store additional information related to your users,
Django provides a method to specify a site-specific related model --
termed a "user profile" -- for this purpose.
To make use of this feature, define a model with fields for the
additional information you'd like to store, or additional methods
you'd like to have available, and also add a ``ForeignKey`` from your
model to the ``User`` model, specified with ``unique=True`` to ensure
only one instance of your model can be created for each ``User``.
To indicate that this model is the user profile model for a given
site, fill in the setting ``AUTH_PROFILE_MODULE`` with a string
consisting of the following items, separated by a dot:
1. The (normalized to lower-case) name of the application in which the
user profile model is defined (in other words, an all-lowercase
version of the name which was passed to ``manage.py startapp`` to
create the application).
2. The (normalized to lower-case) name of the model class.
For example, if the profile model was a class named ``UserProfile``
and was defined inside an application named ``accounts``, the
appropriate setting would be::
AUTH_PROFILE_MODULE = 'accounts.userprofile'
When a user profile model has been defined and specified in this
manner, each ``User`` object will have a method -- ``get_profile()``
-- which returns the instance of the user profile model associated
with that ``User``.
For more information, see `Chapter 12 of the Django book`_.
.. _Chapter 12 of the Django book: http://www.djangobook.com/en/beta/chapter12/#cn226
Authentication in Web requests Authentication in Web requests
============================== ==============================
@ -337,6 +379,17 @@ This example shows how you might use both ``authenticate()`` and ``login()``::
else: else:
# Return an 'invalid login' error message. # Return an 'invalid login' error message.
.. admonition:: Calling ``authenticate()`` first
When you're manually logging a user in, you *must* call
``authenticate()`` before you call ``login()``; ``authenticate()``
sets an attribute on the ``User`` noting which authentication
backend successfully authenticated that user (see the `backends
documentation`_ for details), and this information is needed later
during the login process.
.. _backends documentation: #other-authentication-sources
Manually checking a user's password Manually checking a user's password
----------------------------------- -----------------------------------

View File

@ -168,6 +168,10 @@ development or testing environments. For example::
CACHE_BACKEND = 'simple:///' CACHE_BACKEND = 'simple:///'
**New in Django development version:** This cache backend is deprecated and
will be removed in a future release. New code should use the ``locmem`` backend
instead.
Dummy caching (for development) Dummy caching (for development)
------------------------------- -------------------------------

View File

@ -242,7 +242,7 @@ We've got two roles here:
* Ticket triagers: community members who keep track of tickets, making * Ticket triagers: community members who keep track of tickets, making
sure the tickets are always categorized correctly. sure the tickets are always categorized correctly.
Second, note the four triage stages: Second, note the five triage stages:
1. A ticket starts as "Unreviewed", meaning that a triager has yet to 1. A ticket starts as "Unreviewed", meaning that a triager has yet to
examine the ticket and move it along. examine the ticket and move it along.
@ -254,9 +254,14 @@ Second, note the four triage stages:
3. Once a ticket is ruled to be approved for fixing, it's moved into the 3. Once a ticket is ruled to be approved for fixing, it's moved into the
"Accepted" stage. This stage is where all the real work gets done. "Accepted" stage. This stage is where all the real work gets done.
4. If a ticket has an associated patch (see below), a triager will review the 4. A ticket might be moved to the "Someday/Maybe" state if it's an
patch. If the patch is complete, it'll be marked as "ready for checkin" so enhancement request we are willing to consider if a good patch is
that a core developer knows to review and check in the patches. written. Such tickets are not high priority.
5. If a ticket has an associated patch (see below), a triager will review
the patch. If the patch is complete, it'll be marked as "ready for
checkin" so that a core developer knows to review and check in the
patches.
The second part of this workflow involves a set of flags the describe what the The second part of this workflow involves a set of flags the describe what the
ticket has or needs in order to be "ready for checkin": ticket has or needs in order to be "ready for checkin":
@ -654,9 +659,8 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
./runtests.py --settings=path.to.django.settings ./runtests.py --settings=path.to.django.settings
Yes, the unit tests need a settings module, but only for database connection Yes, the unit tests need a settings module, but only for database connection
info, with the ``DATABASE_ENGINE`` setting. You will also need a ``ROOT_URLCONF`` info, with the ``DATABASE_ENGINE`` setting. You'll also need a ``ROOT_URLCONF``
setting (its value is ignored; it just needs to be present) and a ``SITE_ID`` setting (its value is ignored; it just needs to be present).
setting (any non-zero integer value will do) in order for all the tests to pass.
If you're using the ``sqlite3`` database backend, no further settings are If you're using the ``sqlite3`` database backend, no further settings are
needed. A temporary database will be created in memory when running the tests. needed. A temporary database will be created in memory when running the tests.

View File

@ -1,5 +1,5 @@
=================== ===================
Custom Model Fields Custom model fields
=================== ===================
**New in Django development version** **New in Django development version**
@ -8,9 +8,10 @@ Introduction
============ ============
The `model reference`_ documentation explains how to use Django's standard The `model reference`_ documentation explains how to use Django's standard
field classes. For many purposes, those classes are all you'll need. Sometimes, field classes -- ``CharField``, ``DateField``, etc. For many purposes, those
though, the Django version won't meet your precise requirements, or you'll want classes are all you'll need. Sometimes, though, the Django version won't meet
to use a field that is entirely different from those shipped with Django. your precise requirements, or you'll want to use a field that is entirely
different from those shipped with Django.
Django's built-in field types don't cover every possible database column type -- Django's built-in field types don't cover every possible database column type --
only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
@ -27,10 +28,10 @@ Our example object
Creating custom fields requires a bit of attention to detail. To make things Creating custom fields requires a bit of attention to detail. To make things
easier to follow, we'll use a consistent example throughout this document. easier to follow, we'll use a consistent example throughout this document.
Suppose you have a Python object representing the deal of cards in a hand of Suppose you have a Python object representing the deal of cards in a hand of
Bridge_. It doesn't matter if you don't know how to play Bridge. You only need Bridge_. (Don't worry, you don't know how to play Bridge to follow this
to know that 52 cards are dealt out equally to four players, who are example. You only need to know that 52 cards are dealt out equally to four
traditionally called *north*, *east*, *south* and *west*. Our class looks players, who are traditionally called *north*, *east*, *south* and *west*.)
something like this:: Our class looks something like this::
class Hand(object): class Hand(object):
def __init__(self, north, east, south, west): def __init__(self, north, east, south, west):
@ -42,10 +43,9 @@ something like this::
# ... (other possibly useful methods omitted) ... # ... (other possibly useful methods omitted) ...
This is just an ordinary Python class, nothing Django-specific about it. We This is just an ordinary Python class, with nothing Django-specific about it.
would like to be able to things like this in our models (we assume the We'd like to be able to things like this in our models (we assume the ``hand``
``hand`` attribute on the model is an instance of ``Hand``):: attribute on the model is an instance of ``Hand``)::
example = MyModel.objects.get(pk=1) example = MyModel.objects.get(pk=1)
print example.hand.north print example.hand.north
@ -72,7 +72,7 @@ model support for existing classes where you cannot change the source code.
.. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html .. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html
.. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge .. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
Background Theory Background theory
================= =================
Database storage Database storage
@ -87,7 +87,7 @@ that falls out fairly naturally once you have the database side under control).
Fields in a model must somehow be converted to fit into an existing database Fields in a model must somehow be converted to fit into an existing database
column type. Different databases provide different sets of valid column types, column type. Different databases provide different sets of valid column types,
but the rule is still the same: those are the only types you have to work but the rule is still the same: those are the only types you have to work
with. Anything you want to store in the database must fit into one of with. Anything you want to store in the database must fit into one of
those types. those types.
Normally, you're either writing a Django field to match a particular database Normally, you're either writing a Django field to match a particular database
@ -95,10 +95,9 @@ column type, or there's a fairly straightforward way to convert your data to,
say, a string. say, a string.
For our ``Hand`` example, we could convert the card data to a string of 104 For our ``Hand`` example, we could convert the card data to a string of 104
characters by concatenating all the cards together in a pre-determined order. characters by concatenating all the cards together in a pre-determined order --
Say, all the *north* cards first, then the *east*, *south* and *west* cards, in say, all the *north* cards first, then the *east*, *south* and *west* cards. So
that order. So ``Hand`` objects can be saved to text or character columns in ``Hand`` objects can be saved to text or character columns in the database.
the database.
What does a field class do? What does a field class do?
--------------------------- ---------------------------
@ -109,12 +108,12 @@ mean model fields and not `form fields`_) are subclasses of
field is common to all fields -- name, help text, validator lists, uniqueness field is common to all fields -- name, help text, validator lists, uniqueness
and so forth. Storing all that information is handled by ``Field``. We'll get and so forth. Storing all that information is handled by ``Field``. We'll get
into the precise details of what ``Field`` can do later on; for now, suffice it into the precise details of what ``Field`` can do later on; for now, suffice it
to say that everything descends from ``Field`` and then customises key pieces to say that everything descends from ``Field`` and then customizes key pieces
of the class behaviour. of the class behavior.
.. _form fields: ../newforms/#fields .. _form fields: ../newforms/#fields
It's important to realise that a Django field class is not what is stored in It's important to realize that a Django field class is not what is stored in
your model attributes. The model attributes contain normal Python objects. The your model attributes. The model attributes contain normal Python objects. The
field classes you define in a model are actually stored in the ``Meta`` class field classes you define in a model are actually stored in the ``Meta`` class
when the model class is created (the precise details of how this is done are when the model class is created (the precise details of how this is done are
@ -127,31 +126,35 @@ Keep this in mind when creating your own custom fields. The Django ``Field``
subclass you write provides the machinery for converting between your Python subclass you write provides the machinery for converting between your Python
instances and the database/serializer values in various ways (there are instances and the database/serializer values in various ways (there are
differences between storing a value and using a value for lookups, for differences between storing a value and using a value for lookups, for
example). If this sounds a bit tricky, don't worry. It will hopefully become example). If this sounds a bit tricky, don't worry -- it will become clearer in
clearer in the examples below. Just remember that you will often end up the examples below. Just remember that you will often end up creating two
creating two classes when you want a custom field. The first class is the classes when you want a custom field:
Python object that your users will manipulate. They will assign it to the model
attribute, they will read from it for displaying purposes, things like that. * The first class is the Python object that your users will manipulate.
This is the ``Hand`` class in our example. The second class is the ``Field`` They will assign it to the model attribute, they will read from it for
subclass. This is the class that knows how to convert your first class back and displaying purposes, things like that. This is the ``Hand`` class in our
forth between its permanent storage form and the Python form. example.
* The second class is the ``Field`` subclass. This is the class that knows
how to convert your first class back and forth between its permanent
storage form and the Python form.
Writing a ``Field`` subclass Writing a ``Field`` subclass
============================= =============================
When you are planning your ``Field`` subclass, first give some thought to When planning your ``Field`` subclass, first give some thought to which
which existing field your new field is most similar to. Can you subclass an existing ``Field`` class your new field is most similar to. Can you subclass an
existing Django field and save yourself some work? If not, you should subclass the ``Field`` class, from which everything is descended. existing Django field and save yourself some work? If not, you should subclass
the ``Field`` class, from which everything is descended.
Initialising your new field is a matter of separating out any arguments that Initializing your new field is a matter of separating out any arguments that
are specific to your case from the common arguments and passing the latter to are specific to your case from the common arguments and passing the latter to
the ``__init__()`` method of ``Field`` (or your parent class). the ``__init__()`` method of ``Field`` (or your parent class).
In our example, the Django field we create is going to be called In our example, we'll call our field ``HandField``. (It's a good idea to call
``HandField``. It's not a bad idea to use a similar naming scheme to Django's your ``Field`` subclass ``(Something)Field``, so it's easily identifiable as a
fields so that our new class is identifiable and yet clearly related to the ``Field`` subclass.) It doesn't behave like any existing field, so we'll
``Hand`` class it is wrapping. It doesn't behave like any existing field, so subclass directly from ``Field``::
we'll subclass directly from ``Field``::
from django.db import models from django.db import models
@ -160,7 +163,7 @@ we'll subclass directly from ``Field``::
kwargs['max_length'] = 104 kwargs['max_length'] = 104
super(HandField, self).__init__(*args, **kwargs) super(HandField, self).__init__(*args, **kwargs)
Our ``HandField`` will accept most of the standard field options (see the list Our ``HandField`` accept most of the standard field options (see the list
below), but we ensure it has a fixed length, since it only needs to hold 52 below), but we ensure it has a fixed length, since it only needs to hold 52
card values plus their suits; 104 characters in total. card values plus their suits; 104 characters in total.
@ -171,40 +174,40 @@ card values plus their suits; 104 characters in total.
(``auto_now`` being set implies ``editable=False``). No error is raised in (``auto_now`` being set implies ``editable=False``). No error is raised in
this case. this case.
This behaviour simplifies the field classes, because they don't need to This behavior simplifies the field classes, because they don't need to
check for options that aren't necessary. They just pass all the options to check for options that aren't necessary. They just pass all the options to
the parent class and then don't use them later on. It is up to you whether the parent class and then don't use them later on. It's up to you whether
you want your fields to be more strict about the options they select, or you want your fields to be more strict about the options they select, or
to use the simpler, more permissive behaviour of the current fields. to use the simpler, more permissive behavior of the current fields.
The ``Field.__init__()`` method takes the following parameters, in this The ``Field.__init__()`` method takes the following parameters, in this
order: order:
- ``verbose_name`` * ``verbose_name``
- ``name`` * ``name``
- ``primary_key`` * ``primary_key``
- ``max_length`` * ``max_length``
- ``unique`` * ``unique``
- ``blank`` * ``blank``
- ``null`` * ``null``
- ``db_index`` * ``db_index``
- ``core`` * ``core``
- ``rel``: Used for related fields (like ``ForeignKey``). For advanced use * ``rel``: Used for related fields (like ``ForeignKey``). For advanced use
only. only.
- ``default`` * ``default``
- ``editable`` * ``editable``
- ``serialize``: If ``False``, the field will not be serialized when the * ``serialize``: If ``False``, the field will not be serialized when the
model is passed to Django's serializers_. Defaults to ``True``. model is passed to Django's serializers_. Defaults to ``True``.
- ``prepopulate_from`` * ``prepopulate_from``
- ``unique_for_date`` * ``unique_for_date``
- ``unique_for_month`` * ``unique_for_month``
- ``unique_for_year`` * ``unique_for_year``
- ``validator_list`` * ``validator_list``
- ``choices`` * ``choices``
- ``radio_admin`` * ``radio_admin``
- ``help_text`` * ``help_text``
- ``db_column`` * ``db_column``
- ``db_tablespace``: Currently only used with the Oracle backend and only * ``db_tablespace``: Currently only used with the Oracle backend and only
for index creation. You can usually ignore this option. for index creation. You can usually ignore this option.
All of the options without an explanation in the above list have the same All of the options without an explanation in the above list have the same
@ -218,22 +221,19 @@ The ``SubfieldBase`` metaclass
------------------------------ ------------------------------
As we indicated in the introduction_, field subclasses are often needed for As we indicated in the introduction_, field subclasses are often needed for
two reasons. Either to take advantage of a custom database column type, or to two reasons: either to take advantage of a custom database column type, or to
handle complex Python types. A combination of the two is obviously also handle complex Python types. Obviously, a combination of the two is also
possible. If you are only working with custom database column types and your possible. If you're only working with custom database column types and your
model fields appear in Python as standard Python types direct from the model fields appear in Python as standard Python types direct from the
database backend, you don't need to worry about this section. database backend, you don't need to worry about this section.
If you are handling custom Python types, such as our ``Hand`` class, we need If you're handling custom Python types, such as our ``Hand`` class, we need
to make sure that when Django initialises an instance of our model and assigns to make sure that when Django initializes an instance of our model and assigns
a database value to our custom field attribute we convert that value into the a database value to our custom field attribute, we convert that value into the
appropriate Python object. The details of how this happens internally are a appropriate Python object. The details of how this happens internally are a
little complex. For the field writer, though, things are fairly simple. Make little complex, but the code you need to write in your ``Field`` class is
sure your field subclass uses ``django.db.models.SubfieldBase`` as its simple: make sure your field subclass uses ``django.db.models.SubfieldBase`` as
metaclass. This ensures that the ``to_python()`` method, documented below_, its metaclass::
will always be called when the attribute is initialised.
Our ``HandField`` class now looks like this::
class HandField(models.Field): class HandField(models.Field):
__metaclass__ = models.SubfieldBase __metaclass__ = models.SubfieldBase
@ -241,16 +241,18 @@ Our ``HandField`` class now looks like this::
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# ... # ...
This ensures that the ``to_python()`` method, documented below_, will always be
called when the attribute is initialized.
.. _below: #to-python-self-value .. _below: #to-python-self-value
Useful methods Useful methods
-------------- --------------
Once you've created your ``Field`` subclass and setup up the Once you've created your ``Field`` subclass and set up up the
``__metaclass__``, if necessary, there are a few standard methods you need to ``__metaclass__``, you might consider overriding a few standard methods,
consider overriding. Which of these you need to implement will depend on you depending on your field's behavior. The list of methods below is in
particular field behaviour. The list below is in approximately decreasing approximately decreasing order of importance, so start from the top.
order of importance, so start from the top.
``db_type(self)`` ``db_type(self)``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -337,23 +339,32 @@ field. You are then responsible for creating the column in the right table in
some other way, of course, but this gives you a way to tell Django to get out some other way, of course, but this gives you a way to tell Django to get out
of the way. of the way.
``to_python(self, value)`` ``to_python(self, value)``
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
Converts between all the ways your field can receive its initial value and the Converts a value as returned by your database (or a serializer) to a Python
Python object you want to end up with. The default version just returns object.
``value``, so is useful is the database backend returns the data already in
the correct form (a Python string, for example).
Normally, you will need to override this method. As a general rule, be The default implementation simply returns ``value``, for the common case in
prepared to accept an instance of the right type (e.g. ``Hand`` in our ongoing which the database backend already returns data in the correct format (as a
example), a string (from a deserializer, for example), and whatever the Python string, for example).
database wrapper returns for the column type you are using.
In our ``HandField`` class, we are storing the data in a character field in If your custom ``Field`` class deals with data structures that are more complex
the database, so we need to be able to process strings and ``Hand`` instances than strings, dates, integers or floats, then you'll need to override this
in ``to_python()``:: method. As a general rule, the method should deal gracefully with any of the
following arguments:
* An instance of the correct type (e.g., ``Hand`` in our ongoing example).
* A string (e.g., from a deserializer).
* Whatever the database returns for the column type you're using.
In our ``HandField`` class, we're storing the data as a VARCHAR field in the
database, so we need to be able to process strings and ``Hand`` instances in
``to_python()``::
import re
class HandField(models.Field): class HandField(models.Field):
# ... # ...
@ -362,14 +373,14 @@ in ``to_python()``::
if isinstance(value, Hand): if isinstance(value, Hand):
return value return value
# The string case # The string case.
p1 = re.compile('.{26}') p1 = re.compile('.{26}')
p2 = re.compile('..') p2 = re.compile('..')
args = [p2.findall(x) for x in p1.findall(value)] args = [p2.findall(x) for x in p1.findall(value)]
return Hand(*args) return Hand(*args)
Notice that we always return a ``Hand`` instance from this method. That is the Notice that we always return a ``Hand`` instance from this method. That's the
Python object we want to store in the model's attribute. Python object type we want to store in the model's attribute.
``get_db_prep_save(self, value)`` ``get_db_prep_save(self, value)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -377,7 +388,7 @@ Python object we want to store in the model's attribute.
This is the reverse of ``to_python()`` when working with the database backends This is the reverse of ``to_python()`` when working with the database backends
(as opposed to serialization). The ``value`` parameter is the current value of (as opposed to serialization). The ``value`` parameter is the current value of
the model's attribute (a field has no reference to its containing model, so it the model's attribute (a field has no reference to its containing model, so it
cannot retrieve the value itself) and the method should return data in a cannot retrieve the value itself), and the method should return data in a
format that can be used as a parameter in a query for the database backend. format that can be used as a parameter in a query for the database backend.
For example:: For example::
@ -389,7 +400,6 @@ For example::
return ''.join([''.join(l) for l in (self.north, return ''.join([''.join(l) for l in (self.north,
self.east, self.south, self.west)]) self.east, self.south, self.west)])
``pre_save(self, model_instance, add)`` ``pre_save(self, model_instance, add)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -399,10 +409,10 @@ The attribute name is in ``self.attname`` (this is set up by ``Field``). If
the model is being saved to the database for the first time, the ``add`` the model is being saved to the database for the first time, the ``add``
parameter will be ``True``, otherwise it will be ``False``. parameter will be ``True``, otherwise it will be ``False``.
Often you won't need to override this method. However, at times it can be very You only need to override this method if you want to preprocess the value
useful. For example, the Django ``DateTimeField`` uses this method to set the somehow, just before saving. For example, Django's ``DateTimeField`` uses this
attribute to the correct value before returning it in the cases when method to set the attribute correctly in the case of ``auto_now`` or
``auto_now`` or ``auto_now_add`` are set on the field. ``auto_now_add``.
If you do override this method, you must return the value of the attribute at If you do override this method, you must return the value of the attribute at
the end. You should also update the model's attribute if you make any changes the end. You should also update the model's attribute if you make any changes
@ -460,9 +470,9 @@ All of the ``kwargs`` dictionary is passed directly to the form field's
``__init__()`` method. Normally, all you need to do is set up a good default ``__init__()`` method. Normally, all you need to do is set up a good default
for the ``form_class`` argument and then delegate further handling to the for the ``form_class`` argument and then delegate further handling to the
parent class. This might require you to write a custom form field (and even a parent class. This might require you to write a custom form field (and even a
form widget). See the `forms documentation`_ for information about this. Also form widget). See the `forms documentation`_ for information about this, and
have a look at ``django.contrib.localflavor`` for some examples of custom take a look at the code in ``django.contrib.localflavor`` for some examples of
widgets. custom widgets.
Continuing our ongoing example, we can write the ``formfield()`` method as:: Continuing our ongoing example, we can write the ``formfield()`` method as::
@ -471,14 +481,14 @@ Continuing our ongoing example, we can write the ``formfield()`` method as::
def formfield(self, **kwargs): def formfield(self, **kwargs):
# This is a fairly standard way to set up some defaults # This is a fairly standard way to set up some defaults
# whilst letting the caller override them. # while letting the caller override them.
defaults = {'form_class': MyFormField} defaults = {'form_class': MyFormField}
defaults.update(kwargs) defaults.update(kwargs)
return super(HandField, self).formfield(**defaults) return super(HandField, self).formfield(**defaults)
This assumes we have some ``MyFormField`` field class (which has its own This assumes we're imported a ``MyFormField`` field class (which has its own
default widget) imported. This document doesn't cover the details of writing default widget). This document doesn't cover the details of writing custom form
custom form fields. fields.
.. _helper functions: ../newforms/#generating-forms-for-models .. _helper functions: ../newforms/#generating-forms-for-models
.. _forms documentation: ../newforms/ .. _forms documentation: ../newforms/
@ -490,7 +500,7 @@ Returns a string giving the name of the ``Field`` subclass we are emulating at
the database level. This is used to determine the type of database column for the database level. This is used to determine the type of database column for
simple cases. simple cases.
If you have created a ``db_type()`` method, you do not need to worry about If you have created a ``db_type()`` method, you don't need to worry about
``get_internal_type()`` -- it won't be used much. Sometimes, though, your ``get_internal_type()`` -- it won't be used much. Sometimes, though, your
database storage is similar in type to some other field, so you can use that database storage is similar in type to some other field, so you can use that
other field's logic to create the right column. other field's logic to create the right column.
@ -512,7 +522,7 @@ the database backend you are using -- that is, it doesn't appear in
be used by the serializer, but the default ``db_type()`` method will return be used by the serializer, but the default ``db_type()`` method will return
``None``. See the documentation of ``db_type()`` above_ for reasons why this ``None``. See the documentation of ``db_type()`` above_ for reasons why this
might be useful. Putting a descriptive string in as the type of the field for might be useful. Putting a descriptive string in as the type of the field for
the serializer is a useful idea if you are ever going to be using the the serializer is a useful idea if you're ever going to be using the
serializer output in some other place, outside of Django. serializer output in some other place, outside of Django.
.. _above: #db-type-self .. _above: #db-type-self
@ -528,7 +538,7 @@ serializer output in some other place, outside of Django.
Returns a dictionary, mapping the field's attribute name to a flattened string Returns a dictionary, mapping the field's attribute name to a flattened string
version of the data. This method has some internal uses that aren't of version of the data. This method has some internal uses that aren't of
interest to use here (mostly having to do with manipulators). For our interest to use here (mostly having to do with manipulators). For our
purposes, it is sufficient to return a one item dictionary that maps the purposes, it's sufficient to return a one item dictionary that maps the
attribute name to a string. attribute name to a string.
This method is used by the serializers to convert the field into a string for This method is used by the serializers to convert the field into a string for
@ -549,19 +559,20 @@ we can reuse some existing conversion code::
Some general advice Some general advice
-------------------- --------------------
Writing a custom field can be a tricky process sometimes, particularly if you Writing a custom field can be a tricky process, particularly if you're doing
are doing complex conversions between your Python types and your database and complex conversions between your Python types and your database and
serialization formats. A couple of tips to make things go more smoothly: serialization formats. Here are a couple of tips to make things go more
smoothly:
1. Look at the existing Django fields (in 1. Look at the existing Django fields (in
``django/db/models/fields/__init__.py``) for inspiration. Try to find a field ``django/db/models/fields/__init__.py``) for inspiration. Try to find a
that is already close to what you want and extend it a little bit, in field that's similar to what you want and extend it a little bit,
preference to creating an entirely new field from scratch. instead of creating an entirely new field from scratch.
2. Put a ``__str__()`` or ``__unicode__()`` method on the class you are
wrapping up as a field. There are a lot of places where the default behaviour
of the field code is to call ``force_unicode()`` on the value (in our
examples in this document, ``value`` would be a ``Hand`` instance, not a
``HandField``). So if your ``__unicode__()`` method automatically converts to
the string form of your Python object, you can save yourself a lot of work.
2. Put a ``__str__()`` or ``__unicode__()`` method on the class you're
wrapping up as a field. There are a lot of places where the default
behavior of the field code is to call ``force_unicode()`` on the value.
(In our examples in this document, ``value`` would be a ``Hand``
instance, not a ``HandField``). So if your ``__unicode__()`` method
automatically converts to the string form of your Python object, you can
save yourself a lot of work.

View File

@ -258,6 +258,12 @@ many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
field would also generate an index, but no tablespace for it is specified, so field would also generate an index, but no tablespace for it is specified, so
it would be stored in the model tablespace ``tables`` by default. it would be stored in the model tablespace ``tables`` by default.
The settings.py file supports two additional options to specify
default values for the db_tablespace options. This is useful for
setting a tablespace for the Django internal apps and other
contributed applications. These options are ``DEFAULT_TABLESPACE``
and ``DEFAULT_INDEX_TABLESPACE``.
Django does not create the tablespaces for you. Please refer to `Oracle's Django does not create the tablespaces for you. Please refer to `Oracle's
documentation`_ for details on creating and managing tablespaces. documentation`_ for details on creating and managing tablespaces.

View File

@ -253,9 +253,11 @@ For example::
The class has the following methods: The class has the following methods:
* ``send()`` sends the message, using either the connection that is * ``send(fail_silently=False)`` sends the message, using either
specified in the ``connection`` attribute, or creating a new connection the connection that is specified in the ``connection``
if none already exists. attribute, or creating a new connection if none already
exists. If the keyword argument ``fail_silently`` is ``True``,
exceptions raised while sending the message will be quashed.
* ``message()`` constructs a ``django.core.mail.SafeMIMEText`` object (a * ``message()`` constructs a ``django.core.mail.SafeMIMEText`` object (a
subclass of Python's ``email.MIMEText.MIMEText`` class) or a subclass of Python's ``email.MIMEText.MIMEText`` class) or a

418
docs/form_for_model.txt Normal file
View File

@ -0,0 +1,418 @@
Generating forms for models
===========================
If you're building a database-driven app, chances are you'll have forms that
map closely to Django models. For instance, you might have a ``BlogComment``
model, and you want to create a form that lets people submit comments. In this
case, it would be redundant to define the field types in your form, because
you've already defined the fields in your model.
For this reason, Django provides a few helper functions that let you create a
``Form`` class from a Django model.
``form_for_model()``
--------------------
The method ``django.newforms.form_for_model()`` creates a form based on the
definition of a specific model. Pass it the model class, and it will return a
``Form`` class that contains a form field for each model field.
For example::
>>> from django.newforms import form_for_model
# Create the form class.
>>> ArticleForm = form_for_model(Article)
# Create an empty form instance.
>>> f = ArticleForm()
It bears repeating that ``form_for_model()`` takes the model *class*, not a
model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
Field types
~~~~~~~~~~~
The generated ``Form`` class will have a form field for every model field. Each
model field has a corresponding default form field. For example, a
``CharField`` on a model is represented as a ``CharField`` on a form. A
model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
the full list of conversions:
=============================== ========================================
Model field Form field
=============================== ========================================
``AutoField`` Not represented in the form
``BooleanField`` ``BooleanField``
``CharField`` ``CharField`` with ``max_length`` set to
the model field's ``max_length``
``CommaSeparatedIntegerField`` ``CharField``
``DateField`` ``DateField``
``DateTimeField`` ``DateTimeField``
``DecimalField`` ``DecimalField``
``EmailField`` ``EmailField``
``FileField`` ``FileField``
``FilePathField`` ``CharField``
``FloatField`` ``FloatField``
``ForeignKey`` ``ModelChoiceField`` (see below)
``ImageField`` ``ImageField``
``IntegerField`` ``IntegerField``
``IPAddressField`` ``IPAddressField``
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
below)
``NullBooleanField`` ``CharField``
``PhoneNumberField`` ``USPhoneNumberField``
(from ``django.contrib.localflavor.us``)
``PositiveIntegerField`` ``IntegerField``
``PositiveSmallIntegerField`` ``IntegerField``
``SlugField`` ``CharField``
``SmallIntegerField`` ``IntegerField``
``TextField`` ``CharField`` with ``widget=Textarea``
``TimeField`` ``TimeField``
``URLField`` ``URLField`` with ``verify_exists`` set
to the model field's ``verify_exists``
``USStateField`` ``CharField`` with
``widget=USStateSelect``
(``USStateSelect`` is from
``django.contrib.localflavor.us``)
``XMLField`` ``CharField`` with ``widget=Textarea``
=============================== ========================================
.. note::
The ``FloatField`` form field and ``DecimalField`` model and form fields
are new in the development version.
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
types are special cases:
* ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
* ``ManyToManyField`` is represented by
``django.newforms.ModelMultipleChoiceField``, which is a
``MultipleChoiceField`` whose choices are a model ``QuerySet``.
In addition, each generated form field has attributes set as follows:
* If the model field has ``blank=True``, then ``required`` is set to
``False`` on the form field. Otherwise, ``required=True``.
* The form field's ``label`` is set to the ``verbose_name`` of the model
field, with the first character capitalized.
* The form field's ``help_text`` is set to the ``help_text`` of the model
field.
* If the model field has ``choices`` set, then the form field's ``widget``
will be set to ``Select``, with choices coming from the model field's
``choices``. The choices will normally include the blank choice which is
selected by default. If the field is required, this forces the user to
make a selection. The blank choice will not be included if the model
field has ``blank=False`` and an explicit ``default`` value (the
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
field. See "Overriding the default field types" below.
A full example
~~~~~~~~~~~~~~
Consider this set of models::
from django.db import models
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
With these models, a call to ``form_for_model(Author)`` would return a ``Form``
class equivalent to this::
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(max_length=3,
widget=forms.Select(choices=TITLE_CHOICES))
birth_date = forms.DateField(required=False)
A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
this::
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
The ``save()`` method
~~~~~~~~~~~~~~~~~~~~~
Every form produced by ``form_for_model()`` also has a ``save()`` method. This
method creates and saves a database object from the data bound to the form. For
example::
# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
Note that ``save()`` will raise a ``ValueError`` if the data in the form
doesn't validate -- i.e., ``if form.errors``.
This ``save()`` method accepts an optional ``commit`` keyword argument, which
accepts either ``True`` or ``False``. If you call ``save()`` with
``commit=False``, then it will return an object that hasn't yet been saved to
the database. In this case, it's up to you to call ``save()`` on the resulting
model instance. This is useful if you want to do custom processing on the
object before saving it. ``commit`` is ``True`` by default.
Another side effect of using ``commit=False`` is seen when your model has
a many-to-many relation with another model. If your model has a many-to-many
relation and you specify ``commit=False`` when you save a form, Django cannot
immediately save the form data for the many-to-many relation. This is because
it isn't possible to save many-to-many data for an instance until the instance
exists in the database.
To work around this problem, every time you save a form using ``commit=False``,
Django adds a ``save_m2m()`` method to the form created by ``form_for_model``.
After you've manually saved the instance produced by the form, you can invoke
``save_m2m()`` to save the many-to-many form data. For example::
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)
# Modify the author in some way.
>>> new_author.some_field = 'some_value'
# Save the new instance.
>>> new_author.save()
# Now, save the many-to-many data for the form.
>>> f.save_m2m()
Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
When you use a simple ``save()`` on a form, all data -- including
many-to-many data -- is saved without the need for any additional method calls.
For example::
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()
Using an alternate base class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to add custom methods to the form generated by
``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
and contains your custom methods. Then, use the ``form`` argument to
``form_for_model()`` to tell it to use your custom form as its base class.
For example::
# Create the new base class.
>>> class MyBase(BaseForm):
... def my_method(self):
... # Do whatever the method does
# Create the form class with a different base class.
>>> ArticleForm = form_for_model(Article, form=MyBase)
# Instantiate the form.
>>> f = ArticleForm()
# Use the base class method.
>>> f.my_method()
Using a subset of fields on the form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**New in Django development version**
In some cases, you may not want all the model fields to appear on the generated
form. There are two ways of telling ``form_for_model()`` to use only a subset
of the model fields:
1. Set ``editable=False`` on the model field. As a result, *any* form
created from the model via ``form_for_model()`` will not include that
field.
2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
given, should be a list of field names to include in the form.
For example, if you want a form for the ``Author`` model (defined above)
that includes only the ``name`` and ``title`` fields, you would specify
``fields`` like this::
PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
.. note::
If you specify ``fields`` when creating a form with ``form_for_model()``,
then the fields that are *not* specified will not be set by the form's
``save()`` method. Django will prevent any attempt to save an incomplete
model, so if the model does not allow the missing fields to be empty, and
does not provide a default value for the missing fields, any attempt to
``save()`` a ``form_for_model`` with missing fields will fail. To avoid
this failure, you must use ``save(commit=False)`` and manually set any
extra required fields::
instance = form.save(commit=False)
instance.required_field = 'new value'
instance.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.
.. _section on saving forms: `The save() method`_
Overriding the default field types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default field types, as described in the "Field types" table above, are
sensible defaults; if you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
``form_for_model()`` gives you the flexibility of changing the form field type
for a given model field. You do this by specifying a **formfield callback**.
A formfield callback is a function that, when provided with a model field,
returns a form field instance. When constructing a form, ``form_for_model()``
asks the formfield callback to provide form field types.
By default, ``form_for_model()`` calls the ``formfield()`` method on the model
field::
def default_callback(field, **kwargs):
return field.formfield(**kwargs)
The ``kwargs`` are any keyword arguments that might be passed to the form
field, such as ``required=True`` or ``label='Foo'``.
For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
field on the model, you could define the callback::
>>> def my_callback(field, **kwargs):
... if isinstance(field, models.DateField):
... return MyDateFormField(**kwargs)
... else:
... return field.formfield(**kwargs)
>>> ArticleForm = form_for_model(Article, formfield_callback=my_callback)
Note that your callback needs to handle *all* possible model field types, not
just the ones that you want to behave differently to the default. That's why
this example has an ``else`` clause that implements the default behavior.
.. warning::
The field that is passed into the ``formfield_callback`` function in
``form_for_model()`` and ``form_for_instance`` is the field instance from
your model's class. You **must not** alter that object at all; treat it
as read-only!
If you make any alterations to that object, it will affect any future
users of the model class, because you will have changed the field object
used to construct the class. This is almost certainly what you don't want
to have happen.
Finding the model associated with a form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The model class that was used to construct the form is available
using the ``_model`` property of the generated form::
>>> ArticleForm = form_for_model(Article)
>>> ArticleForm._model
<class 'myapp.models.Article'>
``form_for_instance()``
-----------------------
``form_for_instance()`` is like ``form_for_model()``, but it takes a model
instance instead of a model class::
# Create an Author.
>>> a = Author(name='Joe Smith', title='MR', birth_date=None)
>>> a.save()
# Create a form for this particular Author.
>>> AuthorForm = form_for_instance(a)
# Instantiate the form.
>>> f = AuthorForm()
When a form created by ``form_for_instance()`` is created, the initial data
values for the form fields are drawn from the instance. However, this data is
not bound to the form. You will need to bind data to the form before the form
can be saved.
Unlike ``form_for_model()``, a choice field in form created by
``form_for_instance()`` will not include the blank choice if the respective
model field has ``blank=False``. The initial choice is drawn from the instance.
When you call ``save()`` on a form created by ``form_for_instance()``,
the database instance will be updated. As in ``form_for_model()``, ``save()``
will raise ``ValueError`` if the data doesn't validate.
``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
arguments that behave the same way as they do for ``form_for_model()``.
Let's modify the earlier `contact form`_ view example a little bit. Suppose we
have a ``Message`` model that holds each contact submission. Something like::
class Message(models.Model):
subject = models.CharField(max_length=100)
message = models.TextField()
sender = models.EmailField()
cc_myself = models.BooleanField(required=False)
You could use this model to create a form (using ``form_for_model()``). You
could also use existing ``Message`` instances to create a form for editing
messages. The `simple example view`_ can be changed slightly to accept the ``id`` value
of an existing ``Message`` and present it for editing::
def contact_edit(request, msg_id):
# Create the form from the message id.
message = get_object_or_404(Message, id=msg_id)
ContactForm = form_for_instance(message)
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/url/on_success/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form})
Aside from how we create the ``ContactForm`` class here, the main point to
note is that the form display in the ``GET`` branch of the function
will use the values from the ``message`` instance as initial values for the
form field.
.. _contact form: ../newforms/#simple-view-example
.. _`simple example view`: ../newforms/#simple-view-example
When should you use ``form_for_model()`` and ``form_for_instance()``?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
shortcuts for the common case. If you want to create a form whose fields map to
more than one model, or a form that contains fields that *aren't* on a model,
you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
isn't that difficult, after all.

View File

@ -188,7 +188,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
* ``allow_empty``: A boolean specifying whether to display the page if no * ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available, objects are available. If this is ``False`` and no objects are available,
the view will raise a 404 instead of displaying an empty page. By the view will raise a 404 instead of displaying an empty page. By
default, this is ``False``. default, this is ``True``.
* ``context_processors``: A list of template-context processors to apply to * ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
@ -718,7 +718,7 @@ A page representing a list of objects.
* ``allow_empty``: A boolean specifying whether to display the page if no * ``allow_empty``: A boolean specifying whether to display the page if no
objects are available. If this is ``False`` and no objects are available, objects are available. If this is ``False`` and no objects are available,
the view will raise a 404 instead of displaying an empty page. By the view will raise a 404 instead of displaying an empty page. By
default, this is ``False``. default, this is ``True``.
* ``context_processors``: A list of template-context processors to apply to * ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.

View File

@ -73,13 +73,17 @@ installed.
If you plan to use Django's ``manage.py syncdb`` command to If you plan to use Django's ``manage.py syncdb`` command to
automatically create database tables for your models, you'll need to automatically create database tables for your models, you'll need to
ensure that Django has permission to create tables in the database ensure that Django has permission to create and alter tables in the
you're using; if you plan to manually create the tables, you can database you're using; if you plan to manually create the tables, you
simply grant Django ``SELECT``, ``INSERT``, ``UPDATE`` and ``DELETE`` can simply grant Django ``SELECT``, ``INSERT``, ``UPDATE`` and
permissions. Django does not issue ``ALTER TABLE`` statements, and so ``DELETE`` permissions. On some databases, Django will need to have
will not require permission to do so. If you will be using Django's ``ALTER TABLE`` privileges during ``syncdb`` (in order to create
`testing framework`_ with data fixtures, Django will need permission foreign key constraints properly on databases which do not allow them
to create a temporary test database. to be deferred), but will not issue ``ALTER TABLE`` statements on a
table once ``syncdb`` has finished setting it up.
If you will be using Django's `testing framework`_ with data fixtures,
Django will need permission to create a temporary test database.
.. _PostgreSQL: http://www.postgresql.org/ .. _PostgreSQL: http://www.postgresql.org/
.. _MySQL: http://www.mysql.com/ .. _MySQL: http://www.mysql.com/

654
docs/localflavor.txt Normal file
View File

@ -0,0 +1,654 @@
==========================
The "local flavor" add-ons
==========================
Django comes with assorted pieces of code that are useful only for a particular
country or culture. These pieces of code are organized as a set of
subpackages, named using `ISO 3166 country codes`_.
.. _ISO 3166 country codes: http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
Most of the ``localflavor`` add-ons are localized form components deriving from
the newforms_ framework. To use one of these localized components, just import
the relevant subpackage. For example, a form with a field for French telephone
numbers is created like so::
from django import newforms as forms
from django.contrib.localflavor import fr
class MyForm(forms.Form):
my_french_phone_no = fr.forms.FRPhoneNumberField()
Countries currently supported by ``localflavor`` are:
* Argentina_
* Australia_
* Brazil_
* Canada_
* Chile_
* Finland_
* France_
* Germany_
* Holland_
* Iceland_
* India_
* Italy_
* Japan_
* Mexico_
* Norway_
* Peru_
* Poland_
* Slovakia_
* `South Africa`_
* Spain_
* Switzerland_
* `United Kingdom`_
* `United States of America`_
.. _Argentina: `Argentina (django.contrib.localflavor.ar)`_
.. _Australia: `Australia (django.contrib.localflavor.au)`_
.. _Brazil: `Brazil (django.contrib.localflavor.br)`_
.. _Canada: `Canada (django.contrib.localflavor.ca)`_
.. _Chile: `Chile (django.contrib.localflavor.cl)`_
.. _Finland: `Finland (django.contrib.localflavor.fi)`_
.. _France: `France (django.contrib.localflavor.fr)`_
.. _Germany: `Germany (django.contrib.localflavor.de)`_
.. _Holland: `Holland (django.contrib.localflavor.nl)`_
.. _Iceland: `Iceland (django.contrib.localflavor.is\_)`_
.. _India: `India (django.contrib.localflavor.in\_)`_
.. _Italy: `Italy (django.contrib.localflavor.it)`_
.. _Japan: `Japan (django.contrib.localflavor.jp)`_
.. _Mexico: `Mexico (django.contrib.localflavor.mx)`_
.. _Norway: `Norway (django.contrib.localflavor.no)`_
.. _Peru: `Peru (django.contrib.localflavor.pe)`_
.. _Poland: `Poland (django.contrib.localflavor.pl)`_
.. _Slovakia: `Slovakia (django.contrib.localflavor.sk)`_
.. _South Africa: `South Africa (django.contrib.localflavor.za)`_
.. _Spain: `Spain (django.contrib.localflavor.es)`_
.. _Switzerland: `Switzerland (django.contrib.localflavor.ch)`_
.. _United Kingdom: `United Kingdom (django.contrib.localflavor.uk)`_
.. _United States of America: `United States of America (django.contrib.localflavor.us)`_
The ``localflavor`` add-on also includes the ``generic`` subpackage, containing
useful code that is not specific to one particular country or culture.
Currently, it defines date and date & time input fields based on those from
newforms_, but with non-US default formats. Here's an example of how to use
them::
from django import newforms as forms
from django.contrib.localflavor import generic
class MyForm(forms.Form):
my_date_field = generic.forms.DateField()
.. _newforms: ../newforms/
.. admonition:: Adding a Flavor
We'd love to add more of these to Django, so please create a ticket for
anything that you've found useful. Please use unicode objects
(``u'mystring'``) for strings, rather than setting the encoding in the file
(see any of the existing flavors for examples).
Argentina (``django.contrib.localflavor.ar``)
=============================================
ARPostalCodeField
-----------------
A form field that validates input as either a classic four-digit Argentinian
postal code or a CPA_.
.. _CPA: http://www.correoargentino.com.ar/consulta_cpa/home.php
ARProvinceSelect
----------------
A ``Select`` widget that uses a list of Argentina's provinces as its choices.
Australia (``django.contrib.localflavor.au``)
=============================================
AUPostCodeField
---------------
A form field that validates input as an Australian postcode.
AUPhoneNumberField
------------------
A form field that validates input as an Australian phone number. Valid numbers
have ten digits.
AUStateSelect
-------------
A ``Select`` widget that uses a list of Australian states/territories as its
choices.
Brazil (``django.contrib.localflavor.br``)
==========================================
BRPhoneNumberField
------------------
A form field that validates input as a Brazilian phone number, with the format
XX-XXXX-XXXX.
BRZipCodeField
--------------
A form field that validates input as a Brazilian zip code, with the format
XXXXX-XXX.
BRStateSelect
-------------
A ``Select`` widget that uses a list of Brazilian states/territories as its
choices.
Canada (``django.contrib.localflavor.ca``)
==========================================
CAPhoneNumberField
------------------
A form field that validates input as a Canadian phone number, with the format
XXX-XXX-XXXX.
CAPostalCodeField
-----------------
A form field that validates input as a Canadian postal code, with the format
XXX XXX.
CAProvinceField
---------------
A form field that validates input as a Canadian province name or abbreviation.
CASocialInsuranceNumberField
----------------------------
A form field that validates input as a Canadian Social Insurance Number (SIN).
A valid number must have the format XXX-XXX-XXXX and pass a `Luhn mod-10
checksum`_.
.. _Luhn mod-10 checksum: http://en.wikipedia.org/wiki/Luhn_algorithm
CAProvinceSelect
----------------
A ``Select`` widget that uses a list of Canadian provinces and territories as
its choices.
Chile (``django.contrib.localflavor.cl``)
=========================================
CLRutField
----------
A form field that validates input as a Chilean national identification number
('Rol Unico Tributario' or RUT). The valid format is XX.XXX.XXX-X.
CLRegionSelect
--------------
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
choices.
Finland (``django.contrib.localflavor.fi``)
===========================================
FISocialSecurityNumber
----------------------
A form field that validates input as a Finnish social security number.
FIZipCodeField
--------------
A form field that validates input as a Finnish zip code. Valid codes
consist of five digits.
FIMunicipalitySelect
--------------------
A ``Select`` widget that uses a list of Finnish municipalities as its
choices.
France (``django.contrib.localflavor.fr``)
==========================================
FRPhoneNumberField
------------------
A form field that validates input as a French local phone number. The
correct format is 0X XX XX XX XX. 0X.XX.XX.XX.XX and 0XXXXXXXXX validate
but are corrected to 0X XX XX XX XX.
FRZipCodeField
--------------
A form field that validates input as a French zip code. Valid codes
consist of five digits.
FRDepartmentSelect
------------------
A ``Select`` widget that uses a list of French departments as its choices.
Germany (``django.contrib.localflavor.de``)
===========================================
DEIdentityCardNumberField
-------------------------
A form field that validates input as a German identity card number
(Personalausweis_). Valid numbers have the format
XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes.
.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis
DEZipCodeField
--------------
A form field that validates input as a German zip code. Valid codes
consist of five digits.
DEStateSelect
-------------
A ``Select`` widget that uses a list of German states as its choices.
Holland (``django.contrib.localflavor.nl``)
===========================================
NLPhoneNumberField
------------------
A form field that validates input as a Dutch telephone number.
NLSofiNumberField
-----------------
A form field that validates input as a Dutch social security number
(SoFI/BSN).
NLZipCodeField
--------------
A form field that validates input as a Dutch zip code.
NLProvinceSelect
----------------
A ``Select`` widget that uses a list of Dutch provinces as its list of
choices.
Iceland (``django.contrib.localflavor.is_``)
============================================
ISIdNumberField
---------------
A form field that validates input as an Icelandic identification number
(kennitala). The format is XXXXXX-XXXX.
ISPhoneNumberField
------------------
A form field that validates input as an Icelandtic phone number (seven
digits with an optional hyphen or space after the first three digits).
ISPostalCodeSelect
------------------
A ``Select`` widget that uses a list of Icelandic postal codes as its
choices.
India (``django.contrib.localflavor.in_``)
==========================================
INStateField
------------
A form field that validates input as an Indian state/territory name or
abbreviation. Input is normalized to the standard two-letter vehicle
registration abbreviation for the given state or territory.
INZipCodeField
--------------
A form field that validates input as an Indian zip code, with the
format XXXXXXX.
INStateSelect
-------------
A ``Select`` widget that uses a list of Indian states/territories as its
choices.
Italy (``django.contrib.localflavor.it``)
=========================================
ITSocialSecurityNumberField
---------------------------
A form field that validates input as an Italian social security number
(`codice fiscale`_).
.. _codice fiscale: http://www.agenziaentrate.it/ilwwcm/connect/Nsi/Servizi/Codice+fiscale+-+tessera+sanitaria/Codice+fiscale/NSI+Informazioni+sulla+codificazione+delle+persone+fisiche
ITVatNumberField
----------------
A form field that validates Italian VAT numbers (partita IVA).
ITZipCodeField
--------------
A form field that validates input as an Italian zip code. Valid codes
must have five digits.
ITProvinceSelect
----------------
A ``Select`` widget that uses a list of Italian provinces as its choices.
ITRegionSelect
--------------
A ``Select`` widget that uses a list of Italian regions as its choices.
Japan (``django.contrib.localflavor.jp``)
=========================================
JPPostalCodeField
-----------------
A form field that validates input as a Japanese postcode.
It accepts seven digits, with or without a hyphen.
JPPrefectureSelect
------------------
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
Mexico (``django.contrib.localflavor.mx``)
==========================================
MXStateSelect
-------------
A ``Select`` widget that uses a list of Mexican states as its choices.
Norway (``django.contrib.localflavor.no``)
==========================================
NOSocialSecurityNumber
----------------------
A form field that validates input as a Norwegian social security number
(personnummer_).
.. _personnummer: http://no.wikipedia.org/wiki/Personnummer
NOZipCodeField
--------------
A form field that validates input as a Norwegian zip code. Valid codes
have four digits.
NOMunicipalitySelect
--------------------
A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as
its choices.
Peru (``django.contrib.localflavor.pe``)
========================================
PEDNIField
----------
A form field that validates input as a DNI (Peruvian national identity)
number.
PERUCField
----------
A form field that validates input as an RUC (Registro Unico de
Contribuyentes) number. Valid RUC numbers have eleven digits.
PEDepartmentSelect
------------------
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
Poland (``django.contrib.localflavor.pl``)
==========================================
PLNationalIdentificationNumberField
-----------------------------------
A form field that validates input as a Polish national identification number
(PESEL_).
.. _PESEL: http://en.wikipedia.org/wiki/PESEL
PLNationalBusinessRegisterField
-------------------------------
A form field that validates input as a Polish National Official Business
Register Number (REGON_), having either seven or nine digits. The checksum
algorithm used for REGONs is documented at
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
.. _REGON: http://www.stat.gov.pl/bip/regon_ENG_HTML.htm
PLPostalCodeField
-----------------
A form field that validates input as a Polish postal code. The valid format
is XX-XXX, where X is a digit.
PLTaxNumberField
----------------
A form field that validates input as a Polish Tax Number (NIP). Valid
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
PLAdministrativeUnitSelect
--------------------------
A ``Select`` widget that uses a list of Polish administrative units as its
choices.
PLVoivodeshipSelect
-------------------
A ``Select`` widget that uses a list of Polish voivodeships (administrative
provinces) as its choices.
Slovakia (``django.contrib.localflavor.sk``)
============================================
SKPostalCodeField
-----------------
A form field that validates input as a Slovak postal code. Valid formats
are XXXXX or XXX XX, where X is a digit.
SKDistrictSelect
----------------
A ``Select`` widget that uses a list of Slovak districts as its choices.
SKRegionSelect
--------------
A ``Select`` widget that uses a list of Slovak regions as its choices.
South Africa (``django.contrib.localflavor.za``)
================================================
ZAIDField
---------
A form field that validates input as a South African ID number. Validation
uses the Luhn checksum and a simplistic (i.e., not entirely accurate) check
for birth date.
ZAPostCodeField
---------------
A form field that validates input as a South African postcode. Valid
postcodes must have four digits.
Spain (``django.contrib.localflavor.es``)
=========================================
ESIdentityCardNumberField
-------------------------
A form field that validates input as a Spanish NIF/NIE/CIF (Fiscal
Identification Number) code.
ESCCCField
----------
A form field that validates input as a Spanish bank account number (Codigo
Cuenta Cliente or CCC). A valid CCC number has the format
EEEE-OOOO-CC-AAAAAAAAAA, where the E, O, C and A digits denote the entity,
office, checksum and account, respectively. The first checksum digit
validates the entity and office. The second checksum digit validates the
account. It is also valid to use a space as a delimiter, or to use no
delimiter.
ESPhoneNumberField
------------------
A form field that validates input as a Spanish phone number. Valid numbers
have nine digits, the first of which is 6, 8 or 9.
ESPostalCodeField
-----------------
A form field that validates input as a Spanish postal code. Valid codes
have five digits, the first two being in the range 01 to 52, representing
the province.
ESProvinceSelect
----------------
A ``Select`` widget that uses a list of Spanish provinces as its choices.
ESRegionSelect
--------------
A ``Select`` widget that uses a list of Spanish regions as its choices.
Switzerland (``django.contrib.localflavor.ch``)
===============================================
CHIdentityCardNumberField
-------------------------
A form field that validates input as a Swiss identity card number.
A valid number must confirm to the X1234567<0 or 1234567890 format and
have the correct checksums -- see http://adi.kousz.ch/artikel/IDCHE.htm.
CHPhoneNumberField
------------------
A form field that validates input as a Swiss phone number. The correct
format is 0XX XXX XX XX. 0XX.XXX.XX.XX and 0XXXXXXXXX validate but are
corrected to 0XX XXX XX XX.
CHZipCodeField
--------------
A form field that validates input as a Swiss zip code. Valid codes
consist of four digits.
CHStateSelect
-------------
A ``Select`` widget that uses a list of Swiss states as its choices.
United Kingdom (``django.contrib.localflavor.uk``)
==================================================
UKPostcodeField
---------------
A form field that validates input as a UK postcode. The regular
expression used is sourced from the schema for British Standard BS7666
address types at http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd.
United States of America (``django.contrib.localflavor.us``)
============================================================
USPhoneNumberField
------------------
A form field that validates input as a U.S. phone number.
USSocialSecurityNumberField
---------------------------
A form field that validates input as a U.S. Social Security Number (SSN).
A valid SSN must obey the following rules:
* Format of XXX-XX-XXXX
* No group of digits consisting entirely of zeroes
* Leading group of digits cannot be 666
* Number not in promotional block 987-65-4320 through 987-65-4329
* Number not one known to be invalid due to widespread promotional
use or distribution (e.g., the Woolworth's number or the 1962
promotional number)
USStateField
------------
A form field that validates input as a U.S. state name or abbreviation. It
normalizes the input to the standard two-letter postal service abbreviation
for the given state.
USZipCodeField
--------------
A form field that validates input as a U.S. zip code. Valid formats are
XXXXX or XXXXX-XXXX.
USStateSelect
-------------
A form Select widget that uses a list of U.S. states/territories as its
choices.

View File

@ -58,11 +58,20 @@ Adds a few conveniences for perfectionists:
which should be a list of strings. which should be a list of strings.
* Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW`` * Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW``
settings. If ``APPEND_SLASH`` is ``True``, URLs that lack a trailing settings.
slash will be redirected to the same URL with a trailing slash, unless the
last component in the path contains a period. So ``foo.com/bar`` is If ``APPEND_SLASH`` is ``True`` and the initial URL doesn't end with a slash,
redirected to ``foo.com/bar/``, but ``foo.com/bar/file.txt`` is passed and it is not found in urlpatterns, a new URL is formed by appending a slash
through unchanged. at the end. If this new URL is found in urlpatterns, then an HTTP-redirect is
returned to this new URL; otherwise the initial URL is processed as usual.
So ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if you do not
have a valid urlpattern for ``foo.com/bar``, and do have a valid urlpattern
for ``foo.com/bar/``.
**New in Django development version:** The behaviour of ``APPEND_SLASH`` has
changed slightly in the development version (it didn't used to check to see
if the pattern was matched in the URL patterns).
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
redirected to the same URL with a leading "www." redirected to the same URL with a leading "www."

View File

@ -618,8 +618,9 @@ statement for this field.
**New in Django development version** **New in Django development version**
The name of the database tablespace to use for this field's index, if The name of the database tablespace to use for this field's index, if
indeed this field is indexed. The default is the ``db_tablespace`` of indeed this field is indexed. The default is the project's
the model, if any. If the backend doesn't support tablespaces, this ``DEFAULT_INDEX_TABLESPACE`` setting, if set, or the ``db_tablespace``
of the model, if any. If the backend doesn't support tablespaces, this
option is ignored. option is ignored.
``default`` ``default``

310
docs/modelforms.txt Normal file
View File

@ -0,0 +1,310 @@
==========================
Using newforms with models
==========================
``ModelForm``
=============
If you're building a database-driven app, chances are you'll have forms that
map closely to Django models. For instance, you might have a ``BlogComment``
model, and you want to create a form that lets people submit comments. In this
case, it would be redundant to define the field types in your form, because
you've already defined the fields in your model.
For this reason, Django provides a helper class that let you create a ``Form``
class from a Django model.
For example::
>>> from django.newforms import ModelForm
# Create the form class.
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
# Creating a form to add an article.
>>> article = Article()
>>> form = ArticleForm(article)
# Creating a form to change an existing article.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(article)
Field types
-----------
The generated ``Form`` class will have a form field for every model field. Each
model field has a corresponding default form field. For example, a
``CharField`` on a model is represented as a ``CharField`` on a form. A
model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
the full list of conversions:
=============================== ========================================
Model field Form field
=============================== ========================================
``AutoField`` Not represented in the form
``BooleanField`` ``BooleanField``
``CharField`` ``CharField`` with ``max_length`` set to
the model field's ``max_length``
``CommaSeparatedIntegerField`` ``CharField``
``DateField`` ``DateField``
``DateTimeField`` ``DateTimeField``
``DecimalField`` ``DecimalField``
``EmailField`` ``EmailField``
``FileField`` ``FileField``
``FilePathField`` ``CharField``
``FloatField`` ``FloatField``
``ForeignKey`` ``ModelChoiceField`` (see below)
``ImageField`` ``ImageField``
``IntegerField`` ``IntegerField``
``IPAddressField`` ``IPAddressField``
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
below)
``NullBooleanField`` ``CharField``
``PhoneNumberField`` ``USPhoneNumberField``
(from ``django.contrib.localflavor.us``)
``PositiveIntegerField`` ``IntegerField``
``PositiveSmallIntegerField`` ``IntegerField``
``SlugField`` ``CharField``
``SmallIntegerField`` ``IntegerField``
``TextField`` ``CharField`` with ``widget=Textarea``
``TimeField`` ``TimeField``
``URLField`` ``URLField`` with ``verify_exists`` set
to the model field's ``verify_exists``
``USStateField`` ``CharField`` with
``widget=USStateSelect``
(``USStateSelect`` is from
``django.contrib.localflavor.us``)
``XMLField`` ``CharField`` with ``widget=Textarea``
=============================== ========================================
.. note::
The ``FloatField`` form field and ``DecimalField`` model and form fields
are new in the development version.
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
types are special cases:
* ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
* ``ManyToManyField`` is represented by
``django.newforms.ModelMultipleChoiceField``, which is a
``MultipleChoiceField`` whose choices are a model ``QuerySet``.
In addition, each generated form field has attributes set as follows:
* If the model field has ``blank=True``, then ``required`` is set to
``False`` on the form field. Otherwise, ``required=True``.
* The form field's ``label`` is set to the ``verbose_name`` of the model
field, with the first character capitalized.
* The form field's ``help_text`` is set to the ``help_text`` of the model
field.
* If the model field has ``choices`` set, then the form field's ``widget``
will be set to ``Select``, with choices coming from the model field's
``choices``. The choices will normally include the blank choice which is
selected by default. If the field is required, this forces the user to
make a selection. The blank choice will not be included if the model
field has ``blank=False`` and an explicit ``default`` value (the
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
field. See "Overriding the default field types" below.
A full example
--------------
Consider this set of models::
from django.db import models
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
class BookForm(ModelForm):
class Meta:
model = Book
With these models, the ``ModelForm`` subclasses above would be roughly
equivalent to this (the only difference being the ``save()`` method, which
we'll discuss in a moment.)::
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(max_length=3,
widget=forms.Select(choices=TITLE_CHOICES))
birth_date = forms.DateField(required=False)
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
The ``save()`` method
---------------------
Every form produced by ``ModelForm`` also has a ``save()`` method. This
method creates and saves a database object from the data bound to the form.
A subclass of ``ModelForm`` also requires a model instance as the first
arument to its constructor. For example::
# Create a form instance from POST data.
>>> a = Article()
>>> f = ArticleForm(a, request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
Note that ``save()`` will raise a ``ValueError`` if the data in the form
doesn't validate -- i.e., ``if form.errors``.
This ``save()`` method accepts an optional ``commit`` keyword argument, which
accepts either ``True`` or ``False``. If you call ``save()`` with
``commit=False``, then it will return an object that hasn't yet been saved to
the database. In this case, it's up to you to call ``save()`` on the resulting
model instance. This is useful if you want to do custom processing on the
object before saving it. ``commit`` is ``True`` by default.
Another side effect of using ``commit=False`` is seen when your model has
a many-to-many relation with another model. If your model has a many-to-many
relation and you specify ``commit=False`` when you save a form, Django cannot
immediately save the form data for the many-to-many relation. This is because
it isn't possible to save many-to-many data for an instance until the instance
exists in the database.
To work around this problem, every time you save a form using ``commit=False``,
Django adds a ``save_m2m()`` method to your ``ModelForm`` subclass. After
you've manually saved the instance produced by the form, you can invoke
``save_m2m()`` to save the many-to-many form data. For example::
# Create a form instance with POST data.
>>> a = Author()
>>> f = AuthorForm(a, request.POST)
# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)
# Modify the author in some way.
>>> new_author.some_field = 'some_value'
# Save the new instance.
>>> new_author.save()
# Now, save the many-to-many data for the form.
>>> f.save_m2m()
Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
When you use a simple ``save()`` on a form, all data -- including
many-to-many data -- is saved without the need for any additional method calls.
For example::
# Create a form instance with POST data.
>>> a = Author()
>>> f = AuthorForm(a, request.POST)
# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()
Using a subset of fields on the form
------------------------------------
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
model fields:
1. Set ``editable=False`` on the model field. As a result, *any* form
created from the model via ``ModelForm`` will not include that
field.
2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` class.
This attribute, if given, should be a list of field names to include in
the form.
3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` class.
This attribute, if given, should be a list of field names to exclude
the form.
For example, if you want a form for the ``Author`` model (defined above)
that includes only the ``name`` and ``title`` fields, you would specify
``fields`` or ``exclude`` like this::
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
class PartialAuthorForm(ModelForm):
class Meta:
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::
If you specify ``fields`` or ``exclude`` when creating a form with
``ModelForm``, then the fields that are not in the resulting form will not
be set by the form's ``save()`` method. Django will prevent any attempt to
save an incomplete model, so if the model does not allow the missing fields
to be empty, and does not provide a default value for the missing fields,
any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
To avoid this failure, you must instantiate your model with initial values
for the missing, but required fields, or use ``save(commit=False)`` and
manually set anyextra required fields::
instance = Instance(required_field='value')
form = InstanceForm(instance, request.POST)
new_instance = form.save()
instance = form.save(commit=False)
instance.required_field = 'new value'
new_instance = instance.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.
.. _section on saving forms: `The save() method`_
Overriding the default field types
----------------------------------
The default field types, as described in the "Field types" table above, are
sensible defaults; if you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
``ModelForm`` gives you the flexibility of changing the form field type
for a given model field. You do this by declaratively specifying fields like
you would in a regular ``Form``. Declared fields will override the default
ones generated by using the ``model`` attribute.
For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
field, you could do the following::
>>> class ArticleForm(ModelForm):
... pub_date = MyDateFormField()
...
... class Meta:
... model = Article

View File

@ -759,8 +759,9 @@ For example::
Highlighting required fields in templates Highlighting required fields in templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You may wish to show a visitor which fields are required. Here is the above It's common to show a user which fields are required. Here's an example of how
example modified to insert an asterix after the label of each required field:: to do that, using the above example modified to insert an asterisk after the
label of each required field::
<form method="post" action=""> <form method="post" action="">
<dl> <dl>
@ -775,10 +776,11 @@ example modified to insert an asterix after the label of each required field::
</form> </form>
The ``{% if field.field.required %}*{% endif %}`` fragment is the relevant The ``{% if field.field.required %}*{% endif %}`` fragment is the relevant
addition here. It adds the asterix only if the field is required. Note that we addition here. It adds the asterisk only if the field is required.
check ``field.field.required`` and not ``field.required``. In the template,
``field`` is a ``newforms.forms.BoundField`` instance, which holds the actual Note that we check ``field.field.required`` and not ``field.required``. In the
``Field`` instance in its ``field`` attribute. template, ``field`` is a ``newforms.forms.BoundField`` instance, which holds
the actual ``Field`` instance in its ``field`` attribute.
Binding uploaded files to a form Binding uploaded files to a form
-------------------------------- --------------------------------
@ -1108,9 +1110,9 @@ fields. We've specified ``auto_id=False`` to simplify the output::
**New in Django development version** **New in Django development version**
The ``error_messages`` argument lets you override the default messages which the The ``error_messages`` argument lets you override the default messages that the
field will raise. Pass in a dictionary with keys matching the error messages you field will raise. Pass in a dictionary with keys matching the error messages you
want to override. For example:: want to override. For example, here is the default error message::
>>> generic = forms.CharField() >>> generic = forms.CharField()
>>> generic.clean('') >>> generic.clean('')
@ -1118,14 +1120,16 @@ want to override. For example::
... ...
ValidationError: [u'This field is required.'] ValidationError: [u'This field is required.']
And here is a custom error message::
>>> name = forms.CharField(error_messages={'required': 'Please enter your name'}) >>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
>>> name.clean('') >>> name.clean('')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Please enter your name'] ValidationError: [u'Please enter your name']
In the `built-in Field classes`_ section below, each Field defines the error In the `built-in Field classes`_ section below, each ``Field`` defines the
message keys it uses. error message keys it uses.
Dynamic initial values Dynamic initial values
---------------------- ----------------------
@ -1769,421 +1773,14 @@ You can then use this field whenever you have a form that requires a comment::
Generating forms for models Generating forms for models
=========================== ===========================
If you're building a database-driven app, chances are you'll have forms that The prefered way of generating forms that work with models is explained in the
map closely to Django models. For instance, you might have a ``BlogComment`` `ModelForms documentation`_.
model, and you want to create a form that lets people submit comments. In this
case, it would be redundant to define the field types in your form, because
you've already defined the fields in your model.
For this reason, Django provides a few helper functions that let you create a Looking for the ``form_for_model`` and ``form_for_instance`` documentation?
``Form`` class from a Django model. They've been deprecated, but you can still `view the documentation`_.
``form_for_model()`` .. _ModelForms documentation: ../modelforms/
-------------------- .. _view the documentation: ../form_for_model/
The method ``django.newforms.form_for_model()`` creates a form based on the
definition of a specific model. Pass it the model class, and it will return a
``Form`` class that contains a form field for each model field.
For example::
>>> from django.newforms import form_for_model
# Create the form class.
>>> ArticleForm = form_for_model(Article)
# Create an empty form instance.
>>> f = ArticleForm()
It bears repeating that ``form_for_model()`` takes the model *class*, not a
model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
Field types
~~~~~~~~~~~
The generated ``Form`` class will have a form field for every model field. Each
model field has a corresponding default form field. For example, a
``CharField`` on a model is represented as a ``CharField`` on a form. A
model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
the full list of conversions:
=============================== ========================================
Model field Form field
=============================== ========================================
``AutoField`` Not represented in the form
``BooleanField`` ``BooleanField``
``CharField`` ``CharField`` with ``max_length`` set to
the model field's ``max_length``
``CommaSeparatedIntegerField`` ``CharField``
``DateField`` ``DateField``
``DateTimeField`` ``DateTimeField``
``DecimalField`` ``DecimalField``
``EmailField`` ``EmailField``
``FileField`` ``FileField``
``FilePathField`` ``CharField``
``FloatField`` ``FloatField``
``ForeignKey`` ``ModelChoiceField`` (see below)
``ImageField`` ``ImageField``
``IntegerField`` ``IntegerField``
``IPAddressField`` ``IPAddressField``
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
below)
``NullBooleanField`` ``CharField``
``PhoneNumberField`` ``USPhoneNumberField``
(from ``django.contrib.localflavor.us``)
``PositiveIntegerField`` ``IntegerField``
``PositiveSmallIntegerField`` ``IntegerField``
``SlugField`` ``CharField``
``SmallIntegerField`` ``IntegerField``
``TextField`` ``CharField`` with ``widget=Textarea``
``TimeField`` ``TimeField``
``URLField`` ``URLField`` with ``verify_exists`` set
to the model field's ``verify_exists``
``USStateField`` ``CharField`` with
``widget=USStateSelect``
(``USStateSelect`` is from
``django.contrib.localflavor.us``)
``XMLField`` ``CharField`` with ``widget=Textarea``
=============================== ========================================
.. note::
The ``FloatField`` form field and ``DecimalField`` model and form fields
are new in the development version.
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
types are special cases:
* ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
* ``ManyToManyField`` is represented by
``django.newforms.ModelMultipleChoiceField``, which is a
``MultipleChoiceField`` whose choices are a model ``QuerySet``.
In addition, each generated form field has attributes set as follows:
* If the model field has ``blank=True``, then ``required`` is set to
``False`` on the form field. Otherwise, ``required=True``.
* The form field's ``label`` is set to the ``verbose_name`` of the model
field, with the first character capitalized.
* The form field's ``help_text`` is set to the ``help_text`` of the model
field.
* If the model field has ``choices`` set, then the form field's ``widget``
will be set to ``Select``, with choices coming from the model field's
``choices``. The choices will normally include the blank choice which is
selected by default. If the field is required, this forces the user to
make a selection. The blank choice will not be included if the model
field has ``blank=False`` and an explicit ``default`` value (the
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
field. See "Overriding the default field types" below.
A full example
~~~~~~~~~~~~~~
Consider this set of models::
from django.db import models
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
With these models, a call to ``form_for_model(Author)`` would return a ``Form``
class equivalent to this::
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(max_length=3,
widget=forms.Select(choices=TITLE_CHOICES))
birth_date = forms.DateField(required=False)
A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
this::
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
The ``save()`` method
~~~~~~~~~~~~~~~~~~~~~
Every form produced by ``form_for_model()`` also has a ``save()`` method. This
method creates and saves a database object from the data bound to the form. For
example::
# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
Note that ``save()`` will raise a ``ValueError`` if the data in the form
doesn't validate -- i.e., ``if form.errors``.
This ``save()`` method accepts an optional ``commit`` keyword argument, which
accepts either ``True`` or ``False``. If you call ``save()`` with
``commit=False``, then it will return an object that hasn't yet been saved to
the database. In this case, it's up to you to call ``save()`` on the resulting
model instance. This is useful if you want to do custom processing on the
object before saving it. ``commit`` is ``True`` by default.
Another side effect of using ``commit=False`` is seen when your model has
a many-to-many relation with another model. If your model has a many-to-many
relation and you specify ``commit=False`` when you save a form, Django cannot
immediately save the form data for the many-to-many relation. This is because
it isn't possible to save many-to-many data for an instance until the instance
exists in the database.
To work around this problem, every time you save a form using ``commit=False``,
Django adds a ``save_m2m()`` method to the form created by ``form_for_model``.
After you've manually saved the instance produced by the form, you can invoke
``save_m2m()`` to save the many-to-many form data. For example::
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)
# Modify the author in some way.
>>> new_author.some_field = 'some_value'
# Save the new instance.
>>> new_author.save()
# Now, save the many-to-many data for the form.
>>> f.save_m2m()
Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
When you use a simple ``save()`` on a form, all data -- including
many-to-many data -- is saved without the need for any additional method calls.
For example::
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()
Using an alternate base class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to add custom methods to the form generated by
``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
and contains your custom methods. Then, use the ``form`` argument to
``form_for_model()`` to tell it to use your custom form as its base class.
For example::
# Create the new base class.
>>> class MyBase(BaseForm):
... def my_method(self):
... # Do whatever the method does
# Create the form class with a different base class.
>>> ArticleForm = form_for_model(Article, form=MyBase)
# Instantiate the form.
>>> f = ArticleForm()
# Use the base class method.
>>> f.my_method()
Using a subset of fields on the form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**New in Django development version**
In some cases, you may not want all the model fields to appear on the generated
form. There are two ways of telling ``form_for_model()`` to use only a subset
of the model fields:
1. Set ``editable=False`` on the model field. As a result, *any* form
created from the model via ``form_for_model()`` will not include that
field.
2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
given, should be a list of field names to include in the form.
For example, if you want a form for the ``Author`` model (defined above)
that includes only the ``name`` and ``title`` fields, you would specify
``fields`` like this::
PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
.. note::
If you specify ``fields`` when creating a form with ``form_for_model()``,
then the fields that are *not* specified will not be set by the form's
``save()`` method. Django will prevent any attempt to save an incomplete
model, so if the model does not allow the missing fields to be empty, and
does not provide a default value for the missing fields, any attempt to
``save()`` a ``form_for_model`` with missing fields will fail. To avoid
this failure, you must use ``save(commit=False)`` and manually set any
extra required fields::
instance = form.save(commit=False)
instance.required_field = 'new value'
instance.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.
.. _section on saving forms: `The save() method`_
Overriding the default field types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default field types, as described in the "Field types" table above, are
sensible defaults; if you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
``form_for_model()`` gives you the flexibility of changing the form field type
for a given model field. You do this by specifying a **formfield callback**.
A formfield callback is a function that, when provided with a model field,
returns a form field instance. When constructing a form, ``form_for_model()``
asks the formfield callback to provide form field types.
By default, ``form_for_model()`` calls the ``formfield()`` method on the model
field::
def default_callback(field, **kwargs):
return field.formfield(**kwargs)
The ``kwargs`` are any keyword arguments that might be passed to the form
field, such as ``required=True`` or ``label='Foo'``.
For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
field on the model, you could define the callback::
>>> def my_callback(field, **kwargs):
... if isinstance(field, models.DateField):
... return MyDateFormField(**kwargs)
... else:
... return field.formfield(**kwargs)
>>> ArticleForm = form_for_model(Article, formfield_callback=my_callback)
Note that your callback needs to handle *all* possible model field types, not
just the ones that you want to behave differently to the default. That's why
this example has an ``else`` clause that implements the default behavior.
.. warning::
The field that is passed into the ``formfield_callback`` function in
``form_for_model()`` and ``form_for_instance`` is the field instance from
your model's class. You **must not** alter that object at all; treat it
as read-only!
If you make any alterations to that object, it will affect any future
users of the model class, because you will have changed the field object
used to construct the class. This is almost certainly what you don't want
to have happen.
Finding the model associated with a form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The model class that was used to construct the form is available
using the ``_model`` property of the generated form::
>>> ArticleForm = form_for_model(Article)
>>> ArticleForm._model
<class 'myapp.models.Article'>
``form_for_instance()``
-----------------------
``form_for_instance()`` is like ``form_for_model()``, but it takes a model
instance instead of a model class::
# Create an Author.
>>> a = Author(name='Joe Smith', title='MR', birth_date=None)
>>> a.save()
# Create a form for this particular Author.
>>> AuthorForm = form_for_instance(a)
# Instantiate the form.
>>> f = AuthorForm()
When a form created by ``form_for_instance()`` is created, the initial data
values for the form fields are drawn from the instance. However, this data is
not bound to the form. You will need to bind data to the form before the form
can be saved.
Unlike ``form_for_model()``, a choice field in form created by
``form_for_instance()`` will not include the blank choice if the respective
model field has ``blank=False``. The initial choice is drawn from the instance.
When you call ``save()`` on a form created by ``form_for_instance()``,
the database instance will be updated. As in ``form_for_model()``, ``save()``
will raise ``ValueError`` if the data doesn't validate.
``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
arguments that behave the same way as they do for ``form_for_model()``.
Let's modify the earlier `contact form`_ view example a little bit. Suppose we
have a ``Message`` model that holds each contact submission. Something like::
class Message(models.Model):
subject = models.CharField(max_length=100)
message = models.TextField()
sender = models.EmailField()
cc_myself = models.BooleanField(required=False)
You could use this model to create a form (using ``form_for_model()``). You
could also use existing ``Message`` instances to create a form for editing
messages. The earlier_ view can be changed slightly to accept the ``id`` value
of an existing ``Message`` and present it for editing::
def contact_edit(request, msg_id):
# Create the form from the message id.
message = get_object_or_404(Message, id=msg_id)
ContactForm = form_for_instance(message)
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/url/on_success/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form})
Aside from how we create the ``ContactForm`` class here, the main point to
note is that the form display in the ``GET`` branch of the function
will use the values from the ``message`` instance as initial values for the
form field.
.. _contact form: `Simple view example`_
.. _earlier: `Simple view example`_
When should you use ``form_for_model()`` and ``form_for_instance()``?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
shortcuts for the common case. If you want to create a form whose fields map to
more than one model, or a form that contains fields that *aren't* on a model,
you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
isn't that difficult, after all.
Media Media
===== =====

View File

@ -555,10 +555,13 @@ Three things to note about 404 views:
* The 404 view is also called if Django doesn't find a match after checking * The 404 view is also called if Django doesn't find a match after checking
every regular expression in the URLconf. every regular expression in the URLconf.
* If you don't define your own 404 view -- and simply use the default, * If you don't define your own 404 view -- and simply use the
which is recommended -- you still have one obligation: To create a default, which is recommended -- you still have one obligation:
``404.html`` template in the root of your template directory. The default you must create a ``404.html`` template in the root of your
404 view will use that template for all 404 errors. template directory. The default 404 view will use that template
for all 404 errors. The default 404 view will pass one variable
to the template: ``request_path``, which is the URL which
resulted in the 404.
* 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 will never be used, and the traceback will be displayed instead. view will never be used, and the traceback will be displayed instead.
@ -572,7 +575,8 @@ the view ``django.views.defaults.server_error``, which loads and renders the
template ``500.html``. template ``500.html``.
This means you need to define a ``500.html`` template in your root template This means you need to define a ``500.html`` template in your root template
directory. This template will be used for all server errors. directory. This template will be used for all server errors. The
default 500 view passes no variables to this template.
This ``server_error`` view should suffice for 99% of Web applications, but if This ``server_error`` view should suffice for 99% of Web applications, but if
you want to override the view, you can specify ``handler500`` in your you want to override the view, you can specify ``handler500`` in your

View File

@ -135,8 +135,8 @@ For example::
json_serializer = serializers.get_serializer("json")() json_serializer = serializers.get_serializer("json")()
json_serializer.serialize(queryset, ensure_ascii=False, stream=response) json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
Django ships with a copy of simplejson_ in the source. Be aware, that if The Django source code includes the simplejson_ module. Be aware that if
you're using that for serializing directly that not all Django output can be you're serializing using that module directly, not all Django output can be
passed unmodified to simplejson. In particular, `lazy translation objects`_ passed unmodified to simplejson. In particular, `lazy translation objects`_
need a `special encoder`_ written for them. Something like this will work:: need a `special encoder`_ written for them. Something like this will work::
@ -151,8 +151,3 @@ need a `special encoder`_ written for them. Something like this will work::
.. _lazy translation objects: ../i18n/#lazy-translation .. _lazy translation objects: ../i18n/#lazy-translation
.. _special encoder: http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7/docs/index.html .. _special encoder: http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7/docs/index.html
Writing custom serializers
``````````````````````````
XXX ...

View File

@ -99,6 +99,8 @@ It implements the following standard dictionary methods:
* ``items()`` * ``items()``
* ``setdefault()``
It also has these three methods: It also has these three methods:
* ``set_test_cookie()`` * ``set_test_cookie()``

View File

@ -225,6 +225,27 @@ Whether to append trailing slashes to URLs. This is only used if
``CommonMiddleware`` is installed (see the `middleware docs`_). See also ``CommonMiddleware`` is installed (see the `middleware docs`_). See also
``PREPEND_WWW``. ``PREPEND_WWW``.
AUTHENTICATION_BACKENDS
-----------------------
Default: ``('django.contrib.auth.backends.ModelBackend',)``
A tuple of authentication backend classes (as strings) to use when
attempting to authenticate a user. See the `authentication backends
documentation`_ for details.
.. _authentication backends documentation: ../authentication/#other-authentication-sources
AUTH_PROFILE_MODULE
-------------------
Default: Not defined
The site-specific user profile model used by this site. See the
`documentation on user profile models`_ for details.
.. _documentation on user profile models: ../authentication/#storing-additional-information-about-users
CACHE_BACKEND CACHE_BACKEND
------------- -------------
@ -393,6 +414,22 @@ Default: ``'webmaster@localhost'``
Default e-mail address to use for various automated correspondence from the Default e-mail address to use for various automated correspondence from the
site manager(s). site manager(s).
DEFAULT_TABLESPACE
------------------
Default: ``''`` (Empty string)
Default tablespace to use for models that do not specify one, if the
backend supports it.
DEFAULT_INDEX_TABLESPACE
------------------------
Default: ``''`` (Empty string)
Default tablespace to use for indexes on fields that do not specify
one, if the backend supports it.
DISALLOWED_USER_AGENTS DISALLOWED_USER_AGENTS
---------------------- ----------------------
@ -1129,12 +1166,12 @@ If you're not setting the ``DJANGO_SETTINGS_MODULE`` environment variable, you
settings. settings.
If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``, If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``,
Django will raise an ``EnvironmentError`` exception the first time a setting Django will raise an ``ImportError`` exception the first time a setting
is accessed. is accessed.
If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then* If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then*
call ``configure()``, Django will raise an ``EnvironmentError`` saying settings call ``configure()``, Django will raise a ``RuntimeError`` indicating
have already been configured. that settings have already been configured.
Also, it's an error to call ``configure()`` more than once, or to call Also, it's an error to call ``configure()`` more than once, or to call
``configure()`` after any setting has been accessed. ``configure()`` after any setting has been accessed.

View File

@ -98,8 +98,8 @@ This example is equivalent to::
except MyModel.DoesNotExist: except MyModel.DoesNotExist:
raise Http404 raise Http404
Note: As with ``get()``, an ``AssertionError`` will be raised if more than Note: As with ``get()``, an ``MultipleObjectsReturned`` exception will be
one object is found. raised if more than one object is found.
.. _get(): ../db-api/#get-kwargs .. _get(): ../db-api/#get-kwargs

View File

@ -603,8 +603,9 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
# ITEM LINK -- One of these three is required. The framework looks for # ITEM LINK -- One of these three is required. The framework looks for
# them in this order. # them in this order.
# First, the framework tries the get_absolute_url() method on each item # First, the framework tries the two methods below, in
# returned by items(). Failing that, it tries these two methods: # order. Failing that, it falls back to the get_absolute_url()
# method on each item returned by items().
def item_link(self, item): def item_link(self, item):
""" """

View File

@ -310,58 +310,106 @@ Automatic HTML escaping
**New in Django development version** **New in Django development version**
A very real problem when creating HTML (and other) output using templates and When generating HTML from templates, there's always a risk that a variable will
variable substitution is the possibility of accidently inserting some variable include characters that affect the resulting HTML. For example, consider this
value that affects the resulting HTML. For example, a template fragment such as template fragment::
::
Hello, {{ name }}. Hello, {{ name }}.
seems like a harmless way to display the user's name. However, if you are At first, this seems like a harmless way to display a user's name, but consider
displaying data that the user entered directly and they had entered their name as :: what would happen if the user entered his name as this::
<script>alert('hello')</script> <script>alert('hello')</script>
this would always display a Javascript alert box when the page was loaded. With this name value, the template would be rendered as::
Similarly, if you were displaying some data generated by another process and it
contained a '<' symbol, you couldn't just dump this straight into your HTML, Hello, <script>alert('hello')</script>
because it would be treated as the start of an element. The effects of these
sorts of problems can vary from merely annoying to allowing exploits via `Cross ...which means the browser would pop-up a JavaScript alert box!
Site Scripting`_ (XSS) attacks.
Similarly, what if the name contained a ``'<'`` symbol, like this?
<b>username
That would result in a rendered template like this::
Hello, <b>username
...which, in turn, would result in the remainder of the Web page being bolded!
Clearly, user-submitted data shouldn't be trusted blindly and inserted directly
into your Web pages, because a malicious user could use this kind of hole to
do potentially bad things. This type of security exploit is called a
`Cross Site Scripting`_ (XSS) attack.
To avoid this problem, you have two options:
* One, you can make sure to run each untrusted variable through the
``escape`` filter (documented below), which converts potentially harmful
HTML characters to unharmful ones. This was default the default solution
in Django for its first few years, but the problem is that it puts the
onus on *you*, the developer / template author, to ensure you're escaping
everything. It's easy to forget to escape data.
* Two, you can take advantage of Django's automatic HTML escaping. The
remainder of this section describes how auto-escaping works.
By default in the Django development version, every template automatically
escapes the output of every variable tag. Specifically, these five characters
are escaped:
* ``<`` is converted to ``&lt;``
* ``>`` is converted to ``&gt;``
* ``'`` (single quote) is converted to ``&#39;``
* ``"`` (double quote) is converted to ``&quot;``
* ``&`` is converted to ``&amp;``
Again, we stress that this behavior is on by default. If you're using Django's
template system, you're protected.
.. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting .. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting
In order to provide some protection against these problems, Django How to turn it off
provides automatic (but controllable) HTML escaping for data coming from ------------------
tempate variables. Inside this tag, any data that comes from template
variables is examined to see if it contains one of the five HTML characters
(<, >, ', " and &) that often need escaping and those characters are converted
to their respective HTML entities. It causes no harm if a character is
converted to an entity when it doesn't need to be, so all five characters are
always converted.
Since some variables will contain data that is *intended* to be rendered If you don't want data to be auto-escaped, on a per-site, per-template level or
as HTML, template tag and filter writers can mark their output strings as per-variable level, you can turn it off in several ways.
requiring no further escaping. For example, the ``unordered_list`` filter is
designed to return raw HTML and we want the template processor to simply
display the results as returned, without applying any escaping. That is taken
care of by the filter. The template author need do nothing special in that
case.
By default, automatic HTML escaping is always applied. However, sometimes you Why would you want to turn it off? Because sometimes, template variables
will not want this to occur (for example, if you're using the templating contain data that you *intend* to be rendered as raw HTML, in which case you
system to create an email). To control automatic escaping inside your template, don't want their contents to be escaped. For example, you might store a blob of
wrap the affected content in the ``autoescape`` tag, like so:: HTML in your database and want to embed that directly into your template. Or,
you might be using Django's template system to produce text that is *not* HTML
-- like an e-mail message, for instance.
For individual variables
~~~~~~~~~~~~~~~~~~~~~~~~
To disable auto-escaping for an individual variable, use the ``safe`` filter::
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
Think of *safe* as shorthand for *safe from further escaping* or *can be
safely interpreted as HTML*. In this example, if ``data`` contains ``'<b>'``,
the output will be::
This will be escaped: &lt;b&gt;
This will not be escaped: <b>
For template blocks
~~~~~~~~~~~~~~~~~~~
To control auto-escaping for a template, wrap the template (or just a
particular section of the template) in the ``autoescape`` tag, like so::
{% autoescape off %} {% autoescape off %}
Hello {{ name }} Hello {{ name }}
{% endautoescape %} {% endautoescape %}
The auto-escaping tag passes its effect onto templates that extend the The ``autoescape`` tag takes either ``on`` or ``off`` as its argument. At
current one as well as templates included via the ``include`` tag, just like times, you might want to force auto-escaping when it would otherwise be
all block tags. disabled. Here is an example template::
The ``autoescape`` tag takes either ``on`` or ``off`` as its argument. At times, you might want to force auto-escaping when it would otherwise be disabled. For example::
Auto-escaping is on by default. Hello {{ name }} Auto-escaping is on by default. Hello {{ name }}
@ -370,52 +418,60 @@ The ``autoescape`` tag takes either ``on`` or ``off`` as its argument. At times,
Nor this: {{ other_data }} Nor this: {{ other_data }}
{% autoescape on %} {% autoescape on %}
Auto-escaping applies again, {{ name }} Auto-escaping applies again: {{ name }}
{% endautoescape %} {% endautoescape %}
{% endautoescape %} {% endautoescape %}
For individual variables, the ``safe`` filter can also be used to indicate The auto-escaping tag passes its effect onto templates that extend the
that the contents should not be automatically escaped:: current one as well as templates included via the ``include`` tag, just like
all block tags. For example::
This will be escaped: {{ data }} # base.html
This will not be escaped: {{ data|safe }}
Think of *safe* as shorthand for *safe from further escaping* or *can be {% autoescape off %}
safely interpreted as HTML*. In this example, if ``data`` contains ``'<a>'``, <h1>{% block title %}</h1>
the output will be:: {% block content %}
{% endautoescape %}
This will be escaped: &lt;a&gt;
This will not be escaped: <a>
Generally, you won't need to worry about auto-escaping very much. View # child.html
developers and custom filter authors need to think about when their data
shouldn't be escaped and mark it appropriately. They are in a better position
to know when that should happen than the template author, so it is their
responsibility. By default, all output is escaped unless the template
processor is explicitly told otherwise.
You should also note that if you are trying to write a template that might be {% extends "base.html" %}
used in situations where automatic escaping is enabled or disabled and you {% block title %}This & that{% endblock %}
don't know which (such as when your template is included in other templates), {% block content %}<b>Hello!</b>{% endblock %}
you can safely write as if you were in an ``{% autoescape off %}`` situation.
Scatter ``escape`` filters around for any variables that need escaping. When Because auto-escaping is turned off in the base template, it will also be
auto-escaping is on, these extra filters won't change the output -- any turned off in the child template, resulting in the following rendered HTML::
variables that use the ``escape`` filter do not have further automatic
escaping applied to them. <h1>This & that</h1>
<b>Hello!</b>
Notes
-----
Generally, template authors don't need to worry about auto-escaping very much.
Developers on the Python side (people writing views and custom filters) need to
think about the cases in which data shouldn't be escaped, and mark data
appropriately, so things Just Work in the template.
If you're creating a template that might be used in situations where you're
not sure whether auto-escaping is enabled, then add an ``escape`` filter to any
variable that needs escaping. When auto-escaping is on, there's no danger of
the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not
affect auto-escaped variables.
String literals and automatic escaping String literals and automatic escaping
-------------------------------------- --------------------------------------
Sometimes you will pass a string literal as an argument to a filter. For As we mentioned earlier, filter arguments can be strings::
example::
{{ data|default:"This is a string literal." }} {{ data|default:"This is a string literal." }}
All string literals are inserted **without** any automatic escaping into the All string literals are inserted **without** any automatic escaping into the
template, if they are used (it's as if they were all passed through the template -- they act as if they were all passed through the ``safe`` filter.
``safe`` filter). The reasoning behind this is that the template author is in The reasoning behind this is that the template author is in control of what
control of what goes into the string literal, so they can make sure the text goes into the string literal, so they can make sure the text is correctly
is correctly escaped when the template is written. escaped when the template is written.
This means you would write :: This means you would write ::
@ -426,7 +482,7 @@ This means you would write ::
{{ data|default:"3 > 2" }} <-- Bad! Don't do this. {{ data|default:"3 > 2" }} <-- Bad! Don't do this.
This doesn't affect what happens to data coming from the variable itself. This doesn't affect what happens to data coming from the variable itself.
The variable's contents are still automatically escaped, if necessary, since The variable's contents are still automatically escaped, if necessary, because
they're beyond the control of the template author. they're beyond the control of the template author.
Using the built-in reference Using the built-in reference
@ -1230,11 +1286,11 @@ once, after all other filters).
Escapes a string's HTML. Specifically, it makes these replacements: Escapes a string's HTML. Specifically, it makes these replacements:
* ``"&"`` to ``"&amp;"`` * ``<`` is converted to ``&lt;``
* ``<`` to ``"&lt;"`` * ``>`` is converted to ``&gt;``
* ``>`` to ``"&gt;"`` * ``'`` (single quote) is converted to ``&#39;``
* ``'"'`` (double quote) to ``'&quot;'`` * ``"`` (double quote) is converted to ``&quot;``
* ``"'"`` (single quote) to ``'&#39;'`` * ``&`` is converted to ``&amp;``
The escaping is only applied when the string is output, so it does not matter The escaping is only applied when the string is output, so it does not matter
where in a chained sequence of filters you put ``escape``: it will always be where in a chained sequence of filters you put ``escape``: it will always be
@ -1277,7 +1333,7 @@ value Template Output
======== ======================= ====== ======== ======================= ======
If used with a numeric integer argument, ``floatformat`` rounds a number to If used with a numeric integer argument, ``floatformat`` rounds a number to
that many decimal places. For example: that many decimal places. For example:
======== ========================= ====== ======== ========================= ======
value Template Output value Template Output

View File

@ -727,134 +727,144 @@ Filters and auto-escaping
**New in Django development version** **New in Django development version**
When you are writing a custom filter, you need to give some thought to how When writing a custom filter, give some thought to how the filter will interact
this filter will interact with Django's auto-escaping behaviour. Firstly, you with Django's auto-escaping behavior. Note that three types of strings can be
should realise that there are three types of strings that can be passed around passed around inside the template code:
inside the template code:
* raw strings are the native Python ``str`` or ``unicode`` types. On * **Raw strings** are the native Python ``str`` or ``unicode`` types. On
output, they are escaped if auto-escaping is in effect and presented output, they're escaped if auto-escaping is in effect and presented
unchanged, otherwise. unchanged, otherwise.
* "safe" strings are strings that are safe from further escaping at output * **Safe strings** are strings that have been marked safe from further
time. Any necessary escaping has already been done. They are commonly used escaping at output time. Any necessary escaping has already been done.
for output that contains raw HTML that is intended to be intrepreted on the They're commonly used for output that contains raw HTML that is intended
client side. to be interpreted as-is on the client side.
Internally, these strings are of type ``SafeString`` or ``SafeUnicode``, Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
although they share a common base class in ``SafeData``, so you can test They share a common base class of ``SafeData``, so you can test
for them using code like:: for them using code like::
if isinstance(value, SafeData): if isinstance(value, SafeData):
# Do something with the "safe" string. # Do something with the "safe" string.
* strings which are marked as "needing escaping" are *always* escaped on * **Strings marked as "needing escaping"** are *always* escaped on
output, regardless of whether they are in an ``autoescape`` block or not. output, regardless of whether they are in an ``autoescape`` block or not.
These strings are only escaped once, however, even if auto-escaping These strings are only escaped once, however, even if auto-escaping
applies. This type of string is internally represented by the types applies.
``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry
about these; they exist for the implementation of the ``escape`` filter.
When you are writing a filter, your code will typically fall into one of two Internally, these strings are of type ``EscapeString`` or
situations: ``EscapeUnicode``. Generally you don't have to worry about these; they
exist for the implementation of the ``escape`` filter.
1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``, Template filter code falls into one of two situations:
``'``, ``"`` or ``&``) into the result that were not already present. In
this case, you can let Django take care of all the auto-escaping handling
for you. All you need to do is put the ``is_safe`` attribute on your
filter function and set it to ``True``. This attribute tells Django that
is a "safe" string is passed into your filter, the result will still be
"safe" and if a non-safe string is passed in, Django will automatically
escape it, if necessary. The reason ``is_safe`` is necessary is because
there are plenty of normal string operations that will turn a ``SafeData``
object back into a normal ``str`` or ``unicode`` object and, rather than
try to catch them all, which would be very difficult, Django repairs the
damage after the filter has completed.
For example, suppose you have a filter that adds the string ``xx`` to the 1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``,
end of any input. Since this introduces no dangerous HTML characters into ``'``, ``"`` or ``&``) into the result that were not already present. In
the result (aside from any that were already present), you should mark this case, you can let Django take care of all the auto-escaping
your filter with ``is_safe``:: handling for you. All you need to do is put the ``is_safe`` attribute on
your filter function and set it to ``True``, like so::
@register.filter
def myfilter(value):
return value
myfilter.is_safe = True
This attribute tells Django that if a "safe" string is passed into your
filter, the result will still be "safe" and if a non-safe string is
passed in, Django will automatically escape it, if necessary.
You can think of this as meaning "this filter is safe -- it doesn't
introduce any possibility of unsafe HTML."
The reason ``is_safe`` is necessary is because there are plenty of
normal string operations that will turn a ``SafeData`` object back into
a normal ``str`` or ``unicode`` object and, rather than try to catch
them all, which would be very difficult, Django repairs the damage after
the filter has completed.
For example, suppose you have a filter that adds the string ``xx`` to the
end of any input. Since this introduces no dangerous HTML characters to
the result (aside from any that were already present), you should mark
your filter with ``is_safe``::
@register.filter @register.filter
def add_xx(value): def add_xx(value):
return '%sxx' % value return '%sxx' % value
add_xx.is_safe = True add_xx.is_safe = True
When this filter is used in a template where auto-escaping is enabled, When this filter is used in a template where auto-escaping is enabled,
Django will escape the output whenever the input is not already marked as Django will escape the output whenever the input is not already marked as
"safe". "safe".
By default, ``is_safe`` defaults to ``False`` and you can omit it from By default, ``is_safe`` defaults to ``False``, and you can omit it from
any filters where it isn't required. any filters where it isn't required.
Be careful when deciding if your filter really does leave safe strings Be careful when deciding if your filter really does leave safe strings
as safe. Sometimes if you are *removing* characters, you can as safe. If you're *removing* characters, you might inadvertently leave
inadvertently leave unbalanced HTML tags or entities in the result. unbalanced HTML tags or entities in the result. For example, removing a
For example, removing a ``>`` from the input might turn ``<a>`` into ``>`` from the input might turn ``<a>`` into ``<a``, which would need to
``<a``, which would need to be escaped on output to avoid causing be escaped on output to avoid causing problems. Similarly, removing a
problems. Similarly, removing a semicolon (``;``) can turn ``&amp;`` semicolon (``;``) can turn ``&amp;`` into ``&amp``, which is no longer a
into ``&amp``, which is no longer a valid entity and thus needs valid entity and thus needs further escaping. Most cases won't be nearly
further escaping. Most cases won't be nearly this tricky, but keep an this tricky, but keep an eye out for any problems like that when
eye out for any problems like that when reviewing your code. reviewing your code.
2. Alternatively, your filter code can manually take care of any necessary 2. Alternatively, your filter code can manually take care of any necessary
escaping. This is usually necessary when you are introducing new HTML escaping. This is necessary when you're introducing new HTML markup into
markup into the result. You want to mark the output as safe from further the result. You want to mark the output as safe from further
escaping so that your HTML markup isn't escaped further, so you'll need to escaping so that your HTML markup isn't escaped further, so you'll need
handle the input yourself. to handle the input yourself.
To mark the output as a safe string, use To mark the output as a safe string, use ``django.utils.safestring.mark_safe()``.
``django.utils.safestring.mark_safe()``.
Be careful, though. You need to do more than just mark the output as Be careful, though. You need to do more than just mark the output as
safe. You need to ensure it really *is* safe and what you do will often safe. You need to ensure it really *is* safe, and what you do depends on
depend upon whether or not auto-escaping is in effect. The idea is to whether auto-escaping is in effect. The idea is to write filters than
write filters than can operate in templates where auto-escaping is either can operate in templates where auto-escaping is either on or off in
on or off in order to make things easier for your template authors. order to make things easier for your template authors.
In order for you filter to know the current auto-escaping state, set the In order for you filter to know the current auto-escaping state, set the
``needs_autoescape`` attribute to ``True`` on your function (if you don't ``needs_autoescape`` attribute to ``True`` on your function. (If you
specify this attribute, it defaults to ``False``). This attribute tells don't specify this attribute, it defaults to ``False``). This attribute
Django that your filter function wants to be passed an extra keyword tells Django that your filter function wants to be passed an extra
argument, called ``autoescape`` that is ``True`` is auto-escaping is in keyword argument, called ``autoescape``, that is ``True`` is
effect and ``False`` otherwise. auto-escaping is in effect and ``False`` otherwise.
An example might make this clearer. Let's write a filter that emphasizes For example, let's write a filter that emphasizes the first character of
the first character of a string:: a string::
from django.utils.html import conditional_escape from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
def initial_letter_filter(text, autoescape=None): def initial_letter_filter(text, autoescape=None):
first, other = text[0] ,text[1:] first, other = text[0], text[1:]
if autoescape: if autoescape:
esc = conditional_escape esc = conditional_escape
else: else:
esc = lambda x: x esc = lambda x: x
result = '<strong>%s</strong>%s' % (esc(first), esc(other)) result = '<strong>%s</strong>%s' % (esc(first), esc(other))
return mark_safe(result) return mark_safe(result)
initial_letter_filter.needs_autoescape = True initial_letter_filter.needs_autoescape = True
The ``needs_autoescape`` attribute on the filter function and the The ``needs_autoescape`` attribute on the filter function and the
``autoescape`` keyword argument mean that our function will know whether ``autoescape`` keyword argument mean that our function will know whether
or not automatic escaping is in effect when the filter is called. We use automatic escaping is in effect when the filter is called. We use
``autoescape`` to decide whether the input data needs to be passed through ``autoescape`` to decide whether the input data needs to be passed through
``django.utils.html.conditional_escape`` or not (in the latter case, we ``django.utils.html.conditional_escape`` or not. (In the latter case, we
just use the identity function as the "escape" function). The just use the identity function as the "escape" function.) The
``conditional_escape()`` function is like ``escape()`` except it only ``conditional_escape()`` function is like ``escape()`` except it only
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData`` escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
instance is passed to ``conditional_escape()``, the data is returned instance is passed to ``conditional_escape()``, the data is returned
unchanged. unchanged.
Finally, in the above example, we remember to mark the result as safe Finally, in the above example, we remember to mark the result as safe
so that our HTML is inserted directly into the template without further so that our HTML is inserted directly into the template without further
escaping. escaping.
There is no need to worry about the ``is_safe`` attribute in this case There's no need to worry about the ``is_safe`` attribute in this case
(although including it wouldn't hurt anything). Whenever you are manually (although including it wouldn't hurt anything). Whenever you manually
handling the auto-escaping issues and returning a safe string, the handle the auto-escaping issues and return a safe string, the
``is_safe`` attribute won't change anything either way. ``is_safe`` attribute won't change anything either way.
Writing custom template tags Writing custom template tags
---------------------------- ----------------------------
@ -981,7 +991,7 @@ Auto-escaping considerations
The output from template tags is **not** automatically run through the The output from template tags is **not** automatically run through the
auto-escaping filters. However, there are still a couple of things you should auto-escaping filters. However, there are still a couple of things you should
keep in mind when writing a template tag: keep in mind when writing a template tag.
If the ``render()`` function of your template stores the result in a context If the ``render()`` function of your template stores the result in a context
variable (rather than returning the result in a string), it should take care variable (rather than returning the result in a string), it should take care
@ -991,18 +1001,17 @@ time, so content that should be safe from further escaping needs to be marked
as such. as such.
Also, if your template tag creates a new context for performing some Also, if your template tag creates a new context for performing some
sub-rendering, you should be careful to set the auto-escape attribute to the sub-rendering, set the auto-escape attribute to the current context's value.
current context's value. The ``__init__`` method for the ``Context`` class The ``__init__`` method for the ``Context`` class takes a parameter called
takes a parameter called ``autoescape`` that you can use for this purpose. For ``autoescape`` that you can use for this purpose. For example::
example::
def render(self, context): def render(self, context):
# ... # ...
new_context = Context({'var': obj}, autoescape=context.autoescape) new_context = Context({'var': obj}, autoescape=context.autoescape)
# ... Do something with new_context ... # ... Do something with new_context ...
This is not a very common situation, but it is sometimes useful, particularly This is not a very common situation, but it's useful if you're rendering a
if you are 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.load_template('small_fragment.html')
@ -1010,7 +1019,7 @@ if you are rendering a template yourself. For example::
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
new ``Context`` in this example, the results would have *always* been new ``Context`` in this example, the results would have *always* been
automatically escaped, which may not be the desired behaviour if the template automatically escaped, which may not be the desired behavior if the template
tag is used inside a ``{% autoescape off %}`` block. tag is used inside a ``{% autoescape off %}`` block.
Registering the tag Registering the tag

View File

@ -48,7 +48,7 @@ Recall from Tutorial 1 that you start the development server like so::
Now, open a Web browser and go to "/admin/" on your local domain -- e.g., Now, open a Web browser and go to "/admin/" on your local domain -- e.g.,
http://127.0.0.1:8000/admin/. You should see the admin's login screen: http://127.0.0.1:8000/admin/. You should see the admin's login screen:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin01.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin01.png
:alt: Django admin login screen :alt: Django admin login screen
Enter the admin site Enter the admin site
@ -57,9 +57,9 @@ Enter the admin site
Now, try logging in. (You created a superuser account in the first part of this Now, try logging in. (You created a superuser account in the first part of this
tutorial, remember?) You should see the Django admin index page: tutorial, remember?) You should see the Django admin index page:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin02t.png
:alt: Django admin index page :alt: Django admin index page
:target: http://media.djangoproject.com/img/doc/tutorial/admin02.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin02.png
You should see a few other types of editable content, including groups, users You should see a few other types of editable content, including groups, users
and sites. These are core features Django ships with by default. and sites. These are core features Django ships with by default.
@ -95,23 +95,23 @@ Explore the free admin functionality
Now that ``Poll`` has the inner ``Admin`` class, Django knows that it should be Now that ``Poll`` has the inner ``Admin`` class, Django knows that it should be
displayed on the admin index page: displayed on the admin index page:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin03t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin03t.png
:alt: Django admin index page, now with polls displayed :alt: Django admin index page, now with polls displayed
:target: http://media.djangoproject.com/img/doc/tutorial/admin03.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin03.png
Click "Polls." Now you're at the "change list" page for polls. This page Click "Polls." Now you're at the "change list" page for polls. This page
displays all the polls in the database and lets you choose one to change it. displays all the polls in the database and lets you choose one to change it.
There's the "What's up?" poll we created in the first tutorial: There's the "What's up?" poll we created in the first tutorial:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin04t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04t.png
:alt: Polls change list page :alt: Polls change list page
:target: http://media.djangoproject.com/img/doc/tutorial/admin04.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04.png
Click the "What's up?" poll to edit it: Click the "What's up?" poll to edit it:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin05t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin05t.png
:alt: Editing form for poll object :alt: Editing form for poll object
:target: http://media.djangoproject.com/img/doc/tutorial/admin05.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin05.png
Things to note here: Things to note here:
@ -138,9 +138,9 @@ click "Save and continue editing." Then click "History" in the upper right.
You'll see a page listing all changes made to this object via the Django admin, You'll see a page listing all changes made to this object via the Django admin,
with the timestamp and username of the person who made the change: with the timestamp and username of the person who made the change:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin06t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin06t.png
:alt: History page for poll object :alt: History page for poll object
:target: http://media.djangoproject.com/img/doc/tutorial/admin06.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin06.png
Customize the admin form Customize the admin form
======================== ========================
@ -157,7 +157,7 @@ Let's customize this a bit. We can reorder the fields by explicitly adding a
That made the "Publication date" show up first instead of second: That made the "Publication date" show up first instead of second:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin07.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin07.png
:alt: Fields have been reordered :alt: Fields have been reordered
This isn't impressive with only two fields, but for admin forms with dozens This isn't impressive with only two fields, but for admin forms with dozens
@ -175,9 +175,9 @@ up into fieldsets::
The first element of each tuple in ``fields`` is the title of the fieldset. The first element of each tuple in ``fields`` is the title of the fieldset.
Here's what our form looks like now: Here's what our form looks like now:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin08t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin08t.png
:alt: Form has fieldsets now :alt: Form has fieldsets now
:target: http://media.djangoproject.com/img/doc/tutorial/admin08.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin08.png
You can assign arbitrary HTML classes to each fieldset. Django provides a You can assign arbitrary HTML classes to each fieldset. Django provides a
``"collapse"`` class that displays a particular fieldset initially collapsed. ``"collapse"`` class that displays a particular fieldset initially collapsed.
@ -190,7 +190,7 @@ aren't commonly used::
('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}), ('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}),
) )
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin09.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin09.png
:alt: Fieldset is initially collapsed :alt: Fieldset is initially collapsed
Adding related objects Adding related objects
@ -213,7 +213,7 @@ that would look like::
Now "Choices" is an available option in the Django admin. The "Add choice" form Now "Choices" is an available option in the Django admin. The "Add choice" form
looks like this: looks like this:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin10.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin10.png
:alt: Choice admin page :alt: Choice admin page
In that form, the "Poll" field is a select box containing every poll in the In that form, the "Poll" field is a select box containing every poll in the
@ -250,9 +250,9 @@ deletion of that existing Choice object."
Load the "Add poll" page to see how that looks: Load the "Add poll" page to see how that looks:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin11t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin11t.png
:alt: Add poll page now has choices on it :alt: Add poll page now has choices on it
:target: http://media.djangoproject.com/img/doc/tutorial/admin11.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin11.png
It works like this: There are three slots for related Choices -- as specified It works like this: There are three slots for related Choices -- as specified
by ``num_in_admin`` -- but each time you come back to the "Change" page for an by ``num_in_admin`` -- but each time you come back to the "Change" page for an
@ -270,7 +270,7 @@ alternate way of displaying inline related objects::
With that ``edit_inline=models.TABULAR`` (instead of ``models.STACKED``), the With that ``edit_inline=models.TABULAR`` (instead of ``models.STACKED``), the
related objects are displayed in a more compact, table-based format: related objects are displayed in a more compact, table-based format:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin12.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin12.png
:alt: Add poll page now has more compact choices :alt: Add poll page now has more compact choices
Customize the admin change list Customize the admin change list
@ -281,9 +281,9 @@ Now that the Poll admin page is looking good, let's make some tweaks to the
Here's what it looks like at this point: Here's what it looks like at this point:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin04t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04t.png
:alt: Polls change list page :alt: Polls change list page
:target: http://media.djangoproject.com/img/doc/tutorial/admin04.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04.png
By default, Django displays the ``str()`` of each object. But sometimes it'd By default, Django displays the ``str()`` of each object. But sometimes it'd
be more helpful if we could display individual fields. To do that, use the be more helpful if we could display individual fields. To do that, use the
@ -303,9 +303,9 @@ method from Tutorial 1::
Now the poll change list page looks like this: Now the poll change list page looks like this:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin13t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin13t.png
:alt: Polls change list page, updated :alt: Polls change list page, updated
:target: http://media.djangoproject.com/img/doc/tutorial/admin13.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin13.png
You can click on the column headers to sort by those values -- except in the You can click on the column headers to sort by those values -- except in the
case of the ``was_published_today`` header, because sorting by the output of case of the ``was_published_today`` header, because sorting by the output of
@ -327,9 +327,9 @@ following line to ``Poll.Admin``::
That adds a "Filter" sidebar that lets people filter the change list by the That adds a "Filter" sidebar that lets people filter the change list by the
``pub_date`` field: ``pub_date`` field:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin14t.png .. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin14t.png
:alt: Polls change list page, updated :alt: Polls change list page, updated
:target: http://media.djangoproject.com/img/doc/tutorial/admin14.png :target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin14.png
The type of filter displayed depends on the type of field you're filtering on. The type of filter displayed depends on the type of field you're filtering on.
Because ``pub_date`` is a DateTimeField, Django knows to give the default Because ``pub_date`` is a DateTimeField, Django knows to give the default

View File

@ -1,5 +1,5 @@
""" """
39. Empty model tests 40. Empty model tests
These test that things behave sensibly for the rare corner-case of a model with These test that things behave sensibly for the rare corner-case of a model with
no fields. no fields.

View File

@ -48,4 +48,9 @@ u'Default headline'
>>> d = now - a.pub_date >>> d = now - a.pub_date
>>> d.seconds < 5 >>> d.seconds < 5
True True
# make sure that SafeUnicode fields work
>>> from django.utils.safestring import SafeUnicode
>>> a.headline = SafeUnicode(u'SafeUnicode Headline')
>>> a.save()
"""} """}

View File

@ -78,7 +78,7 @@ Http404: No Article matches the given query.
>>> get_object_or_404(Author.objects.all()) >>> get_object_or_404(Author.objects.all())
Traceback (most recent call last): Traceback (most recent call last):
... ...
AssertionError: get() returned more than one Author -- it returned ...! Lookup parameters were {} MultipleObjectsReturned: get() returned more than one Author -- it returned ...! Lookup parameters were {}
# Using an EmptyQuerySet raises a Http404 error. # Using an EmptyQuerySet raises a Http404 error.
>>> get_object_or_404(Article.objects.none(), title__contains="Run") >>> get_object_or_404(Article.objects.none(), title__contains="Run")

View File

@ -107,6 +107,10 @@ class Car(models.Model):
colour = models.CharField(max_length=5) colour = models.CharField(max_length=5)
model = models.ForeignKey(Model) model = models.ForeignKey(Model)
class MissingRelations(models.Model):
rel1 = models.ForeignKey("Rel1")
rel2 = models.ManyToManyField("Rel2")
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute. model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute. invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute. invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
@ -189,4 +193,6 @@ invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related
invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'.
invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'.
invalid_models.missingrelations: 'rel2' has m2m relation with model Rel2, which has not been installed
invalid_models.missingrelations: 'rel1' has relation with model Rel1, which has not been installed
""" """

View File

@ -1,25 +1,10 @@
""" """
36. Generating HTML forms from models XX. Generating HTML forms from models
Django provides shortcuts for creating Form objects from a model class and a This is mostly just a reworking of the form_for_model/form_for_instance tests
model instance. to use ModelForm. As such, the text may not make sense in all cases, and the
examples are probably a poor fit for the ModelForm syntax. In other words,
The function django.newforms.form_for_model() takes a model class and returns most of these tests should be rewritten.
a Form that is tied to the model. This Form works just like any other Form,
with one additional method: save(). The save() method creates an instance
of the model and returns that newly created instance. It saves the instance to
the database if save(commit=True), which is default. If you pass
commit=False, then you'll get the object without committing the changes to the
database.
The function django.newforms.form_for_instance() takes a model instance and
returns a Form that is tied to the instance. This form works just like any
other Form, with one additional method: save(). The save()
method updates the model instance. It also takes a commit=True parameter.
The function django.newforms.save_instance() takes a bound form instance and a
model instance and saves the form's cleaned_data into the instance. It also takes
a commit=True parameter.
""" """
from django.db import models from django.db import models
@ -30,23 +15,6 @@ ARTICLE_STATUS = (
(3, 'Live'), (3, 'Live'),
) )
STEERING_TYPE = (
('left', 'Left steering wheel'),
('right', 'Right steering wheel'),
)
FUEL_TYPE = (
('gas', 'Gasoline'),
('diesel', 'Diesel'),
('other', 'Other'),
)
TRANSMISSION_TYPE = (
('at', 'Automatic'),
('mt', 'Manual'),
('cvt', 'CVT'),
)
class Category(models.Model): class Category(models.Model):
name = models.CharField(max_length=20) name = models.CharField(max_length=20)
slug = models.SlugField(max_length=20) slug = models.SlugField(max_length=20)
@ -87,21 +55,119 @@ class PhoneNumber(models.Model):
def __unicode__(self): def __unicode__(self):
return self.phone return self.phone
class Car(models.Model):
name = models.CharField(max_length=50)
steering = models.CharField(max_length=5, choices=STEERING_TYPE, default='left')
fuel = models.CharField(max_length=10, choices=FUEL_TYPE)
transmission = models.CharField(max_length=3, choices=TRANSMISSION_TYPE, blank=True, help_text='Leave empty if not applicable.')
__test__ = {'API_TESTS': """ __test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField >>> from django import newforms as forms
>>> from django.newforms.models import ModelForm
The bare bones, absolutely nothing custom, basic case.
>>> class CategoryForm(ModelForm):
... class Meta:
... model = Category
>>> CategoryForm.base_fields.keys()
['name', 'slug', 'url']
Extra fields.
>>> class CategoryForm(ModelForm):
... some_extra_field = forms.BooleanField()
...
... class Meta:
... model = Category
>>> CategoryForm.base_fields.keys()
['name', 'slug', 'url', 'some_extra_field']
Replacing a field.
>>> class CategoryForm(ModelForm):
... url = forms.BooleanField()
...
... class Meta:
... model = Category
>>> CategoryForm.base_fields['url'].__class__
<class 'django.newforms.fields.BooleanField'>
Using 'fields'.
>>> class CategoryForm(ModelForm):
...
... class Meta:
... model = Category
... fields = ['url']
>>> CategoryForm.base_fields.keys()
['url']
Using 'exclude'
>>> class CategoryForm(ModelForm):
...
... class Meta:
... model = Category
... exclude = ['url']
>>> CategoryForm.base_fields.keys()
['name', 'slug']
Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh,
"be liberal in what you accept" and all.
>>> class CategoryForm(ModelForm):
...
... class Meta:
... model = Category
... fields = ['name', 'url']
... exclude = ['url']
>>> CategoryForm.base_fields.keys()
['name']
Don't allow more than one 'model' definition in the inheritance hierarchy.
Technically, it would generate a valid form, but the fact that the resulting
save method won't deal with multiple objects is likely to trip up people not
familiar with the mechanics.
>>> class CategoryForm(ModelForm):
... class Meta:
... model = Category
>>> class BadForm(CategoryForm):
... class Meta:
... model = Article
Traceback (most recent call last):
...
ImproperlyConfigured: BadForm defines more than one model.
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
>>> class BadForm(ArticleForm, CategoryForm):
... pass
Traceback (most recent call last):
...
ImproperlyConfigured: BadForm's base classes define more than one model.
# Old form_for_x tests #######################################################
>>> from django.newforms import ModelForm, CharField
>>> import datetime >>> import datetime
>>> Category.objects.all() >>> Category.objects.all()
[] []
>>> CategoryForm = form_for_model(Category) >>> class CategoryForm(ModelForm):
>>> f = CategoryForm() ... class Meta:
... model = Category
>>> f = CategoryForm(Category())
>>> print f >>> print f
<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> <tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr> <tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
@ -113,13 +179,13 @@ __test__ = {'API_TESTS': """
>>> print f['name'] >>> print f['name']
<input id="id_name" type="text" name="name" maxlength="20" /> <input id="id_name" type="text" name="name" maxlength="20" />
>>> f = CategoryForm(auto_id=False) >>> f = CategoryForm(Category(), auto_id=False)
>>> print f.as_ul() >>> print f.as_ul()
<li>Name: <input type="text" name="name" maxlength="20" /></li> <li>Name: <input type="text" name="name" maxlength="20" /></li>
<li>Slug: <input type="text" name="slug" maxlength="20" /></li> <li>Slug: <input type="text" name="slug" maxlength="20" /></li>
<li>The URL: <input type="text" name="url" maxlength="40" /></li> <li>The URL: <input type="text" name="url" maxlength="40" /></li>
>>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'}) >>> f = CategoryForm(Category(), {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.cleaned_data >>> f.cleaned_data
@ -130,7 +196,7 @@ True
>>> Category.objects.all() >>> Category.objects.all()
[<Category: Entertainment>] [<Category: Entertainment>]
>>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'}) >>> f = CategoryForm(Category(), {'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.cleaned_data >>> f.cleaned_data
@ -144,7 +210,7 @@ True
If you call save() with commit=False, then it will return an object that If you call save() with commit=False, then it will return an object that
hasn't yet been saved to the database. In this case, it's up to you to call hasn't yet been saved to the database. In this case, it's up to you to call
save() on the resulting model instance. save() on the resulting model instance.
>>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'}) >>> f = CategoryForm(Category(), {'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.cleaned_data >>> f.cleaned_data
@ -159,7 +225,7 @@ True
[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>] [<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
If you call save() with invalid data, you'll get a ValueError. If you call save() with invalid data, you'll get a ValueError.
>>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'}) >>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
>>> f.errors >>> f.errors
{'name': [u'This field is required.'], 'slug': [u'This field is required.']} {'name': [u'This field is required.'], 'slug': [u'This field is required.']}
>>> f.cleaned_data >>> f.cleaned_data
@ -170,7 +236,7 @@ AttributeError: 'CategoryForm' object has no attribute 'cleaned_data'
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: The Category could not be created because the data didn't validate. ValueError: The Category could not be created because the data didn't validate.
>>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'}) >>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
>>> f.save() >>> f.save()
Traceback (most recent call last): Traceback (most recent call last):
... ...
@ -184,8 +250,10 @@ Create a couple of Writers.
ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
fields with the 'choices' attribute are represented by a ChoiceField. fields with the 'choices' attribute are represented by a ChoiceField.
>>> ArticleForm = form_for_model(Article) >>> class ArticleForm(ModelForm):
>>> f = ArticleForm(auto_id=False) ... class Meta:
... model = Article
>>> f = ArticleForm(Article(), auto_id=False)
>>> print f >>> print f
<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
<tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr> <tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr>
@ -214,28 +282,23 @@ model created with such a form, you need to ensure that the fields
that are _not_ on the form have default values, or are allowed to have that are _not_ on the form have default values, or are allowed to have
a value of None. If a field isn't specified on a form, the object created a value of None. If a field isn't specified on a form, the object created
from the form can't provide a value for that field! from the form can't provide a value for that field!
>>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) >>> class PartialArticleForm(ModelForm):
>>> f = PartialArticleForm(auto_id=False) ... class Meta:
... model = Article
... fields = ('headline','pub_date')
>>> f = PartialArticleForm(Article(), auto_id=False)
>>> print f >>> print f
<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
You can pass a custom Form class to form_for_model. Make sure it's a
subclass of BaseForm, not Form.
>>> class CustomForm(BaseForm):
... def say_hello(self):
... print 'hello'
>>> CategoryForm = form_for_model(Category, form=CustomForm)
>>> f = CategoryForm()
>>> f.say_hello()
hello
Use form_for_instance to create a Form from a model instance. The difference Use form_for_instance to create a Form from a model instance. The difference
between this Form and one created via form_for_model is that the object's between this Form and one created via form_for_model is that the object's
current values are inserted as 'initial' data in each Field. current values are inserted as 'initial' data in each Field.
>>> w = Writer.objects.get(name='Mike Royko') >>> w = Writer.objects.get(name='Mike Royko')
>>> RoykoForm = form_for_instance(w) >>> class RoykoForm(ModelForm):
>>> f = RoykoForm(auto_id=False) ... class Meta:
... model = Writer
>>> f = RoykoForm(w, auto_id=False)
>>> print f >>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr> <tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr>
@ -243,8 +306,10 @@ current values are inserted as 'initial' data in each Field.
>>> art.save() >>> art.save()
>>> art.id >>> art.id
1 1
>>> TestArticleForm = form_for_instance(art) >>> class TestArticleForm(ModelForm):
>>> f = TestArticleForm(auto_id=False) ... class Meta:
... model = Article
>>> f = TestArticleForm(art, auto_id=False)
>>> print f.as_ul() >>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> <li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
@ -266,7 +331,7 @@ current values are inserted as 'initial' data in each Field.
<option value="2">It&#39;s a test</option> <option value="2">It&#39;s a test</option>
<option value="3">Third test</option> <option value="3">Third test</option>
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
>>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) >>> f = TestArticleForm(art, {'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> test_art = f.save() >>> test_art = f.save()
@ -278,8 +343,11 @@ u'Test headline'
You can create a form over a subset of the available fields You can create a form over a subset of the available fields
by specifying a 'fields' argument to form_for_instance. by specifying a 'fields' argument to form_for_instance.
>>> PartialArticleForm = form_for_instance(art, fields=('headline', 'slug', 'pub_date')) >>> class PartialArticleForm(ModelForm):
>>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False) ... class Meta:
... model = Article
... fields=('headline', 'slug', 'pub_date')
>>> f = PartialArticleForm(art, {'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False)
>>> print f.as_ul() >>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
@ -299,8 +367,10 @@ Add some categories and test the many-to-many form output.
>>> new_art.categories.add(Category.objects.get(name='Entertainment')) >>> new_art.categories.add(Category.objects.get(name='Entertainment'))
>>> new_art.categories.all() >>> new_art.categories.all()
[<Category: Entertainment>] [<Category: Entertainment>]
>>> TestArticleForm = form_for_instance(new_art) >>> class TestArticleForm(ModelForm):
>>> f = TestArticleForm(auto_id=False) ... class Meta:
... model = Article
>>> f = TestArticleForm(new_art, auto_id=False)
>>> print f.as_ul() >>> print f.as_ul()
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
@ -323,7 +393,7 @@ Add some categories and test the many-to-many form output.
<option value="3">Third test</option> <option value="3">Third test</option>
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', >>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}) ... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']})
>>> new_art = f.save() >>> new_art = f.save()
>>> new_art.id >>> new_art.id
@ -333,7 +403,7 @@ Add some categories and test the many-to-many form output.
[<Category: Entertainment>, <Category: It's a test>] [<Category: Entertainment>, <Category: It's a test>]
Now, submit form data with no categories. This deletes the existing categories. Now, submit form data with no categories. This deletes the existing categories.
>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', >>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
... 'writer': u'1', 'article': u'Hello.'}) ... 'writer': u'1', 'article': u'Hello.'})
>>> new_art = f.save() >>> new_art = f.save()
>>> new_art.id >>> new_art.id
@ -343,8 +413,10 @@ Now, submit form data with no categories. This deletes the existing categories.
[] []
Create a new article, with categories, via the form. Create a new article, with categories, via the form.
>>> ArticleForm = form_for_model(Article) >>> class ArticleForm(ModelForm):
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', ... class Meta:
... model = Article
>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
>>> new_art = f.save() >>> new_art = f.save()
>>> new_art.id >>> new_art.id
@ -354,8 +426,10 @@ Create a new article, with categories, via the form.
[<Category: Entertainment>, <Category: It's a test>] [<Category: Entertainment>, <Category: It's a test>]
Create a new article, with no categories, via the form. Create a new article, with no categories, via the form.
>>> ArticleForm = form_for_model(Article) >>> class ArticleForm(ModelForm):
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', ... class Meta:
... model = Article
>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.'}) ... 'writer': u'1', 'article': u'Test.'})
>>> new_art = f.save() >>> new_art = f.save()
>>> new_art.id >>> new_art.id
@ -366,8 +440,10 @@ Create a new article, with no categories, via the form.
Create a new article, with categories, via the form, but use commit=False. Create a new article, with categories, via the form, but use commit=False.
The m2m data won't be saved until save_m2m() is invoked on the form. The m2m data won't be saved until save_m2m() is invoked on the form.
>>> ArticleForm = form_for_model(Article) >>> class ArticleForm(ModelForm):
>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01', ... class Meta:
... model = Article
>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
>>> new_art = f.save(commit=False) >>> new_art = f.save(commit=False)
@ -386,10 +462,10 @@ The m2m data won't be saved until save_m2m() is invoked on the form.
>>> new_art.categories.order_by('name') >>> new_art.categories.order_by('name')
[<Category: Entertainment>, <Category: It's a test>] [<Category: Entertainment>, <Category: It's a test>]
Here, we define a custom Form. Because it happens to have the same fields as Here, we define a custom ModelForm. Because it happens to have the same fields as
the Category model, we can use save_instance() to apply its changes to an the Category model, we can just call the form's save() to apply its changes to an
existing Category instance. existing Category instance.
>>> class ShortCategory(Form): >>> class ShortCategory(ModelForm):
... name = CharField(max_length=5) ... name = CharField(max_length=5)
... slug = CharField(max_length=5) ... slug = CharField(max_length=5)
... url = CharField(max_length=3) ... url = CharField(max_length=3)
@ -398,8 +474,8 @@ existing Category instance.
<Category: Third test> <Category: Third test>
>>> cat.id >>> cat.id
3 3
>>> sc = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}) >>> form = ShortCategory(cat, {'name': 'Third', 'slug': 'third', 'url': '3rd'})
>>> save_instance(sc, cat) >>> form.save()
<Category: Third> <Category: Third>
>>> Category.objects.get(id=3) >>> Category.objects.get(id=3)
<Category: Third> <Category: Third>
@ -407,8 +483,10 @@ existing Category instance.
Here, we demonstrate that choices for a ForeignKey ChoiceField are determined Here, we demonstrate that choices for a ForeignKey ChoiceField are determined
at runtime, based on the data in the database when the form is displayed, not at runtime, based on the data in the database when the form is displayed, not
the data in the database when the form is instantiated. the data in the database when the form is instantiated.
>>> ArticleForm = form_for_model(Article) >>> class ArticleForm(ModelForm):
>>> f = ArticleForm(auto_id=False) ... class Meta:
... model = Article
>>> f = ArticleForm(Article(), auto_id=False)
>>> print f.as_ul() >>> print f.as_ul()
<li>Headline: <input type="text" name="headline" maxlength="50" /></li> <li>Headline: <input type="text" name="headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
@ -609,60 +687,12 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
# PhoneNumberField ############################################################ # PhoneNumberField ############################################################
>>> PhoneNumberForm = form_for_model(PhoneNumber) >>> class PhoneNumberForm(ModelForm):
>>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'}) ... class Meta:
... model = PhoneNumber
>>> f = PhoneNumberForm(PhoneNumber(), {'phone': '(312) 555-1212', 'description': 'Assistance'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.cleaned_data >>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'} {'phone': u'312-555-1212', 'description': u'Assistance'}
# form_for_* blank choices ####################################################
Show the form for a new Car. Note that steering field doesn't include the blank choice,
because the field is obligatory and has an explicit default.
>>> CarForm = form_for_model(Car)
>>> f = CarForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left" selected="selected">Left steering wheel</option>
<option value="right">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="" selected="selected">---------</option>
<option value="gas">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="" selected="selected">---------</option>
<option value="at">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
Create a Car, and display the form for modifying it. Note that now the fuel
selector doesn't include the blank choice as well, since the field is
obligatory and can not be changed to be blank.
>>> honda = Car(name='Honda Accord Wagon', steering='right', fuel='gas', transmission='at')
>>> honda.save()
>>> HondaForm = form_for_instance(honda)
>>> f = HondaForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Honda Accord Wagon" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left">Left steering wheel</option>
<option value="right" selected="selected">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="gas" selected="selected">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="">---------</option>
<option value="at" selected="selected">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
"""} """}

View File

@ -1,5 +1,5 @@
""" """
40. Tests for select_related() 41. Tests for select_related()
``select_related()`` follows all relationships and pre-caches any foreign key ``select_related()`` follows all relationships and pre-caches any foreign key
values so that complex trees can be fetched in a single query. However, this values so that complex trees can be fetched in a single query. However, this

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
41. Serialization 42. Serialization
``django.core.serializers`` provides interfaces to converting Django querysets ``django.core.serializers`` provides interfaces to converting Django querysets
to and from "flat" data (i.e. strings). to and from "flat" data (i.e. strings).

View File

@ -1,6 +1,6 @@
# coding: utf-8 # coding: utf-8
""" """
38. Testing using the Test Client 39. Testing using the Test Client
The test client is a class that can act like a simple The test client is a class that can act like a simple
browser for testing purposes. browser for testing purposes.

View File

@ -1,5 +1,5 @@
""" """
37. User-registered management commands 38. User-registered management commands
The manage.py utility provides a number of useful commands for managing a The manage.py utility provides a number of useful commands for managing a
Django project. If you want to add a utility command of your own, you can. Django project. If you want to add a utility command of your own, you can.

View File

@ -72,6 +72,8 @@ class Cache(unittest.TestCase):
'function' : f, 'function' : f,
'class' : C, 'class' : C,
} }
cache.set("stuff", stuff)
self.assertEqual(cache.get("stuff"), stuff)
def test_expiration(self): def test_expiration(self):
# expiration # expiration

View File

@ -0,0 +1,40 @@
tests = r"""
# ZAIDField #################################################################
ZAIDField validates that the date is a valid birthdate and that the value
has a valid checksum. It allows spaces and dashes, and returns a plain
string of digits.
>>> from django.contrib.localflavor.za.forms import ZAIDField
>>> f = ZAIDField()
>>> f.clean('0002290001003')
'0002290001003'
>>> f.clean('000229 0001 003')
'0002290001003'
>>> f.clean('0102290001001')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid South African ID number']
>>> f.clean('811208')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid South African ID number']
>>> f.clean('0002290001004')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid South African ID number']
# ZAPostCodeField ###########################################################
>>> from django.contrib.localflavor.za.forms import ZAPostCodeField
>>> f = ZAPostCodeField()
>>> f.clean('abcd')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid South African postal code']
>>> f.clean('0000')
u'0000'
>>> f.clean(' 7530')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid South African postal code']
"""

View File

@ -22,6 +22,7 @@ from localflavor.pl import tests as localflavor_pl_tests
from localflavor.sk import tests as localflavor_sk_tests from localflavor.sk import tests as localflavor_sk_tests
from localflavor.uk import tests as localflavor_uk_tests from localflavor.uk import tests as localflavor_uk_tests
from localflavor.us import tests as localflavor_us_tests from localflavor.us import tests as localflavor_us_tests
from localflavor.za import tests as localflavor_za_tests
from regressions import tests as regression_tests from regressions import tests as regression_tests
from util import tests as util_tests from util import tests as util_tests
from widgets import tests as widgets_tests from widgets import tests as widgets_tests
@ -52,6 +53,7 @@ __test__ = {
'localflavor_sk_tests': localflavor_sk_tests, 'localflavor_sk_tests': localflavor_sk_tests,
'localflavor_uk_tests': localflavor_uk_tests, 'localflavor_uk_tests': localflavor_uk_tests,
'localflavor_us_tests': localflavor_us_tests, 'localflavor_us_tests': localflavor_us_tests,
'localflavor_za_tests': localflavor_za_tests,
'regression_tests': regression_tests, 'regression_tests': regression_tests,
'formset_tests': formset_tests, 'formset_tests': formset_tests,
'media_tests': media_tests, 'media_tests': media_tests,

View File

@ -43,7 +43,7 @@ u'django'
Translating a string requiring no auto-escaping shouldn't change the "safe" Translating a string requiring no auto-escaping shouldn't change the "safe"
status. status.
>>> from django.utils.safestring import mark_safe >>> from django.utils.safestring import mark_safe, SafeString
>>> s = mark_safe('Password') >>> s = mark_safe('Password')
>>> type(s) >>> type(s)
<class 'django.utils.safestring.SafeString'> <class 'django.utils.safestring.SafeString'>
@ -51,6 +51,19 @@ status.
>>> type(ugettext(s)) >>> type(ugettext(s))
<class 'django.utils.safestring.SafeUnicode'> <class 'django.utils.safestring.SafeUnicode'>
>>> deactivate() >>> deactivate()
>>> SafeString('a') + s
'aPassword'
>>> s + SafeString('a')
'Passworda'
>>> s + mark_safe('a')
'Passworda'
>>> mark_safe('a') + s
'aPassword'
>>> mark_safe('a') + mark_safe('s')
'as'
>>> print s
Password
""" """
__test__ = { __test__ = {

View File

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
import unittest
from django.test import TestCase
from django.http import HttpRequest
from django.middleware.common import CommonMiddleware
from django.conf import settings
class CommonMiddlewareTest(TestCase):
def _get_request(self, path):
request = HttpRequest()
request.META = {
'SERVER_NAME': 'testserver',
'SERVER_PORT': 80,
}
request.path = "/middleware/%s" % path
return request
def test_append_slash_have_slash(self):
"""
tests that urls with slashes go unmolested
"""
settings.APPEND_SLASH = True
request = self._get_request('slash/')
self.assertEquals(CommonMiddleware().process_request(request), None)
def test_append_slash_slashless_resource(self):
"""
tests that matches to explicit slashless urls go unmolested
"""
settings.APPEND_SLASH = True
request = self._get_request('noslash')
self.assertEquals(CommonMiddleware().process_request(request), None)
def test_append_slash_slashless_unknown(self):
"""
tests that APPEND_SLASH doesn't redirect to unknown resources
"""
settings.APPEND_SLASH = True
request = self._get_request('unknown')
self.assertEquals(CommonMiddleware().process_request(request), None)
def test_append_slash_redirect(self):
"""
tests that APPEND_SLASH redirects slashless urls to a valid pattern
"""
settings.APPEND_SLASH = True
request = self._get_request('slash')
r = CommonMiddleware().process_request(request)
self.assertEquals(r.status_code, 301)
self.assertEquals(r['Location'], 'http://testserver/middleware/slash/')
def test_append_slash_no_redirect_on_POST_in_DEBUG(self):
"""
tests that while in debug mode, an exception is raised with a warning
when a failed attempt is made to POST to an url which would normally be
redirected to a slashed version
"""
settings.APPEND_SLASH = True
settings.DEBUG = True
request = self._get_request('slash')
request.method = 'POST'
self.assertRaises(
RuntimeError,
CommonMiddleware().process_request,
request)
try:
CommonMiddleware().process_request(request)
except RuntimeError, e:
self.assertTrue('end in a slash' in str(e))
def test_append_slash_disabled(self):
"""
tests disabling append slash functionality
"""
settings.APPEND_SLASH = False
request = self._get_request('slash')
self.assertEquals(CommonMiddleware().process_request(request), None)
def test_append_slash_quoted(self):
"""
tests that urls which require quoting are redirected to their slash
version ok
"""
settings.APPEND_SLASH = True
request = self._get_request('needsquoting#')
r = CommonMiddleware().process_request(request)
self.assertEquals(r.status_code, 301)
self.assertEquals(
r['Location'],
'http://testserver/middleware/needsquoting%23/')

View File

@ -0,0 +1,7 @@
from django.conf.urls.defaults import patterns
urlpatterns = patterns('',
(r'^noslash$', 'view'),
(r'^slash/$', 'view'),
(r'^needsquoting#/$', 'view'),
)

View File

@ -18,26 +18,26 @@ class Bar(models.Model):
return "Bar %s" % self.place.name return "Bar %s" % self.place.name
class Whiz(models.Model): class Whiz(models.Model):
name = models.CharField(max_length = 50) name = models.CharField(max_length=50)
def __unicode__(self): def __unicode__(self):
return "Whiz %s" % self.name return "Whiz %s" % self.name
class Child(models.Model): class Child(models.Model):
parent = models.OneToOneField('Base') parent = models.OneToOneField('Base')
name = models.CharField(max_length = 50) name = models.CharField(max_length=50)
def __unicode__(self): def __unicode__(self):
return "Child %s" % self.name return "Child %s" % self.name
class Base(models.Model): class Base(models.Model):
name = models.CharField(max_length = 50) name = models.CharField(max_length=50)
def __unicode__(self): def __unicode__(self):
return "Base %s" % self.name return "Base %s" % self.name
class Article(models.Model): class Article(models.Model):
name = models.CharField(maxlength = 50) name = models.CharField(max_length=50)
text = models.TextField() text = models.TextField()
def __str__(self): def __str__(self):

View File

@ -0,0 +1,18 @@
# coding: utf-8
context_tests = r"""
>>> from django.template import Context
>>> c = Context({'a': 1, 'b': 'xyzzy'})
>>> c['a']
1
>>> c.push()
{}
>>> c['a'] = 2
>>> c['a']
2
>>> c.pop()
{'a': 2}
>>> c['a']
1
"""

View File

@ -18,11 +18,13 @@ from django.utils.safestring import mark_safe
from django.utils.tzinfo import LocalTimezone from django.utils.tzinfo import LocalTimezone
from unicode import unicode_tests from unicode import unicode_tests
from context import context_tests
import filters import filters
# Some other tests we would like to run # Some other tests we would like to run
__test__ = { __test__ = {
'unicode': unicode_tests, 'unicode': unicode_tests,
'context': context_tests,
} }
################################# #################################

View File

@ -1,7 +1,5 @@
from django.http import HttpResponse from django.http import HttpResponse
from django.template import RequestContext
def index_page(request): def index_page(request):
"""Dummy index page""" """Dummy index page"""
return HttpResponse('<html><body>Dummy page</body></html>') return HttpResponse('<html><body>Dummy page</body></html>')

View File

@ -107,8 +107,7 @@ def django_tests(verbosity, interactive, test_labels):
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
) )
if not hasattr(settings, 'SITE_ID'): settings.SITE_ID = 1
settings.SITE_ID = 1
# Load all the ALWAYS_INSTALLED_APPS. # Load all the ALWAYS_INSTALLED_APPS.
# (This import statement is intentionally delayed until after we # (This import statement is intentionally delayed until after we

View File

@ -14,4 +14,7 @@ urlpatterns = patterns('',
# django built-in views # django built-in views
(r'^views/', include('regressiontests.views.urls')), (r'^views/', include('regressiontests.views.urls')),
# test urlconf for middleware tests
(r'^middleware/', include('regressiontests.middleware.urls')),
) )