Browse Source

Fixed #16319 -- added SuccessMessageMixin to contrib.messages

Thanks martinogden for the initial patch and d1ffuz0r for tests.
Paul Collins 12 years ago
parent
commit
9a85ad89c2

+ 1 - 0
AUTHORS

@@ -607,6 +607,7 @@ answer newbie questions, and generally made Django that much better:
     Cheng Zhang
     Hannes Struß <x@hannesstruss.de>
     Deric Crago <deric.crago@gmail.com>
+    Paul Collins <paul.collins.iii@gmail.com>
 
 A big THANK YOU goes to:
 

+ 1 - 0
django/contrib/messages/tests/__init__.py

@@ -2,3 +2,4 @@ from django.contrib.messages.tests.cookie import CookieTest
 from django.contrib.messages.tests.fallback import FallbackTest
 from django.contrib.messages.tests.middleware import MiddlewareTest
 from django.contrib.messages.tests.session import SessionTest
+from django.contrib.messages.tests.mixins import SuccessMessageMixinTests

+ 14 - 0
django/contrib/messages/tests/mixins.py

@@ -0,0 +1,14 @@
+from django.test.testcases import TestCase
+from django.contrib.messages.tests.urls import ContactFormViewWithMsg
+from django.core.urlresolvers import reverse
+
+class SuccessMessageMixinTests(TestCase):
+    urls = 'django.contrib.messages.tests.urls'
+
+    def test_set_messages_success(self):
+        author = {'name': 'John Doe',
+                  'slug': 'success-msg'}
+        add_url = reverse('add_success_msg')
+        req = self.client.post(add_url, author)
+        self.assertIn(ContactFormViewWithMsg.success_message % author,
+                      req.cookies['messages'].value)

+ 17 - 1
django/contrib/messages/tests/urls.py

@@ -1,10 +1,13 @@
-from django.conf.urls import patterns
+from django.conf.urls import patterns, url
 from django.contrib import messages
 from django.core.urlresolvers import reverse
+from django import forms
 from django.http import HttpResponseRedirect, HttpResponse
 from django.template import RequestContext, Template
 from django.template.response import TemplateResponse
 from django.views.decorators.cache import never_cache
+from django.contrib.messages.views import SuccessMessageMixin
+from django.views.generic.edit import FormView
 
 TEMPLATE = """{% if messages %}
 <ul class="messages">
@@ -49,8 +52,21 @@ def show(request):
 def show_template_response(request):
     return TemplateResponse(request, Template(TEMPLATE))
 
+
+class ContactForm(forms.Form):
+    name = forms.CharField(required=True)
+    slug = forms.SlugField(required=True)
+
+
+class ContactFormViewWithMsg(SuccessMessageMixin, FormView):
+    form_class = ContactForm
+    success_url = show
+    success_message = "%(name)s was created successfully"
+
+
 urlpatterns = patterns('',
     ('^add/(debug|info|success|warning|error)/$', add),
+    url('^add/msg/$', ContactFormViewWithMsg.as_view(), name='add_success_msg'),
     ('^show/$', show),
     ('^template_response/add/(debug|info|success|warning|error)/$', add_template_response),
     ('^template_response/show/$', show_template_response),

+ 19 - 0
django/contrib/messages/views.py

@@ -0,0 +1,19 @@
+from django.views.generic.edit import FormMixin
+from django.contrib import messages
+
+
+class SuccessMessageMixin(FormMixin):
+    """
+    Adds a success message on successful form submission.
+    """
+    success_message = ''
+
+    def form_valid(self, form):
+        response = super(SuccessMessageMixin, self).form_valid(form)
+        success_message = self.get_success_message(form.cleaned_data)
+        if success_message:
+            messages.success(self.request, success_message)
+        return response
+
+    def get_success_message(self, cleaned_data):
+        return self.success_message % cleaned_data

+ 47 - 0
docs/ref/contrib/messages.txt

@@ -286,6 +286,53 @@ example::
    use one of the ``add_message`` family of methods. It does not hide failures
    that may occur for other reasons.
 
+Adding messages in Class Based Views
+------------------------------------
+
+.. versionadded:: 1.6
+
+.. class:: django.contrib.messages.views.SuccessMessageMixin
+
+    Adds a success message attribute to
+    :class:`~django.views.generic.edit.FormView` based classes
+
+    .. method:: get_success_message(cleaned_data)
+
+        ``cleaned_data`` is the cleaned data from the form which is used for
+        string formatting
+
+**Example views.py**::
+
+    from django.contrib.messages.views import SuccessMessageMixin
+    from django.views.generic.edit import CreateView
+    from myapp.models import Author
+
+    class AuthorCreate(SuccessMessageMixin, CreateView):
+        model = Author
+        success_url = '/success/'
+        success_message = "%(name)s was created successfully"
+
+The cleaned data from the ``form`` is available for string interpolation using
+the ``%(field_name)s`` syntax. For ModelForms, if you need access to fields
+from the saved ``object`` override the
+:meth:`~django.contrib.messages.views.SuccessMessageMixin.get_success_message`
+method.
+
+**Example views.py for ModelForms**::
+
+    from django.contrib.messages.views import SuccessMessageMixin
+    from django.views.generic.edit import CreateView
+    from myapp.models import ComplicatedModel
+
+    class ComplicatedCreate(SuccessMessageMixin, CreateView):
+        model = ComplicatedModel
+        success_url = '/success/'
+        success_message = "%(calculated_field)s was created successfully"
+
+        def get_success_message(self, cleaned_data):
+            return self.success_message % dict(cleaned_data,
+                                               calculated_field=self.object.calculated_field)
+
 Expiration of messages
 ======================
 

+ 4 - 0
docs/releases/1.6.txt

@@ -126,6 +126,10 @@ Minor features
 * The ``MemcachedCache`` cache backend now uses the latest :mod:`pickle`
   protocol available.
 
+* Added :class:`~django.contrib.messages.views.SuccessMessageMixin` which
+  provides a ``success_message`` attribute for
+  :class:`~django.view.generic.edit.FormView` based classes.
+
 * Added the :attr:`django.db.models.ForeignKey.db_constraint` and
   :attr:`django.db.models.ManyToManyField.db_constraint` options.
 

+ 1 - 0
tests/generic_views/views.py

@@ -1,6 +1,7 @@
 from __future__ import absolute_import
 
 from django.contrib.auth.decorators import login_required
+from django.contrib.messages.views import SuccessMessageMixin
 from django.core.paginator import Paginator
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.utils.decorators import method_decorator