Index: django/views/generic/create_update.py
===================================================================
--- django/views/generic/create_update.py	(revision 5155)
+++ django/views/generic/create_update.py	(working copy)
@@ -1,16 +1,19 @@
+from django import newforms as forms
+from django.contrib.auth.views import redirect_to_login
+from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
 from django.core.xheaders import populate_xheaders
-from django.template import loader
-from django import oldforms
 from django.db.models import FileField
-from django.contrib.auth.views import redirect_to_login
-from django.template import RequestContext
 from django.http import Http404, HttpResponse, HttpResponseRedirect
-from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
 from django.utils.translation import gettext
+from django.template import RequestContext, loader
 
-def create_object(request, model, template_name=None,
-        template_loader=loader, extra_context=None, post_save_redirect=None,
-        login_required=False, follow=None, context_processors=None):
+
+def create_object(request, model,
+        template_name=None, template_loader=loader,
+        extra_context=None, post_save_redirect=None,
+        login_required=False, context_processors=None,
+        not_required_fields=None, hidden_fields=None,
+        default_data=None, choices=None):
     """
     Generic object-creation function.
 
@@ -19,62 +22,93 @@
         form
             the form wrapper for the object
     """
-    if extra_context is None: extra_context = {}
     if login_required and not request.user.is_authenticated():
         return redirect_to_login(request.path)
 
-    manipulator = model.AddManipulator(follow=follow)
-    if request.POST:
-        # If data was POSTed, we're trying to create a new object
+    FormClass = forms.models.form_for_model(model)
+    if request.method == 'POST':
+        # Create a form with POSTed data
         new_data = request.POST.copy()
 
         if model._meta.has_field_type(FileField):
             new_data.update(request.FILES)
 
-        # Check for errors
-        errors = manipulator.get_validation_errors(new_data)
-        manipulator.do_html2python(new_data)
+        form = FormClass(new_data)
 
-        if not errors:
-            # No errors -- this means we can save the data!
-            new_object = manipulator.save(new_data)
+    else:
+        # Create new form with default data
+        if default_data is None: default_data = {}
+        form = FormClass(default_data)
 
-            if request.user.is_authenticated():
-                request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
+    # Modify choices
+    if choices:
+        for field in choices.keys():
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field] = forms.ChoiceField(choices[field])
 
-            # Redirect to the new object: first by trying post_save_redirect,
-            # then by obj.get_absolute_url; fail if neither works.
-            if post_save_redirect:
-                return HttpResponseRedirect(post_save_redirect % new_object.__dict__)
-            elif hasattr(new_object, 'get_absolute_url'):
-                return HttpResponseRedirect(new_object.get_absolute_url())
-            else:
-                raise ImproperlyConfigured("No URL to redirect to from generic create view.")
-    else:
-        # No POST, so we want a brand new form without any data or errors
-        errors = {}
-        new_data = manipulator.flatten_data()
+    # Mark some fields as 'hidden'
+    if hidden_fields:
+        for (field, value) in hidden_fields.iteritems():
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field].widget = forms.HiddenInput()
+            # Prevent hidden field from being modified
+            form.data[field] = value
+            # Empty hidden fields are supposed not to be required
+            if value == "": form.fields[field].required = False
 
-    # Create the FormWrapper, template, context, response
-    form = oldforms.FormWrapper(manipulator, new_data, errors)
-    if not template_name:
+    # Mark some fields as 'not required'
+    if not_required_fields:
+        for field in not_required_fields:
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field].required = False
+
+    if request.method == 'POST' and not form.errors:
+        # Form does't contain errors, save the data
+        new_object = form.save()
+
+        if request.user.is_authenticated():
+            request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
+
+        # Redirect to the new object: first by trying post_save_redirect,
+        # then by obj.get_absolute_url; fail if neither works.
+        if post_save_redirect:
+            return HttpResponseRedirect(post_save_redirect % new_object.__dict__)
+        elif hasattr(new_object, 'get_absolute_url'):
+            return HttpResponseRedirect(new_object.get_absolute_url())
+        else:
+            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
+
+    # Create template
+    if template_name is None:
         template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
     t = template_loader.get_template(template_name)
+
+    # Create context
     c = RequestContext(request, {
         'form': form,
     }, context_processors)
-    for key, value in extra_context.items():
-        if callable(value):
-            c[key] = value()
-        else:
-            c[key] = value
+
+    # Add extra context
+    if extra_context:
+        for key, value in extra_context.items():
+            if callable(value):
+                c[key] = value()
+            else:
+                c[key] = value
+
+    # Render template and return the response
     return HttpResponse(t.render(c))
 
-def update_object(request, model, object_id=None, slug=None,
-        slug_field=None, template_name=None, template_loader=loader,
-        extra_context=None, post_save_redirect=None,
-        login_required=False, follow=None, context_processors=None,
-        template_object_name='object'):
+
+def update_object(request, model,
+        object_id=None, slug=None, slug_field=None,
+        template_name=None, template_loader=loader,
+        template_object_name='object',
+        extra_context=None, context_processors=None,
+        post_save_redirect=None, login_required=False,
+        not_required_fields=None, hidden_fields=None,
+        choices=None):
+
     """
     Generic object-update function.
 
@@ -85,7 +119,6 @@
         object
             the original object being edited
     """
