diff --git a/django/contrib/messages/views.py b/django/contrib/messages/views.py
new file mode 100644
index 0000000..219c524
-
|
+
|
|
| 1 | from django.views.generic.edit import FormMixin |
| 2 | from django.contrib import messages |
| 3 | |
| 4 | |
| 5 | class SuccessMessageMixin(FormMixin): |
| 6 | """ |
| 7 | A mixin that add a success message when a form is completed |
| 8 | """ |
| 9 | success_message = None |
| 10 | |
| 11 | def form_valid(self, form): |
| 12 | success_message = self.get_success_message() |
| 13 | if success_message: |
| 14 | messages.success(self.request, success_message) |
| 15 | return super(SuccessMessageMixin, self).form_valid(form) |
| 16 | |
| 17 | def get_success_message(self): |
| 18 | if hasattr(self, 'object'): |
| 19 | return self.success_message % self.object.__dict__ |
| 20 | return self.success_message |
diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt
index bc921a9..d155a81 100644
a
|
b
|
example::
|
280 | 280 | use one of the ``add_message`` family of methods. It does not hide failures |
281 | 281 | that may occur for other reasons. |
282 | 282 | |
| 283 | Adding a messages in CBV |
| 284 | ------------------------ |
| 285 | |
| 286 | If you're writing a view for processing a form and want to add message |
| 287 | about successful checking, you can use ``'django.contrib.messages.views.SuccessMessageMixin'`` for it. |
| 288 | For example:: |
| 289 | |
| 290 | # views.py |
| 291 | from django.contrib.messages.views import SuccessMessageMixin |
| 292 | from django.views.generic.edit import CreateView |
| 293 | from myapp.models import Author |
| 294 | |
| 295 | |
| 296 | class AuthorCreate(CreateView, SuccessMessageMixin): |
| 297 | model = Author |
| 298 | success_url = '/success/' |
| 299 | success_message = "%(name)s was created successfully" |
| 300 | |
| 301 | .. note:: |
| 302 | ``success_message`` is supported printing only fields what is contains in ``model``. |
| 303 | |
283 | 304 | Expiration of messages |
284 | 305 | ====================== |
285 | 306 | |
diff --git a/tests/regressiontests/generic_views/edit.py b/tests/regressiontests/generic_views/edit.py
index 16f4da8..45638d3 100644
a
|
b
|
class FormMixinTests(TestCase):
|
20 | 20 | initial_2 = FormMixin().get_initial() |
21 | 21 | self.assertNotEqual(initial_1, initial_2) |
22 | 22 | |
| 23 | |
23 | 24 | class ModelFormMixinTests(TestCase): |
24 | 25 | def test_get_form(self): |
25 | 26 | form_class = views.AuthorGetQuerySetFormView().get_form_class() |
26 | 27 | self.assertEqual(form_class._meta.model, Author) |
27 | 28 | |
| 29 | |
| 30 | class SuccessMessageMixinTests(TestCase): |
| 31 | urls = 'regressiontests.generic_views.urls' |
| 32 | |
| 33 | def test_set_messages_success(self): |
| 34 | req = self.client.post('/edit/authors/create/msg/', |
| 35 | {'name': 'John Doe', |
| 36 | 'slug': 'success-msg'}) |
| 37 | self.assertIn('John Doe', req.cookies['messages'].value) |
| 38 | |
| 39 | def test_set_message_false(self): |
| 40 | req = self.client.post('/edit/authors/create/msg/', |
| 41 | {'name': 'John Doe'}) |
| 42 | self.assertFalse('messages' in req.cookies) |
| 43 | |
| 44 | |
28 | 45 | class CreateViewTests(TestCase): |
29 | 46 | urls = 'regressiontests.generic_views.urls' |
30 | 47 | |
… |
… |
class DeleteViewTests(TestCase):
|
298 | 315 | self.fail('Should raise exception -- No redirect URL provided, and no get_absolute_url provided') |
299 | 316 | except ImproperlyConfigured: |
300 | 317 | pass |
301 | | |
diff --git a/tests/regressiontests/generic_views/tests.py b/tests/regressiontests/generic_views/tests.py
index c985ad3..0bc4233 100644
a
|
b
|
|
1 | 1 | from __future__ import absolute_import |
2 | 2 | |
3 | 3 | from .base import (ViewTest, TemplateViewTest, RedirectViewTest, |
4 | | GetContextDataTest) |
| 4 | GetContextDataTest) |
5 | 5 | from .dates import (ArchiveIndexViewTests, YearArchiveViewTests, |
6 | | MonthArchiveViewTests, WeekArchiveViewTests, DayArchiveViewTests, |
7 | | DateDetailViewTests) |
| 6 | MonthArchiveViewTests, WeekArchiveViewTests, |
| 7 | DayArchiveViewTests, DateDetailViewTests) |
8 | 8 | from .detail import DetailViewTest |
9 | 9 | from .edit import (FormMixinTests, ModelFormMixinTests, CreateViewTests, |
10 | | UpdateViewTests, DeleteViewTests) |
| 10 | UpdateViewTests, DeleteViewTests, SuccessMessageMixinTests) |
11 | 11 | from .list import ListViewTests |
diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py
index c72bfec..300f8ec 100644
a
|
b
|
urlpatterns = patterns('',
|
72 | 72 | views.AuthorCreateRestricted.as_view()), |
73 | 73 | (r'^edit/authors/create/$', |
74 | 74 | views.AuthorCreate.as_view()), |
| 75 | (r'^edit/authors/create/msg/$', |
| 76 | views.AuthorCreateViewWithMsg.as_view()), |
75 | 77 | (r'^edit/authors/create/special/$', |
76 | 78 | views.SpecializedAuthorCreate.as_view()), |
77 | 79 | |
diff --git a/tests/regressiontests/generic_views/views.py b/tests/regressiontests/generic_views/views.py
index f7fcf6f..7613f24 100644
a
|
b
|
|
1 | 1 | from __future__ import absolute_import |
2 | 2 | |
3 | 3 | from django.contrib.auth.decorators import login_required |
| 4 | from django.contrib.messages.views import SuccessMessageMixin |
4 | 5 | from django.core.paginator import Paginator |
5 | 6 | from django.core.urlresolvers import reverse |
6 | 7 | from django.utils.decorators import method_decorator |
… |
… |
class AuthorCreateRestricted(AuthorCreate):
|
102 | 103 | post = method_decorator(login_required)(AuthorCreate.post) |
103 | 104 | |
104 | 105 | |
| 106 | class AuthorCreateViewWithMsg(generic.CreateView, SuccessMessageMixin): |
| 107 | model = Author |
| 108 | success_url = '/next/' |
| 109 | success_message = "%(name)s was created successfully" |
| 110 | |
| 111 | |
105 | 112 | class ArtistUpdate(generic.UpdateView): |
106 | 113 | model = Artist |
107 | 114 | |