Retrieving data from an array of check boxes in a Django template - django

In a Django template, I'm displaying some usernames (or unames) along with check boxes like so:
<form method="POST" action="{% url 'process_unames' %}">
{% csrf_token %}
{% for name in unames %}
<input type="checkbox" name="target{{ forloop.counter0 }}" value="{{ unames|index:forloop.counter0 }}" checked>{{ name }}<br>
{% endfor %}
<button name="duration" value="{{ value }}" type="submit">Submit</button>
</form>
And then in the function process_unames, I'm trying to retrieve all checked unames via:
def process_unames(request, *args, **kwargs):
uname_list = request.POST.getlist('unames')
This is consistently yielding an empty list, regardless of which uname I check or uncheck. How do I fix this? An illustrative example would be great.
In case it matters, I haven't declared any form in forms.py with this Django template. Moreover, note that index is a custom template tag which does the following (and I can vouch it's correctly working):
from django.template.defaulttags import register
#register.filter(name='index')
def index(List, i):
return List[int(i)]

You are checking the wrong variable. You access the input by its name.
So for a single value you would retrieve the data for a form like this
<input type="checkbox" name="user_name" value={{uname}}>
via
request.POST.get('user_name')
See: https://docs.djangoproject.com/en/1.10/topics/forms/#the-work-that-needs-to-be-done
And if you have loop, you still give each relevant input the same name and use request.POST.getlist() to access the values as a list.
See: https://stackoverflow.com/a/23470119/630877

You don't have any fields called "unames" in the template. You have a bunch of unrelated checkboxes called "targetX" where X is a number. Replace that with just name="unames" and your code will work.
Note two things: firstly, you should be using Django's forms framework; and secondly, your filter is pointless because {{ name }} would already by the value in unames, since that is what you are iterating over (and, indeed, you are already using that as the label).
{% for name in unames %}
<input type="checkbox" name="unames" value="{{ name }}" checked>{{ name }}<br>
{% endfor %}

Related

Django 3.1: Access objects in template of ModelChoiceField

Using Django 3.1 and I'm struggling with a basic tasks.
I've got a form with a field like this:
forms.ModelChoiceField(queryset=StorageSpace.objects.filter(visible=True), widget=forms.RadioSelect)
I would like to do this in my view:
{% for space in form.available_spaces %}
<label class="btn btn-outline-primary">
<input value="{{ space.id }}" data-storage-price={{ space.price }}>{{ space.title }}
</label>
{% endfor %}
But this doesn't work. How can I access the attributes of my objects for each choice?
Can't be that difficult, can it? I really need to set the data attribute, otherwise I would just use{{space}}.
form.available_spaces.field.queryset
lets you access the object behind the choice-field. As simple as that.

Django - How to display all items inside a Object

I have a Profile Object which has a many to many reationship with a Hobbies object. A profile is used for creating a User. Each User can also have a load of hobbies that are predefined. What I want to do is let Users pick some hobbies they are interested in. However, I am not sure how to display all these Hobbies and let Users pick them on the actual display. Here is the code:
TYPES = (
("Football", "Football"),
("Cricket", "Cricket"),
("Swimming", "Swimming"),
("Cycling", "Cycling")
)
class Hobby(models.Model):
myfield = MultiSelectField(choices = TYPES)
And the User :
class Profile(models.Model):
email = models.CharField(max_length=200)
hobbies = models.ManyToManyField(Hobby)
And the HTML code I use is here:
<span class="fieldname">Hobbies</span>
{% for hobby in all_hobbies %}
<input type="checkbox" name={{hobby}} value={{hobby}}> {{hobby}}<br>
{% endfor %}
However this only displays
What I want it to display is all the hobbies with the choices, instead of the whole Object. I am not sure how to do this and would appreciate any help.
Try doing something like
<span class="fieldname">Hobbies</span>
{% for hobby in all_hobbies %}
<input type="checkbox" name="{{ hobby.myfield }}" value="{{ hobby.myfield }}"> {{ hobby.myfield }}<br />
{% endfor %}
Under Hobby class, you should add the str method that will display the value of your hobby instead of 'Object'
def __str__(self):
return self.myfield
You can also use __unicode__ instead of __str__ if you are with Python 2.x
Edit:
After I read again your question, I understood that your problem was specifically not having several checkboxes for the multiple choices you have, here is how you can show all the choices, you should pass the hobbies field as a context :
{% for value, text in form.hobbies.field.choices %}
<div class="ui slider checkbox">
<input id="id_hobbies_{{ forloop.counter0 }}" name="{{ form.hobbies.name }}" type="checkbox" value="{{ value }}"{% if value in checked_hobbies %} checked="checked"{% endif %}>
<label>{{ text }}</label>
</div>
{% endfor %}

Render form without tags django

