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

gis: Merged revisions 7105-7168 via svnmerge from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7176 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2008-02-28 21:24:51 +00:00
parent 0b52413cc9
commit 22e016ff6c
76 changed files with 9570 additions and 238 deletions

View File

@ -56,6 +56,7 @@ answer newbie questions, and generally made Django that much better:
David Ascher <http://ascher.ca/> David Ascher <http://ascher.ca/>
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com> Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
Arthur <avandorp@gmail.com> Arthur <avandorp@gmail.com>
David Avsajanishvili <avsd05@gmail.com>
axiak@mit.edu axiak@mit.edu
Jiri Barton Jiri Barton
Ned Batchelder <http://www.nedbatchelder.com/> Ned Batchelder <http://www.nedbatchelder.com/>
@ -70,6 +71,7 @@ answer newbie questions, and generally made Django that much better:
boobsd@gmail.com boobsd@gmail.com
Andrew Brehaut <http://brehaut.net/blog> Andrew Brehaut <http://brehaut.net/blog>
brut.alll@gmail.com brut.alll@gmail.com
btoll@bestweb.net
Jonathan Buchanan <jonathan.buchanan@gmail.com> Jonathan Buchanan <jonathan.buchanan@gmail.com>
Can Burak Çilingir <canburak@cs.bilgi.edu.tr> Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
Trevor Caira <trevor@caira.com> Trevor Caira <trevor@caira.com>
@ -168,6 +170,7 @@ answer newbie questions, and generally made Django that much better:
Rob Hudson <http://rob.cogit8.org/> Rob Hudson <http://rob.cogit8.org/>
Jason Huggins <http://www.jrandolph.com/blog/> Jason Huggins <http://www.jrandolph.com/blog/>
Hyun Mi Ae Hyun Mi Ae
Ibon <ibonso@gmail.com>
Tom Insam Tom Insam
Baurzhan Ismagulov <ibr@radix50.net> Baurzhan Ismagulov <ibr@radix50.net>
james_027@yahoo.com james_027@yahoo.com

View File

@ -48,10 +48,11 @@ LANGUAGES = (
('en', gettext_noop('English')), ('en', gettext_noop('English')),
('es', gettext_noop('Spanish')), ('es', gettext_noop('Spanish')),
('es-ar', gettext_noop('Argentinean Spanish')), ('es-ar', gettext_noop('Argentinean Spanish')),
('eu', gettext_noop('Basque')),
('fa', gettext_noop('Persian')), ('fa', gettext_noop('Persian')),
('fi', gettext_noop('Finnish')), ('fi', gettext_noop('Finnish')),
('fr', gettext_noop('French')), ('fr', gettext_noop('French')),
('ga', gettext_noop('Gaeilge')), ('ga', gettext_noop('Irish')),
('gl', gettext_noop('Galician')), ('gl', gettext_noop('Galician')),
('hu', gettext_noop('Hungarian')), ('hu', gettext_noop('Hungarian')),
('he', gettext_noop('Hebrew')), ('he', gettext_noop('Hebrew')),
@ -59,6 +60,7 @@ LANGUAGES = (
('is', gettext_noop('Icelandic')), ('is', gettext_noop('Icelandic')),
('it', gettext_noop('Italian')), ('it', gettext_noop('Italian')),
('ja', gettext_noop('Japanese')), ('ja', gettext_noop('Japanese')),
('ka', gettext_noop('Georgian')),
('ko', gettext_noop('Korean')), ('ko', gettext_noop('Korean')),
('km', gettext_noop('Khmer')), ('km', gettext_noop('Khmer')),
('kn', gettext_noop('Kannada')), ('kn', gettext_noop('Kannada')),

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,117 @@
# Spanish translation for the django-admin JS files.
# Copyright (C)
# This file is distributed under the same license as the PACKAGE package.
#
msgid ""
msgstr ""
"Project-Id-Version: Django JavaScript 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-07-14 13:47-0500\n"
"PO-Revision-Date: 2007-07-14 13:41-0500\n"
"Last-Translator: Jorge Gajon <gajon@gajon.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/dateparse.js:32
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"Urtarrila Otsaila Martxoa Apirila Maiatza Ekaina Uztaila Abuztua Iraila Urria "
"Azaroa Abendua"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "I A A A O O L"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Igandea Astelehene Asteartea Asteazkena Osteguna Ostirala Larunbata"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "%s Erabilgarri"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "Denak aukeratu"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "Gehitu"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Ezabatu"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "%s Aukeratuak"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Egin zure aukerak eta click egin "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Denak garbitu"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Orain"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "Erlojua"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Aukeratu ordu bat"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Gauerdia"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "6 a.m."
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "Eguerdia"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Atzera"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Gaur"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Egutegia"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Atzo"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Bihar"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "Erakutsi"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "Izkutatu"

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
from django.core.management.base import AppCommand from django.core.management.base import AppCommand
class Command(AppCommand): class Command(AppCommand):
help = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)." help = "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s)."
output_transaction = True output_transaction = True

