16

I am an absolute novice to django-cms. I have gone through the tutorial and configured it exactly the same as mentioned in the documentation. Now, I have to build an application which uses a form to upload products.

I dont have a clue as to how to move ahead with it. I want to start it with simple forms as if now, say, a username and password textbox kind of. How can I use django forms in the django-cms page? I have snippet plugin enabled in it too. I need some guidance for this.

Any suggestions plsss. thanks

Maverick
  • 2,738
  • 24
  • 91
  • 157
  • 1
    It really seems there is no reasonable way to do it, which would support both error displaying for errors in the form and using simple Django forms as they are used elsewhere. – Mitar Feb 24 '13 at 20:04

6 Answers6

15

Actually the solution proposed by bennylope is not the preferred way to do it, since using request.POST in a plugin can have very bad side effects (eg: what if the same plugin is twice on a page? Or what if there's multiple plugins waiting for POST data on the same page? Those plugins would confuse each other when there's a POST to that page).

So the preferred way is:

  • Make a CMSPlugin as described by bennylope to render the form.
  • Make the form post to a statically hooked view (or a apphooked view), if the POST is successful, redirect to the page again if you want.
Community
  • 1
  • 1
ojii
  • 4,729
  • 2
  • 23
  • 34
  • Well as I said, I am absolute newbie to django-cms. Can I see an snippet of a cms plugin, to get a better understanding? – Maverick Mar 26 '11 at 18:02
  • Even if the plug below were used on the same page multiple times, the form is not being submitted to the CMS page itself, but to a separate view (as noted in the last sentence of my response). In both examples below each form is agnostic with regard to where it sends the data; that's declared within the plugin template. – bennylope Mar 26 '11 at 19:00
  • bennylope, why do you do have the `if request.method == 'POST'` in there then? – ojii Mar 26 '11 at 19:40
  • Yikes, I actually missed that. Copied that example from [an extension featured in the Django CMS extensions gallery](https://github.com/rtpm/cmsplugin_contact). Was thinking about my first example in context of your comment. – bennylope Mar 27 '11 at 01:27
  • 4
    And what if the form doesn't validate? As lentschi points out below, this isn't really acceptable. – Rich Jun 08 '11 at 10:52
6

Assuming your product application works as expected without Django CMS, what you'd next want to do is create your own plugin to show the form. The plugin would render your form, which you've already defined in your own application using a plugin template that you've created.

This plugin for a contact form allows the contact form to be inserted into the page template anywhere a placeholder will allow it.

class ContactPlugin(CMSPluginBase):
    """Enables latest event to be rendered in CMS"""

    model = CMSPlugin
    name = "Form: Contact"
    render_template = "contact_form/contact_plugin.html"

    def render(self, context, instance, placeholder):
        request = context['request']
        context.update({
            'instance': instance,
            'placeholder': placeholder,
            'form': ContactForm(request=request),
        })
        return context

The template would include all the HTML and Django template language necessary to render the form.

This other contact form plugin shows another example of how to do it. Instead of rendering the form it just updates the context. The upside is that you don't have to create a separate template, but the downside is that you lose some of the modularity of having a plugin. This depends on the page template rendering the form.

class ContactPlugin(CMSPluginBase):
    model = Contact
    name = _("Contact Form")
    render_template = "contact.html"

    def render(self, context, instance, placeholder):
        request = context['request']

         if request.method == "POST":
            form = ContactForm(request.POST)
            if form.is_valid():
                form.send(instance.site_email)
                context.update( {
                    'contact': instance,
                    })
            return context
        else:
            form = ContactForm()

            context.update({
            'contact': instance,
            'form': form,
            })
            return context

In either case you still have to define the view to accept the form submission, which means you'll need to create a view outside of the CMS acknowledging receipt of the form with its own template, redirecting the user back to the referring page, and/or accepting an AJAX request.

J. Ghyllebert
  • 2,009
  • 1
  • 29
  • 35
bennylope
  • 1,113
  • 2
  • 13
  • 24
  • Ok, I see what you mean. But if I create a plugin, what should be its name? and where should I save it? – Maverick Mar 26 '11 at 17:28
  • You can name the plugin whatever you want. What you should do is create the plugin in an aptly named file _within your own application_ and then register your plugin with Django CMS. I would strongly recommend referencing the [custom plugin documentation](http://docs.django-cms.org/en/2.1.3/extending_cms/custom_plugins.html) to understand how to create a basic plugin, and the source of some [example extensions](https://www.django-cms.org/en/extensions/). Once you have your data handling view (in your app) the form plugin is just rendering the form in the template. – bennylope Mar 26 '11 at 19:08
  • Still, POSTing to other view, how you display errors to the user? – Mitar Feb 24 '13 at 20:03
  • 1
    If you're referencing ojii's answers (which is the way to approach this) you display errors by one of two ways: rendering a separate form view (at the URL endpoint which handles the form request) or by doing the same via AJAX. The latter would offer a better user experience. – bennylope Feb 25 '13 at 18:25
  • I created a plugin that takes care of all this because I had a similar problem see my answer or https://github.com/metzlar/cms-form-plugin –  Jan 30 '14 at 23:59
6

I'm new to django-cms too, but the way ojii described in their answer seems like the most reasonable:

  • Make a CMSPlugin as described above to render the form.
  • Make the form post to a statically hooked view (or a apphooked view), if the POST is successful, redirect to the page again if you want.

However for me this only a partial solution because I don't only want to redirect back to the cms page containing the plugin in the case of success but also in the case of form errors which need to be displayed. The redirecting part is not the problem (I just redirect back to request.META["HTTP_REFERER"]), but the part of handing over the form (errors) to the cms page containing the plugin is tricky. The only answer I found for this: I use a session (Writing the form into the session in the static view, and then deleting it again in the plugin's render method). Not the nicest way, but it works. (There would be better ways, if the cms plugins configuration would support some way to redirect instead of rendering, but apparently there is no such option: see http://groups.google.com/group/django-cms/browse_thread/thread/79ab6080c80bbcb5 )

fedorqui
  • 275,237
  • 103
  • 548
  • 598
lentschi
  • 300
  • 1
  • 11
6

I've recently ran across django-form-designer

It's quite nice and lets you design forms in a wysiwyg manner. Works for stand alone django applications and has an additional plugin for Django-CMS. One note: you have to follow the standalone instructions in addition to the Django-CMS instructions for installation.

From the github description:

Key features:

  • Design contact forms, search forms etc from the Django admin, without writing any code
  • Form data can be logged and CSV-exported, sent via e-mail, or forwarded to any web address
  • Integration with Django CMS: Add forms to any page
  • Use drag & drop to change the position of your form fields
  • Fully collapsible admin interface for better overview over your form
  • Implements many form fields included with Django (TextField, EmailField, DateField etc)
  • Validation rules as supplied by Django are fully configurable (maximum length, regular expression etc)
  • Customizable messages and labels
  • Supports POST and GET forms
Community
  • 1
  • 1
Edgar
  • 1,174
  • 8
  • 9
2

This might be way too late but I had a similar problem so I created a more general plugin: https://github.com/metzlar/cms-form-plugin which happens to be very similar to bennylope's answer.

1

You can work around by throwing an exception and catching it in middleware: http://djangosnippets.org/snippets/2541/

Motiejus Jakštys
  • 2,769
  • 2
  • 25
  • 30
  • This one seems quite nice and simpler: https://github.com/jonasgeiregat/django-excepted – Mitar Feb 24 '13 at 20:27