1
0
mirror of https://github.com/django/django.git synced 2025-10-24 22:26:08 +00:00

[soc2009/model-validation] Merged to trunk at r11603

SECURITY ALERT: Corrected regular expressions for URL and email fields.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@11617 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Honza Král
2009-10-12 10:16:17 +00:00
parent 83a3588ff7
commit dfe495fbe8
42 changed files with 551 additions and 369 deletions

View File

@@ -202,6 +202,7 @@ answer newbie questions, and generally made Django that much better:
Kieran Holland <http://www.kieranholland.com>
Sung-Jin Hong <serialx.net@gmail.com>
Leo "hylje" Honkanen <sealage@gmail.com>
Tareque Hossain <http://www.codexn.com>
Richard House <Richard.House@i-logue.com>
Robert Rock Howard <http://djangomojo.com/>
John Huddleston <huddlej@wwu.edu>
@@ -241,6 +242,7 @@ answer newbie questions, and generally made Django that much better:
Igor Kolar <ike@email.si>
Gasper Koren
Martin Kosír <martin@martinkosir.net>
Arthur Koziel <http://arthurkoziel.com>
Honza Kral <honza.kral@gmail.com>
Meir Kriheli <http://mksoft.co.il/>
Bruce Kroeze <http://coderseye.com/>
@@ -402,7 +404,7 @@ answer newbie questions, and generally made Django that much better:
Vasiliy Stavenko <stavenko@gmail.com>
Thomas Steinacher <http://www.eggdrop.ch/>
Johan C. Stöver <johan@nilling.nl>
nowell strite
Nowell Strite <http://nowell.strite.org/>
Thomas Stromberg <tstromberg@google.com>
Pascal Varet
SuperJared

View File

@@ -391,7 +391,7 @@ msgstr "הוספת %s"
#: contrib/admin/options.py:1003
#, python-format
msgid "%(name)s object with primary key %(key)r does not exist."
msgstr "הפריט %(name)s עם המקש %(key)r אינו קיים."
msgstr "הפריט %(name)s עם המפתח הראשי %(key)r אינו קיים."
#: contrib/admin/options.py:860
#, python-format

View File

@@ -1,11 +1,12 @@
try:
from functools import update_wrapper
from functools import update_wrapper, wraps
except ImportError:
from django.utils.functional import update_wrapper # Python 2.3, 2.4 fallback.
from django.utils.functional import update_wrapper, wraps # 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
from django.utils.decorators import auto_adapt_to_methods
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
@@ -13,9 +14,19 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
redirecting to the log-in page if necessary. The test should be a callable
that takes the user object and returns True if the user passes.
"""
def decorate(view_func):
return _CheckLogin(view_func, test_func, login_url, redirect_field_name)
return decorate
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
def decorator(view_func):
def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = urlquote(request.get_full_path())
tup = login_url, redirect_field_name, path
return HttpResponseRedirect('%s?%s=%s' % tup)
return wraps(view_func)(_wrapped_view)
return auto_adapt_to_methods(decorator)
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
@@ -36,46 +47,3 @@ def permission_required(perm, login_url=None):
enabled, redirecting to the log-in page if necessary.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
class _CheckLogin(object):
"""
Class that checks that the user passes the given test, redirecting to
the log-in page if necessary. If the test is passed, the view function
is invoked. The test should be a callable that takes the user object
and returns True if the user passes.
We use a class here so that we can define __get__. This way, when a
_CheckLogin object is used as a method decorator, the view function
is properly bound to its instance.
"""
def __init__(self, view_func, test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
self.view_func = view_func
self.test_func = test_func
self.login_url = login_url
self.redirect_field_name = redirect_field_name
# We can't blindly apply update_wrapper because it udpates __dict__ and
# if the view function is already a _CheckLogin object then
# self.test_func and friends will get stomped. However, we also can't
# *not* update the wrapper's dict because then view function attributes
# don't get updated into the wrapper. So we need to split the
# difference: don't let update_wrapper update __dict__, but then update
# the (parts of) __dict__ that we care about ourselves.
update_wrapper(self, view_func, updated=())
for k in view_func.__dict__:
if k not in self.__dict__:
self.__dict__[k] = view_func.__dict__[k]
def __get__(self, obj, cls=None):
view_func = self.view_func.__get__(obj, cls)
return _CheckLogin(view_func, self.test_func, self.login_url, self.redirect_field_name)
def __call__(self, request, *args, **kwargs):
if self.test_func(request.user):
return self.view_func(request, *args, **kwargs)
path = urlquote(request.get_full_path())
tup = self.login_url, self.redirect_field_name, path
return HttpResponseRedirect('%s?%s=%s' % tup)

View File

@@ -20,6 +20,7 @@ class CommentsAdmin(admin.ModelAdmin):
list_filter = ('submit_date', 'site', 'is_public', 'is_removed')
date_hierarchy = 'submit_date'
ordering = ('-submit_date',)
raw_id_fields = ('user',)
search_fields = ('comment', 'user__username', 'user_name', 'user_email', 'user_url', 'ip_address')
# Only register the default admin if the model is the built-in comment model

View File

@@ -32,11 +32,20 @@ elif SpatialBackend.oracle:
def convert_extent(clob):
if clob:
# Oracle returns a polygon for the extent, we construct
# the 4-tuple from the coordinates in the polygon.
poly = SpatialBackend.Geometry(clob.read())
shell = poly.shell
ll, ur = shell[0], shell[2]
# Generally, Oracle returns a polygon for the extent -- however,
# it can return a single point if there's only one Point in the
# table.
ext_geom = SpatialBackend.Geometry(clob.read())
gtype = str(ext_geom.geom_type)
if gtype == 'Polygon':
# Construct the 4-tuple from the coordinates in the polygon.
shell = ext_geom.shell
ll, ur = shell[0][:2], shell[2][:2]
elif gtype == 'Point':
ll = ext_geom.coords[:2]
ur = ll
else:
raise Exception('Unexpected geometry type returned for extent: %s' % gtype)
xmin, ymin = ll
xmax, ymax = ur
return (xmin, ymin, xmax, ymax)

View File

@@ -1,4 +1,5 @@
import cStringIO, zipfile
from django.conf import settings
from django.http import HttpResponse
from django.template import loader
@@ -6,7 +7,7 @@ def compress_kml(kml):
"Returns compressed KMZ from the given KML string."
kmz = cStringIO.StringIO()
zf = zipfile.ZipFile(kmz, 'a', zipfile.ZIP_DEFLATED)
zf.writestr('doc.kml', kml)
zf.writestr('doc.kml', kml.encode(settings.DEFAULT_CHARSET))
zf.close()
kmz.seek(0)
return kmz.read()

View File

@@ -1,6 +1,7 @@
import os, unittest
from django.contrib.gis.db.backend import SpatialBackend
from django.contrib.gis.tests.utils import no_mysql, no_oracle, no_postgis
from django.contrib.gis.tests.utils import no_mysql, no_oracle, no_postgis, no_spatialite
from django.contrib.gis.shortcuts import render_to_kmz
from models import City
class GeoRegressionTests(unittest.TestCase):
@@ -16,3 +17,19 @@ class GeoRegressionTests(unittest.TestCase):
self.assertEqual(pnt, City.objects.get(name='Pueblo').point)
City.objects.filter(name='Pueblo').update(point=bak)
self.assertEqual(bak, City.objects.get(name='Pueblo').point)
def test02_kmz(self):
"Testing `render_to_kmz` with non-ASCII data, see #11624."
name = '\xc3\x85land Islands'.decode('iso-8859-1')
places = [{'name' : name,
'description' : name,
'kml' : '<Point><coordinates>5.0,23.0</coordinates></Point>'
}]
kmz = render_to_kmz('gis/kml/placemarks.kml', {'places' : places})
@no_spatialite
def test03_extent(self):
"Testing `extent` on a table with a single point, see #11827."
pnt = City.objects.get(name='Pueblo').point
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
self.assertEqual(ref_ext, City.objects.filter(name='Pueblo').extent())

View File

@@ -28,7 +28,7 @@ class FRPhoneNumberField(Field):
'0X XX XX XX XX'.
"""
default_error_messages = {
'invalid': u'Phone numbers must be in 0X XX XX XX XX format.',
'invalid': _('Phone numbers must be in 0X XX XX XX XX format.'),
}
def clean(self, value):