View File

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

View File

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

View File

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

View File

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

View File

@ -41,7 +41,9 @@ class ModelBase(type):
# Build complete list of parents # Build complete list of parents
for base in parents: for base in parents:
if base is not Model: # Things without _meta aren't functional models, so they're
# uninteresting parents.
if hasattr(base, '_meta'):
new_class._meta.parents.append(base) new_class._meta.parents.append(base)
new_class._meta.parents.extend(base._meta.parents) new_class._meta.parents.extend(base._meta.parents)
@ -133,13 +135,16 @@ class Model(object):
def __ne__(self, other): def __ne__(self, other):
return not self.__eq__(other) return not self.__eq__(other)
def __hash__(self):
return hash(self._get_pk_val())
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
# There is a rather weird disparity here; if kwargs, it's set, then args # There is a rather weird disparity here; if kwargs, it's set, then args
# overrides it. It should be one or the other; don't duplicate the work # overrides it. It should be one or the other; don't duplicate the work
# The reason for the kwargs check is that standard iterator passes in by # The reason for the kwargs check is that standard iterator passes in by
# args, and nstantiation for iteration is 33% faster. # args, and instantiation for iteration is 33% faster.
args_len = len(args) args_len = len(args)
if args_len > len(self._meta.fields): if args_len > len(self._meta.fields):
# Daft, but matches old exception sans the err msg. # Daft, but matches old exception sans the err msg.

View File

