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

multi-auth: Merged to [3051]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@3052 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2006-06-02 03:51:30 +00:00
parent aeb807989f
commit 0c341d780e
56 changed files with 582 additions and 362 deletions

View File

@ -45,6 +45,7 @@ answer newbie questions, and generally made Django that much better:
andy@jadedplanet.net
Antonio Cavedoni <http://cavedoni.com/>
C8E
Chris Chamberlin <dja@cdc.msbx.net>
Amit Chakradeo <http://amit.chakradeo.net/>
ChaosKCW
Ian Clelland <clelland@gmail.com>

View File

@ -235,6 +235,7 @@ SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever yo
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
#########
# CACHE #

View File

@ -13,7 +13,7 @@ msgstr ""
"Last-Translator: panos laganakos <panos.laganakos@gmail.com>\n"
"Language-Team: Greek\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-1\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/comments/models.py:67 contrib/comments/models.py:166

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":

View File

@ -7,7 +7,7 @@ body.login { background:#eee; }
.login #content-main { width:100%; }
.login form { margin-top:1em; }
.login .form-row { padding:4px 0; float:left; width:100%; }
.login .form-row label { float:left; width:7em; padding-right:0.5em; line-height:2em; text-align:right; font-size:1em; color:#333; }
.login .form-row #id_username, .login .form-row #id_password { width:16em; }
.login .form-row label { float:left; width:9em; padding-right:0.5em; line-height:2em; text-align:right; font-size:1em; color:#333; }
.login .form-row #id_username, .login .form-row #id_password { width:14em; }
.login span.help { font-size:10px; display:block; }
.login .submit-row { clear:both; padding:1em 0 0 7.4em; }
.login .submit-row { clear:both; padding:1em 0 0 9.4em; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

View File

@ -12,7 +12,7 @@
<div class="breadcrumbs">
<a href="../../../">{% trans "Home" %}</a> &rsaquo;
<a href="../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
{% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|striptags|truncatewords:"18" }}{% endif %}
{% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %}
</div>
{% endif %}{% endblock %}
{% block content %}<div id="content-main">

View File

@ -2,13 +2,9 @@
<div class="{{ class_names }}" >
{% for bound_field in bound_fields %}{{ bound_field.html_error_list }}{% endfor %}
{% for bound_field in bound_fields %}
{% if bound_field.has_label_first %}
{% field_label bound_field %}
{% endif %}
{% if bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% field_widget bound_field %}
{% if not bound_field.has_label_first %}
{% field_label bound_field %}
{% endif %}
{% if not bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% if bound_field.field.help_text %}<p class="help">{{ bound_field.field.help_text }}</p>{% endif %}
{% endfor %}
</div>

View File

@ -3,6 +3,6 @@
<ul>
{% for choice in choices %}
<li{% if choice.selected %} class="selected"{% endif %}>
<a href="{{ choice.query_string }}">{{ choice.display }}</a></li>
<a href="{{ choice.query_string }}">{{ choice.display|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -0,0 +1,10 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title }}</div>{% endblock %}
{% block content %}
<p>{% trans "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." %}</p>
{% endblock %}

View File

@ -24,8 +24,8 @@
{% for action in action_list %}
<tr>
<th scope="row">{{ action.action_time|date:_("DATE_WITH_TIME_FULL") }}</th>
<td>{{ action.user.username }}{% if action.user.first_name %} ({{ action.user.first_name }} {{ action.user.last_name }}){% endif %}</td>
<td>{{ action.change_message}}</td>
<td>{{ action.user.username }}{% if action.user.first_name %} ({{ action.user.first_name|escape }} {{ action.user.last_name|escape }}){% endif %}</td>
<td>{{ action.change_message|escape }}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -42,7 +42,12 @@ class AdminApplistNode(template.Node):
})
if model_list:
model_list.sort()
# Sort using verbose decorate-sort-undecorate pattern
# instead of key argument to sort() for python 2.3 compatibility
decorated = [(x['name'], x) for x in model_list]
decorated.sort()
model_list = [x for key, x in decorated]
app_list.append({
'name': app_label.title(),
'has_module_perms': has_module_perms,

View File

@ -2,7 +2,7 @@ from django.conf.urls.defaults import *
urlpatterns = patterns('',
('^$', 'django.contrib.admin.views.main.index'),
('^r/(\d+)/(\d+)/$', 'django.views.defaults.shortcut'),
('^r/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
('^jsi18n/$', 'django.views.i18n.javascript_catalog', {'packages': 'django.conf'}),
('^logout/$', 'django.contrib.auth.views.logout'),
('^password_change/$', 'django.contrib.auth.views.password_change'),

View File

@ -35,6 +35,7 @@ ORDER_TYPE_VAR = 'ot'
PAGE_VAR = 'p'
SEARCH_VAR = 'q'
IS_POPUP_VAR = 'pop'
ERROR_FLAG = 'e'
# Text to display within change-list table cells if the value is blank.
EMPTY_CHANGELIST_VALUE = '(None)'
@ -73,8 +74,7 @@ def unquote(s):
for item in list:
if item[1:2]:
try:
myappend(mychr(myatoi(item[:2], 16))
+ item[2:])
myappend(mychr(myatoi(item[:2], 16)) + item[2:])
except ValueError:
myappend('_' + item)
else:
@ -143,9 +143,9 @@ class AdminBoundField(object):
return self._display
except AttributeError:
if isinstance(self.field.rel, models.ManyToOneRel):
self._display = getattr(self.original, self.field.attname)
self._display = getattr(self.original, self.field.name)
elif isinstance(self.field.rel, models.ManyToManyRel):
self._display = ", ".join([str(obj) for obj in getattr(self.original, self.field.attname).all()])
self._display = ", ".join([str(obj) for obj in getattr(self.original, self.field.name).all()])
return self._display
def __repr__(self):
@ -557,6 +557,8 @@ class ChangeList(object):
self.params = dict(request.GET.items())
if self.params.has_key(PAGE_VAR):
del self.params[PAGE_VAR]
if self.params.has_key(ERROR_FLAG):
del self.params[ERROR_FLAG]
self.order_field, self.order_type = self.get_ordering()
self.query = request.GET.get(SEARCH_VAR, '')
@ -730,7 +732,14 @@ def change_list(request, app_label, model_name):
try:
cl = ChangeList(request, model)
except IncorrectLookupParameters:
return HttpResponseRedirect(request.path)
# Wacky lookup parameters were given, so redirect to the main
# changelist page, without parameters, and pass an 'invalid=1'
# parameter via the query string. If wacky parameters were given and
# the 'invalid=1' parameter was already in the query string, something
# is screwed up with the database, so display an error page.
if ERROR_FLAG in request.GET.keys():
return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
c = template.RequestContext(request, {
'title': cl.title,
'is_popup': cl.is_popup,

View File

@ -10,8 +10,6 @@ def authenhandler(req, **kwargs):
# that so that the following import works
os.environ.update(req.subprocess_env)
from django.contrib.auth.models import User
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
@ -19,6 +17,11 @@ def authenhandler(req, **kwargs):
permission_name = options.get('DjangoPermissionName', None)
staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
if settings_module:
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
from django.contrib.auth.models import User
# check that the username is valid
kwargs = {'username': req.user, 'is_active': True}

View File

@ -32,7 +32,7 @@ class Permission(models.Model):
ordering = ('content_type', 'codename')
def __str__(self):
return "%r | %s" % (self.content_type, self.name)
return "%s | %s" % (self.content_type, self.name)
class Group(models.Model):
name = models.CharField(_('name'), maxlength=80, unique=True)

View File

@ -79,9 +79,14 @@ class SessionMiddleware:
else:
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
session_key = request.session.session_key or Session.objects.get_new_session_key()
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
max_age = None
expires = None
else:
max_age = settings.SESSION_COOKIE_AGE
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
new_session = Session.objects.save(session_key, request.session._session,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
max_age=settings.SESSION_COOKIE_AGE, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
return response

View File

@ -334,8 +334,8 @@ def get_sql_initial_data_for_model(model):
r"""( # each statement is...
(?: # one or more chunks of ...
(?:[^;'"]+) # not the end of a statement or start of a quote
| (?:'[^']+') # something in single quotes
| (?:"[^"]+") # something in double quotes
| (?:'[^']*') # something in single quotes
| (?:"[^"]*") # something in double quotes
)+)""", re.VERBOSE)
# Find custom SQL, if it's available.

View File

@ -54,6 +54,26 @@ class ObjectPaginator:
def has_previous_page(self, page_number):
return page_number > 0
def first_on_page(self, page_number):
"""
Returns the 1-based index of the first object on the given page,
relative to total objects found (hits).
"""
if page_number == 0:
return 1
return (self.num_per_page * page_number) + 1
def last_on_page(self, page_number):
"""
Returns the 1-based index of the last object on the given page,
relative to total objects found (hits).
"""
if page_number == 0 and self.num_per_page >= self._hits:
return self._hits
elif page_number == (self._pages - 1) and (page_number + 1) * self.num_per_page > self._hits:
return self._hits
return (page_number + 1) * self.num_per_page
def _get_hits(self):
if self._hits is None:
self._hits = self.query_set.count()

View File

@ -20,7 +20,10 @@ alnumurl_re = re.compile(r'^[-\w/]+$')
ansi_date_re = re.compile('^%s$' % _datere)
ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
email_re = re.compile(r'^[A-Z0-9._%-][+A-Z0-9._%-]*@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$', re.IGNORECASE)
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-Z]{2,4}$', re.IGNORECASE) # domain
integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
@ -143,7 +146,11 @@ def isValidImage(field_data, all_data):
from PIL import Image
from cStringIO import StringIO
try:
Image.open(StringIO(field_data['content']))
content = field_data['content']
except TypeError:
raise ValidationError, gettext("No file was submitted. Check the encoding type on the form.")
try:
Image.open(StringIO(content))
except IOError: # Python Imaging Library doesn't recognize it as an image
raise ValidationError, gettext("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
@ -363,9 +370,13 @@ class HasAllowableSize:
self.max_error_message = max_error_message or lazy_inter(gettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)
def __call__(self, field_data, all_data):
if self.min_size is not None and len(field_data['content']) < self.min_size:
try:
content = field_data['content']
except TypeError:
raise ValidationError, gettext_lazy("No file was submitted. Check the encoding type on the form.")
if self.min_size is not None and len(content) < self.min_size:
raise ValidationError, self.min_error_message
if self.max_size is not None and len(field_data['content']) > self.max_size:
if self.max_size is not None and len(content) > self.max_size:
raise ValidationError, self.max_error_message
class MatchesRegularExpression:

View File

@ -45,27 +45,26 @@ def get_indexes(cursor, table_name):
{'primary_key': boolean representing whether it's the primary key,
'unique': boolean representing whether it's a unique index}
"""
# Get the table description because we only have the column indexes, and we
# need the column names.
desc = get_table_description(cursor, table_name)
# This query retrieves each index on the given table.
# This query retrieves each index on the given table, including the
# first associated field name
cursor.execute("""
SELECT idx.indkey, idx.indisunique, idx.indisprimary
SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
pg_catalog.pg_index idx
pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
WHERE c.oid = idx.indrelid
AND idx.indexrelid = c2.oid
AND attr.attrelid = c.oid
AND attr.attnum = idx.indkey[0]
AND c.relname = %s""", [table_name])
indexes = {}
for row in cursor.fetchall():
# row[0] (idx.indkey) is stored in the DB as an array. It comes out as
# row[1] (idx.indkey) is stored in the DB as an array. It comes out as
# a string of space-separated integers. This designates the field
# indexes (1-based) of the fields that have indexes on the table.
# Here, we skip any indexes across multiple fields.
if ' ' in row[0]:
if ' ' in row[1]:
continue
col_name = desc[int(row[0])-1][0]
indexes[col_name] = {'primary_key': row[2], 'unique': row[1]}
indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
return indexes
# Maps type codes to Django Field types.

View File

@ -45,27 +45,26 @@ def get_indexes(cursor, table_name):
{'primary_key': boolean representing whether it's the primary key,
'unique': boolean representing whether it's a unique index}
"""
# Get the table description because we only have the column indexes, and we
# need the column names.
desc = get_table_description(cursor, table_name)
# This query retrieves each index on the given table.
# This query retrieves each index on the given table, including the
# first associated field name
cursor.execute("""
SELECT idx.indkey, idx.indisunique, idx.indisprimary
SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
pg_catalog.pg_index idx
pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
WHERE c.oid = idx.indrelid
AND idx.indexrelid = c2.oid
AND attr.attrelid = c.oid
AND attr.attnum = idx.indkey[0]
AND c.relname = %s""", [table_name])
indexes = {}
for row in cursor.fetchall():
# row[0] (idx.indkey) is stored in the DB as an array. It comes out as
# row[1] (idx.indkey) is stored in the DB as an array. It comes out as
# a string of space-separated integers. This designates the field
# indexes (1-based) of the fields that have indexes on the table.
# Here, we skip any indexes across multiple fields.
if ' ' in row[0]:
if ' ' in row[1]:
continue
col_name = desc[int(row[0])-1][0]
indexes[col_name] = {'primary_key': row[2], 'unique': row[1]}
indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
return indexes
# Maps type codes to Django Field types.

View File

@ -12,6 +12,10 @@ class CursorDebugWrapper:
return self.cursor.execute(sql, params)
finally:
stop = time()
# If params was a list, convert it to a tuple, because string
# formatting with '%' only works with tuples or dicts.
if not isinstance(params, (tuple, dict)):
params = tuple(params)
self.db.queries.append({
'sql': sql % tuple(params),
'time': "%.3f" % (stop - start),

View File

@ -161,7 +161,7 @@ class Model(object):
(backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
# If it does already exist, do an UPDATE.
if cursor.fetchone():
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), False)) for f in non_pks]
db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
@ -171,11 +171,11 @@ class Model(object):
record_exists = False
if not pk_set or not record_exists:
field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), True)) for f in self._meta.fields if not isinstance(f, AutoField)]
db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
# If the PK has been manually set, respect that.
if pk_set:
field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
db_values += [f.get_db_prep_save(f.pre_save(getattr(self, f.column), True)) for f in self._meta.fields if isinstance(f, AutoField)]
db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
placeholders = ['%s'] * len(field_names)
if self._meta.order_with_respect_to:
field_names.append(backend.quote_name('_order'))
@ -279,7 +279,7 @@ class Model(object):
order_field = self._meta.order_with_respect_to
where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
(backend.quote_name('_order'), op, backend.quote_name('_order'),
backend.quote_name(opts.db_table), backend.quote_name(opts.pk.column)),
backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
'%s=%%s' % backend.quote_name(order_field.column)]
params = [self._get_pk_val(), getattr(self, order_field.attname)]
obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()

View File

@ -152,9 +152,9 @@ class Field(object):
def get_internal_type(self):
return self.__class__.__name__
def pre_save(self, value, add):
def pre_save(self, model_instance, add):
"Returns field's value just before saving."
return value
return getattr(model_instance, self.attname)
def get_db_prep_save(self, value):
"Returns field's value prepared for saving into a database."
@ -417,10 +417,13 @@ class DateField(Field):
value = str(value)
return Field.get_db_prep_lookup(self, lookup_type, value)
def pre_save(self, value, add):
def pre_save(self, model_instance, add):
if self.auto_now or (self.auto_now_add and add):
return datetime.datetime.now()
value = datetime.datetime.now()
setattr(model_instance, self.attname, value)
return value
else:
return super(DateField, self).pre_save(model_instance, add)
def contribute_to_class(self, cls, name):
super(DateField,self).contribute_to_class(cls, name)
@ -723,10 +726,13 @@ class TimeField(Field):
value = str(value)
return Field.get_db_prep_lookup(self, lookup_type, value)
def pre_save(self, value, add):
def pre_save(self, model_instance, add):
if self.auto_now or (self.auto_now_add and add):
return datetime.datetime.now().time()
value = datetime.datetime.now().time()
setattr(model_instance, self.attname, value)
return value
else:
return super(TimeField, self).pre_save(model_instance, add)
def get_db_prep_save(self, value):
# Casts dates into string format for entry into database.

View File

@ -3,8 +3,8 @@ from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models import signals
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
import operator
import re
# For Python 2.3
if not hasattr(__builtins__, 'set'):
@ -59,7 +59,7 @@ def orderlist2sql(order_list, opts, prefix=''):
return ', '.join(output)
def quote_only_if_word(word):
if ' ' in word:
if re.search('\W', word): # Don't quote if there are spaces or non-word chars.
return word
else:
return backend.quote_name(word)
@ -380,6 +380,10 @@ class QuerySet(object):
# (so that A.filter(args1) & A.filter(args2) does the same as
# A.filter(args1).filter(args2)
combined = other._clone()
if self._select: combined._select.update(self._select)
if self._where: combined._where.extend(self._where)
if self._params: combined._params.extend(self._params)
if self._tables: combined._tables.extend(self._tables)
# If 'self' is ordered and 'other' isn't, propagate 'self's ordering
if (self._order_by is not None and len(self._order_by) > 0) and \
(combined._order_by is None or len(combined._order_by) == 0):

View File

@ -12,7 +12,10 @@ Managed transactions don't do those commits, but will need some kind of manual
or implicit commits or rollbacks.
"""
import thread
try:
import thread
except ImportError:
import dummy_thread as thread
from django.db import connection
from django.conf import settings

View File

@ -577,7 +577,7 @@ class SelectMultipleField(SelectField):
selected_html = ''
if str(value) in str_data_list:
selected_html = ' selected="selected"'
output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, choice))
output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice)))
output.append(' </select>')
return '\n'.join(output)
@ -641,7 +641,11 @@ class FileUploadField(FormField):
self.validator_list = [self.isNonEmptyFile] + validator_list
def isNonEmptyFile(self, field_data, all_data):
if not field_data['content']:
try:
content = field_data['content']
except TypeError:
raise validators.CriticalValidationError, gettext("No file was submitted. Check the encoding type on the form.")
if not content:
raise validators.CriticalValidationError, gettext("The submitted file is empty.")
def render(self, data):

View File

@ -10,14 +10,14 @@ def render_to_response(*args, **kwargs):
return HttpResponse(loader.render_to_string(*args, **kwargs))
load_and_render = render_to_response # For backwards compatibility.
def get_object_or_404(klass, **kwargs):
def get_object_or_404(klass, *args, **kwargs):
try:
return klass._default_manager.get(**kwargs)
return klass._default_manager.get(*args, **kwargs)
except klass.DoesNotExist:
raise Http404
def get_list_or_404(klass, **kwargs):
obj_list = list(klass._default_manager.filter(**kwargs))
def get_list_or_404(klass, *args, **kwargs):
obj_list = list(klass._default_manager.filter(*args, **kwargs))
if not obj_list:
raise Http404
return obj_list

View File

@ -234,4 +234,7 @@ class local(_localbase):
return __del__
__del__ = __del__()
from threading import currentThread, enumerate, RLock
try:
from threading import currentThread, enumerate, RLock
except ImportError:
from dummy_threading import currentThread, enumerate, RLock

View File

@ -28,7 +28,12 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os, sys, thread, time
import os, sys, time
try:
import thread
except ImportError:
import dummy_thread as thread
RUN_RELOADER = True

View File

@ -217,7 +217,7 @@ class Atom1Feed(SyndicationFeed):
for item in self.items:
handler.startElement(u"entry", {})
handler.addQuickElement(u"title", item['title'])
handler.addQuickElement(u"link", u"", {u"href": item['link']})
handler.addQuickElement(u"link", u"", {u"href": item['link'], u"rel": u"alternate"})
if item['pubdate'] is not None:
handler.addQuickElement(u"updated", rfc3339_date(item['pubdate']).decode('ascii'))

View File

@ -6,7 +6,8 @@ import datetime, time
def archive_index(request, queryset, date_field, num_latest=15,
template_name=None, template_loader=loader,
extra_context={}, allow_empty=False, context_processors=None):
extra_context={}, allow_empty=False, context_processors=None,
mimetype=None):
"""
Generic top-level archive of date-based objects.
@ -40,11 +41,12 @@ def archive_index(request, queryset, date_field, num_latest=15,
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_year(request, year, queryset, date_field, template_name=None,
template_loader=loader, extra_context={}, allow_empty=False,
context_processors=None):
context_processors=None, template_object_name='object', mimetype=None,
make_object_list=False):
"""
Generic yearly archive view.
@ -54,6 +56,9 @@ def archive_year(request, year, queryset, date_field, template_name=None,
List of months in this year with objects
year
This year
object_list
List of objects published in the given month
(Only available if make_object_list argument is True)
"""
model = queryset.model
now = datetime.datetime.now()
@ -66,24 +71,29 @@ def archive_year(request, year, queryset, date_field, template_name=None,
date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month')
if not date_list and not allow_empty:
raise Http404
if make_object_list:
object_list = queryset.filter(**lookup_kwargs).order_by(date_field)
else:
object_list = []
if not template_name:
template_name = "%s/%s_archive_year.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'date_list': date_list,
'year': year,
'%s_list' % template_object_name: object_list,
}, context_processors)
for key, value in extra_context.items():
if callable(value):
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_month(request, year, month, queryset, date_field,
month_format='%b', template_name=None, template_loader=loader,
extra_context={}, allow_empty=False, context_processors=None,
template_object_name='object'):
template_object_name='object', mimetype=None):
"""
Generic monthly archive view.
@ -134,12 +144,12 @@ def archive_month(request, year, month, queryset, date_field,
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_week(request, year, week, queryset, date_field,
template_name=None, template_loader=loader,
extra_context={}, allow_empty=True, context_processors=None,
template_object_name='object'):
template_object_name='object', mimetype=None):
"""
Generic weekly archive view.
@ -181,12 +191,13 @@ def archive_week(request, year, week, queryset, date_field,
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_day(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', template_name=None,
template_loader=loader, extra_context={}, allow_empty=False,
context_processors=None, template_object_name='object'):
context_processors=None, template_object_name='object',
mimetype=None):
"""
Generic daily archive view.
@ -233,7 +244,7 @@ def archive_day(request, year, month, day, queryset, date_field,
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def archive_today(request, **kwargs):
"""
@ -251,7 +262,7 @@ def object_detail(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', object_id=None, slug=None,
slug_field=None, template_name=None, template_name_field=None,
template_loader=loader, extra_context={}, context_processors=None,
template_object_name='object'):
template_object_name='object', mimetype=None):
"""
Generic detail view from year/month/day/slug or year/month/day/id structure.
@ -300,6 +311,6 @@ def object_detail(request, year, month, day, queryset, date_field,
c[key] = value()
else:
c[key] = value
response = HttpResponse(t.render(c))
response = HttpResponse(t.render(c), mimetype=mimetype)
populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
return response

View File

@ -6,7 +6,8 @@ from django.core.exceptions import ObjectDoesNotExist
def object_list(request, queryset, paginate_by=None, allow_empty=False,
template_name=None, template_loader=loader,
extra_context={}, context_processors=None, template_object_name='object'):
extra_context={}, context_processors=None, template_object_name='object',
mimetype=None):
"""
Generic list of objects.
@ -73,12 +74,13 @@ def object_list(request, queryset, paginate_by=None, allow_empty=False,
model = queryset.model
template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
return HttpResponse(t.render(c))
return HttpResponse(t.render(c), mimetype=mimetype)
def object_detail(request, queryset, object_id=None, slug=None,
slug_field=None, template_name=None, template_name_field=None,
template_loader=loader, extra_context={},
context_processors=None, template_object_name='object'):
context_processors=None, template_object_name='object',
mimetype=None):
"""
Generic list of objects.
@ -113,6 +115,6 @@ def object_detail(request, queryset, object_id=None, slug=None,
c[key] = value()
else:
c[key] = value
response = HttpResponse(t.render(c))
response = HttpResponse(t.render(c), mimetype=mimetype)
populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
return response

View File

@ -56,6 +56,15 @@ location to users marked as staff members. You can use a set of
required.
================================ =========================================
Note that sometimes ``SetEnv`` doesn't play well in this mod_python
configuration, for reasons unknown. If you're having problems getting
mod_python to recognize your ``DJANGO_SETTINGS_MODULE``, you can set it using
``PythonOption`` instead of ``SetEnv``. Therefore, these two Apache directives
are equivalent::
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonOption DJANGO_SETTINGS_MODULE mysite.settings
.. _authentication system: http://www.djangoproject.com/documentation/authentication/
.. _Subversion: http://subversion.tigris.org/
.. _mod_dav: http://httpd.apache.org/docs/2.0/mod/mod_dav.html

View File

@ -182,6 +182,9 @@ a date in the *future* are not included.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -247,6 +250,21 @@ with a date in the *future* are not displayed.
* ``context_processors``: A list of template-context processors to apply to
the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in
determining the variable's name.
* ``make_object_list``: A boolean specifying whether to retrieve the full
list of objects for this year and pass those to the template. If ``True``,
this list of objects will be made available to the template as
``object_list``. (The name ``object_list`` may be different; see the docs
for ``object_list`` in the "Template context" section below.) By default,
this is ``False``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -259,8 +277,19 @@ In addition to ``extra_context``, the template's context will be:
* ``date_list``: A list of ``datetime.date`` objects representing all
months that have objects available in the given year, according to
``queryset``, in ascending order.
* ``year``: The given year, as a four-character string.
* ``object_list``: If the ``make_object_list`` parameter is ``True``, this
will be set to a list of objects available for the given year, ordered by
the date field. This variable's name depends on the
``template_object_name`` parameter, which is ``'object'`` by default. If
``template_object_name`` is ``'foo'``, this variable's name will be
``foo_list``.
If ``make_object_list`` is ``False``, ``object_list`` will be passed to
the template as an empty list.
``django.views.generic.date_based.archive_month``
-------------------------------------------------
@ -314,6 +343,9 @@ date in the *future* are not displayed.
view will append ``'_list'`` to the value of this parameter in
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -387,6 +419,9 @@ in the *future* are not displayed.
view will append ``'_list'`` to the value of this parameter in
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -463,6 +498,9 @@ a 404 error, regardless of whether any objects exist for future days.
view will append ``'_list'`` to the value of this parameter in
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -563,6 +601,9 @@ A page representing an individual object.
* ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -627,6 +668,9 @@ A page representing a list of objects.
view will append ``'_list'`` to the value of this parameter in
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template
@ -717,6 +761,9 @@ A page representing an individual object.
* ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
**Template name:**
If ``template_name`` isn't specified, this view will use the template

View File

@ -162,11 +162,15 @@ A date field. Has a few extra optional arguments:
====================== ===================================================
``auto_now`` Automatically set the field to now every time the
object is saved. Useful for "last-modified"
timestamps.
timestamps. Note that the current date is *always*
used; it's not just a default value that you can
override.
``auto_now_add`` Automatically set the field to now when the object
is first created. Useful for creation of
timestamps.
timestamps. Note that the current date is *always*
used; it's not just a default value that you can
override.
====================== ===================================================
The admin represents this as an ``<input type="text">`` with a JavaScript
@ -488,6 +492,10 @@ cleared, the object will be deleted.
It is an error to have an inline-editable relation without at least one
``core=True`` field.
Please note that each field marked "core" is treated as a required field by the
Django admin site. Essentially, this means you should put ``core=True`` on all
required fields in your related object that is being edited inline.
``db_column``
~~~~~~~~~~~~~

View File

@ -197,6 +197,22 @@ will be sent on every request.
Similarly, the ``expires`` part of a session cookie is updated each time the
session cookie is sent.
Browser-length sessions vs. persistent sessions
===============================================
You can control whether the session framework uses browser-length sessions vs.
persistent sessions with the ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` setting.
By default, ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``False``, which
means session cookies will be stored in users' browsers for as long as
``SESSION_COOKIE_AGE``. Use this if you don't want people to have to log in
every time they open a browser.
If ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``True``, Django will use
browser-length cookies -- cookies that expire as soon as the user closes his or
her browser. Use this if you want people to have to log in every time they open
a browser.
Settings
========
@ -225,6 +241,14 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
SESSION_EXPIRE_AT_BROWSER_CLOSE
-------------------------------
Default: ``False``
Whether to expire the session when the user closes his or her browser. See
"Browser-length sessions vs. persistent sessions" above.
SESSION_SAVE_EVERY_REQUEST
--------------------------

View File

@ -603,6 +603,14 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
See the `session docs`_.
SESSION_EXPIRE_AT_BROWSER_CLOSE
-------------------------------
Default: ``False``
Whether to expire the session when the user closes his or her browser.
See the `session docs`_.
SESSION_SAVE_EVERY_REQUEST
--------------------------

View File

@ -85,7 +85,7 @@ creating an empty class means "give this object an admin interface using
all the default options."
Now reload the Django admin page to see your changes. Note that you don't have
to restart the development server -- the server will auto-reloads your project,
to restart the development server -- the server will auto-reload your project,
so any modifications code will be seen immediately in your browser.
Explore the free admin functionality

View File

@ -209,13 +209,13 @@ So let's use Django's template system to separate the design from Python::
})
return HttpResponse(t.render(c))
That code loads the template called "polls/index" and passes it a context. The
That code loads the template called "polls/index.html" and passes it a context. The
context is a dictionary mapping template variable names to Python objects.
Reload the page. Now you'll see an error::
TemplateDoesNotExist: Your TEMPLATE_DIRS settings is empty.
Change it to point to at least one template directory.
TemplateDoesNotExist at /polls/
polls/index.html
Ah. There's no template yet. First, create a directory, somewhere on your
filesystem, whose contents Django can access. (Django runs as whatever user

View File

@ -1,5 +1,12 @@
"""
23. Giving models a custom manager
You can use a custom ``Manager`` in a particular model by extending the base
``Manager`` class and instantiating your custom ``Manager`` in your model.
There are two reasons you might want to customize a ``Manager``: to add extra
``Manager`` methods, and/or to modify the initial ``QuerySet`` the ``Manager``
returns.
"""
from django.db import models
@ -19,7 +26,7 @@ class Person(models.Model):
def __repr__(self):
return "%s %s" % (self.first_name, self.last_name)
# An example of a custom manager that sets a core_filter on its lookups.
# An example of a custom manager that sets get_query_set().
class PublishedBookManager(models.Manager):
def get_query_set(self):

View File

@ -1,5 +1,5 @@
"""
3. Giving models custom methods and custom managers
3. Giving models custom methods
Any method you add to a model will be available to instances.
"""

View File

@ -1,7 +1,12 @@
"""
XXX. Callable defaults
31. Callable defaults
???
You can pass callable objects as the ``default`` parameter to a field. When
the object is created without an explicit value passed in, Django will call
the method to determine the default value.
This example uses ``datetime.datetime.now`` as the default for the ``pub_date``
field.
"""
from django.db import models
@ -9,9 +14,9 @@ from datetime import datetime
class Article(models.Model):
headline = models.CharField(maxlength=100, default='Default headline')
pub_date = models.DateTimeField(default = datetime.now)
pub_date = models.DateTimeField(default=datetime.now)
def __repr__(self):
def __str__(self):
return self.headline
API_TESTS = """
@ -43,6 +48,4 @@ API_TESTS = """
>>> d = now - a.pub_date
>>> d.seconds < 5
True
"""