View File

@@ -134,8 +134,8 @@ class ModPythonRequest(http.HttpRequest):
if not hasattr(self, '_meta'):
self._meta = {
'AUTH_TYPE': self._req.ap_auth_type,
'CONTENT_LENGTH': self._req.clength, # This may be wrong
'CONTENT_TYPE': self._req.content_type, # This may be wrong
'CONTENT_LENGTH': self._req.headers_in.get('content-length', 0),
'CONTENT_TYPE': self._req.headers_in.get('content-type'),
'GATEWAY_INTERFACE': 'CGI/1.1',
'PATH_INFO': self.path_info,
'PATH_TRANSLATED': None, # Not supported

View File

@@ -261,6 +261,82 @@ class ManagementUtility(object):
sys.exit(1)
return klass
def autocomplete(self):
"""
Output completion suggestions for BASH.
The output of this function is passed to BASH's `COMREPLY` variable and
treated as completion suggestions. `COMREPLY` expects a space
separated string as the result.
The `COMP_WORDS` and `COMP_CWORD` BASH environment variables are used
to get information about the cli input. Please refer to the BASH
man-page for more information about this variables.
Subcommand options are saved as pairs. A pair consists of
the long option string (e.g. '--exclude') and a boolean
value indicating if the option requires arguments. When printing to
stdout, a equal sign is appended to options which require arguments.
Note: If debugging this function, it is recommended to write the debug
output in a separate file. Otherwise the debug output will be treated
and formatted as potential completion suggestions.
"""
# Don't complete if user hasn't sourced bash_completion file.
if not os.environ.has_key('DJANGO_AUTO_COMPLETE'):
return
cwords = os.environ['COMP_WORDS'].split()[1:]
cword = int(os.environ['COMP_CWORD'])
try:
curr = cwords[cword-1]
except IndexError:
curr = ''
subcommands = get_commands().keys() + ['help']
options = [('--help', None)]
# subcommand
if cword == 1:
print ' '.join(filter(lambda x: x.startswith(curr), subcommands))
# subcommand options
# special case: the 'help' subcommand has no options
elif cwords[0] in subcommands and cwords[0] != 'help':
subcommand_cls = self.fetch_command(cwords[0])
# special case: 'runfcgi' stores additional options as
# 'key=value' pairs
if cwords[0] == 'runfcgi':
from django.core.servers.fastcgi import FASTCGI_OPTIONS
options += [(k, 1) for k in FASTCGI_OPTIONS]
# special case: add the names of installed apps to options
elif cwords[0] in ('dumpdata', 'reset', 'sql', 'sqlall',
'sqlclear', 'sqlcustom', 'sqlindexes',
'sqlreset', 'sqlsequencereset', 'test'):
try:
from django.conf import settings
# Get the last part of the dotted path as the app name.
options += [(a.split('.')[-1], 0) for a in settings.INSTALLED_APPS]
except ImportError:
# Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
# user will find out once they execute the command.
pass
options += [(s_opt.get_opt_string(), s_opt.nargs) for s_opt in
subcommand_cls.option_list]
# filter out previously specified options from available options
prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
options = filter(lambda (x, v): x not in prev_opts, options)
# filter options by current input
options = [(k, v) for k, v in options if k.startswith(curr)]
for option in options:
opt_label = option[0]
# append '=' to options which require args
if option[1]:
opt_label += '='
print opt_label
sys.exit(1)
def execute(self):
"""
Given the command-line arguments, this figures out which subcommand is
@@ -272,6 +348,7 @@ class ManagementUtility(object):
parser = LaxOptionParser(usage="%prog subcommand [options] [args]",
version=get_version(),
option_list=BaseCommand.option_list)
self.autocomplete()
try:
options, args = parser.parse_args(self.argv)
handle_default_options(options)

View File

@@ -40,7 +40,7 @@ class RegexValidator(object):
class URLValidator(RegexValidator):
regex = re.compile(
r'^https?://' # http:// or https://
r'(?:(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}|' #domain...
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
r'localhost|' #localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
@@ -81,7 +81,7 @@ def validate_integer(value):
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain
validate_email = RegexValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
slug_re = re.compile(r'^[-\w]+$')

View File

@@ -66,7 +66,7 @@ class SQLEvaluator(object):
else:
sql, params = '%s', (child,)
if hasattr(child, 'children') > 1:
if len(getattr(child, 'children', [])) > 1:
format = '(%s)'
else:
format = '%s'

View File

@@ -32,7 +32,6 @@ from util import ErrorList
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, \
FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, \
DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
__all__ = (
'Field', 'CharField', 'IntegerField',

View File

@@ -2,39 +2,64 @@
import types
try:
from functools import wraps
from functools import wraps, update_wrapper
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.utils.functional import wraps, update_wrapper # Python 2.3, 2.4 fallback.
class MethodDecoratorAdaptor(object):
"""
Generic way of creating decorators that adapt to being
used on methods
"""
def __init__(self, decorator, func):
update_wrapper(self, func)
# NB: update the __dict__ first, *then* set
# our own .func and .decorator, in case 'func' is actually
# another MethodDecoratorAdaptor object, which has its
# 'func' and 'decorator' attributes in its own __dict__
self.decorator = decorator
self.func = func
def __call__(self, *args, **kwargs):
return self.decorator(self.func)(*args, **kwargs)
def __get__(self, instance, owner):
return self.decorator(self.func.__get__(instance, owner))
def auto_adapt_to_methods(decorator):
"""
Takes a decorator function, and returns a decorator-like callable that can
be used on methods as well as functions.
"""
def adapt(func):
return MethodDecoratorAdaptor(decorator, func)
return wraps(decorator)(adapt)
def decorator_from_middleware_with_args(middleware_class):
"""
Like decorator_from_middleware, but returns a function
that accepts the arguments to be passed to the middleware_class.
Use like::
cache_page = decorator_from_middleware_with_args(CacheMiddleware)
# ...
@cache_page(3600)
def my_view(request):
# ...
"""
return make_middleware_decorator(middleware_class)
def decorator_from_middleware(middleware_class):
"""
Given a middleware class (not an instance), returns a view decorator. This
lets you use middleware functionality on a per-view basis.
lets you use middleware functionality on a per-view basis. The middleware
is created with no params passed.
"""
def _decorator_from_middleware(*args, **kwargs):
# For historical reasons, these "decorators" are also called as
# dec(func, *args) instead of dec(*args)(func). We handle both forms
# for backwards compatibility.
has_func = True
try:
view_func = kwargs.pop('view_func')
except KeyError:
if len(args):
view_func, args = args[0], args[1:]
else:
has_func = False
if not (has_func and isinstance(view_func, types.FunctionType)):
# We are being called as a decorator.
if has_func:
args = (view_func,) + args
middleware = middleware_class(*args, **kwargs)
def decorator_func(fn):
return _decorator_from_middleware(fn, *args, **kwargs)
return decorator_func
middleware = middleware_class(*args, **kwargs)
return make_middleware_decorator(middleware_class)()
def make_middleware_decorator(middleware_class):
def _make_decorator(*m_args, **m_kwargs):
middleware = middleware_class(*m_args, **m_kwargs)
def _decorator(view_func):
def _wrapped_view(request, *args, **kwargs):
if hasattr(middleware, 'process_request'):
result = middleware.process_request(request)
@@ -58,4 +83,5 @@ def decorator_from_middleware(middleware_class):
return result
return response
return wraps(view_func)(_wrapped_view)
return _decorator_from_middleware
return auto_adapt_to_methods(_decorator)
return _make_decorator

View File

@@ -16,11 +16,37 @@ try:
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.utils.decorators import decorator_from_middleware
from django.utils.decorators import decorator_from_middleware_with_args, auto_adapt_to_methods
from django.utils.cache import patch_cache_control, add_never_cache_headers
from django.middleware.cache import CacheMiddleware
cache_page = decorator_from_middleware(CacheMiddleware)
def cache_page(*args, **kwargs):
# We need backwards compatibility with code which spells it this way:
# def my_view(): pass
# my_view = cache_page(my_view, 123)
# and this way:
# my_view = cache_page(123)(my_view)
# and this:
# my_view = cache_page(my_view, 123, key_prefix="foo")
# and this:
# my_view = cache_page(123, key_prefix="foo")(my_view)
# and possibly this way (?):
# my_view = cache_page(123, my_view)
# We also add some asserts to give better error messages in case people are
# using other ways to call cache_page that no longer work.
key_prefix = kwargs.pop('key_prefix', None)
assert not kwargs, "The only keyword argument accepted is key_prefix"
if len(args) > 1:
assert len(args) == 2, "cache_page accepts at most 2 arguments"
if callable(args[0]):
return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[1], key_prefix=key_prefix)(args[0])
elif callable(args[1]):
return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[0], key_prefix=key_prefix)(args[1])
else:
assert False, "cache_page must be passed either a single argument (timeout) or a view function and a timeout"
else:
return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[0], key_prefix=key_prefix)
def cache_control(**kwargs):
@@ -33,7 +59,7 @@ def cache_control(**kwargs):
return wraps(viewfunc)(_cache_controlled)
return _cache_controller
return auto_adapt_to_methods(_cache_controller)
def never_cache(view_func):
"""
@@ -45,3 +71,4 @@ def never_cache(view_func):
add_never_cache_headers(response)
return response
return wraps(view_func)(_wrapped_view_func)
never_cache = auto_adapt_to_methods(never_cache)

View File

@@ -126,7 +126,7 @@ Here's the default ``static/directory_index.html`` template:
listings. The template that was loaded had to be called
``static/directory_listing`` (with no ``.html`` extension). For backwards
compatibility with earlier versions, Django will still load templates with
the older (no extension) name, but it will prefer a the
the older (no extension) name, but it will prefer the
``directory_index.html`` version.
Limiting use to DEBUG=True

View File

@@ -23,3 +23,4 @@ the hood".
committers
release-process
deprecation
svn

View File

@@ -114,14 +114,9 @@ not; in either case there comes a time when the branch is no longer
being actively worked on by any developer. At this point the branch is
considered closed.
Unfortunately, Subversion has no standard way of indicating
this. Generally, you can recognize a dead branch by viewing it through
the web interface, which lists the date of the most recent change to
the branch. Branches which have gone more than a month or two with no
activity can usually be assumed to be closed. In the future, the
layout of branches in the repository may be rearranged to make it
easier to tell which branches are still active (e.g., by moving closed
or abandoned branches into the ``django/branches/attic`` directory).
Unfortunately, Subversion has no standard way of indicating this. As a
workaround, branches of Django which are closed and no longer
maintained are moved into the directory ``django/branches/attic``.
For reference, the following are branches whose code eventually became
part of Django itself, and so are no longer separately maintained:
@@ -184,6 +179,9 @@ were never finished:
* ``sqlalchemy``
All of the above-mentioned branches now reside in
``django/branches/attic``.
Support and bugfix branches
---------------------------
@@ -201,7 +199,7 @@ will be created there approximately one month after each new Django
release. For example, shortly after the release of Django 1.0, the
branch ``django/branches/releases/1.0.X`` was created to receive bug
fixes, and shortly after the release of Django 1.1 the branch
``django/branches/releases/1.1.X`` will be created.
``django/branches/releases/1.1.X`` was created.
Prior to the Django 1.0 release, these branches were maintaind within
the top-level ``django/branches`` directory, and so the following

View File

@@ -643,8 +643,7 @@ Save these changes and start a new Python interactive shell by running
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]
# Get the poll whose year is 2007. Of course, if you're going through this
# tutorial in another year, change as appropriate.
# Get the poll whose year is 2007.
>>> Poll.objects.get(pub_date__year=2007)
<Poll: What's up?>