@ -228,7 +228,11 @@ class Field(object):
value = int(value) value = int(value)
except ValueError: except ValueError:
raise ValueError("The __year lookup type requires an integer argument") raise ValueError("The __year lookup type requires an integer argument")
return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value] if settings.DATABASE_ENGINE == 'sqlite3':
first = '%s-01-01'
else:
first = '%s-01-01 00:00:00'
return [first % value, '%s-12-31 23:59:59.999999' % value]
raise TypeError("Field has invalid lookup: %s" % lookup_type) raise TypeError("Field has invalid lookup: %s" % lookup_type)
def has_default(self): def has_default(self):
@ -451,6 +455,9 @@ class BooleanField(Field):
kwargs['blank'] = True kwargs['blank'] = True
Field.__init__(self, *args, **kwargs) Field.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "BooleanField"
def to_python(self, value): def to_python(self, value):
if value in (True, False): return value if value in (True, False): return value
if value in ('t', 'True', '1'): return True if value in ('t', 'True', '1'): return True
@ -469,6 +476,9 @@ class CharField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.TextField] return [oldforms.TextField]
def get_internal_type(self):
return "CharField"
def to_python(self, value): def to_python(self, value):
if isinstance(value, basestring): if isinstance(value, basestring):
return value return value
@ -499,6 +509,9 @@ class DateField(Field):
kwargs['blank'] = True kwargs['blank'] = True
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "DateField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -568,6 +581,9 @@ class DateField(Field):
return super(DateField, self).formfield(**defaults) return super(DateField, self).formfield(**defaults)
class DateTimeField(DateField): class DateTimeField(DateField):
def get_internal_type(self):
return "DateTimeField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -638,6 +654,9 @@ class DecimalField(Field):
self.max_digits, self.decimal_places = max_digits, decimal_places self.max_digits, self.decimal_places = max_digits, decimal_places
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "DecimalField"
def to_python(self, value): def to_python(self, value):
if value is None: if value is None:
return value return value
@ -697,9 +716,6 @@ class EmailField(CharField):
kwargs['max_length'] = kwargs.get('max_length', 75) kwargs['max_length'] = kwargs.get('max_length', 75)
CharField.__init__(self, *args, **kwargs) CharField.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "CharField"
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.EmailField] return [oldforms.EmailField]
@ -717,6 +733,9 @@ class FileField(Field):
kwargs['max_length'] = kwargs.get('max_length', 100) kwargs['max_length'] = kwargs.get('max_length', 100)
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "FileField"
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
"Returns field's value prepared for saving into a database." "Returns field's value prepared for saving into a database."
# Need to convert UploadedFile objects provided via a form to unicode for database insertion # Need to convert UploadedFile objects provided via a form to unicode for database insertion
@ -826,12 +845,18 @@ class FilePathField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)] return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
def get_internal_type(self):
return "FilePathField"
class FloatField(Field): class FloatField(Field):
empty_strings_allowed = False empty_strings_allowed = False
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.FloatField] return [oldforms.FloatField]
def get_internal_type(self):
return "FloatField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.FloatField} defaults = {'form_class': forms.FloatField}
defaults.update(kwargs) defaults.update(kwargs)
@ -854,6 +879,9 @@ class ImageField(FileField):
if not self.height_field: if not self.height_field:
setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self)) setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
def get_internal_type(self):
return "ImageField"
def save_file(self, new_data, new_object, original_object, change, rel, save=True): def save_file(self, new_data, new_object, original_object, change, rel, save=True):
FileField.save_file(self, new_data, new_object, original_object, change, rel, save) FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
# If the image has height and/or width field(s) and they haven't # If the image has height and/or width field(s) and they haven't
@ -876,6 +904,9 @@ class IntegerField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.IntegerField] return [oldforms.IntegerField]
def get_internal_type(self):
return "IntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.IntegerField} defaults = {'form_class': forms.IntegerField}
defaults.update(kwargs) defaults.update(kwargs)
@ -890,6 +921,9 @@ class IPAddressField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.IPAddressField] return [oldforms.IPAddressField]
def get_internal_type(self):
return "IPAddressField"
def validate(self, field_data, all_data): def validate(self, field_data, all_data):
validators.isValidIPAddress4(field_data, None) validators.isValidIPAddress4(field_data, None)
@ -904,6 +938,9 @@ class NullBooleanField(Field):
kwargs['null'] = True kwargs['null'] = True
Field.__init__(self, *args, **kwargs) Field.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "NullBooleanField"
def to_python(self, value): def to_python(self, value):
if value in (None, True, False): return value if value in (None, True, False): return value
if value in ('None'): return None if value in ('None'): return None
@ -923,6 +960,9 @@ class PhoneNumberField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PhoneNumberField] return [oldforms.PhoneNumberField]
def get_internal_type(self):
return "PhoneNumberField"
def validate(self, field_data, all_data): def validate(self, field_data, all_data):
validators.isValidPhone(field_data, all_data) validators.isValidPhone(field_data, all_data)
@ -936,6 +976,9 @@ class PositiveIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PositiveIntegerField] return [oldforms.PositiveIntegerField]
def get_internal_type(self):
return "PositiveIntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'min_value': 0} defaults = {'min_value': 0}
defaults.update(kwargs) defaults.update(kwargs)
@ -945,6 +988,9 @@ class PositiveSmallIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.PositiveSmallIntegerField] return [oldforms.PositiveSmallIntegerField]
def get_internal_type(self):
return "PositiveSmallIntegerField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'min_value': 0} defaults = {'min_value': 0}
defaults.update(kwargs) defaults.update(kwargs)
@ -959,14 +1005,23 @@ class SlugField(CharField):
kwargs['db_index'] = True kwargs['db_index'] = True
super(SlugField, self).__init__(*args, **kwargs) super(SlugField, self).__init__(*args, **kwargs)
def get_internal_type(self):
return "SlugField"
class SmallIntegerField(IntegerField): class SmallIntegerField(IntegerField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.SmallIntegerField] return [oldforms.SmallIntegerField]
def get_internal_type(self):
return "SmallIntegerField"
class TextField(Field): class TextField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.LargeTextField] return [oldforms.LargeTextField]
def get_internal_type(self):
return "TextField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'widget': forms.Textarea} defaults = {'widget': forms.Textarea}
defaults.update(kwargs) defaults.update(kwargs)
@ -980,6 +1035,9 @@ class TimeField(Field):
kwargs['editable'] = False kwargs['editable'] = False
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "TimeField"
def get_db_prep_lookup(self, lookup_type, value): def get_db_prep_lookup(self, lookup_type, value):
if settings.DATABASE_ENGINE == 'oracle': if settings.DATABASE_ENGINE == 'oracle':
# Oracle requires a date in order to parse. # Oracle requires a date in order to parse.
@ -1044,9 +1102,6 @@ class URLField(CharField):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.URLField] return [oldforms.URLField]
def get_internal_type(self):
return "CharField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists}
defaults.update(kwargs) defaults.update(kwargs)
@ -1056,6 +1111,9 @@ class USStateField(Field):
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.USStateField] return [oldforms.USStateField]
def get_internal_type(self):
return "USStateField"
def formfield(self, **kwargs): def formfield(self, **kwargs):
from django.contrib.localflavor.us.forms import USStateSelect from django.contrib.localflavor.us.forms import USStateSelect
defaults = {'widget': USStateSelect} defaults = {'widget': USStateSelect}
@ -1067,9 +1125,6 @@ class XMLField(TextField):
self.schema_path = schema_path self.schema_path = schema_path
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
return "TextField"
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)] return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
@ -1080,8 +1135,5 @@ class OrderingField(IntegerField):
kwargs['null'] = True kwargs['null'] = True
IntegerField.__init__(self, **kwargs ) IntegerField.__init__(self, **kwargs )
def get_internal_type(self):
return "IntegerField"
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
return [oldforms.HiddenField(name_prefix + self.name)] return [oldforms.HiddenField(name_prefix + self.name)]