-    if extra_context is None: extra_context = {}
     if login_required and not request.user.is_authenticated():
         return redirect_to_login(request.path)
 
@@ -97,58 +130,92 @@
         lookup_kwargs['%s__exact' % slug_field] = slug
     else:
         raise AttributeError("Generic edit view must be called with either an object_id or a slug/slug_field")
+
     try:
         object = model.objects.get(**lookup_kwargs)
     except ObjectDoesNotExist:
         raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs)
 
-    manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow)
+    FormClass = forms.models.form_for_instance(object)
+    if request.method == 'POST':
+        # Create a form with POSTed data
+        new_data = request.POST.copy()
 
-    if request.POST:
-        new_data = request.POST.copy()
         if model._meta.has_field_type(FileField):
             new_data.update(request.FILES)
-        errors = manipulator.get_validation_errors(new_data)
-        manipulator.do_html2python(new_data)
-        if not errors:
-            object = manipulator.save(new_data)
 
-            if request.user.is_authenticated():
-                request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
+        form = FormClass(new_data)
 
-            # Do a post-after-redirect so that reload works, etc.
-            if post_save_redirect:
-                return HttpResponseRedirect(post_save_redirect % object.__dict__)
-            elif hasattr(object, 'get_absolute_url'):
-                return HttpResponseRedirect(object.get_absolute_url())
-            else:
-                raise ImproperlyConfigured("No URL to redirect to from generic create view.")
     else:
-        errors = {}
-        # This makes sure the form acurate represents the fields of the place.
-        new_data = manipulator.flatten_data()
+        # Create a form with original object data
+        form = FormClass()
 
-    form = oldforms.FormWrapper(manipulator, new_data, errors)
+    # Modify choices
+    if choices:
+        for field in choices.keys():
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field] = forms.ChoiceField(choices[field])
+
+    # Mark some fields as 'hidden'
+    if hidden_fields:
+        for (field, value) in hidden_fields.iteritems():
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field].widget = forms.HiddenInput()
+            # Prevent hidden field from being modified
+            form.data[field] = value
+            # Empty hidden fields are supposed not to be required
+            if value == "": form.fields[field].required = False
+
+    # Mark some fields as 'not required'
+    if not_required_fields:
+        for field in not_required_fields:
+            if not form.fields.has_key(field): raise FieldDoesNotExist
+            form.fields[field].required = False
+
+    if request.method == 'POST' and not form.errors:
+        object = form.save(new_data)
+
+        if request.user.is_authenticated():
+            request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
+
+        # Do a post-after-redirect so that reload works, etc.
+        if post_save_redirect:
+            return HttpResponseRedirect(post_save_redirect % object.__dict__)
+        elif hasattr(object, 'get_absolute_url'):
+            return HttpResponseRedirect(object.get_absolute_url())
+        else:
+            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
+
+    # Create template
     if not template_name:
         template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
     t = template_loader.get_template(template_name)
+
+    # Create context
     c = RequestContext(request, {
         'form': form,
         template_object_name: object,
     }, context_processors)
-    for key, value in extra_context.items():
-        if callable(value):
-            c[key] = value()
-        else:
-            c[key] = value
+
+    # Add extra context
+    if extra_context:
+        for key, value in extra_context.items():
+            if callable(value):
+                c[key] = value()
+            else:
+                c[key] = value
+
+    # Render template and return the response
     response = HttpResponse(t.render(c))
     populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
     return response
 
+
 def delete_object(request, model, post_delete_redirect,
-        object_id=None, slug=None, slug_field=None, template_name=None,
-        template_loader=loader, extra_context=None,
-        login_required=False, context_processors=None, template_object_name='object'):
+        object_id=None, slug=None, slug_field=None,
+        template_name=None, template_loader=loader,
+        template_object_name='object', login_required=False,
+        extra_context=None, context_processors=None):
     """
     Generic object-delete function.
 
@@ -161,7 +228,6 @@
         object
             the original object being deleted
     """
-    if extra_context is None: extra_context = {}
     if login_required and not request.user.is_authenticated():
         return redirect_to_login(request.path)
 
@@ -173,6 +239,7 @@
         lookup_kwargs['%s__exact' % slug_field] = slug
     else:
         raise AttributeError("Generic delete view must be called with either an object_id or a slug/slug_field")
+
     try:
         object = model._default_manager.get(**lookup_kwargs)
     except ObjectDoesNotExist:
@@ -183,18 +250,27 @@
         if request.user.is_authenticated():
             request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
         return HttpResponseRedirect(post_delete_redirect)
+
     else:
+        # Create template
         if not template_name:
-            template_name = "%s/%s_confirm_delete.html" % (model._meta.app_label, model._meta.object_name.lower())
+            template_name = "%s/%s_delete.html" % (model._meta.app_label, model._meta.object_name.lower())
         t = template_loader.get_template(template_name)
+
+        # Create context
         c = RequestContext(request, {
             template_object_name: object,
         }, context_processors)
-        for key, value in extra_context.items():
-            if callable(value):
-                c[key] = value()
-            else:
-                c[key] = value
+
+        # Add extra context
+        if extra_context:
+            for key, value in extra_context.items():
+                if callable(value):
+                    c[key] = value()
+                else:
+                    c[key] = value
+
+        # Render template and return the response
         response = HttpResponse(t.render(c))
         populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
         return response