View File

@@ -25,21 +25,26 @@ Django's admin interface.
Overview
========
There are five steps in activating the Django admin site:
There are six steps in activating the Django admin site:
1. Add ``django.contrib.admin`` to your ``INSTALLED_APPS`` setting.
1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS`
setting.
2. Determine which of your application's models should be editable in the
2. Admin has two dependencies - ``django.contrib.auth`` and
``django.contrib.contenttypes``. If these applications are not
in your :setting:`INSTALLED_APPS` list, add them.
3. Determine which of your application's models should be editable in the
admin interface.
3. For each of those models, optionally create a ``ModelAdmin`` class that
4. For each of those models, optionally create a ``ModelAdmin`` class that
encapsulates the customized admin functionality and options for that
particular model.
4. Instantiate an ``AdminSite`` and tell it about each of your models and
5. Instantiate an ``AdminSite`` and tell it about each of your models and
``ModelAdmin`` classes.
5. Hook the ``AdminSite`` instance into your URLconf.
6. Hook the ``AdminSite`` instance into your URLconf.
Other topics
------------
@@ -845,7 +850,7 @@ the admin application URL dispatching handler to render the pages that deal
with model instances CRUD operations. As a result, completely overriding these
methods will significantly change the behavior of the admin application.
One comon reason for overriding these methods is to augment the context data
One common reason for overriding these methods is to augment the context data
that is provided to the template that renders the view. In the following
example, the change view is overridden so that the rendered template is
provided some extra mapping data that would not otherwise be available::

View File

@@ -89,7 +89,7 @@ different ways you can specify which object to attach to:
Displaying comments
-------------------
To get a the list of comments for some object, use :ttag:`get_comment_list`::
To get the list of comments for some object, use :ttag:`get_comment_list`::
{% get_comment_list for [object] as [varname] %}

View File

@@ -844,7 +844,7 @@ define the details of how the relation works.
current date/time to be chosen.
Instead of a dictionary this can also be a :class:`~django.db.models.Q`
object (an object with a :meth:`get_sql` method) for more complex queries.
object for more :ref:`complex queries <complex-lookups-with-q>`.
``limit_choices_to`` has no effect on the inline FormSets that are created
to display related objects in the admin.

View File

@@ -19,6 +19,17 @@ Available ``Meta`` options
If ``True``, this model will be an :ref:`abstract base class <abstract-base-classes>`.
``app_label``
-------------
.. attribute:: Options.app_label
If a model exists outside of the standard :file:`models.py` (for instance, if
the app's models are in submodules of ``myapp.models``), the model must define
which app it is part of::
app_label = 'myapp'
``db_table``
------------

View File

@@ -20,7 +20,7 @@ Throughout this reference we'll use the :ref:`example weblog models
When QuerySets are evaluated
============================
Internally, a ``QuerySet`` can be constructed, filter, sliced, and generally
Internally, a ``QuerySet`` can be constructed, filtered, sliced, and generally
passed around without actually hitting the database. No database activity
actually occurs until you do something to evaluate the queryset.
@@ -1512,9 +1512,10 @@ regex
Case-sensitive regular expression match.
The regular expression syntax is that of the database backend in use. In the
case of SQLite, which doesn't natively support regular-expression lookups, the
syntax is that of Python's ``re`` module.
The regular expression syntax is that of the database backend in use.
In the case of SQLite, which has no built in regular expression support,
this feature is provided by a (Python) user-defined REGEXP function, and
the regular expression syntax is therefore that of Python's ``re`` module.
Example::

