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
     Cheng Zhang
     Hannes Struß <x@hannesstruss.de>
     Hannes Struß <x@hannesstruss.de>
     Deric Crago <deric.crago@gmail.com>
     Deric Crago <deric.crago@gmail.com>
+    Paul Collins <paul.collins.iii@gmail.com>
 
 
 A big THANK YOU goes to:
 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.fallback import FallbackTest
 from django.contrib.messages.tests.middleware import MiddlewareTest
 from django.contrib.messages.tests.middleware import MiddlewareTest
 from django.contrib.messages.tests.session import SessionTest
 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.contrib import messages
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
+from django import forms
 from django.http import HttpResponseRedirect, HttpResponse
 from django.http import HttpResponseRedirect, HttpResponse
 from django.template import RequestContext, Template
 from django.template import RequestContext, Template
 from django.template.response import TemplateResponse
 from django.template.response import TemplateResponse
 from django.views.decorators.cache import never_cache
 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 %}
 TEMPLATE = """{% if messages %}
 <ul class="messages">
 <ul class="messages">
@@ -49,8 +52,21 @@ def show(request):
 def show_template_response(request):
 def show_template_response(request):
     return TemplateResponse(request, Template(TEMPLATE))
     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('',
 urlpatterns = patterns('',
     ('^add/(debug|info|success|warning|error)/$', add),
     ('^add/(debug|info|success|warning|error)/$', add),
+    url('^add/msg/$', ContactFormViewWithMsg.as_view(), name='add_success_msg'),
     ('^show/$', show),
     ('^show/$', show),
     ('^template_response/add/(debug|info|success|warning|error)/$', add_template_response),
     ('^template_response/add/(debug|info|success|warning|error)/$', add_template_response),
     ('^template_response/show/$', show_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
    use one of the ``add_message`` family of methods. It does not hide failures
    that may occur for other reasons.
    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
 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`
 * The ``MemcachedCache`` cache backend now uses the latest :mod:`pickle`
   protocol available.
   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
 * Added the :attr:`django.db.models.ForeignKey.db_constraint` and
   :attr:`django.db.models.ManyToManyField.db_constraint` options.
   :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 __future__ import absolute_import
 
 
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.decorators import login_required
+from django.contrib.messages.views import SuccessMessageMixin
 from django.core.paginator import Paginator
 from django.core.paginator import Paginator
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.utils.decorators import method_decorator
 from django.utils.decorators import method_decorator