mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
newforms-admin: Merged from trunk up to [7232]
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7233 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
304642769c
commit
bfc5660c47
3
AUTHORS
3
AUTHORS
@ -56,6 +56,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
David Ascher <http://ascher.ca/>
|
||||
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
|
||||
Arthur <avandorp@gmail.com>
|
||||
David Avsajanishvili <avsd05@gmail.com>
|
||||
axiak@mit.edu
|
||||
Jiri Barton
|
||||
Ned Batchelder <http://www.nedbatchelder.com/>
|
||||
@ -71,6 +72,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
boobsd@gmail.com
|
||||
Andrew Brehaut <http://brehaut.net/blog>
|
||||
brut.alll@gmail.com
|
||||
btoll@bestweb.net
|
||||
Jonathan Buchanan <jonathan.buchanan@gmail.com>
|
||||
Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
|
||||
Trevor Caira <trevor@caira.com>
|
||||
@ -111,6 +113,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Sander Dijkhuis <sander.dijkhuis@gmail.com>
|
||||
Jordan Dimov <s3x3y1@gmail.com>
|
||||
dne@mayonnaise.net
|
||||
dready <wil@mojipage.com>
|
||||
Maximillian Dornseif <md@hudora.de>
|
||||
Jeremy Dunck <http://dunck.us/>
|
||||
Andrew Durdin <adurdin@gmail.com>
|
||||
|
@ -52,7 +52,7 @@ LANGUAGES = (
|
||||
('fa', gettext_noop('Persian')),
|
||||
('fi', gettext_noop('Finnish')),
|
||||
('fr', gettext_noop('French')),
|
||||
('ga', gettext_noop('Gaeilge')),
|
||||
('ga', gettext_noop('Irish')),
|
||||
('gl', gettext_noop('Galician')),
|
||||
('hu', gettext_noop('Hungarian')),
|
||||
('he', gettext_noop('Hebrew')),
|
||||
@ -60,6 +60,7 @@ LANGUAGES = (
|
||||
('is', gettext_noop('Icelandic')),
|
||||
('it', gettext_noop('Italian')),
|
||||
('ja', gettext_noop('Japanese')),
|
||||
('ka', gettext_noop('Georgian')),
|
||||
('ko', gettext_noop('Korean')),
|
||||
('km', gettext_noop('Khmer')),
|
||||
('kn', gettext_noop('Kannada')),
|
||||
@ -90,8 +91,8 @@ LANGUAGES_BIDI = ("he", "ar", "fa")
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
LOCALE_PATHS = ()
|
||||
LANGUAGE_COOKIE_NAME = 'django_language'
|
||||
|
||||
# Not-necessarily-technical managers of the site. They get broken link
|
||||
# notifications and other various e-mails.
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -2,13 +2,12 @@
|
||||
# Italian translation of Django.
|
||||
# Copyright (C) 2006 the Lawrence Journal-World
|
||||
# This file is distributed under the same license as the Django package.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-02-02 18:31+0100\n"
|
||||
"PO-Revision-Date: 2008-02-02 19:40+0100\n"
|
||||
"PO-Revision-Date: 2008-03-02 11:40+0100\n"
|
||||
"Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
|
||||
"Language-Team: Italiano\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -79,7 +78,7 @@ msgstr "Francese"
|
||||
|
||||
#: conf/global_settings.py:54
|
||||
msgid "Gaeilge"
|
||||
msgstr ""
|
||||
msgstr "Gaelico"
|
||||
|
||||
#: conf/global_settings.py:55
|
||||
msgid "Galician"
|
||||
|
BIN
django/conf/locale/ka/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/ka/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
4513
django/conf/locale/ka/LC_MESSAGES/django.po
Normal file
4513
django/conf/locale/ka/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/ka/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/ka/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
118
django/conf/locale/ka/LC_MESSAGES/djangojs.po
Normal file
118
django/conf/locale/ka/LC_MESSAGES/djangojs.po
Normal 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 "ხვალ"
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -5,33 +5,16 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Project-Id-Version: Django 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-05-16 17:39+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Rudolph Froger <rfroger@estrate.nl>\n"
|
||||
"POT-Creation-Date: 2008-02-27 10:34+0100\n"
|
||||
"PO-Revision-Date: 2008-02-27 11:22+0100\n"
|
||||
"Last-Translator: jdetaeye <jdetaeye@frepple.com>\n"
|
||||
"Language-Team: nl <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
"januari februari maart april mei juni juli augustus september oktober "
|
||||
"november december"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "Z M D W D V Z"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "zondag maandag dinsdag woensdag donderdag vrijdag zaterdag"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
@ -62,49 +45,72 @@ msgstr "Selecteer uw keuze(s) en klik "
|
||||
msgid "Clear all"
|
||||
msgstr "Allemaal verwijderen"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
msgid "January February March April May June July August September October November December"
|
||||
msgstr "januari februari maart april mei juni juli augustus september oktober november december"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "Z M D W D V Z"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "zondag maandag dinsdag woensdag donderdag vrijdag zaterdag"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||
msgid "Show"
|
||||
msgstr "Tonen"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||
msgid "Hide"
|
||||
msgstr "Verbergen"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Now"
|
||||
msgstr "Nu"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||
msgid "Clock"
|
||||
msgstr "Klok"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||
msgid "Choose a time"
|
||||
msgstr "Kies een tijd"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "Midnight"
|
||||
msgstr "Middernacht"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "6 a.m."
|
||||
msgstr "6 uur"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||
msgid "Noon"
|
||||
msgstr "12 uur"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||
msgid "Today"
|
||||
msgstr "Vandaag"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||
msgid "Calendar"
|
||||
msgstr "Kalender"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||
msgid "Yesterday"
|
||||
msgstr "Gisteren"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||
msgid "Tomorrow"
|
||||
msgstr "Morgen"
|
||||
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -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.conf import settings
|
||||
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.utils.translation import ugettext_lazy, ugettext as _
|
||||
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.")
|
||||
LOGIN_FORM_KEY = 'this_is_the_login_form'
|
||||
@ -104,4 +110,4 @@ def staff_member_required(view_func):
|
||||
else:
|
||||
return _display_login_form(request, ERROR_MESSAGE)
|
||||
|
||||
return _checklogin
|
||||
return wraps(view_func)(_checklogin)
|
||||
|
@ -6,7 +6,7 @@ try:
|
||||
except NameError:
|
||||
from sets import Set as set # Python 2.3 fallback
|
||||
|
||||
class ModelBackend:
|
||||
class ModelBackend(object):
|
||||
"""
|
||||
Authenticate against django.contrib.auth.models.User
|
||||
"""
|
||||
|
@ -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.http import HttpResponseRedirect
|
||||
from django.utils.http import urlquote
|
||||
@ -51,7 +56,7 @@ class _CheckLogin(object):
|
||||
self.test_func = test_func
|
||||
self.login_url = login_url
|
||||
self.redirect_field_name = redirect_field_name
|
||||
self.__name__ = view_func.__name__
|
||||
update_wrapper(self, view_func)
|
||||
|
||||
def __get__(self, obj, cls=None):
|
||||
view_func = self.view_func.__get__(obj, cls)
|
||||
|
@ -39,13 +39,19 @@ class GenericForeignKey(object):
|
||||
# content-type/object-id fields.
|
||||
if self.name in kwargs:
|
||||
value = kwargs.pop(self.name)
|
||||
kwargs[self.ct_field] = self.get_content_type(value)
|
||||
kwargs[self.ct_field] = self.get_content_type(obj=value)
|
||||
kwargs[self.fk_field] = value._get_pk_val()
|
||||
|
||||
def get_content_type(self, obj):
|
||||
def get_content_type(self, obj=None, id=None):
|
||||
# Convenience function using get_model avoids a circular import when using this model
|
||||
ContentType = get_model("contenttypes", "contenttype")
|
||||
return ContentType.objects.get_for_model(obj)
|
||||
if obj:
|
||||
return ContentType.objects.get_for_model(obj)
|
||||
elif id:
|
||||
return ContentType.objects.get_for_id(id)
|
||||
else:
|
||||
# This should never happen. I love comments like this, don't you?
|
||||
raise Exception("Impossible arguments to GFK.get_content_type!")
|
||||
|
||||
def __get__(self, instance, instance_type=None):
|
||||
if instance is None:
|
||||
@ -55,8 +61,15 @@ class GenericForeignKey(object):
|
||||
return getattr(instance, self.cache_attr)
|
||||
except AttributeError:
|
||||
rel_obj = None
|
||||
ct = getattr(instance, self.ct_field)
|
||||
if ct:
|
||||
|
||||
# Make sure to use ContentType.objects.get_for_id() to ensure that
|
||||
# lookups are cached (see ticket #5570). This takes more code than
|
||||
# the naive ``getattr(instance, self.ct_field)``, but has better
|
||||
# performance when dealing with GFKs in loops and such.
|
||||
f = self.model._meta.get_field(self.ct_field)
|
||||
ct_id = getattr(instance, f.get_attname(), None)
|
||||
if ct_id:
|
||||
ct = self.get_content_type(id=ct_id)
|
||||
try:
|
||||
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
|
||||
except ObjectDoesNotExist:
|
||||
@ -71,7 +84,7 @@ class GenericForeignKey(object):
|
||||
ct = None
|
||||
fk = None
|
||||
if value is not None:
|
||||
ct = self.get_content_type(value)
|
||||
ct = self.get_content_type(obj=value)
|
||||
fk = value._get_pk_val()
|
||||
|
||||
setattr(instance, self.ct_field, ct)
|
||||
|
@ -2,23 +2,47 @@ from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
CONTENT_TYPE_CACHE = {}
|
||||
class ContentTypeManager(models.Manager):
|
||||
|
||||
# Cache to avoid re-looking up ContentType objects all over the place.
|
||||
# This cache is shared by all the get_for_* methods.
|
||||
_cache = {}
|
||||
|
||||
def get_for_model(self, model):
|
||||
"""
|
||||
Returns the ContentType object for the given model, creating the
|
||||
ContentType if necessary.
|
||||
Returns the ContentType object for a given model, creating the
|
||||
ContentType if necessary. Lookups are cached so that subsequent lookups
|
||||
for the same model don't hit the database.
|
||||
"""
|
||||
opts = model._meta
|
||||
key = (opts.app_label, opts.object_name.lower())
|
||||
try:
|
||||
ct = CONTENT_TYPE_CACHE[key]
|
||||
ct = self.__class__._cache[key]
|
||||
except KeyError:
|
||||
# The smart_unicode() is needed around opts.verbose_name_raw because it might
|
||||
# be a django.utils.functional.__proxy__ object.
|
||||
ct, created = self.model._default_manager.get_or_create(app_label=key[0],
|
||||
model=key[1], defaults={'name': smart_unicode(opts.verbose_name_raw)})
|
||||
CONTENT_TYPE_CACHE[key] = ct
|
||||
# Load or create the ContentType entry. The smart_unicode() is
|
||||
# needed around opts.verbose_name_raw because name_raw might be a
|
||||
# django.utils.functional.__proxy__ object.
|
||||
ct, created = self.get_or_create(
|
||||
app_label = opts.app_label,
|
||||
model = opts.object_name.lower(),
|
||||
defaults = {'name': smart_unicode(opts.verbose_name_raw)},
|
||||
)
|
||||
self._add_to_cache(ct)
|
||||
|
||||
return ct
|
||||
|
||||
def get_for_id(self, id):
|
||||
"""
|
||||
Lookup a ContentType by ID. Uses the same shared cache as get_for_model
|
||||
(though ContentTypes are obviously not created on-the-fly by get_by_id).
|
||||
"""
|
||||
try:
|
||||
ct = self.__class__._cache[id]
|
||||
except KeyError:
|
||||
# This could raise a DoesNotExist; that's correct behavior and will
|
||||
# make sure that only correct ctypes get stored in the cache dict.
|
||||
ct = self.get(pk=id)
|
||||
self._add_to_cache(ct)
|
||||
return ct
|
||||
|
||||
def clear_cache(self):
|
||||
@ -28,14 +52,21 @@ class ContentTypeManager(models.Manager):
|
||||
django.contrib.contenttypes.management.update_contenttypes for where
|
||||
this gets called).
|
||||
"""
|
||||
global CONTENT_TYPE_CACHE
|
||||
CONTENT_TYPE_CACHE = {}
|
||||
self.__class__._cache.clear()
|
||||
|
||||
def _add_to_cache(self, ct):
|
||||
"""Insert a ContentType into the cache."""
|
||||
model = ct.model_class()
|
||||
key = (model._meta.app_label, model._meta.object_name.lower())
|
||||
self.__class__._cache[key] = ct
|
||||
self.__class__._cache[ct.id] = ct
|
||||
|
||||
class ContentType(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
app_label = models.CharField(max_length=100)
|
||||
model = models.CharField(_('python model class name'), max_length=100)
|
||||
objects = ContentTypeManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('content type')
|
||||
verbose_name_plural = _('content types')
|
||||
|
47
django/contrib/contenttypes/tests.py
Normal file
47
django/contrib/contenttypes/tests.py
Normal file
@ -0,0 +1,47 @@
|
||||
"""
|
||||
Make sure that the content type cache (see ContentTypeManager) works correctly.
|
||||
Lookups for a particular content type -- by model or by ID -- should hit the
|
||||
database only on the first lookup.
|
||||
|
||||
First, let's make sure we're dealing with a blank slate (and that DEBUG is on so
|
||||
that queries get logged)::
|
||||
|
||||
>>> from django.conf import settings
|
||||
>>> settings.DEBUG = True
|
||||
|
||||
>>> from django.contrib.contenttypes.models import ContentType
|
||||
>>> ContentType.objects.clear_cache()
|
||||
|
||||
>>> from django import db
|
||||
>>> db.reset_queries()
|
||||
|
||||
At this point, a lookup for a ContentType should hit the DB::
|
||||
|
||||
>>> ContentType.objects.get_for_model(ContentType)
|
||||
<ContentType: content type>
|
||||
|
||||
>>> len(db.connection.queries)
|
||||
1
|
||||
|
||||
A second hit, though, won't hit the DB, nor will a lookup by ID::
|
||||
|
||||
>>> ct = ContentType.objects.get_for_model(ContentType)
|
||||
>>> len(db.connection.queries)
|
||||
1
|
||||
>>> ContentType.objects.get_for_id(ct.id)
|
||||
<ContentType: content type>
|
||||
>>> len(db.connection.queries)
|
||||
1
|
||||
|
||||
Once we clear the cache, another lookup will again hit the DB::
|
||||
|
||||
>>> ContentType.objects.clear_cache()
|
||||
>>> ContentType.objects.get_for_model(ContentType)
|
||||
<ContentType: content type>
|
||||
>>> len(db.connection.queries)
|
||||
2
|
||||
|
||||
Don't forget to reset DEBUG!
|
||||
|
||||
>>> settings.DEBUG = False
|
||||
"""
|
@ -8,8 +8,6 @@ from django.utils.translation import get_date_formats
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.views.generic import date_based
|
||||
import datetime
|
||||
import time
|
||||
|
||||
class CalendarPlugin(DatabrowsePlugin):
|
||||
def __init__(self, field_names=None):
|
||||
|
@ -7,8 +7,6 @@ from django.utils.text import capfirst
|
||||
from django.utils.encoding import smart_str, force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.views.generic import date_based
|
||||
import datetime
|
||||
import time
|
||||
import urllib
|
||||
|
||||
class FieldChoicePlugin(DatabrowsePlugin):
|
||||
|
@ -2,8 +2,6 @@ from django.db.models import FieldDoesNotExist, DateTimeField
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render_to_response
|
||||
from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
|
||||
import datetime
|
||||
import time
|
||||
|
||||
###########
|
||||
# CHOICES #
|
||||
|
@ -3,7 +3,6 @@ Formtools Preview application.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template.context import RequestContext
|
||||
|
@ -3,8 +3,6 @@ from django.contrib.formtools import preview
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
|
||||
|
||||
success_string = "Done was called!"
|
||||
test_data = {'field1': u'foo',
|
||||
@ -88,6 +86,3 @@ class PreviewTests(TestCase):
|
||||
response = self.client.post('/test1/', test_data)
|
||||
self.assertEqual(response.content, success_string)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -2,8 +2,7 @@ from django.utils.translation import ungettext, ugettext as _
|
||||
from django.utils.encoding import force_unicode
|
||||
from django import template
|
||||
from django.template import defaultfilters
|
||||
from django.conf import settings
|
||||
from datetime import date, timedelta
|
||||
from datetime import date
|
||||
import re
|
||||
|
||||
register = template.Library()
|
||||
|
@ -7,7 +7,6 @@ from django.newforms import ValidationError
|
||||
from django.newforms.fields import RegexField, CharField, Select, EMPTY_VALUES
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.translation import ugettext
|
||||
import re
|
||||
|
||||
class ARProvinceSelect(Select):
|
||||
"""
|
||||
|
@ -7,8 +7,6 @@ from django.newforms import ValidationError
|
||||
from django.utils.translation import ugettext
|
||||
from django.newforms.fields import RegexField, Select
|
||||
|
||||
import re
|
||||
|
||||
class JPPostalCodeField(RegexField):
|
||||
"""
|
||||
A form field that validates its input is a Japanese postcode.
|
||||
|
@ -1,10 +1,5 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import datetime
|
||||
import base64
|
||||
import md5
|
||||
import random
|
||||
import cPickle as pickle
|
||||
|
||||
from django.db import models
|
||||
|
@ -14,7 +14,6 @@ u'lorem ipsum dolor'
|
||||
"""
|
||||
|
||||
from django.contrib.webdesign.lorem_ipsum import *
|
||||
import datetime
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
|
@ -109,7 +109,8 @@ class BaseHandler(object):
|
||||
except exceptions.PermissionDenied:
|
||||
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
|
||||
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.
|
||||
# Get the exception info now, in case another exception is thrown later.
|
||||
exc_info = sys.exc_info()
|
||||
|
@ -6,7 +6,7 @@ from django.core import signals
|
||||
from django.core.handlers.base import BaseHandler
|
||||
from django.dispatch import dispatcher
|
||||
from django.utils import datastructures
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.encoding import force_unicode, smart_str
|
||||
|
||||
# NOTE: do *not* import settings (or any module which eventually imports
|
||||
# settings) until after ModPythonHandler has been called; otherwise os.environ
|
||||
@ -36,8 +36,9 @@ class ModPythonRequest(http.HttpRequest):
|
||||
meta = pformat(self.META)
|
||||
except:
|
||||
meta = '<could not parse>'
|
||||
return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
|
||||
(self.path, get, post, cookies, meta)
|
||||
return smart_str(u'<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' %
|
||||
(self.path, unicode(get), unicode(post),
|
||||
unicode(cookies), unicode(meta)))
|
||||
|
||||
def get_full_path(self):
|
||||
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
|
||||
|
@ -318,8 +318,8 @@ def send_mail(subject, message, from_email, recipient_list, fail_silently=False,
|
||||
If auth_user is None, the EMAIL_HOST_USER setting is used.
|
||||
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
|
||||
|
||||
NOTE: This method is deprecated. It exists for backwards compatibility.
|
||||
New code should use the EmailMessage class directly.
|
||||
Note: The API for this method is frozen. New code wanting to extend the
|
||||
functionality should use the EmailMessage class directly.
|
||||
"""
|
||||
connection = SMTPConnection(username=auth_user, password=auth_password,
|
||||
fail_silently=fail_silently)
|
||||
@ -335,8 +335,8 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password
|
||||
If auth_user is None, the EMAIL_HOST_USER setting is used.
|
||||
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
|
||||
|
||||
NOTE: This method is deprecated. It exists for backwards compatibility.
|
||||
New code should use the EmailMessage class directly.
|
||||
Note: The API for this method is frozen. New code wanting to extend the
|
||||
functionality should use the EmailMessage class directly.
|
||||
"""
|
||||
connection = SMTPConnection(username=auth_user, password=auth_password,
|
||||
fail_silently=fail_silently)
|
||||
|
@ -6,10 +6,22 @@ import sys
|
||||
|
||||
from django.utils import termcolors
|
||||
|
||||
def supports_color():
|
||||
"""
|
||||
Returns True if the running system's terminal supports color, and False
|
||||
otherwise.
|
||||
"""
|
||||
unsupported_platform = (sys.platform in ('win32', 'Pocket PC')
|
||||
or sys.platform.startswith('java'))
|
||||
# isatty is not always implemented, #6223.
|
||||
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
|
||||
if unsupported_platform or not is_a_tty:
|
||||
return False
|
||||
return True
|
||||
|
||||
def color_style():
|
||||
"""Returns a Style object with the Django color scheme."""
|
||||
if (sys.platform == 'win32' or sys.platform == 'Pocket PC'
|
||||
or sys.platform.startswith('java') or not sys.stdout.isatty()):
|
||||
if not supports_color():
|
||||
return no_style()
|
||||
class dummy: pass
|
||||
style = dummy()
|
||||
|
@ -30,7 +30,8 @@ class Command(BaseCommand):
|
||||
show_traceback = options.get('traceback', False)
|
||||
|
||||
# Keep a count of the installed objects and fixtures
|
||||
count = [0, 0]
|
||||
fixture_count = 0
|
||||
object_count = 0
|
||||
models = set()
|
||||
|
||||
humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
|
||||
@ -65,7 +66,12 @@ class Command(BaseCommand):
|
||||
else:
|
||||
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:
|
||||
print "Checking %s for fixtures..." % humanize(fixture_dir)
|
||||
|
||||
@ -86,14 +92,14 @@ class Command(BaseCommand):
|
||||
transaction.leave_transaction_management()
|
||||
return
|
||||
else:
|
||||
count[1] += 1
|
||||
fixture_count += 1
|
||||
if verbosity > 0:
|
||||
print "Installing %s fixture '%s' from %s." % \
|
||||
(format, fixture_name, humanize(fixture_dir))
|
||||
try:
|
||||
objects = serializers.deserialize(format, fixture)
|
||||
for obj in objects:
|
||||
count[0] += 1
|
||||
object_count += 1
|
||||
models.add(obj.object.__class__)
|
||||
obj.save()
|
||||
label_found = True
|
||||
@ -102,10 +108,12 @@ class Command(BaseCommand):
|
||||
transaction.rollback()
|
||||
transaction.leave_transaction_management()
|
||||
if show_traceback:
|
||||
raise
|
||||
sys.stderr.write(
|
||||
self.style.ERROR("Problem installing fixture '%s': %s\n" %
|
||||
(full_path, str(e))))
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
sys.stderr.write(
|
||||
self.style.ERROR("Problem installing fixture '%s': %s\n" %
|
||||
(full_path, str(e))))
|
||||
return
|
||||
fixture.close()
|
||||
except:
|
||||
@ -113,7 +121,7 @@ class Command(BaseCommand):
|
||||
print "No %s fixture '%s' in %s." % \
|
||||
(format, fixture_name, humanize(fixture_dir))
|
||||
|
||||
if count[0] > 0:
|
||||
if object_count > 0:
|
||||
sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
|
||||
if sequence_sql:
|
||||
if verbosity > 1:
|
||||
@ -124,9 +132,9 @@ class Command(BaseCommand):
|
||||
transaction.commit()
|
||||
transaction.leave_transaction_management()
|
||||
|
||||
if count[0] == 0:
|
||||
if object_count == 0:
|
||||
if verbosity >= 2:
|
||||
print "No fixtures found."
|
||||
else:
|
||||
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)
|
||||
|
@ -67,6 +67,8 @@ class Command(NoArgsCommand):
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in seen_models:
|
||||
sql.extend(sql_for_pending_references(refto, self.style, pending_references))
|
||||
sql.extend(sql_for_pending_references(model, self.style, pending_references))
|
||||
if verbosity >= 1:
|
||||
print "Creating table %s" % model._meta.db_table
|
||||
|
@ -90,6 +90,8 @@ def sql_create(app, style):
|
||||
final_output.extend(output)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in known_models:
|
||||
final_output.extend(sql_for_pending_references(refto, style, pending_references))
|
||||
final_output.extend(sql_for_pending_references(model, style, pending_references))
|
||||
# Keep track of the fact that we've created the table for this model.
|
||||
known_models.add(model)
|
||||
|
@ -4,7 +4,6 @@ Serialize data to/from JSON
|
||||
|
||||
import datetime
|
||||
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 Deserializer as PythonDeserializer
|
||||
try:
|
||||
|
@ -4,7 +4,6 @@ YAML serializer.
|
||||
Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from django.db import models
|
||||
from django.core.serializers.python import Serializer as PythonSerializer
|
||||
from django.core.serializers.python import Deserializer as PythonDeserializer
|
||||
|
@ -21,7 +21,6 @@ if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
|
||||
|
||||
from MySQLdb.converters import conversions
|
||||
from MySQLdb.constants import FIELD_TYPE
|
||||
import types
|
||||
import re
|
||||
|
||||
# Raise exceptions for database warnings if DEBUG is on
|
||||
|
@ -27,6 +27,11 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||
def deferrable_sql(self):
|
||||
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):
|
||||
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
|
||||
return cursor.fetchone()[0]
|
||||
|
@ -132,6 +132,9 @@ class Model(object):
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._get_pk_val())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
|
||||
|
||||
|
@ -226,7 +226,11 @@ class Field(object):
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
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)
|
||||
|
||||
def has_default(self):
|
||||
@ -445,6 +449,9 @@ class BooleanField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "BooleanField"
|
||||
|
||||
def to_python(self, value):
|
||||
if value in (True, False): return value
|
||||
if value in ('t', 'True', '1'): return True
|
||||
@ -463,6 +470,9 @@ class CharField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.TextField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
def to_python(self, value):
|
||||
if isinstance(value, basestring):
|
||||
return value
|
||||
@ -493,6 +503,9 @@ class DateField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DateField"
|
||||
|
||||
def to_python(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
@ -562,6 +575,9 @@ class DateField(Field):
|
||||
return super(DateField, self).formfield(**defaults)
|
||||
|
||||
class DateTimeField(DateField):
|
||||
def get_internal_type(self):
|
||||
return "DateTimeField"
|
||||
|
||||
def to_python(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
@ -632,6 +648,9 @@ class DecimalField(Field):
|
||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DecimalField"
|
||||
|
||||
def to_python(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
@ -691,9 +710,6 @@ class EmailField(CharField):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||
CharField.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.EmailField]
|
||||
|
||||
@ -711,6 +727,9 @@ class FileField(Field):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "FileField"
|
||||
|
||||
def get_db_prep_save(self, value):
|
||||
"Returns field's value prepared for saving into a database."
|
||||
# Need to convert UploadedFile objects provided via a form to unicode for database insertion
|
||||
@ -820,12 +839,18 @@ class FilePathField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "FilePathField"
|
||||
|
||||
class FloatField(Field):
|
||||
empty_strings_allowed = False
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.FloatField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "FloatField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.FloatField}
|
||||
defaults.update(kwargs)
|
||||
@ -848,6 +873,9 @@ class ImageField(FileField):
|
||||
if not self.height_field:
|
||||
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):
|
||||
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
|
||||
@ -870,6 +898,9 @@ class IntegerField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.IntegerField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "IntegerField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.IntegerField}
|
||||
defaults.update(kwargs)
|
||||
@ -884,6 +915,9 @@ class IPAddressField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.IPAddressField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "IPAddressField"
|
||||
|
||||
def validate(self, field_data, all_data):
|
||||
validators.isValidIPAddress4(field_data, None)
|
||||
|
||||
@ -898,6 +932,9 @@ class NullBooleanField(Field):
|
||||
kwargs['null'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "NullBooleanField"
|
||||
|
||||
def to_python(self, value):
|
||||
if value in (None, True, False): return value
|
||||
if value in ('None'): return None
|
||||
@ -921,6 +958,9 @@ class PhoneNumberField(IntegerField):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.PhoneNumberField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PhoneNumberField"
|
||||
|
||||
def validate(self, field_data, all_data):
|
||||
validators.isValidPhone(field_data, all_data)
|
||||
|
||||
@ -934,6 +974,9 @@ class PositiveIntegerField(IntegerField):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.PositiveIntegerField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PositiveIntegerField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'min_value': 0}
|
||||
defaults.update(kwargs)
|
||||
@ -943,6 +986,9 @@ class PositiveSmallIntegerField(IntegerField):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.PositiveSmallIntegerField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PositiveSmallIntegerField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'min_value': 0}
|
||||
defaults.update(kwargs)
|
||||
@ -957,14 +1003,23 @@ class SlugField(CharField):
|
||||
kwargs['db_index'] = True
|
||||
super(SlugField, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "SlugField"
|
||||
|
||||
class SmallIntegerField(IntegerField):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.SmallIntegerField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "SmallIntegerField"
|
||||
|
||||
class TextField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.LargeTextField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "TextField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'widget': forms.Textarea}
|
||||
defaults.update(kwargs)
|
||||
@ -978,6 +1033,9 @@ class TimeField(Field):
|
||||
kwargs['editable'] = False
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "TimeField"
|
||||
|
||||
def get_db_prep_lookup(self, lookup_type, value):
|
||||
if settings.DATABASE_ENGINE == 'oracle':
|
||||
# Oracle requires a date in order to parse.
|
||||
@ -1042,9 +1100,6 @@ class URLField(CharField):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.URLField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists}
|
||||
defaults.update(kwargs)
|
||||
@ -1054,6 +1109,9 @@ class USStateField(Field):
|
||||
def get_manipulator_field_objs(self):
|
||||
return [oldforms.USStateField]
|
||||
|
||||
def get_internal_type(self):
|
||||
return "USStateField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
from django.contrib.localflavor.us.forms import USStateSelect
|
||||
defaults = {'widget': USStateSelect}
|
||||
@ -1065,9 +1123,6 @@ class XMLField(TextField):
|
||||
self.schema_path = schema_path
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "TextField"
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
|
||||
|
||||
@ -1078,8 +1133,5 @@ class OrderingField(IntegerField):
|
||||
kwargs['null'] = True
|
||||
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):
|
||||
return [oldforms.HiddenField(name_prefix + self.name)]
|
||||
|
@ -23,26 +23,64 @@ RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
|
||||
|
||||
pending_lookups = {}
|
||||
|
||||
def add_lookup(rel_cls, field):
|
||||
name = field.rel.to
|
||||
module = rel_cls.__module__
|
||||
key = (module, name)
|
||||
# Has the model already been loaded?
|
||||
# If so, resolve the string reference right away
|
||||
model = get_model(rel_cls._meta.app_label, field.rel.to, False)
|
||||
def add_lazy_relation(cls, field, relation):
|
||||
"""
|
||||
Adds a lookup on ``cls`` when a related field is defined using a string,
|
||||
i.e.::
|
||||
|
||||
class MyModel(Model):
|
||||
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:
|
||||
field.rel.to = model
|
||||
field.do_related_class(model, rel_cls)
|
||||
field.do_related_class(model, cls)
|
||||
else:
|
||||
# Mark the related field for later lookup
|
||||
pending_lookups.setdefault(key, []).append((rel_cls, field))
|
||||
key = (app_label, model_name)
|
||||
value = (cls, field)
|
||||
pending_lookups.setdefault(key, []).append(value)
|
||||
|
||||
def do_pending_lookups(sender):
|
||||
other_cls = sender
|
||||
key = (other_cls.__module__, other_cls.__name__)
|
||||
for rel_cls, field in pending_lookups.setdefault(key, []):
|
||||
field.rel.to = other_cls
|
||||
field.do_related_class(other_cls, rel_cls)
|
||||
"""
|
||||
Handle any pending relations to the sending model. Sent from class_prepared.
|
||||
"""
|
||||
key = (sender._meta.app_label, sender.__name__)
|
||||
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)
|
||||
|
||||
@ -66,9 +104,7 @@ class RelatedField(object):
|
||||
sup.contribute_to_class(cls, name)
|
||||
other = self.rel.to
|
||||
if isinstance(other, basestring):
|
||||
if other == RECURSIVE_RELATIONSHIP_CONSTANT:
|
||||
self.rel.to = cls.__name__
|
||||
add_lookup(cls, self)
|
||||
add_lazy_relation(cls, self, other)
|
||||
else:
|
||||
self.do_related_class(other, cls)
|
||||
|
||||
|
@ -3,23 +3,25 @@ from Cookie import SimpleCookie
|
||||
from pprint import pformat
|
||||
from urllib import urlencode
|
||||
from urlparse import urljoin
|
||||
from django.utils.datastructures import MultiValueDict, FileDict
|
||||
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||
from utils import *
|
||||
|
||||
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
|
||||
|
||||
try:
|
||||
# The mod_python version is more efficient, so try importing it first.
|
||||
from mod_python.util import parse_qsl
|
||||
except ImportError:
|
||||
from cgi import parse_qsl
|
||||
|
||||
from django.utils.datastructures import MultiValueDict, FileDict
|
||||
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||
|
||||
from utils import *
|
||||
|
||||
RESERVED_CHARS="!*'();:@&=+$,/?%#[]"
|
||||
|
||||
|
||||
class Http404(Exception):
|
||||
pass
|
||||
|
||||
class HttpRequest(object):
|
||||
"A basic HTTP request"
|
||||
"""A basic HTTP request."""
|
||||
|
||||
# The encoding used in GET/POST dicts. None means use default setting.
|
||||
_encoding = None
|
||||
@ -46,7 +48,7 @@ class HttpRequest(object):
|
||||
__contains__ = has_key
|
||||
|
||||
def get_host(self):
|
||||
"Returns the HTTP host using the environment or request headers."
|
||||
"""Returns the HTTP host using the environment or request headers."""
|
||||
# We try three options, in order of decreasing preference.
|
||||
if 'HTTP_X_FORWARDED_HOST' in self.META:
|
||||
host = self.META['HTTP_X_FORWARDED_HOST']
|
||||
@ -98,7 +100,7 @@ class HttpRequest(object):
|
||||
encoding = property(_get_encoding, _set_encoding)
|
||||
|
||||
def parse_file_upload(header_dict, post_data):
|
||||
"Returns a tuple of (POST QueryDict, FILES MultiValueDict)"
|
||||
"""Returns a tuple of (POST QueryDict, FILES MultiValueDict)."""
|
||||
import email, email.Message
|
||||
from cgi import parse_header
|
||||
raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()])
|
||||
@ -130,6 +132,7 @@ def parse_file_upload(header_dict, post_data):
|
||||
POST.appendlist(name_dict['name'], submessage.get_payload())
|
||||
return POST, FILES
|
||||
|
||||
|
||||
class QueryDict(MultiValueDict):
|
||||
"""
|
||||
A specialized MultiValueDict that takes a query string when initialized.
|
||||
@ -148,12 +151,13 @@ class QueryDict(MultiValueDict):
|
||||
self.encoding = encoding
|
||||
self._mutable = True
|
||||
for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True
|
||||
self.appendlist(force_unicode(key, encoding, errors='replace'), force_unicode(value, encoding, errors='replace'))
|
||||
self.appendlist(force_unicode(key, encoding, errors='replace'),
|
||||
force_unicode(value, encoding, errors='replace'))
|
||||
self._mutable = mutable
|
||||
|
||||
def _assert_mutable(self):
|
||||
if not self._mutable:
|
||||
raise AttributeError, "This QueryDict instance is immutable"
|
||||
raise AttributeError("This QueryDict instance is immutable")
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._assert_mutable()
|
||||
@ -171,7 +175,7 @@ class QueryDict(MultiValueDict):
|
||||
dict.__setitem__(result, key, value)
|
||||
return result
|
||||
|
||||
def __deepcopy__(self, memo={}):
|
||||
def __deepcopy__(self, memo):
|
||||
import copy
|
||||
result = self.__class__('', mutable=True)
|
||||
memo[id(self)] = result
|
||||
@ -222,8 +226,8 @@ class QueryDict(MultiValueDict):
|
||||
return MultiValueDict.setdefault(self, key, default)
|
||||
|
||||
def copy(self):
|
||||
"Returns a mutable copy of this object."
|
||||
return self.__deepcopy__()
|
||||
"""Returns a mutable copy of this object."""
|
||||
return self.__deepcopy__({})
|
||||
|
||||
def urlencode(self):
|
||||
output = []
|
||||
@ -243,7 +247,7 @@ def parse_cookie(cookie):
|
||||
return cookiedict
|
||||
|
||||
class HttpResponse(object):
|
||||
"A basic HTTP response, with content and dictionary-accessed headers"
|
||||
"""A basic HTTP response, with content and dictionary-accessed headers."""
|
||||
|
||||
status_code = 200
|
||||
|
||||
@ -272,13 +276,13 @@ class HttpResponse(object):
|
||||
self._headers = {'content-type': ('Content-Type', content_type)}
|
||||
|
||||
def __str__(self):
|
||||
"Full HTTP message, including headers"
|
||||
"""Full HTTP message, including headers."""
|
||||
return '\n'.join(['%s: %s' % (key, value)
|
||||
for key, value in self._headers.values()]) \
|
||||
+ '\n\n' + self.content
|
||||
|
||||
def _convert_to_ascii(self, *values):
|
||||
"Convert all values to ascii strings"
|
||||
"""Converts all values to ascii strings."""
|
||||
for value in values:
|
||||
if isinstance(value, unicode):
|
||||
try:
|
||||
@ -303,7 +307,7 @@ class HttpResponse(object):
|
||||
return self._headers[header.lower()][1]
|
||||
|
||||
def has_header(self, header):
|
||||
"Case-insensitive check for a header"
|
||||
"""Case-insensitive check for a header."""
|
||||
return self._headers.has_key(header.lower())
|
||||
|
||||
__contains__ = has_header
|
||||
@ -314,16 +318,23 @@ class HttpResponse(object):
|
||||
def get(self, header, alternate):
|
||||
return self._headers.get(header.lower(), (None, alternate))[1]
|
||||
|
||||
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None):
|
||||
def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
|
||||
domain=None, secure=False):
|
||||
self.cookies[key] = value
|
||||
for var in ('max_age', 'path', 'domain', 'secure', 'expires'):
|
||||
val = locals()[var]
|
||||
if val is not None:
|
||||
self.cookies[key][var.replace('_', '-')] = val
|
||||
if max_age is not None:
|
||||
self.cookies[key]['max-age'] = max_age
|
||||
if expires is not None:
|
||||
self.cookies[key]['expires'] = expires
|
||||
if path is not None:
|
||||
self.cookies[key]['path'] = path
|
||||
if domain is not None:
|
||||
self.cookies[key]['domain'] = domain
|
||||
if secure:
|
||||
self.cookies[key]['secure'] = True
|
||||
|
||||
def delete_cookie(self, key, path='/', domain=None):
|
||||
self.set_cookie(key, max_age=0, path=path, domain=domain,
|
||||
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
||||
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
||||
|
||||
def _get_content(self):
|
||||
if self.has_header('Content-Encoding'):
|
||||
@ -354,7 +365,7 @@ class HttpResponse(object):
|
||||
# See http://docs.python.org/lib/bltin-file-objects.html
|
||||
def write(self, content):
|
||||
if not self._is_string:
|
||||
raise Exception, "This %s instance is not writable" % self.__class__
|
||||
raise Exception("This %s instance is not writable" % self.__class__)
|
||||
self._container.append(content)
|
||||
|
||||
def flush(self):
|
||||
@ -362,7 +373,7 @@ class HttpResponse(object):
|
||||
|
||||
def tell(self):
|
||||
if not self._is_string:
|
||||
raise Exception, "This %s instance cannot tell its position" % self.__class__
|
||||
raise Exception("This %s instance cannot tell its position" % self.__class__)
|
||||
return sum([len(chunk) for chunk in self._container])
|
||||
|
||||
class HttpResponseRedirect(HttpResponse):
|
||||
@ -419,7 +430,7 @@ def get_host(request):
|
||||
# this slightly more restricted function.
|
||||
def str_to_unicode(s, encoding):
|
||||
"""
|
||||
Convert basestring objects to unicode, using the given encoding. Illegaly
|
||||
Converts basestring objects to unicode, using the given encoding. Illegally
|
||||
encoded input characters are replaced with Unicode "unknown" codepoint
|
||||
(\ufffd).
|
||||
|
||||
@ -429,4 +440,3 @@ def str_to_unicode(s, encoding):
|
||||
return unicode(s, encoding, 'replace')
|
||||
else:
|
||||
return s
|
||||
|
||||
|
@ -134,7 +134,7 @@ class BaseForm(StrAndUnicode):
|
||||
bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
||||
if bf.is_hidden:
|
||||
if bf_errors:
|
||||
top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
||||
top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
||||
hidden_fields.append(unicode(bf))
|
||||
else:
|
||||
if errors_on_separate_row and bf_errors:
|
||||
@ -155,7 +155,7 @@ class BaseForm(StrAndUnicode):
|
||||
help_text = u''
|
||||
output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text})
|
||||
if top_errors:
|
||||
output.insert(0, error_row % top_errors)
|
||||
output.insert(0, error_row % force_unicode(top_errors))
|
||||
if hidden_fields: # Insert any hidden fields in the last row.
|
||||
str_hidden = u''.join(hidden_fields)
|
||||
if output:
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
import re
|
||||
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.conf import settings
|
||||
@ -35,7 +39,7 @@ def stringfilter(func):
|
||||
for attr in ('is_safe', 'needs_autoescape'):
|
||||
if hasattr(func, attr):
|
||||
setattr(_dec, attr, getattr(func, attr))
|
||||
return _dec
|
||||
return wraps(func)(_dec)
|
||||
|
||||
###################
|
||||
# STRINGS #
|
||||
|
@ -100,7 +100,7 @@ __all__ = [
|
||||
|
||||
import __future__
|
||||
|
||||
import sys, traceback, inspect, linecache, os, re, types
|
||||
import sys, traceback, inspect, linecache, os, re
|
||||
import unittest, difflib, pdb, tempfile
|
||||
import warnings
|
||||
from StringIO import StringIO
|
||||
|
@ -1,7 +1,5 @@
|
||||
import datetime
|
||||
import sys
|
||||
from cStringIO import StringIO
|
||||
from urlparse import urlparse
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.core.handlers.base import BaseHandler
|
||||
|
@ -146,4 +146,3 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
|
||||
teardown_test_environment()
|
||||
|
||||
return len(result.failures) + len(result.errors)
|
||||
|
@ -3,7 +3,7 @@ class MergeDict(object):
|
||||
A simple class for creating new "virtual" dictionaries that actually look
|
||||
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.
|
||||
"""
|
||||
def __init__(self, *dicts):
|
||||
@ -145,7 +145,7 @@ class SortedDict(dict):
|
||||
"""Returns a copy of this object."""
|
||||
# This way of initializing the copy means it works for subclasses, too.
|
||||
obj = self.__class__(self)
|
||||
obj.keyOrder = self.keyOrder
|
||||
obj.keyOrder = self.keyOrder[:]
|
||||
return obj
|
||||
|
||||
def __repr__(self):
|
||||
@ -155,6 +155,10 @@ class SortedDict(dict):
|
||||
"""
|
||||
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):
|
||||
pass
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
"Functions that help with dynamically creating decorators for views."
|
||||
|
||||
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):
|
||||
"""
|
||||
@ -53,5 +57,5 @@ def decorator_from_middleware(middleware_class):
|
||||
if result is not None:
|
||||
return result
|
||||
return response
|
||||
return _wrapped_view
|
||||
return wraps(view_func)(_wrapped_view)
|
||||
return _decorator_from_middleware
|
||||
|
@ -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 _curried(*moreargs, **morekwargs):
|
||||
return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
|
||||
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):
|
||||
"""
|
||||
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)
|
||||
cache[mem_args] = result
|
||||
return result
|
||||
return wrapper
|
||||
return wraps(func)(wrapper)
|
||||
|
||||
class Promise(object):
|
||||
"""
|
||||
@ -110,7 +222,7 @@ def lazy(func, *resultclasses):
|
||||
# Creates the proxy object, instead of the actual value.
|
||||
return __proxy__(args, kw)
|
||||
|
||||
return __wrapper__
|
||||
return wraps(func)(__wrapper__)
|
||||
|
||||
def allow_lazy(func, *resultclasses):
|
||||
"""
|
||||
@ -126,4 +238,4 @@ def allow_lazy(func, *resultclasses):
|
||||
else:
|
||||
return func(*args, **kwargs)
|
||||
return lazy(func, *resultclasses)(*args, **kwargs)
|
||||
return wrapper
|
||||
return wraps(func)(wrapper)
|
||||
|
@ -1,4 +1,4 @@
|
||||
"Translation helper functions"
|
||||
"""Translation helper functions."""
|
||||
|
||||
import locale
|
||||
import os
|
||||
@ -7,7 +7,6 @@ import sys
|
||||
import gettext as gettext_module
|
||||
from cStringIO import StringIO
|
||||
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe, SafeData
|
||||
|
||||
try:
|
||||
@ -30,7 +29,7 @@ _active = {}
|
||||
# The default translation is based on the settings file.
|
||||
_default = None
|
||||
|
||||
# This is a cache for normalised accept-header languages to prevent multiple
|
||||
# This is a cache for normalized accept-header languages to prevent multiple
|
||||
# file lookups when checking the same locale on repeated requests.
|
||||
_accepted = {}
|
||||
|
||||
@ -56,7 +55,7 @@ def to_locale(language, to_lower=False):
|
||||
return language.lower()
|
||||
|
||||
def to_language(locale):
|
||||
"Turns a locale name (en_US) into a language name (en-us)."
|
||||
"""Turns a locale name (en_US) into a language name (en-us)."""
|
||||
p = locale.find('_')
|
||||
if p >= 0:
|
||||
return locale[:p].lower()+'-'+locale[p+1:].lower()
|
||||
@ -229,7 +228,7 @@ def deactivate_all():
|
||||
_active[currentThread()] = gettext_module.NullTranslations()
|
||||
|
||||
def get_language():
|
||||
"Returns the currently selected language."
|
||||
"""Returns the currently selected language."""
|
||||
t = _active.get(currentThread(), None)
|
||||
if t is not None:
|
||||
try:
|
||||
@ -251,7 +250,7 @@ def get_language_bidi():
|
||||
|
||||
def catalog():
|
||||
"""
|
||||
This function returns the current active catalog for further processing.
|
||||
Returns the current active catalog for further processing.
|
||||
This can be used if you need to modify the catalog or want to access the
|
||||
whole message catalog instead of just translating one string.
|
||||
"""
|
||||
@ -355,7 +354,7 @@ def get_language_from_request(request):
|
||||
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
||||
return lang_code
|
||||
|
||||
lang_code = request.COOKIES.get('django_language')
|
||||
lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
|
||||
if lang_code and lang_code in supported and check_for_language(lang_code):
|
||||
return lang_code
|
||||
|
||||
@ -374,7 +373,7 @@ def get_language_from_request(request):
|
||||
normalized = locale.locale_alias.get(to_locale(accept_lang, True))
|
||||
if not normalized:
|
||||
continue
|
||||
# Remove the default encoding from locale_alias
|
||||
# Remove the default encoding from locale_alias.
|
||||
normalized = normalized.split('.')[0]
|
||||
|
||||
if normalized in _accepted:
|
||||
@ -396,9 +395,9 @@ def get_language_from_request(request):
|
||||
|
||||
def get_date_formats():
|
||||
"""
|
||||
This function checks whether translation files provide a translation for some
|
||||
technical message ID to store date and time formats. If it doesn't contain
|
||||
one, the formats provided in the settings will be used.
|
||||
Checks whether translation files provide a translation for some technical
|
||||
message ID to store date and time formats. If it doesn't contain one, the
|
||||
formats provided in the settings will be used.
|
||||
"""
|
||||
from django.conf import settings
|
||||
date_format = ugettext('DATE_FORMAT')
|
||||
@ -414,9 +413,9 @@ def get_date_formats():
|
||||
|
||||
def get_partial_date_formats():
|
||||
"""
|
||||
This function checks whether translation files provide a translation for some
|
||||
technical message ID to store partial date formats. If it doesn't contain
|
||||
one, the formats provided in the settings will be used.
|
||||
Checks whether translation files provide a translation for some technical
|
||||
message ID to store partial date formats. If it doesn't contain one, the
|
||||
formats provided in the settings will be used.
|
||||
"""
|
||||
from django.conf import settings
|
||||
year_month_format = ugettext('YEAR_MONTH_FORMAT')
|
||||
@ -440,6 +439,7 @@ block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""")
|
||||
endblock_re = re.compile(r"""^\s*endblocktrans$""")
|
||||
plural_re = re.compile(r"""^\s*plural$""")
|
||||
constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
|
||||
|
||||
def templatize(src):
|
||||
"""
|
||||
Turns a Django template into something that is understood by xgettext. It
|
||||
@ -475,7 +475,7 @@ def templatize(src):
|
||||
elif pluralmatch:
|
||||
inplural = True
|
||||
else:
|
||||
raise SyntaxError, "Translation blocks must not include other block tags: %s" % t.contents
|
||||
raise SyntaxError("Translation blocks must not include other block tags: %s" % t.contents)
|
||||
elif t.token_type == TOKEN_VAR:
|
||||
if inplural:
|
||||
plural.append('%%(%s)s' % t.contents)
|
||||
@ -541,4 +541,3 @@ def parse_accept_lang_header(lang_string):
|
||||
result.append((lang, priority))
|
||||
result.sort(lambda x, y: -cmp(x[1], y[1]))
|
||||
return result
|
||||
|
||||
|
@ -5,7 +5,11 @@ import time
|
||||
from datetime import timedelta, tzinfo
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
DEFAULT_ENCODING = locale.getdefaultlocale()[1] or 'ascii'
|
||||
try:
|
||||
DEFAULT_ENCODING = locale.getdefaultlocale()[1] or 'ascii'
|
||||
except:
|
||||
# Any problems at all determining the locale and we fallback. See #5846.
|
||||
DEFAULT_ENCODING = 'ascii'
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"Fixed offset in minutes east from UTC."
|
||||
|
@ -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.
|
||||
"""
|
||||
|
||||
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.cache import patch_cache_control, add_never_cache_headers
|
||||
from django.middleware.cache import CacheMiddleware
|
||||
@ -26,7 +31,7 @@ def cache_control(**kwargs):
|
||||
patch_cache_control(response, **kwargs)
|
||||
return response
|
||||
|
||||
return _cache_controlled
|
||||
return wraps(viewfunc)(_cache_controlled)
|
||||
|
||||
return _cache_controller
|
||||
|
||||
@ -39,4 +44,4 @@ def never_cache(view_func):
|
||||
response = view_func(request, *args, **kwargs)
|
||||
add_never_cache_headers(response)
|
||||
return response
|
||||
return _wrapped_view_func
|
||||
return wraps(view_func)(_wrapped_view_func)
|
||||
|
@ -2,6 +2,11 @@
|
||||
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.middleware.http import ConditionalGetMiddleware
|
||||
from django.http import HttpResponseNotAllowed
|
||||
@ -24,7 +29,7 @@ def require_http_methods(request_method_list):
|
||||
if request.method not in request_method_list:
|
||||
return HttpResponseNotAllowed(request_method_list)
|
||||
return func(request, *args, **kwargs)
|
||||
return inner
|
||||
return wraps(func)(inner)
|
||||
return decorator
|
||||
|
||||
require_GET = require_http_methods(["GET"])
|
||||
|
@ -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
|
||||
|
||||
def vary_on_headers(*headers):
|
||||
@ -16,7 +21,7 @@ def vary_on_headers(*headers):
|
||||
response = func(*args, **kwargs)
|
||||
patch_vary_headers(response, headers)
|
||||
return response
|
||||
return inner_func
|
||||
return wraps(func)(inner_func)
|
||||
return decorator
|
||||
|
||||
def vary_on_cookie(func):
|
||||
@ -32,4 +37,4 @@ def vary_on_cookie(func):
|
||||
response = func(*args, **kwargs)
|
||||
patch_vary_headers(response, ('Cookie',))
|
||||
return response
|
||||
return inner_func
|
||||
return wraps(func)(inner_func)
|
||||
|
@ -28,7 +28,7 @@ def set_language(request):
|
||||
if hasattr(request, 'session'):
|
||||
request.session['django_language'] = lang_code
|
||||
else:
|
||||
response.set_cookie('django_language', lang_code)
|
||||
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
|
||||
return response
|
||||
|
||||
NullSource = """
|
||||
|
@ -83,12 +83,12 @@ Methods
|
||||
objects in the same way as any other `Django model`_::
|
||||
|
||||
myuser.groups = [group_list]
|
||||
myuser.groups.add(group, group,...)
|
||||
myuser.groups.remove(group, group,...)
|
||||
myuser.groups.add(group, group, ...)
|
||||
myuser.groups.remove(group, group, ...)
|
||||
myuser.groups.clear()
|
||||
myuser.user_permissions = [permission_list]
|
||||
myuser.user_permissions.add(permission, permission, ...)
|
||||
myuser.user_permissions.remove(permission, permission, ...]
|
||||
myuser.user_permissions.remove(permission, permission, ...)
|
||||
myuser.user_permissions.clear()
|
||||
|
||||
In addition to those automatic API methods, ``User`` objects have the following
|
||||
|
@ -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.
|
||||
|
||||
``select_related()`` is documented in the "QuerySet methods that return new
|
||||
QuerySets" section above.
|
||||
``select_related()`` is documented in the `QuerySet methods that return new QuerySets`_ section above.
|
||||
|
||||
Backward
|
||||
~~~~~~~~
|
||||
|
@ -166,7 +166,7 @@ logical to us.
|
||||
We're well aware that there are other awesome Web frameworks out there, and
|
||||
we're not averse to borrowing ideas where appropriate. However, Django was
|
||||
developed precisely because we were unhappy with the status quo, so please be
|
||||
aware that "because <Framework X>" does it is not going to be sufficient reason
|
||||
aware that "because <Framework X> does it" is not going to be sufficient reason
|
||||
to add a given feature to Django.
|
||||
|
||||
Why did you write all of Django from scratch, instead of using other Python libraries?
|
||||
@ -353,7 +353,7 @@ How do I install mod_python on Windows?
|
||||
working`_.
|
||||
|
||||
.. _`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
|
||||
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html
|
||||
|
||||
|
@ -24,11 +24,14 @@ Installation
|
||||
|
||||
To install the flatpages app, follow these steps:
|
||||
|
||||
1. Add ``'django.contrib.flatpages'`` to your INSTALLED_APPS_ setting.
|
||||
2. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
|
||||
1. Install the `sites framework`_ by adding ``'django.contrib.sites'`` to
|
||||
your INSTALLED_APPS_ setting, if it's not already in there.
|
||||
2. Add ``'django.contrib.flatpages'`` to your INSTALLED_APPS_ setting.
|
||||
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
|
||||
to your MIDDLEWARE_CLASSES_ setting.
|
||||
3. Run the command ``manage.py syncdb``.
|
||||
4. Run the command ``manage.py syncdb``.
|
||||
|
||||
.. _sites framework: ../sites/
|
||||
.. _INSTALLED_APPS: ../settings/#installed-apps
|
||||
.. _MIDDLEWARE_CLASSES: ../settings/#middleware-classes
|
||||
|
||||
|
@ -547,7 +547,7 @@ following this algorithm:
|
||||
|
||||
* First, it looks for a ``django_language`` key in the the current user's
|
||||
`session`_.
|
||||
* Failing that, it looks for a cookie called ``django_language``.
|
||||
* Failing that, it looks for a cookie that is named according to your ``LANGUAGE_COOKIE_NAME`` setting (the default name is: ``django_language``).
|
||||
* Failing that, it looks at the ``Accept-Language`` HTTP header. This
|
||||
header is sent by your browser and tells the server which language(s) you
|
||||
prefer, in order by priority. Django tries each language in the header
|
||||
@ -719,7 +719,8 @@ Activate this view by adding the following line to your URLconf::
|
||||
The view expects to be called via the ``POST`` method, with a ``language``
|
||||
parameter set in request. If session support is enabled, the view
|
||||
saves the language choice in the user's session. Otherwise, it saves the
|
||||
language choice in a ``django_language`` cookie.
|
||||
language choice in a cookie that is by default named ``django_language``
|
||||
(the name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting).
|
||||
|
||||
After setting the language choice, Django redirects the user, following this
|
||||
algorithm:
|
||||
|
@ -784,9 +784,17 @@ you can use the name of the model, rather than the model object itself::
|
||||
class Manufacturer(models.Model):
|
||||
# ...
|
||||
|
||||
Note, however, that you can only use strings to refer to models in the same
|
||||
models.py file -- you cannot use a string to reference a model in a different
|
||||
application, or to reference a model that has been imported from elsewhere.
|
||||
Note, however, that this only refers to models in the same models.py file -- you
|
||||
cannot use a string to reference a model defined in another application or
|
||||
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
|
||||
database column name. In the above example, the database table for the ``Car``
|
||||
|
@ -226,7 +226,7 @@ For example::
|
||||
|
||||
# Create a form instance with POST data.
|
||||
>>> a = Author()
|
||||
>>> f = AuthorForm(a, request.POST)
|
||||
>>> f = AuthorForm(request.POST, instance=a)
|
||||
|
||||
# Create and save the new author instance. There's no need to do anything else.
|
||||
>>> new_author = f.save()
|
||||
@ -238,34 +238,34 @@ In some cases, you may not want all the model fields to appear on the generated
|
||||
form. There are three ways of telling ``ModelForm`` to use only a subset of the
|
||||
model fields:
|
||||
|
||||
1. Set ``editable=False`` on the model field. As a result, *any* form
|
||||
created from the model via ``ModelForm`` will not include that
|
||||
field.
|
||||
1. Set ``editable=False`` on the model field. As a result, *any* form
|
||||
created from the model via ``ModelForm`` will not include that
|
||||
field.
|
||||
|
||||
2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` class.
|
||||
This attribute, if given, should be a list of field names to include in
|
||||
the form.
|
||||
2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta``
|
||||
class. This attribute, if given, should be a list of field names
|
||||
to include in the form.
|
||||
|
||||
3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` class.
|
||||
This attribute, if given, should be a list of field names to exclude
|
||||
the form.
|
||||
3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta``
|
||||
class. This attribute, if given, should be a list of field names
|
||||
to exclude from the form.
|
||||
|
||||
For example, if you want a form for the ``Author`` model (defined above)
|
||||
that includes only the ``name`` and ``title`` fields, you would specify
|
||||
``fields`` or ``exclude`` like this::
|
||||
For example, if you want a form for the ``Author`` model (defined
|
||||
above) that includes only the ``name`` and ``title`` fields, you would
|
||||
specify ``fields`` or ``exclude`` like this::
|
||||
|
||||
class PartialAuthorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Author
|
||||
fields = ('name', 'title')
|
||||
class PartialAuthorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Author
|
||||
fields = ('name', 'title')
|
||||
|
||||
class PartialAuthorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Author
|
||||
exclude = ('birth_date',)
|
||||
class PartialAuthorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Author
|
||||
exclude = ('birth_date',)
|
||||
|
||||
Since the Author model has only 3 fields, 'name', 'title', and
|
||||
'birth_date', the forms above will contain exactly the same fields.
|
||||
Since the Author model has only 3 fields, 'name', 'title', and
|
||||
'birth_date', the forms above will contain exactly the same fields.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -323,17 +323,18 @@ parameter when declaring the form field::
|
||||
|
||||
Form inheritance
|
||||
----------------
|
||||
As with the basic forms, you can extend and reuse ``ModelForms`` by inheriting
|
||||
them. Normally, this will be useful if you need to declare some extra fields
|
||||
or extra methods on a parent class for use in a number of forms derived from
|
||||
models. For example, using the previous ``ArticleForm`` class::
|
||||
|
||||
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
|
||||
is some extra validation and cleaning for the ``pub_date`` field.
|
||||
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::
|
||||
@ -342,17 +343,18 @@ the ``Meta.fields`` or ``Meta.excludes`` lists::
|
||||
... class Meta(ArticleForm.Meta):
|
||||
... exclude = ['body']
|
||||
|
||||
This adds in the extra method from the ``EnhancedArticleForm`` and modifies
|
||||
This adds the extra method from the ``EnhancedArticleForm`` and modifies
|
||||
the original ``ArticleForm.Meta`` to remove one field.
|
||||
|
||||
There are a couple of things to note, however. Most of these won't normally be
|
||||
of concern unless you are trying to do something tricky with subclassing.
|
||||
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
|
||||
used. This means the child's ``Meta``, if it exists, otherwise the
|
||||
``Meta`` of the first parent, etc.
|
||||
|
||||
* For technical reasons, you cannot have a subclass that is inherited from
|
||||
both a ``ModelForm`` and a ``Form`` simultaneously.
|
||||
* 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.
|
||||
|
@ -246,6 +246,10 @@ object::
|
||||
>>> f.cleaned_data
|
||||
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
|
||||
|
||||
.. note::
|
||||
**New in Django development version** The ``cleaned_data`` attribute was
|
||||
called ``clean_data`` in earlier releases.
|
||||
|
||||
Note that any text-based field -- such as ``CharField`` or ``EmailField`` --
|
||||
always cleans the input into a Unicode string. We'll cover the encoding
|
||||
implications later in this document.
|
||||
@ -1563,7 +1567,7 @@ The three types of cleaning methods are:
|
||||
|
||||
Note that any errors raised by your ``Form.clean()`` override will not
|
||||
be associated with any field in particular. They go into a special
|
||||
"field" (called ``__all__``, which you can access via the
|
||||
"field" (called ``__all__``), which you can access via the
|
||||
``non_field_errors()`` method if you need to.
|
||||
|
||||
These methods are run in the order given above, one field at a time. That is,
|
||||
|
@ -576,7 +576,7 @@ Three things to note about 404 views:
|
||||
in the 404.
|
||||
|
||||
* 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``).
|
||||
|
||||
* If ``DEBUG`` is set to ``True`` (in your settings module), then your 404
|
||||
|
@ -88,7 +88,7 @@ something like::
|
||||
|
||||
for deserialized_object in serializers.deserialize("xml", data):
|
||||
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
|
||||
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.
|
||||
|
@ -579,6 +579,16 @@ in standard language format. For example, U.S. English is ``"en-us"``. See the
|
||||
|
||||
.. _internationalization docs: ../i18n/
|
||||
|
||||
LANGUAGE_COOKIE_NAME
|
||||
--------------------
|
||||
|
||||
Default: ``'django_language'``
|
||||
|
||||
The name of the cookie to use for the language cookie. This can be whatever
|
||||
you want (but should be different from SESSION_COOKIE_NAME). See the
|
||||
`internationalization docs`_ for details.
|
||||
|
||||
|
||||
LANGUAGES
|
||||
---------
|
||||
|
||||
@ -822,8 +832,8 @@ SESSION_COOKIE_NAME
|
||||
|
||||
Default: ``'sessionid'``
|
||||
|
||||
The name of the cookie to use for sessions. This can be whatever you want.
|
||||
See the `session docs`_.
|
||||
The name of the cookie to use for sessions. This can be whatever you want (but
|
||||
should be different from ``LANGUAGE_COOKIE_NAME``). See the `session docs`_.
|
||||
|
||||
SESSION_COOKIE_PATH
|
||||
-------------------
|
||||
|
@ -30,9 +30,9 @@ Optional arguments
|
||||
``context_instance``
|
||||
The context instance to render the template with. By default, the template
|
||||
will be rendered with a ``Context`` instance (filled with values from
|
||||
``dictionary``). If you need to use `context processors`_, you will want to
|
||||
render the template with a ``RequestContext`` instance instead. Your code
|
||||
might look something like this::
|
||||
``dictionary``). If you need to use `context processors`_, render the
|
||||
template with a ``RequestContext`` instance instead. Your code might look
|
||||
something like this::
|
||||
|
||||
return render_to_response('my_template.html',
|
||||
my_data_dictionary,
|
||||
|
@ -1406,6 +1406,8 @@ Joins a list with a string, like Python's ``str.join(list)``.
|
||||
last
|
||||
~~~~
|
||||
|
||||
**New in Django development version.**
|
||||
|
||||
Returns the last item in a list.
|
||||
|
||||
length
|
||||
|
@ -395,6 +395,8 @@ See the `internationalization docs`_ for more.
|
||||
django.core.context_processors.media
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
||||
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
|
||||
value of the `MEDIA_URL setting`_.
|
||||
@ -627,9 +629,10 @@ the given Python module name, not the name of the app.
|
||||
Once you've created that Python module, you'll just have to write a bit of
|
||||
Python code, depending on whether you're writing filters or tags.
|
||||
|
||||
To be a valid tag library, the module contain a module-level variable named
|
||||
``register`` that is a ``template.Library`` instance, in which all the tags and
|
||||
filters are registered. So, near the top of your module, put the following::
|
||||
To be a valid tag library, the module must contain a module-level variable
|
||||
named ``register`` that is a ``template.Library`` instance, in which all the
|
||||
tags and filters are registered. So, near the top of your module, put the
|
||||
following::
|
||||
|
||||
from django import template
|
||||
|
||||
@ -981,7 +984,7 @@ Notes:
|
||||
exception. It should fail silently, just as template filters should.
|
||||
|
||||
Ultimately, this decoupling of compilation and rendering results in an
|
||||
efficient template system, because a template can render multiple context
|
||||
efficient template system, because a template can render multiple contexts
|
||||
without having to be parsed multiple times.
|
||||
|
||||
Auto-escaping considerations
|
||||
@ -1014,7 +1017,7 @@ This is not a very common situation, but it's useful if you're rendering a
|
||||
template yourself. For example::
|
||||
|
||||
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))
|
||||
|
||||
If we had neglected to pass in the current ``context.autoescape`` value to our
|
||||
|
@ -191,12 +191,12 @@ The remaining arguments should be tuples in this format::
|
||||
`Passing extra options to view functions`_ below.)
|
||||
|
||||
.. note::
|
||||
Since `patterns()` is a function call, it accepts a maximum of 255
|
||||
Because `patterns()` is a function call, it accepts a maximum of 255
|
||||
arguments (URL patterns, in this case). This is a limit for all Python
|
||||
function calls. This will rarely be problem in practice, since you'll
|
||||
function calls. This is rarely a problem in practice, because you'll
|
||||
typically structure your URL patterns modularly by using `include()`
|
||||
sections. However, on the off-chance you do hit the 255-argument limit,
|
||||
realise that `patterns()` returns a Python list, so you can split up the
|
||||
realize that `patterns()` returns a Python list, so you can split up the
|
||||
construction of the list.
|
||||
|
||||
::
|
||||
@ -209,8 +209,8 @@ The remaining arguments should be tuples in this format::
|
||||
)
|
||||
|
||||
Python lists have unlimited size, so there's no limit to how many URL
|
||||
patterns you can construct; merely that you may only create 254 at a time
|
||||
(the 255-th argument is the initial prefix argument).
|
||||
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
|
||||
---
|
||||
|
@ -61,13 +61,13 @@ _django_completion()
|
||||
||
|
||||
# python manage.py, /some/path/python manage.py (if manage.py exists)
|
||||
( ${COMP_CWORD} -eq 2 &&
|
||||
( $( basename ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
|
||||
( $( basename ${COMP_WORDS[1]} ) == manage.py) &&
|
||||
( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
|
||||
( $( basename -- ${COMP_WORDS[1]} ) == manage.py) &&
|
||||
( -r ${COMP_WORDS[1]} ) )
|
||||
||
|
||||
( ${COMP_CWORD} -eq 2 &&
|
||||
( $( basename ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
|
||||
( $( basename ${COMP_WORDS[1]} ) == django-admin.py) &&
|
||||
( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
|
||||
( $( basename -- ${COMP_WORDS[1]} ) == django-admin.py) &&
|
||||
( -r ${COMP_WORDS[1]} ) ) ]] ; then
|
||||
|
||||
case ${cur} in
|
||||
@ -149,7 +149,7 @@ unset pythons
|
||||
if command -v whereis &>/dev/null; then
|
||||
python_interpreters=$(whereis python | cut -d " " -f 2-)
|
||||
for python in $python_interpreters; do
|
||||
pythons="${pythons} $(basename $python)"
|
||||
pythons="${pythons} $(basename -- $python)"
|
||||
done
|
||||
pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ")
|
||||
else
|
||||
|
11
setup.py
11
setup.py
@ -27,19 +27,16 @@ for scheme in INSTALL_SCHEMES.values():
|
||||
# an easy way to do this.
|
||||
packages, data_files = [], []
|
||||
root_dir = os.path.dirname(__file__)
|
||||
django_dir = os.path.join(root_dir, 'django')
|
||||
pieces = fullsplit(root_dir)
|
||||
if pieces[-1] == '':
|
||||
len_root_dir = len(pieces) - 1
|
||||
else:
|
||||
len_root_dir = len(pieces)
|
||||
if root_dir != '':
|
||||
os.chdir(root_dir)
|
||||
django_dir = 'django'
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(django_dir):
|
||||
# Ignore dirnames that start with '.'
|
||||
for i, dirname in enumerate(dirnames):
|
||||
if dirname.startswith('.'): del dirnames[i]
|
||||
if '__init__.py' in filenames:
|
||||
packages.append('.'.join(fullsplit(dirpath)[len_root_dir:]))
|
||||
packages.append('.'.join(fullsplit(dirpath)))
|
||||
elif filenames:
|
||||
data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
|
||||
|
||||
|
@ -5,6 +5,11 @@
|
||||
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
|
||||
|
||||
class Article(models.Model):
|
||||
@ -389,4 +394,10 @@ year, including Jan. 1 and Dec. 31.
|
||||
>>> a.save()
|
||||
>>> Article.objects.get(pk=a.id).headline
|
||||
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
|
||||
"""
|
||||
|
@ -1,18 +1,22 @@
|
||||
"""
|
||||
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 *
|
||||
|
||||
class Parent(Model):
|
||||
name = CharField(max_length=100, core=True)
|
||||
|
||||
# Use a simple string for forward declarations.
|
||||
bestchild = ForeignKey("Child", null=True, related_name="favoured_by")
|
||||
|
||||
class Child(Model):
|
||||
name = CharField(max_length=100)
|
||||
parent = ForeignKey(Parent)
|
||||
|
||||
# You can also explicitally specify the related app.
|
||||
parent = ForeignKey("mutually_referential.Parent")
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Create a Parent
|
||||
|
@ -77,6 +77,8 @@ MultiValueDictKeyError: "Key 'lastname' not found in <MultiValueDict: {'position
|
||||
'not one'
|
||||
>>> d.keys() == d.copy().keys()
|
||||
True
|
||||
>>> d2 = d.copy()
|
||||
>>> d2['four'] = 'four'
|
||||
>>> print repr(d)
|
||||
{'one': 'not one', 'two': 'two', 'three': 'three'}
|
||||
>>> d.pop('one', 'missing')
|
||||
@ -99,6 +101,12 @@ Init from sequence of tuples
|
||||
>>> print repr(d)
|
||||
{1: 'one', 0: 'zero', 2: 'two'}
|
||||
|
||||
>>> d.clear()
|
||||
>>> d
|
||||
{}
|
||||
>>> d.keyOrder
|
||||
[]
|
||||
|
||||
### DotExpandedDict ############################################################
|
||||
|
||||
>>> d = DotExpandedDict({'person.1.firstname': ['Simon'], 'person.1.lastname': ['Willison'], 'person.2.firstname': ['Adrian'], 'person.2.lastname': ['Holovaty']})
|
||||
|
@ -56,4 +56,30 @@ datetime.date(1938, 6, 4)
|
||||
datetime.time(5, 30)
|
||||
>>> d3.consumed_at
|
||||
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)
|
||||
[]
|
||||
|
||||
"""}
|
||||
|
0
tests/regressiontests/decorators/__init__.py
Normal file
0
tests/regressiontests/decorators/__init__.py
Normal file
2
tests/regressiontests/decorators/models.py
Normal file
2
tests/regressiontests/decorators/models.py
Normal file
@ -0,0 +1,2 @@
|
||||
# A models.py so that tests run.
|
||||
|
56
tests/regressiontests/decorators/tests.py
Normal file
56
tests/regressiontests/decorators/tests.py
Normal 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__')
|
@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"pk": "1",
|
||||
"model": "fixtures_regress.absolute",
|
||||
"fields": {
|
||||
"name": "Load Absolute Path Test"
|
||||
}
|
||||
}
|
||||
]
|
@ -1,6 +1,7 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
import os
|
||||
|
||||
class Animal(models.Model):
|
||||
name = models.CharField(max_length=150)
|
||||
@ -28,6 +29,16 @@ class Stuff(models.Model):
|
||||
name = None
|
||||
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':"""
|
||||
>>> from django.core import management
|
||||
|
||||
@ -49,4 +60,15 @@ __test__ = {'API_TESTS':"""
|
||||
>>> Stuff.objects.all()
|
||||
[<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
|
||||
|
||||
"""}
|
||||
|
3
tests/regressiontests/requests/__init__.py
Normal file
3
tests/regressiontests/requests/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
"""
|
||||
Tests for Django's various Request objects.
|
||||
"""
|
1
tests/regressiontests/requests/models.py
Normal file
1
tests/regressiontests/requests/models.py
Normal file
@ -0,0 +1 @@
|
||||
# Need a models module for the test runner.
|
34
tests/regressiontests/requests/tests.py
Normal file
34
tests/regressiontests/requests/tests.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""
|
||||
>>> from django.http import HttpRequest
|
||||
>>> print repr(HttpRequest())
|
||||
<HttpRequest
|
||||
GET:{},
|
||||
POST:{},
|
||||
COOKIES:{},
|
||||
META:{}>
|
||||
|
||||
>>> from django.core.handlers.wsgi import WSGIRequest
|
||||
>>> print repr(WSGIRequest({'PATH_INFO': 'bogus', 'REQUEST_METHOD': 'bogus'}))
|
||||
<WSGIRequest
|
||||
GET:<QueryDict: {}>,
|
||||
POST:<QueryDict: {}>,
|
||||
COOKIES:{},
|
||||
META:{...}>
|
||||
|
||||
>>> from django.core.handlers.modpython import ModPythonRequest
|
||||
>>> class FakeModPythonRequest(ModPythonRequest):
|
||||
... def __init__(self, *args, **kwargs):
|
||||
... super(FakeModPythonRequest, self).__init__(*args, **kwargs)
|
||||
... self._get = self._post = self._meta = self._cookies = {}
|
||||
>>> class Dummy: pass
|
||||
...
|
||||
>>> req = Dummy()
|
||||
>>> req.uri = 'bogus'
|
||||
>>> print repr(FakeModPythonRequest(req))
|
||||
<ModPythonRequest
|
||||
path:bogus,
|
||||
GET:{},
|
||||
POST:{},
|
||||
COOKIES:{},
|
||||
META:{}>
|
||||
"""
|
@ -39,6 +39,7 @@ class Base(models.Model):
|
||||
class Article(models.Model):
|
||||
name = models.CharField(max_length=50)
|
||||
text = models.TextField()
|
||||
submitted_from = models.IPAddressField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return "Article %s" % self.name
|
||||
@ -98,4 +99,11 @@ __test__ = {'API_TESTS': ur"""
|
||||
|
||||
>>> Article.objects.get(text__contains='quick brown fox')
|
||||
<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>]
|
||||
|
||||
"""}
|
||||
|
Loading…
x
Reference in New Issue
Block a user