View File

@@ -262,7 +262,7 @@ a subclass of dictionary. Exceptions are outlined here:
Returns the value for the given key. If the key has more than one value,
``__getitem__()`` returns the last value. Raises
``django.utils.datastructure.MultiValueDictKeyError`` if the key does not
``django.utils.datastructures.MultiValueDictKeyError`` if the key does not
exist. (This is a subclass of Python's standard ``KeyError``, so you can
stick to catching ``KeyError``.)

View File

@@ -8,6 +8,9 @@ A list of all the signals that Django sends.
.. seealso::
See the documentation on the :ref:`signal dispatcher <topics-signals>` for
information regarding how to register for and receive signals.
The :ref:`comment framework <ref-contrib-comments-index>` sends a :ref:`set
of comment-related signals <ref-contrib-comments-signals>`.

View File

@@ -115,7 +115,7 @@ it was available in a model's pre-save signal handler.
In Django 1.1 the file is saved as part of saving the model in the database, so
the actual file name used on disk cannot be relied on until *after* the model
has been saved saved.
has been saved.
Changes to how model formsets are saved
---------------------------------------

View File

@@ -212,14 +212,15 @@ Methods
.. method:: models.User.has_perm(perm)
Returns ``True`` if the user has the specified permission, where perm is
in the format ``"<application name>.<lowercased model name>"``. If the
user is inactive, this method will always return ``False``.
in the format ``"<app label>.<permission codename>"``.
If the user is inactive, this method will always return ``False``.
.. method:: models.User.has_perms(perm_list)
Returns ``True`` if the user has each of the specified permissions,
where each perm is in the format ``"package.codename"``. If the user is
inactive, this method will always return ``False``.
where each perm is in the format
``"<app label>.<permission codename>"``. If the user is inactive,
this method will always return ``False``.
.. method:: models.User.has_module_perms(package_name)
@@ -689,8 +690,10 @@ The login_required decorator
* If the user isn't logged in, redirect to
:setting:`settings.LOGIN_URL <LOGIN_URL>` (``/accounts/login/`` by
default), passing the current absolute URL in the query string as
``next`` or the value of ``redirect_field_name``. For example:
default), passing the current absolute URL in the query string. The
name of the GET argument is determined by the ``redirect_field_name``
argument provided to the decorator. The default argument name is
``next``. For example:
``/accounts/login/?next=/polls/3/``.
* If the user is logged in, execute the view normally. The view code is
@@ -1060,8 +1063,8 @@ The permission_required decorator
my_view = permission_required('polls.can_vote')(my_view)
As for the :meth:`User.has_perm` method, permission names take the form
``"<application name>.<lowercased model name>"`` (i.e. ``polls.choice`` for
a ``Choice`` model in the ``polls`` application).
``"<app label>.<permission codename>"`` (i.e. ``polls.can_vote`` for a
permission on a model in the ``polls`` application).
Note that :func:`~django.contrib.auth.decorators.permission_required()`
also takes an optional ``login_url`` parameter. Example::

