Lacrymology
Lacrymology

Reputation: 2259

Conditional field in form

I need to make a Form class that may or not have a ReCaptcha field depending on whether the user is logged in or not.

Because this is a CommentForm, I have no access to the request object on form creation/definition, so I can't rely on that.

For the POST request the solution is easy: I've got this:

class ReCaptchaCommentForm(CommentForm):
    def __init__(self, data=None, *args, **kwargs):
        super(ReCaptchaCommentForm, self).__init__(data, *args, **kwargs)
        if data and 'recaptcha_challenge_field' in data:
            self.fields['captcha'] = ReCaptchaField()

Having done this, form validation should work as intended. The problem now is on the template side. I need the template to be like this:

<form action={% comment_form_target %} method="post">
{# usual form stuff #}
{% if not user.is_authenticated %}
<script  type="text/javascript"
         src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<div id="recaptcha-div"></div>
<script type="text/javascript">
  Recaptcha.create({{ public_key }}, "recaptcha-div",
                   { theme: 'white',
                     callback: Recaptcha.focus_response_field });
</script>
{% endif %}
</form>

But I'd like not to have to repeat that code on every comments/*/form.html template. I gather there should be some way of adding equivalent code from a widget's render method and Media definition.

Can anyone think of a nice way to do this?

Upvotes: 5

Views: 6155

Answers (4)

Murph
Murph

Reputation: 520

Use crispy-forms! You can include html elements in the form layout that would allow you to exclude/include a field based on the views request context. Extremely useful features outside of that as well.

Here's the relevant doc section.

Upvotes: 3

manu
manu

Reputation: 66

What I am doing about conditional fields is having a base class (which inherits from Form) and other subclasses with the extra conditional fields.

Then in my view, depending on the condition I choose the required subclassed form. I know that it involves some duplicated code, but it seems easier than other approaches.

Upvotes: 1

zaan
zaan

Reputation: 897

I assume that you instatiate your form in a view, so you could just pass the user from request to the form (just like in auth app SetPassword form):

def __init__(self, user, data=None, *args, **kwargs):
    super(ReCaptchaCommentForm, self).__init__(data, *args, **kwargs)
    if user.is_authenticated():
        self.fields['captcha'] = ReCaptchaField()

Upvotes: 5

Chris Pratt
Chris Pratt

Reputation: 239290

Well, it's unfortunate that django-floppyforms doesn't give access to the request. It would have been nice to know it was an option, as I've recently started using django-floppyforms in my own project.

Short of that, the best thing I can think of is to simply rely on template inheritance. You can create a comments/form.html file and then have each comments/*/form.html extend that. Put the Recaptcha code as you have it in the base form.html and you're good to go.

Upvotes: 0

Related Questions