Display image as property of a ChoiceField in a form - django

Hi Have a choice field
class PropertyReportForm(forms.Form):
property = forms.ChoiceField(widget = forms.RadioSelect,required = False)
def __init__(self,*args,**kwargs):
properties = kwargs.pop('properties')
property_choice = []
for property1 in properties:
index = (property1.id,"Name :"+property1.name+" Area:"+str(property1.area)+" "+property1.image)
property_choice.append(index)
super( PropertyReportForm, self).__init__(*args, **kwargs)
self.fields['property'].choices = property_choice
Now while displaying I want it to display
How can I do this?
Template code similar to what I want. This does not work. But I want this
{% for field in propertyreportform %}
{{ field }} <img src="/media/{{ field.image }}" />
{% endfor %}

To solve this problem you basically have three options:
Create your own renderer, and use it as argument for ChoiceField, unfortunately you will need to create it from scratch, since django doesn't allow you to simply override RadioFieldRenderer class. https://github.com/django/django/blob/1.5.4/django/forms/widgets.py#L693
Just loop over your choices and use manually created radio input tags, there's not a lot of validation to do and retrieving selected item or model object is also simple enough.
The simplest and less recommended way could be to include the whole image tag inside label string (use settings to get media url part).

Related

Can't make Django ModelForm Select Choice Field work in Template

