Permalink
Browse files

[multi-db] Merged trunk to [4158]. Some tests still failing.

  • Loading branch information...
jpellerin committed Dec 4, 2006
1 parent 0162eac commit 55d7f6519c8d13a685cff3f9873b5784fc511a87
View
@@ -151,6 +151,7 @@ answer newbie questions, and generally made Django that much better:
SmileyChris <smileychris@gmail.com>
sopel
Thomas Steinacher <tom@eggdrop.ch>
+ nowell strite
Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/>
@@ -2,7 +2,7 @@
urlpatterns = patterns('',
# Example:
- # (r'^{{ project_name }}/', include('{{ project_name }}.apps.foo.urls.foo')),
+ # (r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls')),
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
-<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemapindex/0.9">
+<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %}
</sitemapindex>
@@ -84,7 +84,11 @@ def get_response(self, request):
# Complain if the view returned None (a common error).
if response is None:
- raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, callback.func_name)
+ try:
+ view_name = callback.func_name # If it's a function
+ except AttributeError:
+ view_name = callback.__class__.__name__ + '.__call__' # If it's a class
+ raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)
return response
except http.Http404, e:
@@ -62,7 +62,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
data in the body.
"""
if not size:
- return copyfileobj(fsrc, fdst, length)
+ return
while size > 0:
buf = fsrc.read(min(length, size))
if not buf:
@@ -157,8 +157,11 @@ def _get_raw_post_data(self):
return self._raw_post_data
except AttributeError:
buf = StringIO()
- # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd)
- content_length = int(self.environ.get('CONTENT_LENGTH', 0))
+ try:
+ # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd)
+ content_length = int(self.environ.get('CONTENT_LENGTH', 0))
+ except ValueError: # if CONTENT_LENGTH was empty string or not an integer
+ content_length = 0
safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length)
self._raw_post_data = buf.getvalue()
buf.close()
@@ -457,9 +457,7 @@ def get_follow(self, override=None):
def get_db_prep_save(self, value):
# Casts dates into string format for entry into database.
- if isinstance(value, datetime.datetime):
- value = value.date().strftime('%Y-%m-%d')
- elif isinstance(value, datetime.date):
+ if value is not None:
value = value.strftime('%Y-%m-%d')
return Field.get_db_prep_save(self, value)
@@ -489,7 +487,7 @@ def to_python(self, value):
def pre_save(self, model_instance, add):
value = super(DateField, self).pre_save(model_instance, add)
- if isinstance(value, datetime.datetime):
+ if value is not None:
# MySQL will throw a warning if microseconds are given, because it
# doesn't support microseconds.
settings = model_instance._default_manager.db.connection.settings
@@ -501,13 +499,6 @@ def get_db_prep_save(self, value):
# Casts dates into string format for entry into database.
if value is not None:
value = str(value)
- elif isinstance(value, datetime.date):
- # MySQL will throw a warning if microseconds are given, because it
- # doesn't support microseconds.
- if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
- value = datetime.datetime(value.year, value.month, value.day, microsecond=0)
- value = str(value)
-
return Field.get_db_prep_save(self, value)
def get_db_prep_lookup(self, lookup_type, value):
View
@@ -208,7 +208,7 @@ def delete_cookie(self, key, path='/', domain=None):
if path is not None:
self.cookies[key]['path'] = path
if domain is not None:
- self.cookies[key]['domain'] = path
+ self.cookies[key]['domain'] = domain
self.cookies[key]['expires'] = 0
self.cookies[key]['max-age'] = 0
@@ -14,15 +14,4 @@
from widgets import *
from fields import *
from forms import Form
-
-##########################
-# DATABASE API SHORTCUTS #
-##########################
-
-def form_for_model(model):
- "Returns a Form instance for the given Django model class."
- raise NotImplementedError
-
-def form_for_fields(field_list):
- "Returns a Form instance for the given list of Django database field instances."
- raise NotImplementedError
+from models import *
View
@@ -76,6 +76,8 @@ def clean(self, value):
of int().
"""
super(IntegerField, self).clean(value)
+ if not self.required and value in EMPTY_VALUES:
+ return u''
try:
return int(value)
except (ValueError, TypeError):
@@ -170,6 +172,8 @@ def clean(self, value):
Field.clean(self, value)
if value in EMPTY_VALUES: value = u''
value = smart_unicode(value)
+ if not self.required and value == u'':
+ return value
if not self.regex.search(value):
raise ValidationError(self.error_message)
return value
@@ -246,6 +250,8 @@ def clean(self, value):
value = Field.clean(self, value)
if value in EMPTY_VALUES: value = u''
value = smart_unicode(value)
+ if not self.required and value == u'':
+ return value
valid_values = set([str(k) for k, v in self.choices])
if value not in valid_values:
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
@@ -259,10 +265,12 @@ def clean(self, value):
"""
Validates that the input is a list or tuple.
"""
- if not isinstance(value, (list, tuple)):
- raise ValidationError(u'Enter a list of values.')
if self.required and not value:
raise ValidationError(u'This field is required.')
+ elif not self.required and not value:
+ return []
+ if not isinstance(value, (list, tuple)):
+ raise ValidationError(u'Enter a list of values.')
new_value = []
for val in value:
val = smart_unicode(val)
@@ -277,6 +285,11 @@ def clean(self, value):
class ComboField(Field):
def __init__(self, fields=(), required=True, widget=None):
Field.__init__(self, required, widget)
+ # Set 'required' to False on the individual fields, because the
+ # required validation will be handled by ComboField, not by those
+ # individual fields.
+ for f in fields:
+ f.required = False
self.fields = fields
def clean(self, value):
View
@@ -3,8 +3,9 @@
"""
from django.utils.datastructures import SortedDict
+from django.utils.html import escape
from fields import Field
-from widgets import TextInput, Textarea
+from widgets import TextInput, Textarea, HiddenInput
from util import ErrorDict, ErrorList, ValidationError
NON_FIELD_ERRORS = '__all__'
@@ -36,6 +37,7 @@ class Form(object):
__metaclass__ = DeclarativeFieldsMetaclass
def __init__(self, data=None, auto_id=False): # TODO: prefix stuff
+ self.ignore_errors = data is None
self.data = data or {}
self.auto_id = auto_id
self.clean_data = None # Stores the data after clean() has been called.
@@ -56,69 +58,78 @@ def __getitem__(self, name):
raise KeyError('Key %r not found in Form' % name)
return BoundField(self, field, name)
- def clean(self):
- if self.__errors is None:
- self.full_clean()
- return self.clean_data
-
- def errors(self):
+ def _errors(self):
"Returns an ErrorDict for self.data"
if self.__errors is None:
self.full_clean()
return self.__errors
+ errors = property(_errors)
def is_valid(self):
"""
- Returns True if the form has no errors. Otherwise, False. This exists
- solely for convenience, so client code can use positive logic rather
- than confusing negative logic ("if not form.errors()").
+ Returns True if the form has no errors. Otherwise, False. If errors are
+ being ignored, returns False.
"""
- return not bool(self.errors())
+ return not self.ignore_errors and not bool(self.errors)
def as_table(self):
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
- return u'\n'.join(['<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])
-
- def as_ul(self):
- "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
- return u'\n'.join(['<li>%s: %s</li>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])
-
- def as_table_with_errors(self):
- "Returns this form rendered as HTML <tr>s, with errors."
output = []
- if self.errors().get(NON_FIELD_ERRORS):
+ if self.errors.get(NON_FIELD_ERRORS):
# Errors not corresponding to a particular field are displayed at the top.
- output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]]))
+ output.append(u'<tr><td colspan="2">%s</td></tr>' % self.non_field_errors())
for name, field in self.fields.items():
bf = BoundField(self, field, name)
- if bf.errors:
- output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors]))
- output.append('<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), bf))
+ if bf.is_hidden:
+ if bf.errors:
+ new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors])
+ output.append(u'<tr><td colspan="2">%s</td></tr>' % new_errors)
+ output.append(str(bf))
+ else:
+ if bf.errors:
+ output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors)
+ output.append(u'<tr><td>%s</td><td>%s</td></tr>' % (bf.label_tag(escape(bf.verbose_name+':')), bf))
return u'\n'.join(output)
- def as_ul_with_errors(self):
- "Returns this form rendered as HTML <li>s, with errors."
+ def as_ul(self):
+ "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
output = []
- if self.errors().get(NON_FIELD_ERRORS):
+ if self.errors.get(NON_FIELD_ERRORS):
# Errors not corresponding to a particular field are displayed at the top.
- output.append('<li><ul>%s</ul></li>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]]))
+ output.append(u'<li>%s</li>' % self.non_field_errors())
for name, field in self.fields.items():
bf = BoundField(self, field, name)
- line = '<li>'
- if bf.errors:
- line += '<ul>%s</ul>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors])
- line += '%s: %s</li>' % (pretty_name(name), bf)
- output.append(line)
+ if bf.is_hidden:
+ if bf.errors:
+ new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors])
+ output.append(u'<li>%s</li>' % new_errors)
+ output.append(str(bf))
+ else:
+ output.append(u'<li>%s%s %s</li>' % (bf.errors, bf.label_tag(escape(bf.verbose_name+':')), bf))
return u'\n'.join(output)
+ def non_field_errors(self):
+ """
+ Returns an ErrorList of errors that aren't associated with a particular
+ field -- i.e., from Form.clean(). Returns an empty ErrorList if there
+ are none.
+ """
+ return self.errors.get(NON_FIELD_ERRORS, ErrorList())
+
def full_clean(self):
"""
Cleans all of self.data and populates self.__errors and self.clean_data.
"""
self.clean_data = {}
errors = ErrorDict()
+ if self.ignore_errors: # Stop further processing.
+ self.__errors = errors
+ return
for name, field in self.fields.items():
- value = self.data.get(name, None)
+ # value_from_datadict() gets the data from the dictionary.
+ # Each widget type knows how to retrieve its own data, because some
+ # widgets split data over several HTML fields.
+ value = field.widget.value_from_datadict(self.data, name)
try:
value = field.clean(value)
self.clean_data[name] = value
@@ -138,7 +149,9 @@ def full_clean(self):
def clean(self):
"""
Hook for doing any extra form-wide cleaning after Field.clean() been
- called on every field.
+ called on every field. Any ValidationError raised by this method will
+ not be associated with a particular field; it will have a special-case
+ association with the field named '__all__'.
"""
return self.clean_data
@@ -153,25 +166,31 @@ def __str__(self):
"Renders this field as an HTML widget."
# Use the 'widget' attribute on the field to determine which type
# of HTML widget to use.
- return self.as_widget(self._field.widget)
+ value = self.as_widget(self._field.widget)
+ if not isinstance(value, basestring):
+ # Some Widget render() methods -- notably RadioSelect -- return a
+ # "special" object rather than a string. Call the __str__() on that
+ # object to get its rendered value.
+ value = value.__str__()
+ return value
def _errors(self):
"""
Returns an ErrorList for this field. Returns an empty ErrorList
if there are none.
"""
try:
- return self._form.errors()[self._name]
+ return self._form.errors[self._name]
except KeyError:
return ErrorList()
errors = property(_errors)
def as_widget(self, widget, attrs=None):
attrs = attrs or {}
auto_id = self.auto_id
- if not attrs.has_key('id') and not widget.attrs.has_key('id') and auto_id:
+ if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'):
attrs['id'] = auto_id
- return widget.render(self._name, self._form.data.get(self._name, None), attrs=attrs)
+ return widget.render(self._name, self.data, attrs=attrs)
def as_text(self, attrs=None):
"""
@@ -183,6 +202,39 @@ def as_textarea(self, attrs=None):
"Returns a string of HTML for representing this as a <textarea>."
return self.as_widget(Textarea(), attrs)
+ def as_hidden(self, attrs=None):
+ """
+ Returns a string of HTML for representing this as an <input type="hidden">.
+ """
+ return self.as_widget(HiddenInput(), attrs)
+
+ def _data(self):
+ "Returns the data for this BoundField, or None if it wasn't given."
+ return self._form.data.get(self._name, None)
+ data = property(_data)
+
+ def _verbose_name(self):
+ return pretty_name(self._name)
+ verbose_name = property(_verbose_name)
+
+ def label_tag(self, contents=None):
+ """
+ Wraps the given contents in a <label>, if the field has an ID attribute.
+ Does not HTML-escape the contents. If contents aren't given, uses the
+ field's HTML-escaped verbose_name.
+ """
+ contents = contents or escape(self.verbose_name)
+ widget = self._field.widget
+ id_ = widget.attrs.get('id') or self.auto_id
+ if id_:
+ contents = '<label for="%s">%s</label>' % (widget.id_for_label(id_), contents)
+ return contents
+
+ def _is_hidden(self):
+ "Returns True if this BoundField's widget is hidden."
+ return self._field.widget.is_hidden
+ is_hidden = property(_is_hidden)
+
def _auto_id(self):
"""
Calculates and returns the ID attribute for this BoundField, if the
Oops, something went wrong.

0 comments on commit 55d7f65

Please sign in to comment.