View File

@@ -361,6 +361,17 @@ then requests to ``/foo/1/`` and ``/foo/23/`` will be cached separately, as
you may expect. But once a particular URL (e.g., ``/foo/23/``) has been
requested, subsequent requests to that URL will use the cache.
``cache_page`` can also take an optional keyword argument, ``key_prefix``, which
works in the same way as the ``CACHE_MIDDLEWARE_KEY_PREFIX`` setting for the
middleware. It can be used like this::
my_view = cache_page(my_view, 60 * 15, key_prefix="site1")
Or, using Python 2.4's decorator syntax::
@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
Specifying per-view cache in the URLconf
----------------------------------------

View File

@@ -622,6 +622,8 @@ To avoid this problem, simply save the ``QuerySet`` and reuse it::
>>> print [p.headline for p in queryset] # Evaluate the query set.
>>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.
.. _complex-lookups-with-q:
Complex lookups with Q objects
==============================

View File

@@ -371,6 +371,35 @@ parameter when declaring the form field::
... class Meta:
... model = Article
.. note::
If you explicitly instantiate a form field like this, Django assumes that you
want to completely define its behavior; therefore, default attributes (such as
``max_length`` or ``required``) are not drawn from the corresponding model. If
you want to maintain the behavior specified in the model, you must set the
relevant arguments explicitly when declaring the form field.
For example, if the ``Article`` model looks like this::
class Article(models.Model):
headline = models.CharField(max_length=200, null=True, blank=True,
help_text="Use puns liberally")
content = models.TextField()
and you want to do some custom validation for ``headline``, while keeping
the ``blank`` and ``help_text`` values as specified, you might define
``ArticleForm`` like this::
class ArticleForm(ModelForm):
headline = MyFormField(max_length=200, required=False,
help_text="Use puns liberally")
class Meta:
model = Article
See the :ref:`form field documentation <ref-forms-fields>` for more information
on fields and their arguments.
Changing the order of fields
----------------------------
@@ -512,6 +541,12 @@ Then, pass your ``BaseAuthorFormSet`` class to the factory function::
>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
If you want to return a formset that doesn't include *any* pre-existing
instances of the model, you can specify an empty QuerySet::
>>> AuthorFormSet(queryset=Author.objects.none())
Controlling which fields are used with ``fields`` and ``exclude``
-----------------------------------------------------------------

