Changeset 7952
- Timestamp:
- 07/18/08 14:45:00 (3 months ago)
- Files:
-
- django/trunk/django/views/generic/create_update.py (modified) (7 diffs)
- django/trunk/django/views/generic/__init__.py (modified) (1 diff)
- django/trunk/docs/generic_views.txt (modified) (9 diffs)
- django/trunk/tests/regressiontests/views/fixtures/testdata.json (modified) (2 diffs)
- django/trunk/tests/regressiontests/views/models.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/views/tests/generic/create_update.py (added)
- django/trunk/tests/regressiontests/views/tests/__init__.py (modified) (1 diff)
- django/trunk/tests/regressiontests/views/urls.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/views/views.py (modified) (1 diff)
- django/trunk/tests/templates/views/article_confirm_delete.html (copied) (copied from django/trunk/tests/templates/views/article_detail.html)
- django/trunk/tests/templates/views/article_detail.html (modified) (1 diff)
- django/trunk/tests/templates/views/article_form.html (added)
- django/trunk/tests/templates/views/urlarticle_detail.html (added)
- django/trunk/tests/templates/views/urlarticle_form.html (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/views/generic/create_update.py
r5877 r7952 1 from django.newforms.models import ModelFormMetaclass, ModelForm 2 from django.template import RequestContext, loader 3 from django.http import Http404, HttpResponse, HttpResponseRedirect 1 4 from django.core.xheaders import populate_xheaders 2 from django.template import loader3 from django import oldforms4 from django.db.models import FileField5 from django.contrib.auth.views import redirect_to_login6 from django.template import RequestContext7 from django.http import Http404, HttpResponse, HttpResponseRedirect8 5 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 9 6 from django.utils.translation import ugettext 10 11 def create_object(request, model, template_name=None, 7 from django.contrib.auth.views import redirect_to_login 8 from django.views.generic import GenericViewError 9 10 def deprecate_follow(follow): 11 """ 12 Issues a DeprecationWarning if follow is anything but None. 13 14 The old Manipulator-based forms used a follow argument that is no longer 15 needed for newforms-based forms. 16 """ 17 if follow is not None: 18 import warning 19 msg = ("Generic views have been changed to use newforms, and the" 20 "'follow' argument is no longer used. Please update your code" 21 "to not use the 'follow' argument.") 22 warning.warn(msg, DeprecationWarning, stacklevel=3) 23 24 def apply_extra_context(extra_context, context): 25 """ 26 Adds items from extra_context dict to context. If a value in extra_context 27 is callable, then it is called and the result is added to context. 28 """ 29 for key, value in extra_context.iteritems(): 30 if callable(value): 31 context[key] = value() 32 else: 33 context[key] = value 34 35 def get_model_and_form_class(model, form_class): 36 """ 37 Returns a model and form class based on the model and form_class 38 parameters that were passed to the generic view. 39 40 If ``form_class`` is given then its associated model will be returned along 41 with ``form_class`` itself. Otherwise, if ``model`` is given, ``model`` 42 itself will be returned along with a ``ModelForm`` class created from 43 ``model``. 44 """ 45 if form_class: 46 return form_class._meta.model, form_class 47 if model: 48 # The inner Meta class fails if model = model is used for some reason. 49 tmp_model = model 50 # TODO: we should be able to construct a ModelForm without creating 51 # and passing in a temporary inner class. 52 class Meta: 53 model = tmp_model 54 class_name = model.__name__ + 'Form' 55 form_class = ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta}) 56 return model, form_class 57 raise GenericViewError("Generic view must be called with either a model or" 58 " form_class argument.") 59 60 def redirect(post_save_redirect, obj): 61 """ 62 Returns a HttpResponseRedirect to ``post_save_redirect``. 63 64 ``post_save_redirect`` should be a string, and can contain named string- 65 substitution place holders of ``obj`` field names. 66 67 If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned 68 by ``get_absolute_url()``. If ``obj`` has no ``get_absolute_url`` method, 69 then raise ImproperlyConfigured. 70 71 This method is meant to handle the post_save_redirect parameter to the 72 ``create_object`` and ``update_object`` views. 73 """ 74 if post_save_redirect: 75 return HttpResponseRedirect(post_save_redirect % obj.__dict__) 76 elif hasattr(obj, 'get_absolute_url'): 77 return HttpResponseRedirect(obj.get_absolute_url()) 78 else: 79 raise ImproperlyConfigured( 80 "No URL to redirect to. Either pass a post_save_redirect" 81 " parameter to the generic view or define a get_absolute_url" 82 " method on the Model.") 83 84 def lookup_object(model, object_id, slug, slug_field): 85 """ 86 Return the ``model`` object with the passed ``object_id``. If 87 ``object_id`` is None, then return the the object whose ``slug_field`` 88 equals the passed ``slug``. If ``slug`` and ``slug_field`` are not passed, 89 then raise Http404 exception. 90 """ 91 lookup_kwargs = {} 92 if object_id: 93 lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 94 elif slug and slug_field: 95 lookup_kwargs['%s__exact' % slug_field] = slug 96 else: 97 raise GenericViewError( 98 "Generic view must be called with either an object_id or a" 99 " slug/slug_field.") 100 try: 101 return model.objects.get(**lookup_kwargs) 102 except ObjectDoesNotExist: 103 raise Http404("No %s found for %s" 104 % (model._meta.verbose_name, lookup_kwargs)) 105 106 def create_object(request, model=None, template_name=None, 12 107 template_loader=loader, extra_context=None, post_save_redirect=None, 13 login_required=False, follow=None, context_processors=None): 108 login_required=False, follow=None, context_processors=None, 109 form_class=None): 14 110 """ 15 111 Generic object-creation function. … … 18 114 Context: 19 115 form 20 the form wrapper for the object 21 """ 116 the form for the object 117 """ 118 deprecate_follow(follow) 22 119 if extra_context is None: extra_context = {} 23 120 if login_required and not request.user.is_authenticated(): 24 121 return redirect_to_login(request.path) 25 122 26 manipulator = model.AddManipulator(follow=follow) 27 if request.POST: 28 # If data was POSTed, we're trying to create a new object 29 new_data = request.POST.copy() 30 31 if model._meta.has_field_type(FileField): 32 new_data.update(request.FILES) 33 34 # Check for errors 35 errors = manipulator.get_validation_errors(new_data) 36 manipulator.do_html2python(new_data) 37 38 if not errors: 39 # No errors -- this means we can save the data! 40 new_object = manipulator.save(new_data) 41 123 model, form_class = get_model_and_form_class(model, form_class) 124 if request.method == 'POST': 125 form = form_class(request.POST, request.FILES) 126 if form.is_valid(): 127 new_object = form.save() 42 128 if request.user.is_authenticated(): 43 129 request.user.message_set.create(message=ugettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name}) 44 45 # Redirect to the new object: first by trying post_save_redirect, 46 # then by obj.get_absolute_url; fail if neither works. 47 if post_save_redirect: 48 return HttpResponseRedirect(post_save_redirect % new_object.__dict__) 49 elif hasattr(new_object, 'get_absolute_url'): 50 return HttpResponseRedirect(new_object.get_absolute_url()) 51 else: 52 raise ImproperlyConfigured("No URL to redirect to from generic create view.") 53 else: 54 # No POST, so we want a brand new form without any data or errors 55 errors = {} 56 new_data = manipulator.flatten_data() 57 58 # Create the FormWrapper, template, context, response 59 form = oldforms.FormWrapper(manipulator, new_data, errors) 130 return redirect(post_save_redirect, new_object) 131 else: 132 form = form_class() 133 134 # Create the template, context, response 60 135 if not template_name: 61 136 template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) … … 64 139 'form': form, 65 140 }, context_processors) 66 for key, value in extra_context.items(): 67 if callable(value): 68 c[key] = value() 69 else: 70 c[key] = value 141 apply_extra_context(extra_context, c) 71 142 return HttpResponse(t.render(c)) 72 143 73 def update_object(request, model , object_id=None, slug=None,144 def update_object(request, model=None, object_id=None, slug=None, 74 145 slug_field='slug', template_name=None, template_loader=loader, 75 146 extra_context=None, post_save_redirect=None, 76 147 login_required=False, follow=None, context_processors=None, 77 template_object_name='object' ):148 template_object_name='object', form_class=None): 78 149 """ 79 150 Generic object-update function. … … 82 153 Context: 83 154 form 84 the form wrapperfor the object155 the form for the object 85 156 object 86 157 the original object being edited 87 158 """ 159 deprecate_follow(follow) 88 160 if extra_context is None: extra_context = {} 89 161 if login_required and not request.user.is_authenticated(): 90 162 return redirect_to_login(request.path) 91 163 92 # Look up the object to be edited 93 lookup_kwargs = {} 94 if object_id: 95 lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 96 elif slug and slug_field: 97 lookup_kwargs['%s__exact' % slug_field] = slug 98 else: 99 raise AttributeError("Generic edit view must be called with either an object_id or a slug/slug_field") 100 try: 101 object = model.objects.get(**lookup_kwargs) 102 except ObjectDoesNotExist: 103 raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs) 104 105 manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow) 106 107 if request.POST: 108 new_data = request.POST.copy() 109 if model._meta.has_field_type(FileField): 110 new_data.update(request.FILES) 111 errors = manipulator.get_validation_errors(new_data) 112 manipulator.do_html2python(new_data) 113 if not errors: 114 object = manipulator.save(new_data) 115 164 model, form_class = get_model_and_form_class(model, form_class) 165 obj = lookup_object(model, object_id, slug, slug_field) 166 167 if request.method == 'POST': 168 form = form_class(request.POST, request.FILES, instance=obj) 169 if form.is_valid(): 170 obj = form.save() 116 171 if request.user.is_authenticated(): 117 172 request.user.message_set.create(message=ugettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name}) 118 119 # Do a post-after-redirect so that reload works, etc. 120 if post_save_redirect: 121 return HttpResponseRedirect(post_save_redirect % object.__dict__) 122 elif hasattr(object, 'get_absolute_url'): 123 return HttpResponseRedirect(object.get_absolute_url()) 124 else: 125 raise ImproperlyConfigured("No URL to redirect to from generic create view.") 126 else: 127 errors = {} 128 # This makes sure the form acurate represents the fields of the place. 129 new_data = manipulator.flatten_data() 130 131 form = oldforms.FormWrapper(manipulator, new_data, errors) 173 return redirect(post_save_redirect, obj) 174 else: 175 form = form_class(instance=obj) 176 132 177 if not template_name: 133 178 template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) … … 135 180 c = RequestContext(request, { 136 181 'form': form, 137 template_object_name: obj ect,182 template_object_name: obj, 138 183 }, context_processors) 139 for key, value in extra_context.items(): 140 if callable(value): 141 c[key] = value() 142 else: 143 c[key] = value 184 apply_extra_context(extra_context, c) 144 185 response = HttpResponse(t.render(c)) 145 populate_xheaders(request, response, model, getattr(obj ect, object._meta.pk.attname))186 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) 146 187 return response 147 188 148 def delete_object(request, model, post_delete_redirect, 149 object_id=None,slug=None, slug_field='slug', template_name=None,150 template_loader=loader, extra_context=None, 151 login_required=False,context_processors=None, template_object_name='object'):189 def delete_object(request, model, post_delete_redirect, object_id=None, 190 slug=None, slug_field='slug', template_name=None, 191 template_loader=loader, extra_context=None, login_required=False, 192 context_processors=None, template_object_name='object'): 152 193 """ 153 194 Generic object-delete function. … … 166 207 return redirect_to_login(request.path) 167 208 168 # Look up the object to be edited 169 lookup_kwargs = {} 170 if object_id: 171 lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 172 elif slug and slug_field: 173 lookup_kwargs['%s__exact' % slug_field] = slug 174 else: 175 raise AttributeError("Generic delete view must be called with either an object_id or a slug/slug_field") 176 try: 177 object = model._default_manager.get(**lookup_kwargs) 178 except ObjectDoesNotExist: 179 raise Http404, "No %s found for %s" % (model._meta.app_label, lookup_kwargs) 209 obj = lookup_object(model, object_id, slug, slug_field) 180 210 181 211 if request.method == 'POST': 182 obj ect.delete()212 obj.delete() 183 213 if request.user.is_authenticated(): 184 214 request.user.message_set.create(message=ugettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name}) … … 189 219 t = template_loader.get_template(template_name) 190 220 c = RequestContext(request, { 191 template_object_name: obj ect,221 template_object_name: obj, 192 222 }, context_processors) 193 for key, value in extra_context.items(): 194 if callable(value): 195 c[key] = value() 196 else: 197 c[key] = value 223 apply_extra_context(extra_context, c) 198 224 response = HttpResponse(t.render(c)) 199 populate_xheaders(request, response, model, getattr(obj ect, object._meta.pk.attname))225 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) 200 226 return response django/trunk/django/views/generic/__init__.py
r4265 r7952 1 class GenericViewError(Exception): 2 """A problem in a generic view.""" 3 pass django/trunk/docs/generic_views.txt
r7866 r7952 702 702 the URLconf. See `Notes on pagination`_ below. 703 703 704 * ``page``: The current page number, as an integer. This is 1-based. 704 * ``page``: The current page number, as an integer. This is 1-based. 705 705 See `Notes on pagination`_ below. 706 706 … … 810 810 /objects/?page=3 811 811 812 * To loop over all the available page numbers, use the ``page_range`` 813 variable. You can iterate over the list provided by ``page_range`` 812 * To loop over all the available page numbers, use the ``page_range`` 813 variable. You can iterate over the list provided by ``page_range`` 814 814 to create a link to every page of results. 815 815 816 816 These values and lists are 1-based, not 0-based, so the first page would be 817 represented as page ``1``. 817 represented as page ``1``. 818 818 819 819 For more on pagination, read the `pagination documentation`_. … … 821 821 .. _`pagination documentation`: ../pagination/ 822 822 823 **New in Django development version:** 823 **New in Django development version:** 824 824 825 825 As a special case, you are also permitted to use ``last`` as a value for … … 828 828 /objects/?page=last 829 829 830 This allows you to access the final page of results without first having to 830 This allows you to access the final page of results without first having to 831 831 determine how many pages there are. 832 832 … … 907 907 for creating, editing and deleting objects. 908 908 909 **Changed in Django development version:** 910 911 ``django.views.generic.create_update.create_object`` and 912 ``django.views.generic.create_update.update_object`` now use `newforms`_ to 913 build and display the form. 914 915 .. _newforms: ../newforms/ 916 909 917 ``django.views.generic.create_update.create_object`` 910 918 ---------------------------------------------------- … … 913 921 914 922 A page that displays a form for creating an object, redisplaying the form with 915 validation errors (if there are any) and saving the object. This uses the 916 automatic manipulators that come with Django models. 917 918 **Required arguments:** 919 920 * ``model``: The Django model class of the object that the form will 921 create. 923 validation errors (if there are any) and saving the object. 924 925 **Required arguments:** 926 927 * Either ``form_class`` or ``model`` is required. 928 929 If you provide ``form_class``, it should be a 930 ``django.newforms.ModelForm`` subclass. Use this argument when you need 931 to customize the model's form. See the `ModelForm docs`_ for more 932 information. 933 934 Otherwise, ``model`` should be a Django model class and the form used 935 will be a standard ``ModelForm`` for ``model``. 922 936 923 937 **Optional arguments:** … … 960 974 In addition to ``extra_context``, the template's context will be: 961 975 962 * ``form``: A ``django. oldforms.FormWrapper`` instance representing the form963 for editing the object. This lets you refer to form fields easily in the976 * ``form``: A ``django.newforms.ModelForm`` instance representing the form 977 for creating the object. This lets you refer to form fields easily in the 964 978 template system. 965 979 966 For example, if ``model``has two fields, ``name`` and ``address``::980 For example, if the model has two fields, ``name`` and ``address``:: 967 981 968 982 <form action="" method="post"> 969 <p> <label for="id_name">Name:</label>{{ form.name }}</p>970 <p> <label for="id_address">Address:</label>{{ form.address }}</p>983 <p>{{ form.name.label_tag }} {{ form.name }}</p> 984 <p>{{ form.address.label_tag }} {{ form.address }}</p> 971 985 </form> 972 986 973 See the ` manipulator and formfield documentation`_ for more information974 about using ``FormWrapper`` objects in templates.987 See the `newforms documentation`_ for more information about using 988 ``Form`` objects in templates. 975 989 976 990 .. _authentication system: ../authentication/ 977 .. _manipulator and formfield documentation: ../forms/ 991 .. _ModelForm docs: ../newforms/modelforms 992 .. _newforms documentation: ../newforms/ 978 993 979 994 ``django.views.generic.create_update.update_object`` … … 988 1003 **Required arguments:** 989 1004 990 * ``model``: The Django model class of the object that the form will 991 create. 1005 * Either ``form_class`` or ``model`` is required. 1006 1007 If you provide ``form_class``, it should be a 1008 ``django.newforms.ModelForm`` subclass. Use this argument when you need 1009 to customize the model's form. See the `ModelForm docs`_ for more 1010 information. 1011 1012 Otherwise, ``model`` should be a Django model class and the form used 1013 will be a standard ``ModelForm`` for ``model``. 992 1014 993 1015 * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required. … … 1042 1064 In addition to ``extra_context``, the template's context will be: 1043 1065 1044 * ``form``: A ``django. oldforms.FormWrapper`` instance representing the form1066 * ``form``: A ``django.newforms.ModelForm`` instance representing the form 1045 1067 for editing the object. This lets you refer to form fields easily in the 1046 1068 template system. 1047 1069 1048 For example, if ``model``has two fields, ``name`` and ``address``::1070 For example, if the model has two fields, ``name`` and ``address``:: 1049 1071 1050 1072 <form action="" method="post"> 1051 <p> <label for="id_name">Name:</label>{{ form.name }}</p>1052 <p> <label for="id_address">Address:</label>{{ form.address }}</p>1073 <p>{{ form.name.label_tag }} {{ form.name }}</p> 1074 <p>{{ form.address.label_tag }} {{ form.address }}</p> 1053 1075 </form> 1054 1076 1055 See the ` manipulator and formfield documentation`_ for more information1056 about using ``FormWrapper`` objects in templates.1077 See the `newforms documentation`_ for more information about using 1078 ``Form`` objects in templates. 1057 1079 1058 1080 * ``object``: The original object being edited. This variable's name django/trunk/tests/regressiontests/views/fixtures/testdata.json
r6374 r7952 1 1 [ 2 { 3 "pk": "1", 4 "model": "auth.user", 5 "fields": { 6 "username": "testclient", 7 "first_name": "Test", 8 "last_name": "Client", 9 "is_active": true, 10 "is_superuser": false, 11 "is_staff": false, 12 "last_login": "2006-12-17 07:03:31", 13 "groups": [], 14 "user_permissions": [], 15 "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161", 16 "email": "testclient@example.com", 17 "date_joined": "2006-12-17 07:03:31" 18 } 19 }, 2 20 { 3 21 "pk": 1, … … 30 48 } 31 49 }, 32 50 { 51 "pk": 1, 52 "model": "views.urlarticle", 53 "fields": { 54 "author": 1, 55 "title": "Old Article", 56 "slug": "old_article", 57 "date_created": "2001-01-01 21:22:23" 58 } 59 }, 33 60 { 34 61 "pk": 1, django/trunk/tests/regressiontests/views/models.py
r7294 r7952 1 1 """ 2 Regression tests for Django built-in views 2 Regression tests for Django built-in views. 3 3 """ 4 4 5 5 from django.db import models 6 from django.conf import settings7 6 8 7 class Author(models.Model): … … 15 14 return '/views/authors/%s/' % self.id 16 15 17 18 class Article(models.Model): 16 class BaseArticle(models.Model): 17 """ 18 An abstract article Model so that we can create article models with and 19 without a get_absolute_url method (for create_update generic views tests). 20 """ 19 21 title = models.CharField(max_length=100) 20 22 slug = models.SlugField() 21 23 author = models.ForeignKey(Author) 22 24 date_created = models.DateTimeField() 23 25 26 class Meta: 27 abstract = True 28 24 29 def __unicode__(self): 25 30 return self.title 26 31 32 class Article(BaseArticle): 33 pass 34 35 class UrlArticle(BaseArticle): 36 """ 37 An Article class with a get_absolute_url defined. 38 """ 39 def get_absolute_url(self): 40 return '/urlarticles/%s/' % self.slug django/trunk/tests/regressiontests/views/tests/__init__.py
r7294 r7952 3 3 from static import * 4 4 from generic.date_based import * 5 from generic.create_update import * django/trunk/tests/regressiontests/views/urls.py
r7294 r7952 5 5 from models import * 6 6 import views 7 7 8 8 9 base_dir = path.dirname(path.abspath(__file__)) … … 15 16 } 16 17 17 date_based_info_dict = { 18 'queryset': Article.objects.all(), 19 'date_field': 'date_created', 20 'month_format': '%m', 21 } 18 date_based_info_dict = { 19 'queryset': Article.objects.all(), 20 'date_field': 'date_created', 21 'month_format': '%m', 22 } 22 23 23 24 urlpatterns = patterns('', 24 25 (r'^$', views.index_page), 25 26 26 27 # Default views 27 28 (r'^shortcut/(\d+)/(.*)/$', 'django.views.defaults.shortcut'), 28 29 (r'^non_existing_url/', 'django.views.defaults.page_not_found'), 29 30 (r'^server_error/', 'django.views.defaults.server_error'), 30 31 31 32 # i18n views 32 (r'^i18n/', include('django.conf.urls.i18n')), 33 (r'^i18n/', include('django.conf.urls.i18n')), 33 34 (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), 34 35 35 36 # Static views 36 37 (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': media_dir}), 37 38 # Date-based generic views39 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$',40 'django.views.generic.date_based.object_detail',41 dict(slug_field='slug', **date_based_info_dict)),42 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/allow_future/$',43 'django.views.generic.date_based.object_detail',44 dict(allow_future=True, slug_field='slug', **date_based_info_dict)),45 (r'^date_based/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',46 'django.views.generic.date_based.archive_month',47 date_based_info_dict),48 38 ) 39 40 # Date-based generic views. 41 urlpatterns += patterns('django.views.generic.date_based', 42 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$', 43 'object_detail', 44 dict(slug_field='slug', **date_based_info_dict)), 45 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/allow_future/$', 46 'object_detail', 47 dict(allow_future=True, slug_field='slug', **date_based_info_dict)), 48 (r'^date_based/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$', 49 'archive_month', 50 date_based_info_dict), 51 ) 52 53 # crud generic views. 54 55 urlpatterns += patterns('django.views.generic.create_update', 56 (r'^create_update/member/create/article/$', 'create_object', 57 dict(login_required=True, model=Article)), 58 (r'^create_update/create/article/$', 'create_object', 59 dict(post_save_redirect='/views/create_update/view/article/%(slug)s/', 60 model=Article)), 61 (r'^create_update/update/article/(?P<slug>[-\w]+)/$', 'update_object', 62 dict(post_save_redirect='/views/create_update/view/article/%(slug)s/', 63 slug_field='slug', model=Article)), 64 (r'^create_update/create_custom/article/$', views.custom_create), 65 (r'^create_update/delete/article/(?P<slug>[-\w]+)/$', 'delete_object', 66 dict(post_delete_redirect='/views/create_update/', slug_field='slug', 67 model=Article)), 68 69 # No post_save_redirect and no get_absolute_url on model. 70 (r'^create_update/no_redirect/create/article/$', 'create_object', 71 dict(model=Article)), 72 (r'^create_update/no_redirect/update/article/(?P<slug>[-\w]+)/$', 73 'update_object', dict(slug_field='slug', model=Article)), 74 75 # get_absolute_url on model, but no passed post_save_redirect. 76 (r'^create_update/no_url/create/article/$', 'create_object', 77 dict(model=UrlArticle)), 78 (r'^create_update/no_url/update/article/(?P<slug>[-\w]+)/$', 79 'update_object', dict(slug_field='slug', model=UrlArticle)), 80 ) django/trunk/tests/regressiontests/views/views.py
r7294 r7952 1 1 from django.http import HttpResponse 2 import django.newforms as forms 3 from django.views.generic.create_update import create_object 4 5 from models import Article 6 2 7 3 8 def index_page(request): 4 9 """Dummy index page""" 5 10 return HttpResponse('<html><body>Dummy page</body></html>') 11 12 13 def custom_create(request): 14 """ 15 Calls create_object generic view with a custom form class. 16 """ 17 class SlugChangingArticleForm(forms.ModelForm): 18 """Custom form class to overwrite the slug.""" 19 20 class Meta: 21 model = Article 22 23 def save(self, *args, **kwargs): 24 self.cleaned_data['slug'] = 'some-other-slug' 25 return super(SlugChangingArticleForm, self).save(*args, **kwargs) 26 27 return create_object(request, 28 post_save_redirect='/views/create_update/view/article/%(slug)s/', 29 form_class=SlugChangingArticleForm) django/trunk/tests/templates/views/article_detail.html
r7294 r7952 1 This template intentionally left blank 1 Article detail template.