View File

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

View File

@ -171,7 +171,7 @@ class QueryDict(MultiValueDict):
dict.__setitem__(result, key, value) dict.__setitem__(result, key, value)
return result return result
def __deepcopy__(self, memo={}): def __deepcopy__(self, memo):
import copy import copy
result = self.__class__('', mutable=True) result = self.__class__('', mutable=True)
memo[id(self)] = result memo[id(self)] = result
@ -223,7 +223,7 @@ class QueryDict(MultiValueDict):
def copy(self): def copy(self):
"Returns a mutable copy of this object." "Returns a mutable copy of this object."
return self.__deepcopy__() return self.__deepcopy__({})
def urlencode(self): def urlencode(self):
output = [] output = []

View File

@ -22,23 +22,40 @@ def pretty_name(name):
name = name[0].upper() + name[1:] name = name[0].upper() + name[1:]
return name.replace('_', ' ') return name.replace('_', ' ')
def get_declared_fields(bases, attrs, with_base_fields=True):
"""
Create a list of form field instances from the passed in 'attrs', plus any
similar fields on the base classes (in 'bases'). This is used by both the
Form and ModelForm metclasses.
If 'with_base_fields' is True, all fields from the bases are used.
Otherwise, only fields in the 'declared_fields' attribute on the bases are
used. The distinction is useful in ModelForm subclassing.
"""
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.
if with_base_fields:
for base in bases[::-1]:
if hasattr(base, 'base_fields'):
fields = base.base_fields.items() + fields
else:
for base in bases[::-1]:
if hasattr(base, 'declared_fields'):
fields = base.declared_fields.items() + fields
return SortedDict(fields)
class DeclarativeFieldsMetaclass(type): class DeclarativeFieldsMetaclass(type):
""" """
Metaclass that converts Field attributes to a dictionary called Metaclass that converts Field attributes to a dictionary called
'base_fields', taking into account parent class 'base_fields' as well. 'base_fields', taking into account parent class 'base_fields' as well.
""" """
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] attrs['base_fields'] = get_declared_fields(bases, attrs)
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
attrs['base_fields'] = SortedDict(fields)
return type.__new__(cls, name, bases, attrs) return type.__new__(cls, name, bases, attrs)
class BaseForm(StrAndUnicode): class BaseForm(StrAndUnicode):

