Search code examples
djangodjango-formsdjango-views

Django adding a feedback form on every page


I have a form view for user feedback:

urls.py:

url(
    r'^feedback/$',
    'tool.views.Feedback',
    name='feedback'
),
url(
    r'^thanks/$',
    direct_to_template, {
        'template': 'tool_feedback_thanks.html'
    },
    name='feedback_thanks'
),

forms.py:

class FeedbackForm(forms.Form):
    yes_no = forms.ChoiceField(
        choices=YES_NO_CHOICE,
        initial=1,
        widget=forms.RadioSelect(attrs={'class': 'can_reveal_input'}),
        label="Are you happy with Our service?"
    )
    comments = forms.CharField(
        widget=forms.Textarea(attrs={
            'class': 'hidden', 'placeholder': 'Leave us your comments...'
        }),
        required=False,
        label=""
    )

views.py:

def Feedback(request,
                 template_name='tool_feedback.html'):
    title = u'Leave us some feedback'
    form = FeedbackForm(request.POST or None)
    if form.is_valid():
        yes_no = form.cleaned_data['yes_no']
        comments = form.cleaned_data['comments']
        sender = "A Unirac website user"
        recipients = ['person@example.com']
        send_mail(yes_no, comments, sender, recipients)
        return HttpResponseRedirect(
            reverse('feedback_thanks')
        )
    return render_to_response(template_name, {
        'title': title,
        'form': form,
    }, RequestContext(request))

This works a treat, but now the client is asking that this form be included on every single page. I guess the form can be submitted via JS to the appropriate URL, but what is the best way to include the unbound form on every page?


Solution

  • I'd create a context processor, to include the form in every view.

    EDIT:

    To get the user to the previous URL he/she was browsing, you can use just URLs.

    # yourapp/context_processors.py
    def feedback_form_context_processor(request):
        return {
            'feedback_form': FeedbackForm(),
            'feedback_form_url': reverse("feed_app:form_process", args=(request.path))
        }
    

    This is how urls.py could look like:

    urlpatterns = patterns('feed_app.views',
        url(r'^process-feedback-form/(?P<next_url>\d+)', 'form_process', name='form_process'),
    )
    

    And the view for the form:

    def form_process(request, next_url):
        # Process form, do your stuff here
        # if its valid redirect to the url
        return redirect(next_url)
    

    And you should structure your templates to have the correct layout. For example, having a base template:

    # templates/base.html
    <html>
    <body>
    ..
    {% block maincontent %}
    {% endblock %}
    ..
    {# The form!!! #}
    <form action='{{feedback_form_url}}' method='POST'>
    @csrftoken
    {{ feedback_form.as_p }}
    </form>
    
    </body>
    </html>
    

    To create a simple view just use the correct template.

    # templates/just_a_random_view.html
    
    {% extends base.html %}
    
    {% block maincontent %}
    <h1>Content!</h1>
    {% endblock %}
    

    Finally, include it in your settings:

    # settings.py
    TEMPLATE_CONTEXT_PROCESSORS = (
        "django.contrib.auth.context_processors.auth",
        ...
        "yourapp.context_processors.feedback_form_context_processor"
    )