Add custom html to choicefield label in django
Asked Answered
R

4

6

I am struggling with a requirement now, I want to add an image to choice field label and I really dont have a clue how to do it. I am using django form wizard to render the form. Here is the image which shows what I want to achieve : enter image description here

And here is what I have got right now ( to make the radio buttons inline, I know it could be achieved through css): enter image description here

Here is the forms.py:

from django import forms
from django.utils.translation import gettext as _


CHOICES=[('0','Pay by card'), ('1','Invoice')]




class PaymentForm(forms.Form):
    title = 'payment'
    payment_method = forms.ChoiceField(label = _("Payment Options"), choices=CHOICES, widget=forms.RadioSelect(), required = True)

I am rendering using wizard form:

 {{ wizard.form.payment_method.label_tag }}
                                {{ wizard.form.payment_method|safe }}
                                {{ wizard.form.payment.errors}}

Anyone has any suggestion for this apart from custom widget?

Rawlinson answered 19/7, 2013 at 13:5 Comment(2)
Depends on how you render your form. If you use form.as_p() or similiar build in function, you would have to override this behaviour. You can also do your form manually in html. docs.djangoproject.com/en/dev/topics/formsTrice
I just edited my question.Rawlinson
K
2

1) Shortly (but i'm not sure) call a function where 'Pay by card' and return all <img>... that you need.

2) You can make somthing like @Gahbu said

3)Long [Better, i think, but untested :( ]: Make a renderer:

from myapp.my_widgets import CardsRadioFieldRenderer

CARD_CHOICE = '0'

CHOICES=[(CARD_CHOICE,'Pay by card'), ('1','Invoice')]

class PaymentForm(forms.Form):
    title = 'payment'
    payment_method = forms.ChoiceField(label = _("Payment Options"), choices=CHOICES,widget=forms.RadioSelect(renderer=CardsRadioFieldRenderer), required = True)

# myapp/my_widgets.py

class CardRadioInput(RadioInput):
    def __init__(self, name, value, attrs, choice, index):
        self.name, self.value = name, value
        self.attrs = attrs
        choice_value = force_text(choice[0])
        self.choice_value = choice_value
        if choice_value == CARD_CHOICE:
            choice_label = force_text(self.get_html_for_card_choice())
        else:
            choice_label = force_text(choice[1])
        self.choice_label = choice_label
        self.index = index

   def get_html_for_card_choice(self):
        #some logic to get the images tags (<img ...> <img ...>)
        return text


class CardsRadioFieldRenderer(RadioFieldRenderer):
    def __getitem__(self, idx):
        choice = self.choices[idx] # Let the IndexError propogate
        return CardRadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
Karalee answered 19/7, 2013 at 13:40 Comment(1)
Well, even I am not sure if point 1 could be achieved, but Gahbu's solution is not working for me right now, and I kept the point 3 as the last option, I was just not sure if there is any simple solution to achieve this, so thought of posting it here.Rawlinson
M
3

Without a widget:

from django.utils.safestring import mark_safe
CHOICES=[('0', mark_safe('Pay by card <img src="by_card.jpg"/>')),
         ('1', mark_safe('Invoice <img src="no_card.jpg"/>'))
]

Credit: setting help_text for each choice in a RadioSelect

Mobilize answered 23/1, 2014 at 1:23 Comment(0)
M
2

In your template do something like :

 {% for choice in wizard.form.payment_method.choices %}
    {{ choice.0 }} {# value #} {{ choice.1 }} {# value #}
    {% if choice.0 == PAYMENT_BY_PAYPAL %}
     ...
    {% endif %}
 {% endfor %}

You can also write :

  {% for key, value in wizard.form.payment_method.choices %}
    {% if key == PAYMENT_BY_PAYPAL %}
     ...
    {% endif %}
 {% endfor %}
Meiny answered 19/7, 2013 at 13:25 Comment(3)
Yes, me too, see above.Meiny
Is PAYMENT_BY_PAYPAL, the key name? Which is '0' in my question?Rawlinson
Yes, in your case it is '0' the other one is '1'.Meiny
K
2

1) Shortly (but i'm not sure) call a function where 'Pay by card' and return all <img>... that you need.

2) You can make somthing like @Gahbu said

3)Long [Better, i think, but untested :( ]: Make a renderer:

from myapp.my_widgets import CardsRadioFieldRenderer

CARD_CHOICE = '0'

CHOICES=[(CARD_CHOICE,'Pay by card'), ('1','Invoice')]

class PaymentForm(forms.Form):
    title = 'payment'
    payment_method = forms.ChoiceField(label = _("Payment Options"), choices=CHOICES,widget=forms.RadioSelect(renderer=CardsRadioFieldRenderer), required = True)

# myapp/my_widgets.py

class CardRadioInput(RadioInput):
    def __init__(self, name, value, attrs, choice, index):
        self.name, self.value = name, value
        self.attrs = attrs
        choice_value = force_text(choice[0])
        self.choice_value = choice_value
        if choice_value == CARD_CHOICE:
            choice_label = force_text(self.get_html_for_card_choice())
        else:
            choice_label = force_text(choice[1])
        self.choice_label = choice_label
        self.index = index

   def get_html_for_card_choice(self):
        #some logic to get the images tags (<img ...> <img ...>)
        return text


class CardsRadioFieldRenderer(RadioFieldRenderer):
    def __getitem__(self, idx):
        choice = self.choices[idx] # Let the IndexError propogate
        return CardRadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
Karalee answered 19/7, 2013 at 13:40 Comment(1)
Well, even I am not sure if point 1 could be achieved, but Gahbu's solution is not working for me right now, and I kept the point 3 as the last option, I was just not sure if there is any simple solution to achieve this, so thought of posting it here.Rawlinson
P
0

If you want to tweak it from the template, you need to use the "safe" which tells Jinja not to escape it. like below

{{ some_object.some_property|safe }}

Yet if you want to use it inside your python code while defining the form/modelform just use mark_safe as below.

mark_up = 'this is a <a href="http://www.google.com">link</a>'
choices = list()
choices.append(('some_id', mark_safe(mark_up)))
self.fields['some_field'].choices = choices
Puckett answered 10/1, 2017 at 12:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.