View File

@ -11,7 +11,7 @@ from django.utils.datastructures import SortedDict
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from util import ValidationError, ErrorList from util import ValidationError, ErrorList
from forms import BaseForm from forms import BaseForm, get_declared_fields
from fields import Field, ChoiceField, EMPTY_VALUES from fields import Field, ChoiceField, EMPTY_VALUES
from widgets import Select, SelectMultiple, MultipleHiddenInput from widgets import Select, SelectMultiple, MultipleHiddenInput
@ -211,57 +211,39 @@ class ModelFormOptions(object):
self.fields = getattr(options, 'fields', None) self.fields = getattr(options, 'fields', None)
self.exclude = getattr(options, 'exclude', None) self.exclude = getattr(options, 'exclude', None)
class ModelFormMetaclass(type): class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs, def __new__(cls, name, bases, attrs,
formfield_callback=lambda f: f.formfield()): formfield_callback=lambda f: f.formfield()):
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] try:
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) parents = [b for b in bases if issubclass(b, ModelForm)]
except NameError:
# We are defining ModelForm itself.
parents = None
if not parents:
return super(ModelFormMetaclass, cls).__new__(cls, name, bases,
attrs)
# If this class is subclassing another Form, add that Form's fields. new_class = type.__new__(cls, name, bases, attrs)
# Note that we loop over the bases in *reverse*. This is necessary in declared_fields = get_declared_fields(bases, attrs, False)
# order to preserve the correct order of fields. opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
for base in bases[::-1]: if opts.model:
if hasattr(base, 'base_fields'): # If a model is defined, extract form fields from it.
fields = base.base_fields.items() + fields fields = fields_for_model(opts.model, opts.fields,
declared_fields = SortedDict(fields) opts.exclude, formfield_callback)
# Override default model fields with any custom declared ones
opts = ModelFormOptions(attrs.get('Meta', None)) # (plus, include all the other declared fields).
attrs['_meta'] = opts fields.update(declared_fields)
# Don't allow more than one Meta model definition 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 different Meta model than 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 and base_model is not opts.model:
raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
model_fields = fields_for_model(opts.model, opts.fields,
opts.exclude, formfield_callback)
# fields declared in base classes override fields from the model
model_fields.update(declared_fields)
attrs['base_fields'] = model_fields
else: else:
attrs['base_fields'] = declared_fields fields = declared_fields
return type.__new__(cls, name, bases, attrs) new_class.declared_fields = declared_fields
new_class.base_fields = fields
return new_class
class BaseModelForm(BaseForm): class BaseModelForm(BaseForm):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=':', instance=None): initial=None, error_class=ErrorList, label_suffix=':',
instance=None):
opts = self._meta opts = self._meta
if instance is None: if instance is None:
# if we didn't get an instance, instantiate a new one # if we didn't get an instance, instantiate a new one
@ -277,7 +259,8 @@ class BaseModelForm(BaseForm):
def save(self, commit=True): def save(self, commit=True):
""" """
Saves this ``form``'s cleaned_data into model instance ``self.instance``. Saves this ``form``'s cleaned_data into model instance
``self.instance``.
If commit=True, then the changes to ``instance`` will be saved to the If commit=True, then the changes to ``instance`` will be saved to the
database. Returns ``instance``. database. Returns ``instance``.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -88,7 +88,7 @@ change:
API changes may be necessary. API changes may be necessary.
- Generic relations will most likely be moved out of core and into the - Generic relations will most likely be moved out of core and into the
content-types contrib package to avoid core dependancies on optional content-types contrib package to avoid core dependencies on optional
components. components.
- The comments framework, which is yet undocumented, will likely get a complete - The comments framework, which is yet undocumented, will likely get a complete

View File

