I should add patches that I promise to add ;)

--Lennart

On Monday, December 7, 2015 at 9:23:19 PM UTC+1, Lennart Buit wrote:
>
> Hey all,
>
> One of my minor annoyances with the class based view system in django is 
> that there is no clear way to model a confirmable action. The concept does 
> exists in cbv, but only for deleting objects. I however think that there 
> are more usages for confirming actions other then delete.
>
> Lets look at an example, a news site can CRUD newsaticles. But this news 
> site has some articles for free, and some other behind a paywall. Also, 
> editors on this site can publish newsarticles (after which they come in the 
> pay section), and then promote them to free articles. The views in django 
> would then look as follows (with some brevity):
>
>     # This also goes for Update/Delete/...
>     class NewsArticleCreateView(CreateView):
>         model = NewsArticle
>
>     # This also goes for Promote
>     class NewsArticlePublishView(DetailView):
>         model = NewsArticle
>         success_url = 'somewhere'
>
>         def post(self, *args, **kwargs):
>             self.object = self.get_object()
>             success_url = self.get_success_url()
>             self.object.published = True
>             self.object.save()
>
>             return HttpResponseRedirect(success_url)
>
>         def get_success_url(self):
>             if self.success_url:
>                 return self.success_url.format(**self.object.__dict__)
>             else:
>                 raise ImproperlyConfigured(
>                     "No URL to redirect to. Provide a success_url.")
>
> The problem, I think, is that we are copying most of a DeleteView for a 
> fairly standard confirmable action. The get_success_url function is almost 
> the same, and most of the code found in the post function is that of delete 
> in DeleteView. I think therefore that we should consider splitting the 
> DeleteMixin in a more generic ConfirmMixin, make DeleteMixin a subclass of 
> ConfirmMixin, and introduce the (more) generic BaseConfirmView and 
> ConfirmView. The above example will then look as follows:
>
>     class NewsArticlePublishView(ConfirmView):
>         model = NewsArticle
>         success_url = 'somewhere'
>
>         def action_confirmed(self):
>             self.object.published = True
>             self.object.save()
>
> I think the benefits of this solution are clear, we introduce readability 
> in these types of views (look at the class declaration, its a confirm view 
> alright!) at the cost of library size (another 3 classes got added).
>
> Please be gentle, I am new here ;). But, I enjoy a technical discussion! 
> And I attached a patch that implement this proposal, it however should be 
> treated as a POC, not a complete implementation with tests and docs and 
> such.
>
> --Lennart
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/16df2f54-fee9-4b5d-9882-bc9954a5c8dd%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
diff --git a/django/views/generic/edit.py b/django/views/generic/edit.py
index 644110f..23c4832 100644
--- a/django/views/generic/edit.py
+++ b/django/views/generic/edit.py
@@ -247,26 +247,22 @@ class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
     template_name_suffix = '_form'
 
 
-class DeletionMixin(object):
+class ConfirmMixin(object):
     """
-    A mixin providing the ability to delete objects
+    A mixin providing the ability to do a confirmed action on an object
     """
     success_url = None
 
-    def delete(self, request, *args, **kwargs):
-        """
-        Calls the delete() method on the fetched object and then
-        redirects to the success URL.
-        """
+    def action_confirmed(self):
+        raise ImproperlyConfigured(
+            "No confirmable action was defined. Implement action_confirmed().")
+
+    def post(self, request, *args, **kwargs):
         self.object = self.get_object()
         success_url = self.get_success_url()
-        self.object.delete()
+        self.action_confirmed()
         return HttpResponseRedirect(success_url)
 
-    # Add support for browsers which only accept GET and POST for now.
-    def post(self, request, *args, **kwargs):
-        return self.delete(request, *args, **kwargs)
-
     def get_success_url(self):
         if self.success_url:
             return self.success_url.format(**self.object.__dict__)
@@ -275,6 +271,44 @@ class DeletionMixin(object):
                 "No URL to redirect to. Provide a success_url.")
 
 
+class DeletionMixin(ConfirmMixin):
+    """
+    A mixin providing the ability to delete objects
+    """
+    success_url = None
+
+    def delete(self, request, *args, **kwargs):
+        """
+        Calls the delete() method on the fetched object and then
+        redirects to the success URL.
+        """
+        return self.post(request, *args, **kwargs)
+
+    def action_confirmed(self):
+        """
+        A DeletionMixin should delete its object as the confirmed action
+        """
+        self.object.delete()
+
+
+class BaseConfirmView(ConfirmMixin, BaseDetailView):
+    """
+    Base view for confirming an action on an object. If your objective is to
+    delete an object, use DeleteView.
+
+    Using this base class requires subclassing to provide a response mixin.
+    """
+
+
+class ConfirmView(SingleObjectTemplateResponseMixin, BaseConfirmView):
+    """
+    View that invokes an action on an object after confirmation,
+    implement `action_confirmed` to specify the action that should happen
+    after confirmation
+    """
+    template_name_suffix = '_confirm'
+
+
 class BaseDeleteView(DeletionMixin, BaseDetailView):
     """
     Base view for deleting an object.

Reply via email to