Permalink
Browse files

newforms-admin: Cleaned up the implementation and APIs of all the for…

…mset classes. Backwards-incompatible.

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7270 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 40d5523 commit 93c45b570427b0a0f875a6f551d229f20e2ac5ee @jkocherhans jkocherhans committed Mar 17, 2008
@@ -1,6 +1,7 @@
from django import oldforms, template
from django import newforms as forms
from django.newforms.formsets import all_valid
+from django.newforms.models import _modelform_factory, _inlineformset_factory
from django.contrib.contenttypes.models import ContentType
from django.contrib.admin import widgets
from django.contrib.admin.util import get_deleted_objects
@@ -340,7 +341,7 @@ def form_add(self, request):
fields = flatten_fieldsets(self.declared_fieldsets)
else:
fields = None
- return forms.form_for_model(self.model, fields=fields, formfield_callback=self.formfield_for_dbfield)
+ return _modelform_factory(self.model, fields=fields, formfield_callback=self.formfield_for_dbfield)
def form_change(self, request, obj):
"""
@@ -350,7 +351,7 @@ def form_change(self, request, obj):
fields = flatten_fieldsets(self.declared_fieldsets)
else:
fields = None
- return forms.form_for_instance(obj, fields=fields, formfield_callback=self.formfield_for_dbfield)
+ return _modelform_factory(self.model, fields=fields, formfield_callback=self.formfield_for_dbfield)
def save_add(self, request, model, form, formsets, post_url_continue):
"""
@@ -496,14 +497,14 @@ def add_view(self, request, form_url=''):
if request.method == 'POST':
form = ModelForm(request.POST, request.FILES)
for FormSet in self.formsets_add(request):
- inline_formset = FormSet(obj, data=request.POST, files=request.FILES)
+ inline_formset = FormSet(data=request.POST, files=request.FILES, instance=obj)
inline_formsets.append(inline_formset)
if all_valid(inline_formsets) and form.is_valid():
return self.save_add(request, model, form, inline_formsets, '../%s/')
else:
form = ModelForm(initial=request.GET)
for FormSet in self.formsets_add(request):
- inline_formset = FormSet(obj)
+ inline_formset = FormSet(instance=obj)
inline_formsets.append(inline_formset)
adminForm = AdminForm(form, list(self.fieldsets_add(request)), self.prepopulated_fields)
@@ -553,17 +554,17 @@ def change_view(self, request, object_id):
ModelForm = self.form_change(request, obj)
inline_formsets = []
if request.method == 'POST':
- form = ModelForm(request.POST, request.FILES)
+ form = ModelForm(request.POST, request.FILES, instance=obj)
for FormSet in self.formsets_change(request, obj):
- inline_formset = FormSet(obj, request.POST, request.FILES)
+ inline_formset = FormSet(request.POST, request.FILES, instance=obj)
inline_formsets.append(inline_formset)
if all_valid(inline_formsets) and form.is_valid():
return self.save_change(request, model, form, inline_formsets)
else:
- form = ModelForm()
+ form = ModelForm(instance=obj)
for FormSet in self.formsets_change(request, obj):
- inline_formset = FormSet(obj)
+ inline_formset = FormSet(instance=obj)
inline_formsets.append(inline_formset)
## Populate the FormWrapper.
@@ -740,26 +741,26 @@ def formset_add(self, request):
fields = flatten_fieldsets(self.declared_fieldsets)
else:
fields = None
- return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra)
+ return _inlineformset_factory(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra)
def formset_change(self, request, obj):
"""Returns an InlineFormSet class for use in admin change views."""
if self.declared_fieldsets:
fields = flatten_fieldsets(self.declared_fieldsets)
else:
fields = None
- return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra)
+ return _inlineformset_factory(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra)
def fieldsets_add(self, request):
if self.declared_fieldsets:
return self.declared_fieldsets
- form = self.formset_add(request).form_class
+ form = self.formset_add(request).form
return [(None, {'fields': form.base_fields.keys()})]
def fieldsets_change(self, request, obj):
if self.declared_fieldsets:
return self.declared_fieldsets
- form = self.formset_change(request, obj).form_class
+ form = self.formset_change(request, obj).form
return [(None, {'fields': form.base_fields.keys()})]
class StackedInline(InlineModelAdmin):
@@ -778,14 +779,14 @@ def __init__(self, inline, formset, fieldsets):
self.fieldsets = fieldsets
def __iter__(self):
- for form, original in zip(self.formset.change_forms, self.formset.get_queryset()):
+ for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
- for form in self.formset.add_forms:
+ for form in self.formset.extra_forms:
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
def fields(self):
for field_name in flatten_fieldsets(self.fieldsets):
- yield self.formset.form_class.base_fields[field_name]
+ yield self.formset.form.base_fields[field_name]
class InlineAdminForm(AdminForm):
"""
View
@@ -69,7 +69,8 @@ class BaseForm(StrAndUnicode):
# information. Any improvements to the form API should be made to *this*
# class, not to the Form class.
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
- initial=None, error_class=ErrorList, label_suffix=':'):
+ initial=None, error_class=ErrorList, label_suffix=':',
+ empty_permitted=False):
self.is_bound = data is not None or files is not None
self.data = data or {}
self.files = files or {}
@@ -78,6 +79,7 @@ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
self.initial = initial or {}
self.error_class = error_class
self.label_suffix = label_suffix
+ self.empty_permitted = empty_permitted
self._errors = None # Stores the errors after clean() has been called.
# The base_fields class attribute is the *class-wide* definition of
@@ -189,24 +191,6 @@ def non_field_errors(self):
"""
return self.errors.get(NON_FIELD_ERRORS, self.error_class())
- def is_empty(self, exceptions=None):
- """
- Returns True if this form has been bound and all fields that aren't
- listed in exceptions are empty.
- """
- # TODO: This could probably use some optimization
- exceptions = exceptions or []
- for name, field in self.fields.items():
- if name in exceptions:
- continue
- # value_from_datadict() gets the data from the data dictionaries.
- # 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, self.files, self.add_prefix(name))
- if not field.widget.is_empty(value):
- return False
- return True
-
def full_clean(self):
"""
Cleans all of self.data and populates self._errors and
@@ -216,6 +200,10 @@ def full_clean(self):
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
+ # If the form is permitted to be empty, and none of the form data has
+ # changed from the initial data, short circuit any validation.
+ if self.empty_permitted and not self.has_changed():
+ return
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
@@ -251,11 +239,24 @@ def clean(self):
"""
return self.cleaned_data
- def reset(self):
- """Return this form to the state it was in before data was passed to it."""
- self.data = {}
- self.is_bound = False
- self.__errors = None
+ def has_changed(self):
+ """
+ Returns True if data differs from initial.
+ """
+ # XXX: For now we're asking the individual widgets whether or not the
+ # data has changed. It would probably be more efficient to hash the
+ # initial data, store it in a hidden field, and compare a hash of the
+ # submitted data, but we'd need a way to easily get the string value
+ # for a given field. Right now, that logic is embedded in the render
+ # method of each widget.
+ for name, field in self.fields.items():
+ prefixed_name = self.add_prefix(name)
+ data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
+ initial_value = self.initial.get(name, field.initial)
+ if field.widget._has_changed(initial_value, data_value):
+ #print field
+ return True
+ return False
def _get_media(self):
"""
Oops, something went wrong.

0 comments on commit 93c45b5

Please sign in to comment.