@ -215,7 +215,7 @@ each ``TaggedItem`` will have a ``content_object`` field that returns the
object it's related to, and you can also assign to that field or use it when object it's related to, and you can also assign to that field or use it when
creating a ``TaggedItem``:: creating a ``TaggedItem``::
>>> from django.contrib.models.auth import User >>> from django.contrib.auth.models import User
>>> guido = User.objects.get(username='Guido') >>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl') >>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save() >>> t.save()
@ -235,7 +235,7 @@ a "reverse" generic relationship to enable an additional API. For example::
``Bookmark`` instances will each have a ``tags`` attribute, which can ``Bookmark`` instances will each have a ``tags`` attribute, which can
be used to retrieve their associated ``TaggedItems``:: be used to retrieve their associated ``TaggedItems``::
>>> b = Bookmark('http://www.djangoproject.com/') >>> b = Bookmark(url='http://www.djangoproject.com/')
>>> b.save() >>> b.save()
>>> t1 = TaggedItem(content_object=b, tag='django') >>> t1 = TaggedItem(content_object=b, tag='django')
>>> t1.save() >>> t1.save()

View File

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

View File

@ -5,7 +5,7 @@ Third-party distributions of Django
Several third-party distributors are now providing versions of Django integrated Several third-party distributors are now providing versions of Django integrated
with their package-management systems. These can make installation and upgrading with their package-management systems. These can make installation and upgrading
much easier for users of Django since the integration includes the ability to much easier for users of Django since the integration includes the ability to
automatically install dependancies (like database adapters) that Django automatically install dependencies (like database adapters) that Django
requires. requires.
Typically, these packages are based on the latest stable release of Django, so Typically, these packages are based on the latest stable release of Django, so

View File

@ -767,7 +767,7 @@ a command that can be executed as an action when you run ``manage.py``::
views.py views.py
In this example, the ``explode`` command will be made available to any project In this example, the ``explode`` command will be made available to any project
that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``. that includes the ``blog`` application in ``settings.INSTALLED_APPS``.
The ``explode.py`` module has only one requirement -- it must define a class The ``explode.py`` module has only one requirement -- it must define a class
called ``Command`` that extends ``django.core.management.base.BaseCommand``. called ``Command`` that extends ``django.core.management.base.BaseCommand``.

View File

@ -353,7 +353,7 @@ How do I install mod_python on Windows?
working`_. working`_.
.. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24 .. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24
.. _`Django on Windows howto`: http://thinkhole.org/wp/2006/04/03/django-on-windows-howto/ .. _`Django on Windows howto`: http://thinkhole.org/wp/django-on-windows/
.. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f .. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html .. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html

View File

@ -138,7 +138,7 @@ Installing a distribution-specific package
Check the `distribution specific notes`_ to see if your Check the `distribution specific notes`_ to see if your
platform/distribution provides official Django packages/installers. platform/distribution provides official Django packages/installers.
Distribution-provided packages will typically allow for automatic Distribution-provided packages will typically allow for automatic
installation of dependancies and easy upgrade paths. installation of dependencies and easy upgrade paths.
Installing an official release Installing an official release
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -384,7 +384,7 @@ The admin represents this as an ``<input type="text">`` (a single-line input).
``IPAddressField`` ``IPAddressField``
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
An IP address, in string format (i.e. "24.124.1.30"). An IP address, in string format (e.g. "192.0.2.30").
The admin represents this as an ``<input type="text">`` (a single-line input). The admin represents this as an ``<input type="text">`` (a single-line input).
@ -784,9 +784,17 @@ you can use the name of the model, rather than the model object itself::
class Manufacturer(models.Model): class Manufacturer(models.Model):
# ... # ...
Note, however, that you can only use strings to refer to models in the same Note, however, that this only refers to models in the same models.py file -- you
models.py file -- you cannot use a string to reference a model in a different cannot use a string to reference a model defined in another application or
application, or to reference a model that has been imported from elsewhere. imported from elsewhere.
**New in Django development version:** to refer to models defined in another
application, you must instead explicitially specify the application label. That
is, if the ``Manufacturer`` model above is defined in another application called
``production``, you'd need to use::
class Car(models.Model):
manufacturer = models.ForeignKey('production.Manufacturer')
Behind the scenes, Django appends ``"_id"`` to the field name to create its Behind the scenes, Django appends ``"_id"`` to the field name to create its
database column name. In the above example, the database table for the ``Car`` database column name. In the above example, the database table for the ``Car``
@ -952,10 +960,10 @@ the relationship should work. All are optional:
``limit_choices_to`` See the description under ``ForeignKey`` above. ``limit_choices_to`` See the description under ``ForeignKey`` above.
``symmetrical`` Only used in the definition of ManyToManyFields on self. ``symmetrical`` Only used in the definition of ManyToManyFields on self.
Consider the following model: Consider the following model::
class Person(models.Model): class Person(models.Model):
friends = models.ManyToManyField("self") friends = models.ManyToManyField("self")
When Django processes this model, it identifies that it has When Django processes this model, it identifies that it has
a ``ManyToManyField`` on itself, and as a result, it a ``ManyToManyField`` on itself, and as a result, it
@ -1872,7 +1880,7 @@ more simply as::
If you define a ``__unicode__()`` method on your model and not a ``__str__()`` If you define a ``__unicode__()`` method on your model and not a ``__str__()``
method, Django will automatically provide you with a ``__str__()`` that calls method, Django will automatically provide you with a ``__str__()`` that calls
``__unicode()__`` and then converts the result correctly to a UTF-8 encoded ``__unicode__()`` and then converts the result correctly to a UTF-8 encoded
string object. This is recommended development practice: define only string object. This is recommended development practice: define only
``__unicode__()`` and let Django take care of the conversion to string objects ``__unicode__()`` and let Django take care of the conversion to string objects
when required. when required.