{% for fields in form %}
{{ field.label }}
{{ field }}
{% endfor %}
The {{ field }} will render something similar to:
<input type="text" id="something_id" .../>
Is there a way I can render a field without having to let it wrap it in a tag? So for instance, I render a field and I get (without the input tag):
type='text' id='_something_id'
In this case, I can go ahead to manually add custom classes as and when and where I want like:
<input {{ field }} class='class class-again' required autocomplete='off' />
Is there a way I can do that in Django, render a field without it wrapped in the element?
Obviously, such a hard way of formatting can be tiring if working on tons of fields making such an approach impractical. In my case, I'm just wanting to tailor some css to just two fields, and having to go through Django Forms, or template tags etc, I find the process lengthy
You can do this if you know the input type:
{% for field in form %}
{{ field.label_tag }}
<input type="text" id="{{ field.id_for_label }}" name="{{ field.html_name }}" value="{{ field.value }}"/>
{% endfor %}
If you have different input types you could still go through the fields manually instead of iterating over them (using their name, eg. form.username).
However in most cases it is better to do those things on the backend using the widget API like this:
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
It is possible. You could write your own HTML code, you know that Django assigns id and name attributes with a format, like: id='something_id'. The name attribute is the important one, you should make sure it is the same that Django would assigns.
Another option is this:
# I will assume you have a field named something
something = forms.CharField(widget=forms.TextInput(attrs={'class':'class class-again''}))
This should do what you need. I hope this helps.

Django Forms to values of html <input> field

I am trying to access the values of a Bootstrap btn-group from Django and from the documentation I have found, it seems that you should use Forms in Django for such tasks.
This is what the html looks like, right now:
<div class="col-md-6">
{% for metric in metrics %}
<input name="{{ metric.name }}" type="hidden" value="0"/>
{% endfor %}
<div class="btn-group" data-toggle="buttons">
{% for metric in metrics %}
<button type="button" class="btn btn-default" data-checkbox-name="{{ metric.name }}">{{ metric.name }}</button>
{% endfor %}
</div>
</div>
How can I use forms to get the values of the input fields?
Here it is a basic example about using a form in django
views.py:
#login_required
def your_view(request): # Add this code into your view
if request.method == 'POST':
# So here you can do a loop over POST fields like this
data_list = [] # We will insert all the inputs in this array
for key in request.POST:
data_list.append(request.POST[key])
# Here you can manage the the data_list and do whatever you need
# The content of the data_list depend on your inputs
# It could be string, integer....
# YOUR VIEW CODE
template (form example):
<form action="." method="post" id="add_user_form">
{% csrf_token %}
{% for metric in metrics %}
<input type="text" name="{{ metric.name }}" placeholder="whatever you want">
{% endfor %}
<input type="submit" value="submit" class="default"/> # Submit button
</form>
{% csrf_token %} : You need to put this in every form you use
action="." : This make the post to the actual page
But anyway I strongly recommend you to check this Django Forms Documentation to unterstand better the logic, and also check the ModelForms because can save you a lot of time when you need to make a form for a model that exists in your Django Models
You are'n forced to use django forms, this is just a way to get a sort of organization.
in you views toy can get the values sent to the server by using request.GET or request.POST, depending of the method of the form.
to get a list of values you have received just do a
print request.POST
request.POST is a dictionary, so you can get any value fron them by its key:
print request.POST['<key>']

Easiest way to get the value of a key in request.POST

I have a user with a list of schools he has entered in his userprofile. I want to give him the ability to delete any one of his entries.
The following is the way I am currently using to delete a database entry, based upon the value of a key in the template:
# in template
{% for education in educations %}
<p>{{ education.school }}
<input type="submit" name="delete_{{education.id}}" value="Delete" /></p>
{% endfor %}
# in view
if 'Delete' in request.POST.values():
for key in request.POST.keys():
if key.startswith('delete'):
education_id = key[7:]
profile.educations.remove(Education.objects.get(id=education_id))
Is there an easier way to get the value of a key, rather than having to iterate over for key in request.POST.keys()? Thank you.
Forms are free. Make more of them.
{% for education in educations %}
something something
<form action="..." method="POST">
<input type="hidden" name="id" value="{{ education.id }}">
<input type="submit" value="Delete">
</form>
{% endfor %}
Then in the view:
id = request.POST['id']
profile.educations.remove(...)
Or put the id a GET parameter, instead of a hidden field (just make sure you don't use GET method for a form — those should never have any side effects).
While I also agree that forms are nice, you can also simplify your code a bit:
if 'Delete' in request.POST.values():
for key in request.POST.keys():
if key.startswith('delete'):
education_id = key[7:]
profile.educations.remove(Education.objects.get(id=education_id))
Could be simplified into:
for education_id in [key[7:] for key, value in request.POST.iteritems() if value == 'Delete' and key.startswith('delete')]:
profile.educations.remove(Education.objects.get(id=education_id))
I came up with another approach using the filter function but it was much messier and looked less elegant than the above.
if request.method == 'POST' and 'button_name' in request.POST.keys():
do_something
elif other button name