I tried multiple solutions around but couldn't make my select field work in Django Template. I am beginner and humbly apologize if my question is not up to standard. My select button is not showing any options in django form. I only have two options to show. Is there anyway I can get form field without having iterate through it in template? Using Django 3 and Python 3.8. Help will be much appreciated.
Model:
class User(AbstracUser):
ACC_TYPE = (('Student', 'Student'), ('Teacher', 'Teacher'))
role = models.CharField(max_length=100, choices=ACC_TYPE
.....
Form:
class UserForm(UserCreationForm): #Using django's default form
account_type = forms.CharField(widget=forms.Select(choices=User.ACC_TYPE))
model = User
fields =('.............,
'account_type')
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
self.fields['account_type'].choices = [(each[0], each[1]) for each in User.ACC_TYPE]
self.fields['account_type'].required = True
Template:
.......
<select>
{% for opt, val in form.account_type.choices %}
<option value="{{ opt }}">{{ value }}</option>
{% endfor %}
</select>
......
Your logic is fine. You shouldn't be having this issue. Only reason could be and its a long shot...that you are using some bootstrap theme with customized CSS classes in it. Now either you load those custom classes per field or you can use django-crispy-fields that inherits all classes with form-group. You will need to load the form with {{ form|crispy }}. For details please check settings for django-crispy-forms. Remember to load the tag at top of page where you want to use it as per settings {% load crispy_forms_tags %}. Read Docs here.

Django - MultipleChoiceField is being displayed as a string instead of a list

I have a MultipleChoiceField forms field (associated with a models CharField) which shows up in the database like this. It seems to have been converted to a string in the database, because when I try to display it with a 'for property in property_type' statement in the HTML, it shows up like this. I want it to be displayed like this
So I have to write some code to fix this issue. My pseudocode will look something like:
for record in property_type:
split record at comma
for i in record:
if record[i] is not a letter or number:
remove record[i]
Now my question is, where do I write this code? Do I write it in the views.py or in the HTML file? I tried doing it in views but I don't know how to select a single database record. I tried doing it in the HTML but I was limited by the template tags.
Here is the shortened version of my code:
models.py:
property_type = models.CharField(max_length=50, help_text="You can select more than 1 option")
forms.py:
property_type = forms.MultipleChoiceField(widget=forms.SelectMultiple, choices=BuyerListing.PROPERTY_TYPE)
HTML:
{% for property in listing.property_type %}
<p>Property type: {{ property }}</p>
{% endfor %}
EDIT:
Got it to work thanks to #ytsejam and #Daniel Roseman. With ytsejam's code, the result will show up like this:
['1' '2']
I added a basic regex to ytsejam's code to remove the brackets and quotes:
def split_properties(self):
a = self.property_type
a = re.sub(r'[\]\[\']', '', a)
a = a.split(',')
return a
Now the list will display like this, which is very easy to manipulate in HTML.
1 2
in your models.py
def split_properties(self):
return self.properties.split(',')
and in your template use
{% for property in className.split_properties %} {{ property }} {% endfor %}

Manually render Django form fields with variable label

I am creating forms with dynamic fields (and field names) using the below code
class BuyItemForm (forms.Form):
def __init__(self, inventory_list, *args, **kwargs):
super(BuyItemForm, self).__init__(*args, **kwargs)
for item in inventory_list:
self.fields["count%s"%item.item_name] = forms.IntegerField()
self.fields["price%s"%item.item_name] = forms.FloatField()
So I get a form that has field names like "counteggs", "priceeggs", "countmilk", etc... when these items are in the inventory_list
I now want to render the fields manually in my template. I am able to iterate through the set of fields, for example
{% for field in form %}
{{ field }}
{% endfor %}
But I am unable to pick out each field individually by using the field name in a string. I have tried
{{ form.fields['counteggs'] }}
but this doesnt work. Any ideas how I can make this work?
Did you try {{ form.fields.counteggs }} ? In the templates, dictionaries are accessed with dot notation.
So, I found a rather convoluted way of doing this by creating a filter in views.py that receives the form and a key as parameters. It iterates through the form till a field that has a label matching the key is found.
#register.filter
def get_countitem(myform, key):
for field in myform:
if field.label.lower() == key.lower():
return field
return "none"
and in the template
{{ form|get_countitem:"counteggs" }}
It works. I can get my template to render form fields by passing the field label in a string but doesnt seem like a particularly elegant solution to me. Any other ideas are most welcome.

Muliple instances of modelform

I have a list in my template. For each item in the list, I have a {{ modelform }} that contains a checkbox. I can check the box and it updates as should. The problem is that when I check the box for one item and submit, it submits for all of the checkboxes because they are the same in each instance. Is there a way to set up a unique checkbox instance for each item in the list?
Current each modelform checkbox renders the same like this:
<input name="is_solution" type="checkbox" class="is_solution" id="is_solution">
I also tried using
test = request.POST.get('checkbox')
and
test = request.POST.get('checkbox')
thinking that using this I might be able to post an update in my view. I think I am going about this all wrong and I am lost. Essentially, I would like to have a checkbox on a list much like here on stackexchange where you can confirm an answer. Any suggestions?
You have to use form's prefix in the view like (just something unique for each form object):
def foo(request, ...):
objs = Model.objects.filter(...)
forms = []
for i, obj in enumerate(objs):
form = ModelForm(instance=obj, prefix=str(i))
forms.append(form)
...
This will make sure each form has unique identifier, hence you will be able to submit a specific form.
And you can render the forms like usual in the template:
<form ...>
{% csrf_token %}
{% for form in forms %}
{{ form }}
{% endfor %}
</form>

Custom rendering a radioselect in django form / accessing single element?

I have a form like this:
CHOICES = [
('a', 'a_value'),
('b', 'b_value'),
('c', 'c_value')
]
self.fields["choice"] = forms.ChoiceField(
widget=RadioSelect(),
choices=CHOICES,
)
How can I select a single element of this form field in my template? I want to be able to do something like:
<tr><td>{{form.choice.a}}</td><td>some custom extra field</td></tr>
Or is there another way to change how the RadioSelect is rendered?
See full doc -
https://docs.djangoproject.com/en/dev/ref/forms/widgets/#radioselect
{% for radio in form.my_radio_select %}
- {{ radio.choice_label }}
- {{ radio.tag }}
{% endfor %}
You cannot do this via parameters or something, the way it is rendered is hardcoded in its widget class! See eg. http://code.djangoproject.com/browser/django/trunk/django/forms/widgets.py: RadioSelect.render (->RadioFieldRenderer.render); subclass it and override the render method, then use it in your form myfield = forms.MultipleChoiceField(widget=MyWidget(...)).
I labored over this for a few hours trying to find some way to use a custom renderer on a RadioSelect, but there is no way to pass in the choice number. Instead I went for a kludgey, but simple approach. In added an __init__ function to my form:
def __init__(self, *args, **kwargs):
super(FormName, self).__init__(*args, **kwargs)
self.radiofield_choice = re.findall(r'<li>(.+?)</li>',
unicode(self['radiofield_name']))
That uses the RadioSelect's default render to create the widget, and then parses out the individual choice HTML. You could even combine that with the defined choices to create a dictionary instead of a list.
In my template I used {{ form.radiofield_choice.0|safe }} to render just the first item. Increment the zero to get the other items.
If, for some reason, only the input fields without enclosing labels are needed, use r'(<input.+/>)'.