View File

@ -1,5 +1,7 @@
"""
26. A test to check that the model validator works can correctly identify errors in a model.
26. Invalid models
This example exists purely to point out errors in models.
"""
from django.db import models

View File

@ -1,8 +1,7 @@
"""
27. Many-to-many and many-to-one relationships to the same table.
This is a response to bug #1535
28. Many-to-many and many-to-one relationships to the same table
Make sure to set ``related_name`` if you use relationships to the same table.
"""
from django.db import models
@ -14,8 +13,9 @@ class Issue(models.Model):
num = models.IntegerField()
cc = models.ManyToManyField(User, blank=True, related_name='test_issue_cc')
client = models.ForeignKey(User, related_name='test_issue_client')
def __repr__(self):
return "<Issue %d>" % (self.num,)
def __str__(self):
return str(self.num)
class Meta:
ordering = ('num',)
@ -47,20 +47,20 @@ API_TESTS = """
>>> i3.cc.add(r)
>>> from django.db.models.query import Q
>>> Issue.objects.filter(client=r.id)
[<Issue 1>, <Issue 2>]
[<Issue: 1>, <Issue: 2>]
>>> Issue.objects.filter(client=g.id)
[<Issue 3>]
[<Issue: 3>]
>>> Issue.objects.filter(cc__id__exact=g.id)
[]
>>> Issue.objects.filter(cc__id__exact=r.id)
[<Issue 2>, <Issue 3>]
[<Issue: 2>, <Issue: 3>]
# Queries that combine results from the m2m and the m2o relationship.
# 3 ways of saying the same thing:
>>> Issue.objects.filter(Q(cc__id__exact=r.id) | Q(client=r.id))
[<Issue 1>, <Issue 2>, <Issue 3>]
[<Issue: 1>, <Issue: 2>, <Issue: 3>]
>>> Issue.objects.filter(cc__id__exact=r.id) | Issue.objects.filter(client=r.id)
[<Issue 1>, <Issue 2>, <Issue 3>]
[<Issue: 1>, <Issue: 2>, <Issue: 3>]
>>> Issue.objects.filter(Q(client=r.id) | Q(cc__id__exact=r.id))
[<Issue 1>, <Issue 2>, <Issue 3>]
[<Issue: 1>, <Issue: 2>, <Issue: 3>]
"""