View File

@@ -64,7 +64,7 @@ code! --, actually the ``direct_to_template`` view simply grabs information from
the extra-parameters dictionary and uses that information when rendering the
view.
Because this generic view -- and all the others -- is a regular view functions
Because this generic view -- and all the others -- is a regular view function
like any other, we can reuse it inside our own views. As an example, let's
extend our "about" example to map URLs of the form ``/about/<whatever>/`` to
statically rendered ``about/<whatever>.html``. We'll do this by first modifying

View File

@@ -453,6 +453,20 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
SESSION_COOKIE_PATH
-------------------
.. versionadded:: 1.0
Default: ``'/'``
The path set on the session cookie. This should either match the URL path of
your Django installation or be parent of that path.
This is useful if you have multiple Django instances running under the same
hostname. They can use different cookie paths, and each instance will only see
its own session cookie.
SESSION_COOKIE_SECURE
---------------------

View File

@@ -147,7 +147,7 @@ will be returned::
``get_object_or_404``
=====================
.. function:: get_object_or_404(object, *args, **kwargs)
.. function:: get_object_or_404(klass, *args, **kwargs)
Calls :meth:`~django.db.models.QuerySet.get()` on a given model manager,
but it raises ``django.http.Http404`` instead of the model's

View File

@@ -515,7 +515,7 @@ arguments at time of construction:
>>> c = Client()
>>> c.get('/customers/details/?name=fred&age=7')
If you provide URL both an encoded GET data and a data argument,
If you provide a URL with both an encoded GET data and a data argument,
the data argument will take precedence.
If you set ``follow`` to ``True`` the client will follow any redirects
@@ -627,7 +627,7 @@ arguments at time of construction:
.. versionadded:: 1.1
Makes an PUT request on the provided ``path`` and returns a
Makes a PUT request on the provided ``path`` and returns a
``Response`` object. Useful for testing RESTful interfaces. Acts just
like :meth:`Client.post` except with the PUT request method.
@@ -1127,11 +1127,11 @@ Django, such as your machine's mail server, if you're running one.)
During test running, each outgoing e-mail is saved in
``django.core.mail.outbox``. This is a simple list of all
:class:`<~django.core.mail.EmailMessage>` instances that have been sent.
:class:`~django.core.mail.EmailMessage` instances that have been sent.
It does not exist under normal execution conditions, i.e., when you're not
running unit tests. The outbox is created during test setup, along with the
dummy :class:`<~django.core.mail.SMTPConnection>`. When the test framework is
torn down, the standard :class:`<~django.core.mail.SMTPConnection>` class is
dummy :class:`~django.core.mail.SMTPConnection`. When the test framework is
torn down, the standard :class:`~django.core.mail.SMTPConnection` class is
restored, and the test outbox is destroyed.
The ``outbox`` attribute is a special attribute that is created *only* when

View File

