{% if change %}
@@ -82,7 +72,7 @@
{% submit_row %}
{% if add %}
- '
+
{% endif %}
{% if auto_populated_fields %}
diff --git a/django/conf/admin_templates/admin_field_line.html b/django/conf/admin_templates/admin_field_line.html
index 1b3903b71e..cbcac1588c 100644
--- a/django/conf/admin_templates/admin_field_line.html
+++ b/django/conf/admin_templates/admin_field_line.html
@@ -1,36 +1,21 @@
- {% 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 %}
-
- {% field_widget bound_field %}
-
- {% if not bound_field.has_label_first %}
- {% field_label bound_field %}
- {% endif %}
-
- {% if change %}
- {% if bound_field.field.primary_key %}
- {{ bound_field.original_value }}
- {% endif %}
-
- {% if bound_field.raw_id_admin %}
- {% if bound_field.existing_repr %}
- {{ bound_field.existing_repr|truncatewords:"14" }}
- {% endif %}
- {% endif %}
- {% endif %}
-
- {% if bound_field.field.help_text %}
-
- {{bound_field.field.help_text}}
-
- {% endif %}
-
- {% endfor %}
+{% 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 %}
+ {% field_widget bound_field %}
+ {% if not bound_field.has_label_first %}
+ {% field_label bound_field %}
+ {% endif %}
+ {% if change %}
+ {% if bound_field.field.primary_key %}
+ {{ bound_field.original_value }}
+ {% endif %}
+ {% if bound_field.raw_id_admin %}
+ {% if bound_field.existing_repr %} {{ bound_field.existing_repr|truncatewords:"14" }}{% endif %}
+ {% endif %}
+ {% endif %}
+ {% if bound_field.field.help_text %}
{{bound_field.field.help_text}}
{% endif %}
+{% endfor %}
diff --git a/django/core/cache.py b/django/core/cache.py
index cbf02f2f3b..6391304158 100644
--- a/django/core/cache.py
+++ b/django/core/cache.py
@@ -15,7 +15,7 @@ The CACHE_BACKEND setting is a quasi-URI; examples are:
memcached://127.0.0.1:11211/ A memcached backend; the server is running
on localhost port 11211.
- db://tablename/ A database backend in a table named
+ db://tablename/ A database backend in a table named
"tablename". This table should be created
with "django-admin createcachetable".
@@ -26,7 +26,7 @@ The CACHE_BACKEND setting is a quasi-URI; examples are:
probably don't want to use this except for
testing. Note that this cache backend is
NOT threadsafe!
-
+
locmem:/// A more sophisticaed local memory cache;
this is multi-process- and thread-safe.
@@ -72,7 +72,6 @@ class InvalidCacheBackendError(Exception):
################################
class _Cache:
-
def __init__(self, params):
timeout = params.get('timeout', 300)
try:
@@ -132,8 +131,7 @@ except ImportError:
_MemcachedCache = None
else:
class _MemcachedCache(_Cache):
- """Memcached cache backend."""
-
+ "Memcached cache backend."
def __init__(self, server, params):
_Cache.__init__(self, params)
self._cache = memcache.Client([server])
@@ -161,8 +159,7 @@ else:
import time
class _SimpleCache(_Cache):
- """Simple single-process in-memory cache"""
-
+ "Simple single-process in-memory cache."
def __init__(self, host, params):
_Cache.__init__(self, params)
self._cache = {}
@@ -230,11 +227,11 @@ try:
import cPickle as pickle
except ImportError:
import pickle
+import copy
from django.utils.synch import RWLock
class _LocMemCache(_SimpleCache):
- """Thread-safe in-memory cache"""
-
+ "Thread-safe in-memory cache."
def __init__(self, host, params):
_SimpleCache.__init__(self, host, params)
self._lock = RWLock()
@@ -250,7 +247,7 @@ class _LocMemCache(_SimpleCache):
elif exp < now:
should_delete = True
else:
- return self._cache[key]
+ return copy.deepcopy(self._cache[key])
finally:
self._lock.reader_leaves()
if should_delete:
@@ -261,14 +258,14 @@ class _LocMemCache(_SimpleCache):
return default
finally:
self._lock.writer_leaves()
-
+
def set(self, key, value, timeout=None):
self._lock.writer_enters()
try:
_SimpleCache.set(self, key, value, timeout)
finally:
self._lock.writer_leaves()
-
+
def delete(self, key):
self._lock.writer_enters()
try:
@@ -284,8 +281,7 @@ import os
import urllib
class _FileCache(_SimpleCache):
- """File-based cache"""
-
+ "File-based cache."
def __init__(self, dir, params):
self._dir = dir
if not os.path.exists(self._dir):
@@ -293,7 +289,7 @@ class _FileCache(_SimpleCache):
_SimpleCache.__init__(self, dir, params)
del self._cache
del self._expire_info
-
+
def get(self, key, default=None):
fname = self._key_to_file(key)
try:
@@ -308,7 +304,7 @@ class _FileCache(_SimpleCache):
except (IOError, pickle.PickleError):
pass
return default
-
+
def set(self, key, value, timeout=None):
fname = self._key_to_file(key)
if timeout is None:
@@ -327,16 +323,16 @@ class _FileCache(_SimpleCache):
pickle.dump(value, f, 2)
except (IOError, OSError):
raise
-
+
def delete(self, key):
try:
os.remove(self._key_to_file(key))
except (IOError, OSError):
pass
-
+
def has_key(self, key):
return os.path.exists(self._key_to_file(key))
-
+
def _cull(self, filelist):
if self.cull_frequency == 0:
doomed = filelist
@@ -348,7 +344,7 @@ class _FileCache(_SimpleCache):
except (IOError, OSError):
pass
- def _createdir(self):
+ def _createdir(self):
try:
os.makedirs(self._dir)
except OSError:
@@ -366,22 +362,21 @@ from django.core.db import db, DatabaseError
from datetime import datetime
class _DBCache(_Cache):
- """SQL cache backend"""
-
+ "SQL cache backend."
def __init__(self, table, params):
_Cache.__init__(self, params)
self._table = table
- max_entries = params.get('max_entries', 300)
- try:
- self._max_entries = int(max_entries)
- except (ValueError, TypeError):
- self._max_entries = 300
- cull_frequency = params.get('cull_frequency', 3)
- try:
- self._cull_frequency = int(cull_frequency)
- except (ValueError, TypeError):
- self._cull_frequency = 3
-
+ max_entries = params.get('max_entries', 300)
+ try:
+ self._max_entries = int(max_entries)
+ except (ValueError, TypeError):
+ self._max_entries = 300
+ cull_frequency = params.get('cull_frequency', 3)
+ try:
+ self._cull_frequency = int(cull_frequency)
+ except (ValueError, TypeError):
+ self._cull_frequency = 3
+
def get(self, key, default=None):
cursor = db.cursor()
cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
@@ -394,7 +389,7 @@ class _DBCache(_Cache):
db.commit()
return default
return pickle.loads(base64.decodestring(row[1]))
-
+
def set(self, key, value, timeout=None):
if timeout is None:
timeout = self.default_timeout
@@ -417,17 +412,17 @@ class _DBCache(_Cache):
pass
else:
db.commit()
-
+
def delete(self, key):
cursor = db.cursor()
cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
db.commit()
-
+
def has_key(self, key):
cursor = db.cursor()
cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
return cursor.fetchone() is not None
-
+
def _cull(self, cursor, now):
if self._cull_frequency == 0:
cursor.execute("DELETE FROM %s" % self._table)
@@ -438,7 +433,7 @@ class _DBCache(_Cache):
if num > self._max_entries:
cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % self._table, [num / self._cull_frequency])
cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % self._table, [cursor.fetchone()[0]])
-
+
##########################################
# Read settings and load a cache backend #
##########################################
diff --git a/django/core/db/backends/mysql.py b/django/core/db/backends/mysql.py
index 2e77adbc43..af0dbca6c0 100644
--- a/django/core/db/backends/mysql.py
+++ b/django/core/db/backends/mysql.py
@@ -143,6 +143,7 @@ DATA_TYPES = {
'DateTimeField': 'datetime',
'EmailField': 'varchar(75)',
'FileField': 'varchar(100)',
+ 'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
diff --git a/django/core/db/backends/postgresql.py b/django/core/db/backends/postgresql.py
index 683ae3c9ee..6ec7bfbfcb 100644
--- a/django/core/db/backends/postgresql.py
+++ b/django/core/db/backends/postgresql.py
@@ -154,6 +154,7 @@ DATA_TYPES = {
'DateTimeField': 'timestamp with time zone',
'EmailField': 'varchar(75)',
'FileField': 'varchar(100)',
+ 'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
diff --git a/django/core/db/backends/sqlite3.py b/django/core/db/backends/sqlite3.py
index d4b936f82e..ea05302a61 100644
--- a/django/core/db/backends/sqlite3.py
+++ b/django/core/db/backends/sqlite3.py
@@ -154,6 +154,7 @@ DATA_TYPES = {
'DateTimeField': 'datetime',
'EmailField': 'varchar(75)',
'FileField': 'varchar(100)',
+ 'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
diff --git a/django/core/formfields.py b/django/core/formfields.py
index ca35957a5e..03760e0e19 100644
--- a/django/core/formfields.py
+++ b/django/core/formfields.py
@@ -822,6 +822,29 @@ class IPAddressField(TextField):
# MISCELLANEOUS #
####################
+class FilePathField(SelectField):
+ "A SelectField whose choices are the files in a given directory."
+ def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[]):
+ import os
+ if match is not None:
+ import re
+ match_re = re.compile(match)
+ choices = []
+ if recursive:
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if match is None or match_re.search(f):
+ choices.append((os.path.join(path, f), f))
+ else:
+ try:
+ for f in os.listdir(path):
+ full_file = os.path.join(path, f)
+ if os.path.isfile(full_file) and (match is None or match_re.search(f)):
+ choices.append((full_file, f))
+ except OSError:
+ pass
+ SelectField.__init__(self, field_name, choices, 1, is_required, validator_list)
+
class PhoneNumberField(TextField):
"A convenience FormField for validating phone numbers (e.g. '630-555-1234')"
def __init__(self, field_name, is_required=False, validator_list=[]):
diff --git a/django/core/management.py b/django/core/management.py
index afb498ae63..49f447cc74 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -144,6 +144,10 @@ def get_sql_delete(mod):
for row in cursor.fetchall():
output.append("DELETE FROM auth_admin_log WHERE content_type_id = %s;" % row[0])
+ # Close database connection explicitly, in case this output is being piped
+ # directly into a database client, to avoid locking issues.
+ db.db.close()
+
return output[::-1] # Reverse it, to deal with table dependencies.
get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given model module name(s)."
get_sql_delete.args = APP_ARGS
@@ -636,8 +640,9 @@ def runserver(addr, port):
sys.exit(1)
except KeyboardInterrupt:
sys.exit(0)
- from django.utils import autoreload
- autoreload.main(inner_run)
+ #from django.utils import autoreload
+ #autoreload.main(inner_run)
+ inner_run()
runserver.args = '[optional port number, or ipaddr:port]'
def createcachetable(tablename):
diff --git a/django/core/meta/__init__.py b/django/core/meta/__init__.py
index 2670a36b52..7f32913fbc 100644
--- a/django/core/meta/__init__.py
+++ b/django/core/meta/__init__.py
@@ -232,10 +232,8 @@ class RelatedObject(object):
count = min(count, self.field.rel.max_num_in_admin)
else:
count = self.field.rel.num_in_admin
-
+
fields = []
-
-
for i in range(count):
for f in self.opts.fields + self.opts.many_to_many:
if follow.get(f.name, False):
@@ -424,27 +422,20 @@ class Options:
return [RelatedObject(self, opts, field) for opts, field in self.get_all_related_objects()]
def get_data_holders(self, follow=None):
+ if follow == None :
+ follow = self.get_follow()
return [f for f in self.fields + self.many_to_many + self.get_all_related_objects_wrapped() if follow.get(f.name, None) ]
def get_follow(self, override=None):
follow = {}
-
- for f in self.fields + self.many_to_many:
+ for f in self.fields + self.many_to_many + self.get_all_related_objects_wrapped():
if override and override.has_key(f.name):
- fol = override[f.name]
+ child_override = override[f.name]
else:
- fol = f.editable
+ child_override = None
+ fol = f.get_follow(child_override)
if fol:
follow[f.name] = fol
-
- for f in self.get_all_related_objects_wrapped():
- if override and override.has_key(f.name):
- fol = f.get_follow(override[f.name])
- else:
- fol = f.get_follow(None)
- if fol:
- follow[f.name] = fol
-
return follow
def get_all_related_many_to_many_objects(self):
@@ -478,6 +469,7 @@ class Options:
Returns True if this object's admin form has at least one of the given
field_type (e.g. FileField).
"""
+ #TODO: follow
if not hasattr(self, '_field_types'):
self._field_types = {}
if not self._field_types.has_key(field_type):
diff --git a/django/core/meta/fields.py b/django/core/meta/fields.py
index 556d8a0a7f..9fa250a96d 100644
--- a/django/core/meta/fields.py
+++ b/django/core/meta/fields.py
@@ -290,7 +290,12 @@ class Field(object):
values from.
"""
return { self.get_db_column(): self._get_val_from_obj(obj)}
-
+
+ def get_follow(self, override=None):
+ if override:
+ return override
+ else:
+ return self.editable
class AutoField(Field):
empty_strings_allowed = False
@@ -463,6 +468,14 @@ class FileField(Field):
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
return os.path.normpath(f)
+class FilePathField(Field):
+ def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
+ self.path, self.match, self.recursive = path, match, recursive
+ Field.__init__(self, verbose_name, name, **kwargs)
+
+ def get_manipulator_field_objs(self):
+ return [curry(formfields.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
+
class FloatField(Field):
empty_strings_allowed = False
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
diff --git a/django/middleware/cache.py b/django/middleware/cache.py
index 8216c40ae1..04f98122f7 100644
--- a/django/middleware/cache.py
+++ b/django/middleware/cache.py
@@ -1,4 +1,3 @@
-import copy
from django.conf import settings
from django.core.cache import cache
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers
@@ -49,7 +48,7 @@ class CacheMiddleware:
return None # No cache information available, need to rebuild.
request._cache_update_cache = False
- return copy.copy(response)
+ return response
def process_response(self, request, response):
"Sets the cache, if needed."
diff --git a/django/templatetags/admin_modify.py b/django/templatetags/admin_modify.py
index 040834126a..5ec7a8381a 100644
--- a/django/templatetags/admin_modify.py
+++ b/django/templatetags/admin_modify.py
@@ -8,7 +8,7 @@ from django.utils.functional import curry
from django.core.template_decorators import simple_tag, inclusion_tag
from django.views.admin.main import AdminBoundField
-from django.core.meta.fields import BoundField
+from django.core.meta.fields import BoundField, Field
import re
word_re = re.compile('[A-Z][a-z]+')
@@ -24,7 +24,7 @@ include_admin_script = simple_tag(include_admin_script)
#@inclusion_tag('admin_submit_line', takes_context=True)
-def submit_row(context):
+def submit_row(context):
change = context['change']
add = context['add']
show_delete = context['show_delete']
@@ -68,41 +68,43 @@ field_label = simple_tag(field_label)
class FieldWidgetNode(template.Node):
+ nodelists = {}
+ default = None
+
def __init__(self, bound_field_var):
self.bound_field_var = bound_field_var
- self.nodelists = {}
- t = template_loader.get_template("widget/default")
- self.default = t.nodelist
+ def get_nodelist(cls, klass):
+ if not cls.nodelists.has_key(klass):
+ try:
+ field_class_name = klass.__name__
+ template_name = "widget/%s" % \
+ class_name_to_underscored(field_class_name)
+ nodelist = template_loader.get_template(template_name).nodelist
+ except template.TemplateDoesNotExist:
+ super_klass = bool(klass.__bases__) and klass.__bases__[0] or None
+ if super_klass and super_klass != Field:
+ nodelist = cls.get_nodelist(super_klass)
+ else:
+ if not cls.default:
+ cls.default = template_loader.get_template("widget/default").nodelist
+ nodelist = cls.default
+
+ cls.nodelists[klass] = nodelist
+ return nodelist
+ else:
+ return cls.nodelists[klass]
+ get_nodelist = classmethod(get_nodelist)
+
+
def render(self, context):
bound_field = template.resolve_variable(self.bound_field_var, context)
- add = context['add']
- change = context['change']
context.push()
context['bound_field'] = bound_field
- klass = bound_field.field.__class__
- if not self.nodelists.has_key(klass):
- t = None
- while klass:
- try:
- field_class_name = klass.__name__
- template_name = "widget/%s" % \
- class_name_to_underscored(field_class_name)
- t = template_loader.get_template(template_name)
- break
- except template.TemplateDoesNotExist:
- klass = bool(klass.__bases__) and klass.__bases__[0] or None
-
- if t == None:
- nodelist = self.default
- else:
- nodelist = t.nodelist
-
- self.nodelists[klass] = nodelist
-
- output = self.nodelists[klass].render(context)
+
+ output = self.get_nodelist(bound_field.field.__class__).render(context)
context.pop()
return output
diff --git a/django/utils/decorators.py b/django/utils/decorators.py
index b21a4e4248..1333f9da88 100644
--- a/django/utils/decorators.py
+++ b/django/utils/decorators.py
@@ -12,6 +12,10 @@ def decorator_from_middleware(middleware_class):
result = middleware.process_request(request)
if result is not None:
return result
+ if hasattr(middleware, 'process_view'):
+ result = middleware.process_view(request, view_func, **kwargs)
+ if result is not None:
+ return result
response = view_func(request, *args, **kwargs)
if hasattr(middleware, 'process_response'):
result = middleware.process_response(request, response)
diff --git a/django/views/admin/main.py b/django/views/admin/main.py
index fc24b590ef..fcce2533cc 100644
--- a/django/views/admin/main.py
+++ b/django/views/admin/main.py
@@ -605,6 +605,7 @@ class AdminBoundFieldSet(BoundFieldSet):
def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''):
admin_field_objs = opts.admin.get_field_objs(opts)
+
ordered_objects = opts.get_ordered_objects()[:]
auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
@@ -621,9 +622,13 @@ def fill_extra_context(opts, app_label, context, add=False, change=False, show_d
form = context['form']
original = context['original']
+
+ field_sets = opts.admin.get_field_sets(opts)
bound_field_sets = [field_set.bind(form, original, AdminBoundFieldSet)
- for field_set in opts.admin.get_field_sets(opts)]
-
+ for field_set in field_sets]
+
+ first_form_field = bound_field_sets[0].bound_field_lines[0].bound_fields[0].form_fields[0];
+
inline_related_objects = opts.get_inline_related_objects_wrapped()
ordered_object_names = ' '.join(['object.%s' % o.pk.name for o in ordered_objects])
@@ -631,6 +636,7 @@ def fill_extra_context(opts, app_label, context, add=False, change=False, show_d
extra_context = {
'add': add,
'change': change,
+ 'first_form_field_id': first_form_field.get_id(),
'ordered_objects' : ordered_objects,
'ordered_object_names' : ordered_object_names,
'auto_populated_fields' : auto_populated_fields,
@@ -643,7 +649,8 @@ def fill_extra_context(opts, app_label, context, add=False, change=False, show_d
'inline_related_objects': inline_related_objects,
'content_type_id' : opts.get_content_type_id(),
'save_on_top' : opts.admin.save_on_top,
- 'verbose_name_plural': opts.verbose_name_plural,
+ 'verbose_name_plural': opts.verbose_name_plural,
+ 'verbose_name': opts.verbose_name,
'save_as': opts.admin.save_as,
'app_label': app_label,
'object_name': opts.object_name,
@@ -711,7 +718,7 @@ def add_stage_new(request, app_label, module_name, show_delete=False, form_url='
c['object_id'] = object_id_override
- fill_extra_context(opts, app_label, c, change=False)
+ fill_extra_context(opts, app_label, c, add=True)
return render_to_response("admin_change_form", context_instance=c)
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
index 6328b7097a..f4cdf90c56 100644
--- a/django/views/generic/list_detail.py
+++ b/django/views/generic/list_detail.py
@@ -32,6 +32,8 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F
the previous page
pages
number of pages, total
+ hits
+ number of objects, total
"""
mod = models.get_module(app_label, module_name)
lookup_kwargs = extra_lookup_kwargs.copy()
@@ -56,6 +58,7 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F
'next': page + 1,
'previous': page - 1,
'pages': paginator.pages,
+ 'hits' : paginator.hits,
})
else:
object_list = mod.get_list(**lookup_kwargs)
diff --git a/docs/db-api.txt b/docs/db-api.txt
index 8a02437aaa..b80d4e8647 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -449,8 +449,7 @@ Related objects (e.g. ``Choices``) are created using convenience functions::
>>> p.get_choice_count()
4
-Each of those ``add_choice`` methods is equivalent to (except obviously much
-simpler than)::
+Each of those ``add_choice`` methods is equivalent to (but much simpler than)::
>>> c = polls.Choice(poll_id=p.id, choice="Over easy", votes=0)
>>> c.save()
@@ -459,6 +458,8 @@ Note that when using the `add_foo()`` methods, you do not give any value
for the ``id`` field, nor do you give a value for the field that stores
the relation (``poll_id`` in this case).
+The ``add_FOO()`` method always returns the newly created object.
+
Deleting objects
================
diff --git a/docs/generic_views.txt b/docs/generic_views.txt
index 62e7c14e2b..1c0de07a7a 100644
--- a/docs/generic_views.txt
+++ b/docs/generic_views.txt
@@ -115,7 +115,7 @@ The date-based generic functions are:
Yearly archive. Requires that the ``year`` argument be present in the URL
pattern.
- Uses the template ``app_label/module_name__archive_year`` by default.
+ Uses the template ``app_label/module_name_archive_year`` by default.
Has the following template context:
@@ -134,7 +134,7 @@ The date-based generic functions are:
default, which is a three-letter month abbreviation. To change it to use
numbers, use ``"%m"``.
- Uses the template ``app_label/module_name__archive_month`` by default.
+ Uses the template ``app_label/module_name_archive_month`` by default.
Has the following template context:
@@ -151,7 +151,7 @@ The date-based generic functions are:
also pass ``day_format``, which defaults to ``"%d"`` (day of the month as a
decimal number, 1-31).
- Uses the template ``app_label/module_name__archive_day`` by default.
+ Uses the template ``app_label/module_name_archive_day`` by default.
Has the following template context:
@@ -246,6 +246,8 @@ Individual views are:
The previous page
``pages``
Number of pages total
+ ``hits``
+ Total number of objects
``object_detail``
Object detail page. This works like and takes the same arguments as
@@ -272,7 +274,7 @@ The create/update/delete views are:
be interpolated against the object's field attributes. For example, you
could use ``post_save_redirect="/polls/%(slug)s/"``.
- Uses the template ``app_label/module_name__form`` by default. This is the
+ Uses the template ``app_label/module_name_form`` by default. This is the
same template as the ``update_object`` view below. Your template can tell
the different by the presence or absence of ``{{ object }}`` in the
context.
@@ -294,7 +296,7 @@ The create/update/delete views are:
``list_detail.object_detail`` does (see above), and the same
``post_save_redirect`` as ``create_object`` does.
- Uses the template ``app_label/module_name__form`` by default.
+ Uses the template ``app_label/module_name_form`` by default.
Has the following template context:
diff --git a/docs/install.txt b/docs/install.txt
index b347006cbb..b18d26d5c8 100644
--- a/docs/install.txt
+++ b/docs/install.txt
@@ -21,14 +21,15 @@ See `How to use Django with mod_python`_ for information on how to configure
mod_python once you have it installed.
If you can't use mod_python for some reason, fear not: Django follows the WSGI_
-spec, which allows it to run on a variety of server platforms. As people
-experiment with different server platforms, we'll update this document to
-give specific installation instructions for each platform.
+spec, which allows it to run on a variety of server platforms. See the
+`server-arrangements wiki page`_ for specific installation instructions for
+each platform.
.. _Apache: http://httpd.apache.org/
.. _mod_python: http://www.modpython.org/
.. _WSGI: http://www.python.org/peps/pep-0333.html
.. _How to use Django with mod_python: http://www.djangoproject.com/documentation/modpython/
+.. _server-arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements
Get your database running
=========================
@@ -37,11 +38,6 @@ If you plan to use Django's database API functionality, you'll need to
make sure a database server is running. Django works with PostgreSQL_
(recommended), MySQL_ and SQLite_.
-Note that support for MySQL and SQLite is a recent development, and Django
-hasn't been comprehensively tested in those environments. If you find any bugs
-in Django's MySQL or SQLite bindings, please file them in
-`Django's ticket system`_ so we can fix them immediately.
-
Additionally, you'll need to make sure your Python database bindings are
installed.
diff --git a/docs/model-api.txt b/docs/model-api.txt
index 4af193ca48..140518e80e 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -95,8 +95,8 @@ The following arguments are available to all field types. All are optional.
('GR', 'Graduate'),
)
- The first element in each tuple is the actual value to be stored. The
- second element is the human-readable name for the option.
+ The first element in each tuple is the actual value to be stored. The
+ second element is the human-readable name for the option.
``core``
For objects that are edited inline to a related object.
@@ -248,18 +248,18 @@ Here are all available field types:
uploaded files don't fill up the given directory).
The admin represents this as an ```` (a file-upload widget).
-
- Using a `FieldField` or an ``ImageField`` (see below) in a model takes a few
+
+ Using a `FieldField` or an ``ImageField`` (see below) in a model takes a few
steps:
-
+
1. In your settings file, you'll need to define ``MEDIA_ROOT``as the
full path to a directory where you'd like Django to store uploaded
files. (For performance, these files are not stored in the database.)
Define ``MEDIA_URL`` as the base public URL of that directory. Make
sure that this directory is writable by the Web server's user
account.
-
- 2. Add the ``FileField`` or ``ImageField`` to your model, making sure
+
+ 2. Add the ``FileField`` or ``ImageField`` to your model, making sure
to define the ``upload_to`` option to tell Django to which
subdirectory of ``MEDIA_ROOT`` it should upload files.
@@ -269,9 +269,44 @@ Here are all available field types:
example, if your ``ImageField`` is called ``mug_shot``, you can get
the absolute URL to your image in a template with ``{{
object.get_mug_shot_url }}``.
-
+
.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
+``FilePathField``
+ A field whose choices are limited to the filenames in a certain directory
+ on the filesystem. Has three special arguments, of which the first is
+ required:
+
+ ====================== ===================================================
+ Argument Description
+ ====================== ===================================================
+ ``path`` Required. The absolute filesystem path to a
+ directory from which this ``FilePathField`` should
+ get its choices. Example: ``"/home/images"``.
+
+ ``match`` Optional. A regular expression, as a string, that
+ ``FilePathField`` will use to filter filenames.
+ Note that the regex will be applied to the
+ base filename, not the full path. Example:
+ ``"foo.*\.txt^"``, which will match a file called
+ ``foo23.txt`` but not ``bar.txt`` or ``foo23.gif``.
+
+ ``recursive`` Optional. Either ``True`` or ``False``. Default is
+ ``False``. Specifies whether all subdirectories of
+ ``path`` should be included.
+ ====================== ===================================================
+
+ Of course, these arguments can be used together.
+
+ The one potential gotcha is that ``match`` applies to the base filename,
+ not the full path. So, this example::
+
+ FilePathField(path="/home/images", match="foo.*", recursive=True)
+
+ ...will match ``/home/images/foo.gif`` but not ``/home/images/foo/bar.gif``
+ because the ``match`` applies to the base filename (``foo.gif`` and
+ ``bar.gif``).
+
``FloatField``
A floating-point number. Has two **required** arguments:
@@ -302,7 +337,7 @@ Here are all available field types:
width of the image each time a model instance is saved.
Requires the `Python Imaging Library`_.
-
+
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
``IntegerField``
@@ -721,7 +756,9 @@ Here's a list of all possible ``META`` options. No options are required. Adding
unique_together = (("driver", "restaurant"),)
This is a list of lists of fields that must be unique when considered
- together. It's used in the Django admin.
+ together. It's used in the Django admin and is enforced at the database
+ level (i.e., the appropriate ``UNIQUE`` statements are included in the
+ ``CREATE TABLE`` statement).
``verbose_name``
A human-readable name for the object, singular::
diff --git a/docs/modpython.txt b/docs/modpython.txt
index 72c2d9a073..0f54de86ac 100644
--- a/docs/modpython.txt
+++ b/docs/modpython.txt
@@ -143,6 +143,9 @@ particular part of the site::
Just change ``Location`` to the root URL of your media files.
+Note that the Django development server automagically serves admin media files,
+but this is not the case when you use any other server arrangement.
+
.. _lighttpd: http://www.lighttpd.net/
.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
.. _Apache: http://httpd.apache.org/