View File

@ -1,5 +1,5 @@
"""
26. Many-to-many relationships between the same two tables
27. Many-to-many relationships between the same two tables
In this example, A Person can have many friends, who are also people. Friendship is a
symmetrical relationshiup - if I am your friend, you are my friend.

View File

@ -1,5 +1,7 @@
"""
25. Default manipulators
26. Default manipulators
Each model gets an AddManipulator and ChangeManipulator by default.
"""
from django.db import models

View File

@ -1,6 +1,7 @@
"""
XX. Model inheritance
Model inheritance isn't yet supported.
"""
from django.db import models

View File

@ -1,12 +1,11 @@
"""
20. Object Pagination
Django provides a framework for paginating a list of objects in a few.
This is often useful for dividing search results or long lists of objects
in to easily readable pages.
29. Object pagination
Django provides a framework for paginating a list of objects in a few lines
of code. This is often useful for dividing search results or long lists of
objects into easily readable pages.
"""
from django.db import models
class Article(models.Model):
@ -56,4 +55,13 @@ False
>>> paginator.has_previous_page(1)
True
>>> paginator.first_on_page(0)
1
>>> paginator.first_on_page(1)
6
>>> paginator.last_on_page(0)
5
>>> paginator.last_on_page(1)
9
"""

View File

@ -1,5 +1,7 @@
"""
22. Using properties on models
Use properties on models just like on any other Python object.
"""
from django.db import models

View File

@ -1,5 +1,5 @@
"""
XXX. Transactions
15. Transactions
Django handles transactions in three different ways. The default is to commit
each transaction upon a write, but you can decorate a function to get

View File

@ -1,5 +1,7 @@
"""
XX. Validation
30. Validation
This is an experimental feature!
Each model instance has a validate() method that returns a dictionary of
validation errors in the instance's fields. This method has a side effect