@@ -31,136 +31,10 @@
#
# To uninstall, just remove the line from your .bash_profile and .bashrc.
# Enable extended pattern matching operators.
shopt -s extglob
_django_completion()
{
local cur prev opts actions action_shell_opts action_runfcgi_opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
# Standalone options
opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version --locale --domain"
# Actions
actions="createcachetable createsuperuser compilemessages \
dbshell diffsettings dumpdata flush inspectdb loaddata \
makemessages reset runfcgi runserver shell sql sqlall sqlclear \
sqlcustom sqlflush sqlindexes sqlreset sqlsequencereset startapp \
startproject syncdb test validate"
# Action's options
action_shell_opts="--plain"
action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
if [[ # django-admin.py, django-admin, ./manage, manage.py
( ${COMP_CWORD} -eq 1 &&
( ${COMP_WORDS[0]} == django-admin.py ||
${COMP_WORDS[0]} == django-admin ||
${COMP_WORDS[0]} == ./manage.py ||
${COMP_WORDS[0]} == manage.py ) )
||
# 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) &&
( -r ${COMP_WORDS[1]} ) )
||
( ${COMP_CWORD} -eq 2 &&
( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
( $( basename -- ${COMP_WORDS[1]} ) == django-admin.py) &&
( -r ${COMP_WORDS[1]} ) )
||
( ${COMP_CWORD} -eq 2 &&
( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
( $( basename -- ${COMP_WORDS[1]} ) == django-admin) &&
( -r ${COMP_WORDS[1]} ) ) ]] ; then
case ${cur} in
-*)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
action=$COMPREPLY
return 0
;;
*)
COMPREPLY=( $(compgen -W "${actions}" -- ${cur}) )
action=$COMPREPLY
return 0
;;
esac
else
case ${prev} in
dumpdata|reset| \
sql|sqlall|sqlclear|sqlcustom|sqlindexes| \
sqlreset|sqlsequencereset|test)
# App completion
settings=""
# If settings.py in the PWD, use that
if [ -e settings.py ] ; then
settings="$PWD/settings.py"
else
# Use the ENV variable if it is set
if [ $DJANGO_SETTINGS_MODULE ] ; then
settings=$DJANGO_SETTINGS_MODULE
fi
fi
# Couldn't find settings so return nothing
if [ -z $settings ] ; then
COMPREPLY=()
# Otherwise inspect settings.py file
else
apps=`sed -n "/INSTALLED_APPS = (/,/)/p" $settings | \
grep -v "django.contrib" |
sed -n "s/^[ ]*'\(.*\.\)*\(.*\)'.*$/\2 /pg" | \
tr -d "\n"`
COMPREPLY=( $(compgen -W "${apps}" -- ${cur}) )
fi
return 0
;;
createcachetable|cleanup|compilemessages|dbshell| \
diffsettings|inspectdb|makemessages| \
runserver|startapp|startproject|syncdb| \
validate)
COMPREPLY=()
return 0
;;
shell)
COMPREPLY=( $(compgen -W "$action_shell_opts" -- ${cur}) )
return 0
;;
runfcgi)
COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
return 0
;;
host*|port*|socket*|method*|maxspare*|minspare*|maxchildren*|daemonize*|pidfile*|workdir*)
if [ "$action" == "runfcgi" ] ; then
COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
return 0
fi
return 0
;;
*)
#COMPREPLY=( $(compgen -W "auth core" -- ${cur}) )
COMPREPLY=()
return 0
;;
esac
fi
COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \
COMP_CWORD=$COMP_CWORD \
DJANGO_AUTO_COMPLETE=1 $1 ) )
}
complete -F _django_completion django-admin.py manage.py django-admin
# Support for multiple interpreters.
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)"
done
pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ")
else
pythons=python
fi
complete -F _django_completion -o default $pythons
complete -F _django_completion -o default django-admin.py manage.py

View File