View File

@ -320,3 +320,41 @@ parameter when declaring the form field::
... ...
... class Meta: ... class Meta:
... model = Article ... model = Article
Form inheritance
----------------
As with basic forms, you can extend and reuse ``ModelForms`` by inheriting
them. This is useful if you need to declare extra fields or extra methods on a
parent class for use in a number of forms derived from models. For example,
using the previous ``ArticleForm`` class::
>>> class EnhancedArticleForm(ArticleForm):
... def clean_pub_date(self):
... ...
This creates a form that behaves identically to ``ArticleForm``, except there's
some extra validation and cleaning for the ``pub_date`` field.
You can also subclass the parent's ``Meta`` inner class if you want to change
the ``Meta.fields`` or ``Meta.excludes`` lists::
>>> class RestrictedArticleForm(EnhancedArticleForm):
... class Meta(ArticleForm.Meta):
... exclude = ['body']
This adds the extra method from the ``EnhancedArticleForm`` and modifies
the original ``ArticleForm.Meta`` to remove one field.
There are a couple of things to note, however.
* Normal Python name resolution rules apply. If you have multiple base
classes that declare a ``Meta`` inner class, only the first one will be
used. This means the child's ``Meta``, if it exists, otherwise the
``Meta`` of the first parent, etc.
* For technical reasons, a subclass cannot inherit from both a ``ModelForm``
and a ``Form`` simultaneously.
Chances are these notes won't affect you unless you're trying to do something
tricky with subclassing.

View File

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

View File

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

View File

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

View File

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

View File

@ -395,6 +395,8 @@ See the `internationalization docs`_ for more.
django.core.context_processors.media django.core.context_processors.media
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**New in Django development version**
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the ``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
value of the `MEDIA_URL setting`_. value of the `MEDIA_URL setting`_.
@ -1014,7 +1016,7 @@ This is not a very common situation, but it's useful if you're rendering a
template yourself. For example:: template yourself. For example::
def render(self, context): def render(self, context):
t = template.load_template('small_fragment.html') t = template.loader.get_template('small_fragment.html')
return t.render(Context({'var': obj}, autoescape=context.autoescape)) return t.render(Context({'var': obj}, autoescape=context.autoescape))
If we had neglected to pass in the current ``context.autoescape`` value to our If we had neglected to pass in the current ``context.autoescape`` value to our

View File

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

View File

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

View File

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

View File

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

View File

