How to display option-names instead of option-values? - django

I poked around with get_FOO_display to no avail, here's what I've got (I trimmed some stuff to make it easier to read, like a custom def save:
class Profile(models.Model):
LEVEL_CHOICES = (
(1, 'Primary'),
(2, 'Secondary'),
(3, 'Tertiary'),
)
level = models.IntegerField( verbose_name = 'Level', blank=True, null=True, choices=LEVEL_CHOICES)
piplevel = models.ForeignKey(AccessLevel, related_name='profiles')
vanity = models.ForeignKey(AccessLevel, related_name='vanity')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
# HTML CODE from Template below
<tbody>
{% for field in user_form %}
<tr>
<th>{{ field.label_tag }}</th>
<td class="updatable">
<div class="field">
{{ field }}
</div>
{% if field.errors %}{{ field.errors }}{% endif %}
</td>
</tr>
{% endfor %}
{% for field in profile_form %}
<tr>
<th>{{ field.label_tag }}</th>
<td class="updatable">
<div class="field">
{{ field }}
</div>
{% if field.errors %}{{ field.errors }}{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
The output I get:
Level 1
Piplevel 15
Vanity 20
The output I want:
Level Primary
Piplevel Diamond
Vanity Ambassador
I tried replacing the {{ field }} and for loop with {{field.get.level.display}} and {{ field.get_piplevel_display }} but it they just returned blanks. When these display, they're a drop-down menu and DO have all the named-options available - that is, when I click on the "15" I do get an option list i.e.:
Piplevel 15 click (current selected is 15)(option value="1">Regular(/option>(option value="2">Platinum(/option>etc. (not html code)
Am I missing some easy function in Django for this?
Edit: Here's the HTML output I GET currently.
<tr class="even">
<th>
<label for="id_piplevel">Piplevel</label>
</th>
<td class="updatable" title="Click to modify">
<div class="field" style="display: none;">
<select id="id_piplevel" name="piplevel">
<option value="">---------</option>
<option value="1">Regular</option>
<option value="2">Platinum</option>
...
<option selected="selected" value="7">Emerald</option>
</select>
</div>
<div>7</div>
</td>
</tr>
Here's the HTML output I WANT, ideally:
<tr class="even">
<th>
<label for="id_piplevel">Piplevel</label>
</th>
<td class="updatable" title="Click to modify">
<div class="field" style="display: none;">
<select id="id_piplevel" name="piplevel">
<option value="">---------</option>
<option value="1">Regular</option>
<option value="2">Platinum</option>
...
<option selected="selected" value="7">Emerald</option>
</select>
</div>
<div>Emerald</div>
</td>
</tr>
And, if I replace {{ field }} with {{field.get_piplevel_display}} or {{field.choice.get_piplevel_display}}, I get this as output:
<tr class="even">
<th>
<label for="id_piplevel">Piplevel</label>
</th>
<td class="updatable">
<div class="field"> </div>
</td>
</tr>
It seems like this is something everyone would want, and so I expected there to be some argument in Django that just... fixes this, but I can't find it. Sorry for making a simple question seem so complicated - this is supposed to be a simple question, isn't it?

For every field that has choices, Django automatically adds a get_FOO_display() method on the model (docs). All this method does is take the already stored value for the field, looks it up in the provided choices for the field and returns the "display" text for that value.
This method is not available on the field or the form. You must reference an existing object or the instance of the form (e.g. form.instance).
Again, I'm not sure what you're trying to accomplish, because the <select>s are already populated such that they display the text and not the underlying value. Even if you're editing an existing object, the <select> will still show the display text for the currently set value.

I don't really see what you're trying to do, but:
{{field.get.level.display}}
should be something like
{{field.choices.get_level_display}}
# or
{{field.get_level_display}}

Related

Django hidden input being rendered as <td> in html

I'm using a modelformset to allow the user to add/edit/delete food item's on their restaurant's menu.
FoodItemFormset = modelformset_factory(FoodItem, fields = '__all__', can_delete = True)
I'm then iterating over all of the forms in my template and displaying them in a table:
<table>
<tr>
<th>Food Item</th>
<th></th> <!-- empty <th> lines up with hidden input field -->
<th>Delete</th>
</tr>
{% for form in food_formset %}
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" name="" value="Submit">
However, that can_delete attribute does not only lead to a checkbox being rendered, it also renders the hidden field containing the object's id as an actual table element, leading to an empty gutter between the tables contents.
<td><input type="text" name="form-0-name" value="Mozzarella Sticks" maxlength="200" id="id_form-0-name"></td>
<td><input type="hidden" name="form-0-id" value="2" id="id_form-0-id"></td> <!-- this just looks like an empty gutter -->
<td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE"></td>
Is there a way to get around this? Thanks for any help.
Loop over form.visible_fields to only include visible fields.
{% for field in form.visible_fields %}
<td>{{ field }}</td>
{% endfor %}
You will also need to render the hidden fields but this doesn't need to be in it's own table cell.
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}

how to pass the selected check box id of a input tag to views in django and bulk update the selected rows in table

** 1.how to pass the selected check box id of a input tag(which is in for loop, so the name and value of input tag are dynamic ) to views in django and bulk update the selected rows of table in django**
<div class="jumbotron">
<form method="post" action="">
{% csrf_token %}
{{form|crispy}}
<input class = "btn btn-primary" type="submit" value="Search">
</form>
<h3 > Model values </h3>
<ul>
<table class="table" id="tab1">
<thead>
{% if teams %}
<tr>
<th>Select</th>
<th>#</th>
<th><b>Logo</b> </th>
<th><b> Team </b></th>
</tr>
</thead>
<tbody>
{% for value in models %}
<tr>
<td><input name="lol" type = "checkbox" value = "{{value.id}}"/> </td>
<td> {{forloop.counter}}</td>
<td> <img class="w3-display-topmiddle w3-container" src="{{ value.logUri.url }}" alt="alt txt" height="910" width="910"></td>
<td> {{ value.name }} </td>
</tr>
{% endfor %}
</tbody>
</table>
**realized that since i am not keeping input tag in form tag the input tag's name values is not captured by request.POST(now changes are dome in html as below ),later in django views i removed the unnecessary keysvalues using dict.pop() and created a list containing on primary keys
in django orm (model.filter(id__in= lst_of_id_captured).update(field='somevalue') **
<form method="post" action="">
{% csrf_token %}
{{form|crispy}}
<h3 > Model values </h3>
<ul>
<table class="table" id="tab1">
<thead>
{% if teams %}
<tr>
<th>Select</th>
<th>#</th>
<th><b>Logo</b> </th>
<th><b> Team </b></th>
</tr>
</thead>
<tbody>
{% for value in models %}
<tr>
<td><input name="lol" type = "checkbox" value = "{{value.id}}"/> </td>
<td> {{forloop.counter}}</td>
<td> <img class="w3-display-topmiddle w3-container" src="{{ value.logUri.url }}" alt="alt txt" height="910" width="910"></td>
<td> {{ value.name }} </td>
</tr>
{% endfor %}
</tbody>
</table>
<input class = "btn btn-primary" type="submit" value="Search">
</form>

Display models that includes certain values (basic search)

I must start by saying that I am VERY new to Django (Python I know :) ).
Let me show you what I have so far and then I'll get into the issue.
The model:
class Machine(models.Model):
name = models.CharField(max_length=255, primary_key=True)
user = models.CharField(max_length=255)
mail = models.CharField(max_length=255)
datetime = models.DateTimeField(blank=True, null=True, default="")
licenses = models.CharField(max_length=10000, blank=True, null=True, default="")
The view:
def home(request):
...
return render_to_response("inventory/home.html", {'machines': Machine.objects.all()})
and here is part of my HTML:
<fieldset class="module aligned ">
<div class="form-row field-name">
<div>
<label class="required" for="id_name">License:</label>
<input class="vTextField" id="id_license" maxlength="255" name="license" type="text" value="">
</div>
</div>
</fieldset>
<div class=results>
<table width="100%" border="1" cellpadding="4" cellspacing="0" bordercolor="#eeeeee">
<tr bgcolor='WhiteSmoke' style="color: 'black'">
<td><input type="checkbox" id="action-toggle" style="display: inline-block;"></td>
<td>Name</td>
<td>User</td>
<td>Mail</td>
<td>Registration date</td>
<td>Registered licenses</td>
</tr>
{% for machine in machines %}
{% if machine.datetime %}
<tr bgcolor='CCFF66'>
{% else %}
<tr bgcolor='FF6666'>
{% endif %}
<td class="action-checkbox">
<input class="action-select" name="_selected_action" type="checkbox" value="{{machine.name}}">
</td>
<td>{{ machine.name }}</td>
<td>{{ machine.user }}</td>
<td>{{ machine.mail }}</td>
<td>{{ machine.datetime|default:"N/A" }}</td>
<td>{{ machine.licenses|default:"N/A"|truncatewords:"5" }}</td>
</tr>
{% endfor %}
</table>
</div>
Here is the result:
As you can see above, currently all items (called machines) are being displayed but I would like to present only the machines with a certain license text.
So as soon as user starts typing into "license search field" only the items with that license would show up (I hope I have managed to explain the issue well enough).
At this point I don't really know where to start looking! I check some django tutorial but they don't get into stuff maybe this advanced!
You can perform the search at server side, for this follow steps
Put the License search box into a HTML form and add a submit button next to it.
On submit call a view which will get the value entered in `license' text box.
Perform a filter on table
return the results.
The first part of HTML will be changed to -
<fieldset class="module aligned ">
<div class="form-row field-name">
<div>
<form method="post">
<label class="required" for="id_name">License:</label>
<input class="vTextField" id="id_license" maxlength="255" name="license" type="text" value="">
<button type="submit">Search</button>
</form>
</div>
</div>
</fieldset>
And view will look something like this -
def home(request):
...
if request.POST:
license_text = request.POST.get('license', '')
machines = Machine.objects.filter(licenses__istartswith=license_text) #or you can use __in operator
else:
machines: Machine.objects.all()
return render_to_response("inventory/home.html", {'machines': machines})
No other changes are required. Code not tested but it should work

django table form ad a 3rd column for errors

I am trying to get my possible error messages in a 3rd column behind the input fields. but except for customizing my whole html in my template I have no idea how to do this. An with my eyes on the widgets and ModelForm class I guess there should be something for it.
My form:
class ProvinceForm(forms.ModelForm):
"""Form to create or edit Provinces."""
name = forms.CharField()
choice_set = Country.objects.all()
country= forms.ModelChoiceField(queryset=choice_set, empty_label="Choose its country")
flavor = forms.CharField(
widget=forms.Textarea(attrs={'width': 300, 'height': 200}))
class Meta:
model = Province
And then my template:
<form action="{% url 'create_province' %}" method="post">{% csrf_token %}
<table>
{{ province_form.as_table }}
<tr>
<td></td>
<td style="float: right;"><input type="submit" value="add province" /></td>
</tr>
</table>
</form>
What would be the logical way to add that 3rd column instead of stripping the whole {{ province_form.as_table }} apart
You need to render each field separately as:
<table>
{% for field in province_form %}
<tr>
<td>{{field.label}}</td> <td> {{field}} </td> <td> {{field.errors}} </td>
</tr>
{%endfor%}
<tr>
<td></td>
<td style="float: right;"><input type="submit" value="add province" /></td>
</tr>
</table>
Note: you may want to change rendering of errors appropriately by looping over {{field.errors}}.

Django model filter not pulling in object

I'm using Django 1.4 with Python 2.7 on Ubuntu 12.04.
I have a template that is supposed to show a product and a list of product features for each product and for some reason the features don't show in the template.
Here is the view:
#login_required
def view_products(request):
"""
.. function:: view_products()
View the Products
:param request: Django Request object
"""
data = { 'user' : request.user }
if (request.user.is_authenticated() and request.user.is_superuser):
products = Products.objects.all()
add_feature_form = rsb.forms.AddProductFeatureForm();
data.update({ 'form' : add_feature_form })
data.update({ 'products' : products })
data.update(csrf(request))
return render_to_response("view_products.html", data)
return render_to_response("index.html", data)
Here is the portion of the template working with the product features:
<table>
{% for product in products %}
<tr>
<td align="right">Product Name:</td><td>{{ product.name }}</td>
</tr>
<tr>
<td align="right">Price:<br /></td><td>${{ product.price }}</td>
</tr>
<tr>
<ul>
{% for productfeature in product.productfeature_set.all %}
<form action="/removeProductFeature/" method="post">{% csrf_token %}
<li>
{{ productfeature.feature }}
<input type="hidden" name="feature" value={{ productfeature.feature }}>
<input type="hidden" name="product_id" value={{ product.id }}>
<label class="formlabel"> </label><input type="submit" value="Remove ►">
</tr>
</form>
{% endfor %}
</ul>
</tr>
<tr>
<form action="/addProductFeature/" method="post">{% csrf_token %}
<table>
<tr>
<td align="right"><label class="formlabel">Add Feature:<br /></label></td><td>{{ form.feature }}</td>
</tr>
<input type="hidden" name="product_id" value={{ product.id }}>
<tr>
<td align="right"><label class="formlabel"> </label></td><td><input type="submit" value="Add ►"></td>
</tr>
</form>
</table>
</tr>
{% endfor %}
</table>
Basically this template should show you a product. Each feature will be listed below it with the option to "remove" that feature. Then, at the bottom, a field that allows you to add additional features.
The existing features do not show up at all. Any suggestions on what I might be doing wrong?
UPDATE 1:
I missed an s in the template. product.productfeatures_set.all not product.productfeature_set.all. I'm good to go. Thanks all!
Please don't do this:
product_features = []
for product in products:
features = ProductFeatures.objects.filter(product = product)
product_features.append(features)
product.features = product_features
Instead, just pass your products variable to the template context.
And in the template do:
{% for product in products %}
Product id: {{ product.pk }}
{% for productfeature in product.productfeature_set.all %}
{{ productfeature.feature }}
{% endfor %}
{% endfor %}
What is productfeature_set you would ask (or, I hope you would ask :D), and that's a very good question. Don't panic, it's all documented.
Now, this is going to cause subqueries to spawn. The solution is to use prefetch_related. But you don't have to worry about that for the moment I think :)
Yes, you are trying to implement something that is already build into Django!
You should use the build in reverse relations of django.
# give an Product instance product
# this should work
product.productfeature_set.all()
Which is accessible from the template a product.productfeature_set.all
and can be itterated over.