@@ -56,6 +56,16 @@ __test__ = {'API_TESTS': """
>>> company_query
[{'num_chairs': 2302, 'name': u'Example Inc.', 'num_employees': 2300}, {'num_chairs': 5, 'name': u'Foobar Ltd.', 'num_employees': 3}, {'num_chairs': 34, 'name': u'Test GmbH', 'num_employees': 32}]
# Law of order of operations is followed
>>> _ =company_query.update(num_chairs=F('num_employees') + 2 * F('num_employees'))
>>> company_query
[{'num_chairs': 6900, 'name': u'Example Inc.', 'num_employees': 2300}, {'num_chairs': 9, 'name': u'Foobar Ltd.', 'num_employees': 3}, {'num_chairs': 96, 'name': u'Test GmbH', 'num_employees': 32}]
# Law of order of operations can be overridden by parentheses
>>> _ =company_query.update(num_chairs=((F('num_employees') + 2) * F('num_employees')))
>>> company_query
[{'num_chairs': 5294600, 'name': u'Example Inc.', 'num_employees': 2300}, {'num_chairs': 15, 'name': u'Foobar Ltd.', 'num_employees': 3}, {'num_chairs': 1088, 'name': u'Test GmbH', 'num_employees': 32}]
# The relation of a foreign key can become copied over to an other foreign key.
>>> Company.objects.update(point_of_contact=F('ceo'))
3

View File

@@ -6,7 +6,7 @@
<field type="BooleanField" name="alive">True</field>
</object>
<object pk="2" model="admin_views.person">
<field type="CharField" name="name">Grace Hooper</field>
<field type="CharField" name="name">Grace Hopper</field>
<field type="IntegerField" name="gender">1</field>
<field type="BooleanField" name="alive">False</field>
</object>

View File

@@ -908,7 +908,7 @@ class AdminViewListEditable(TestCase):
self.client.post('/test_admin/admin/admin_views/person/', data)
self.failUnlessEqual(Person.objects.get(name="John Mauchly").alive, False)
self.failUnlessEqual(Person.objects.get(name="Grace Hooper").gender, 2)
self.failUnlessEqual(Person.objects.get(name="Grace Hopper").gender, 2)
# test a filtered page
data = {
@@ -1616,4 +1616,3 @@ class NeverCacheTests(TestCase):
"Check the never-cache status of the Javascript i18n view"
response = self.client.get('/test_admin/jsi18n/')
self.failUnlessEqual(get_max_age(response), None)

View File

@@ -1,11 +1,16 @@
from unittest import TestCase
from sys import version_info
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
from django.http import HttpResponse
from django.http import HttpResponse, HttpRequest
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.utils.decorators import auto_adapt_to_methods
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.contrib.admin.views.decorators import staff_member_required
@@ -85,3 +90,64 @@ class DecoratorsTest(TestCase):
self.assertEqual(response, ['test2', 'test1'])
def test_cache_page_new_style(self):
"""
Test that we can call cache_page the new way
"""
def my_view(request):
return "response"
my_view_cached = cache_page(123)(my_view)
self.assertEqual(my_view_cached(HttpRequest()), "response")
my_view_cached2 = cache_page(123, key_prefix="test")(my_view)
self.assertEqual(my_view_cached2(HttpRequest()), "response")
def test_cache_page_old_style(self):
"""
Test that we can call cache_page the old way
"""
def my_view(request):
return "response"
my_view_cached = cache_page(my_view, 123)
self.assertEqual(my_view_cached(HttpRequest()), "response")
my_view_cached2 = cache_page(my_view, 123, key_prefix="test")
self.assertEqual(my_view_cached2(HttpRequest()), "response")
class MethodDecoratorAdapterTests(TestCase):
def test_auto_adapt_to_methods(self):
"""
Test that auto_adapt_to_methods actually works.
"""
# Need 2 decorators with auto_adapt_to_methods,
# to check it plays nicely with composing itself.
def my_decorator(func):
def wrapped(*args, **kwargs):
# need to ensure that the first arg isn't 'self'
self.assertEqual(args[0], "test")
return "my_decorator:" + func(*args, **kwargs)
wrapped.my_decorator_custom_attribute = True
return wraps(func)(wrapped)
my_decorator = auto_adapt_to_methods(my_decorator)
def my_decorator2(func):
def wrapped(*args, **kwargs):
# need to ensure that the first arg isn't 'self'
self.assertEqual(args[0], "test")
return "my_decorator2:" + func(*args, **kwargs)
wrapped.my_decorator2_custom_attribute = True
return wraps(func)(wrapped)
my_decorator2 = auto_adapt_to_methods(my_decorator2)
class MyClass(object):
def my_method(self, *args, **kwargs):
return "my_method:%r %r" % (args, kwargs)
my_method = my_decorator2(my_decorator(my_method))
obj = MyClass()
self.assertEqual(obj.my_method("test", 123, name='foo'),
"my_decorator2:my_decorator:my_method:('test', 123) {'name': 'foo'}")
self.assertEqual(obj.my_method.__name__, 'my_method')
self.assertEqual(getattr(obj.my_method, 'my_decorator_custom_attribute', False),
True)
self.assertEqual(getattr(obj.my_method, 'my_decorator2_custom_attribute', False),
True)

View File

@@ -381,6 +381,17 @@ class TestFields(TestCase):
self.assertEqual(u'example@valid-----hyphens.com', f.clean('example@valid-----hyphens.com'))
self.assertEqual(u'example@valid-with-hyphens.com', f.clean('example@valid-with-hyphens.com'))
def test_email_regexp_for_performance(self):
f = EmailField()
# Check for runaway regex security problem. This will take for-freeking-ever
# if the security fix isn't in place.
self.assertRaisesErrorWithMessage(
ValidationError,
"[u'Enter a valid e-mail address.']",
f.clean,
'viewx3dtextx26qx3d@yahoo.comx26latlngx3d15854521645943074058'
)
def test_emailfield_33(self):
f = EmailField(required=False)
self.assertEqual(u'', f.clean(''))
@@ -431,6 +442,7 @@ class TestFields(TestCase):
self.assertRaisesErrorWithMessage(ValidationError, "[u'This field is required.']", f.clean, None)
self.assertEqual(u'http://localhost/', f.clean('http://localhost'))
self.assertEqual(u'http://example.com/', f.clean('http://example.com'))
self.assertEqual(u'http://example.com./', f.clean('http://example.com.'))
self.assertEqual(u'http://www.example.com/', f.clean('http://www.example.com'))
self.assertEqual(u'http://www.example.com:8000/test', f.clean('http://www.example.com:8000/test'))
self.assertEqual(u'http://valid-with-hyphens.com/', f.clean('valid-with-hyphens.com'))
@@ -441,6 +453,8 @@ class TestFields(TestCase):
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://example')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://example.')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'com.')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, '.')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://.com')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://invalid-.com')
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://-invalid.com')
@@ -448,6 +462,15 @@ class TestFields(TestCase):
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://inv-.-alid.com')
self.assertEqual(u'http://valid-----hyphens.com/', f.clean('http://valid-----hyphens.com'))
def test_url_regexp_for_performance(self):
f = URLField()
# hangs "forever" if catastrophic backtracking in ticket:#11198 not fixed
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://%s' % ("X"*200,))
# a second test, to make sure the problem is really addressed, even on
# domains that don't fail the domain label length check in the regex
self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://%s' % ("X"*60,))
def test_urlfield_38(self):
f = URLField(required=False)
self.assertEqual(u'', f.clean(''))