@ -155,29 +155,52 @@ familiar with the mechanics.
... class Meta: ... class Meta:
... model = Category ... model = Category
>>> class BadForm(CategoryForm): >>> class OddForm(CategoryForm):
... class Meta: ... class Meta:
... model = Article ... model = Article
Traceback (most recent call last):
... OddForm is now an Article-related thing, because BadForm.Meta overrides
ImproperlyConfigured: BadForm defines a different model than its parent. CategoryForm.Meta.
>>> OddForm.base_fields.keys()
['headline', 'slug', 'pub_date', 'writer', 'article', 'status', 'categories']
>>> class ArticleForm(ModelForm): >>> class ArticleForm(ModelForm):
... class Meta: ... class Meta:
... model = Article ... model = Article
First class with a Meta class wins.
>>> class BadForm(ArticleForm, CategoryForm): >>> class BadForm(ArticleForm, CategoryForm):
... pass ... pass
Traceback (most recent call last): >>> OddForm.base_fields.keys()
... ['headline', 'slug', 'pub_date', 'writer', 'article', 'status', 'categories']
ImproperlyConfigured: BadForm's base classes define more than one model.
This one is OK since the subclass specifies the same model as the parent. Subclassing without specifying a Meta on the class will use the parent's Meta
(or the first parent in the MRO if there are multiple parent classes).
>>> class SubCategoryForm(CategoryForm): >>> class CategoryForm(ModelForm):
... class Meta: ... class Meta:
... model = Category ... model = Category
>>> class SubCategoryForm(CategoryForm):
... pass
>>> SubCategoryForm.base_fields.keys()
['name', 'slug', 'url']
We can also subclass the Meta inner class to change the fields list.
>>> class CategoryForm(ModelForm):
... checkbox = forms.BooleanField()
...
... class Meta:
... model = Category
>>> class SubCategoryForm(CategoryForm):
... class Meta(CategoryForm.Meta):
... exclude = ['url']
>>> print SubCategoryForm()
<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_checkbox">Checkbox:</label></th><td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>
# Old form_for_x tests ####################################################### # Old form_for_x tests #######################################################

View File

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

View File

@ -2,8 +2,8 @@
6. Specifying ordering 6. Specifying ordering
Specify default ordering for a model using the ``ordering`` attribute, which Specify default ordering for a model using the ``ordering`` attribute, which
should be a list or tuple of field names. This tells Django how to order the should be a list or tuple of field names. This tells Django how to order
results of ``get_list()`` and other similar functions. queryset results.
If a field name in ``ordering`` starts with a hyphen, that field will be If a field name in ``ordering`` starts with a hyphen, that field will be
ordered in descending order. Otherwise, it'll be ordered in ascending order. ordered in descending order. Otherwise, it'll be ordered in ascending order.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,5 @@
import sys
tests = """ tests = """
>>> from django.utils.translation.trans_real import parse_accept_lang_header >>> from django.utils.translation.trans_real import parse_accept_lang_header
>>> p = parse_accept_lang_header >>> p = parse_accept_lang_header
@ -83,7 +85,14 @@ source tree.
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'} >>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'}
>>> g(r) >>> g(r)
'es-ar' 'es-ar'
"""
# Python 2.3 returns slightly different results for completely bogus locales,
# so we omit this test for that anything below 2.4. It's relatively harmless in
# any cases (GIGO). This also means this won't be executed on Jython currently,
# but life's like that sometimes.
if sys.version_info >= (2, 4):
tests += """
This test assumes there won't be a Django translation to a US variation This test assumes there won't be a Django translation to a US variation
of the Spanish language, a safe assumption. When the user sets it of the Spanish language, a safe assumption. When the user sets it
as the preferred language, the main 'es' translation should be selected as the preferred language, the main 'es' translation should be selected
@ -91,7 +100,9 @@ instead.
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'} >>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'}
>>> g(r) >>> g(r)
'es' 'es'
"""
tests += """
This tests the following scenario: there isn't a main language (zh) This tests the following scenario: there isn't a main language (zh)
translation of Django but there is a translation to variation (zh_CN) translation of Django but there is a translation to variation (zh_CN)
the user sets zh-cn as the preferred language, it should be selected by the user sets zh-cn as the preferred language, it should be selected by

View File

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