Unique HTML element IDs for each model with Django - python

I've got django models displaying on a page using a checkbox input that has a label over it like so:
{% if recipes_list %}
<table>
{% for r in recipes_list %}
<tr>
<td>
<section class="ac-container">
<div>
<input id="ac-1" type="checkbox" />
<label for="ac-1">{{r.name}}</label>
<article class="ac-small">
<ul>
{% for i in r.ingredient_list%}
<li>{{i.part}}, {{i.amount}}</li>
{% endfor %}
</ul>
</article>
</div>
</section>
</td>
</tr>
{% endfor %}
</table>
When I click on the label of each entry in recipes_list, it obviously always opens the article of the first one. I've been looking around for solutions for the past couple days on how to give a unique id in the html for each model entry, but I can't find anything that works with this situation. I've tried forms, model forms, various javascript, and php. How can I do this?

You can use the forloop.counter to achieve this:
{% if recipes_list %}
<table>
{% for r in recipes_list %}
<tr>
<td>
<section class="ac-container">
<div>
<input id="ac-{{forloop.counter}}" type="checkbox" />
<label for="ac-{{forloop.counter}}">{{r.name}}</label>
<article id="article-{{forloop.counter}}" class="ac-small">
<ul>
{% for i in r.ingredient_list%}
<li>{{i.part}}, {{i.amount}}</li>
{% endfor %}
</ul>
</article>
</div>
</section>
</td>
</tr>
{% endfor %}
</table>
Hope this helps!

You can write a filter which gets the model name
from django import template
register = template.Library()
#register.filter(name='class_name')
def class_name(obj):
return obj.__class__.__name__
and in the template:
and in the template, wherever you want the id/classname:
<article id={{obj|class_name}}>
{# further code #}
</article>
OR
class MyModel(models.Model):
#fields
def class_name(self):
return "%s"%self.__class__.__name__ #returns the model instance name
If you want to return the instance name:
from django.template.defaultfilters import slugify
class MyModel(models.Model):
def class_name(self):
return "%s"%(slugify(self.name)) #or whatever field has the specific instance name
and in the template:
{{obj.class_name}}

Its simple use object primary key as id because its unique (unless you have another loop from another model):
{% for r in recipes_list %}
<input id="ac-{{ r.id }}" type="checkbox" />
{% endfor %}
Or use forloop.counter:
{% for r in recipes_list %}
<input id="ac-{{ forloop.counter }}" type="checkbox" />
{% endfor %}

Related

Html content not showing up after if statement in Django

Im having some issues with my html content not showing up after putting in some {% if %} {% endif %} statements in my templates
I have this snippet in my code where I display the checkout table if and only if the current user's username matches the one from my Order model. (order.customer_name has a foreign key that is set to the current users username)
{% for order in latest_order %}
{% if user.username == order.customer_name %}
<tr>
<td>{{ order.order_name }}</td>
<td>
<form method="post">
{% csrf_token %}
<button type="submit" name="remove_quantity" value="{{ order.id }}" class="mr-3 btn
btn-outline-info">-</button>
{{ order.order_quantity }}
<button type="submit" name="add_quantity" value="{{ order.id }}" class="ml-3 btn btn-
outline-info">+</button>
</form>
</td>
<td>${{ order.order_individual_price }}</td>
<form method="post">
{% csrf_token %}
<th><button type="submit" name="delete" value="{{ order.id }}" class="btn btn-
danger">Delete Item</button></th>
</form>
</tr>
{% endif %}
{% endfor %}`
I tried the following to see if it prints out the same username, which it does
<h1>{{ user.username }}</h1>
{% for order in latest_order %}
<h1>{{ order.customer_name }}</h1>
{% endfor %}
Picture of the page with user.username and order.customername as h1
When I delete the if statement, this is what the website SHOULD look like
Proper working table
Im pretty sure I'm missing something very obvious, Any help is appreciated!

How to populate table after button click in django template?

1) I want to insert the values in the input field from the dictionary using DTL.
Here's the snippet of code that on load page, making invisible this code tag in the table (may be because of if condition turns False) but just after data submission from dictionary, showing inserted value in the same tag.
How can I make it work and remains all the td tags visible on the page load as well?
2) Also since my data.items having 6 keys, so its iterating 6 times, I just want to get single time.
I know I'm not very clear but sorry I can't post the whole code since is too big and confidential.
Please Help it out, I'm totally new in django. Thanks.
....
...
..
{% for key, value in data.items %}
{% for key2,value2 in value.items %}
<tr class="info">
<td>1</td>
<td>Cholesterol -HDL</td>
<td>
{% if value2.test_name == "Cholesterol -HDL" %}
<div class="form-group">
<input type="text" class="form-control" name="cholesterol_hdl_result" value="{{ value2.results }}">
</div>
</td>
<td><div class="form-group">
<input type="text" class="form-control" name="cholesterol_hdl_uom" value="{{ value2.units }}">
</div></td>
<td><div class="form-group">
<input type="text" class="form-control" value="40.00" name="cholesterol_hdl_lr">
</div></td>
<td><div class="form-group">
<input type="text" class="form-control" value="60.00" name="cholesterol_hdl_hr">
</div></td>
{% endif %}
</tr>
{% endfor %}
{% endfor %}
..
...
....
So, when the dictionary is empty you have to check that in if and else condition and write that <td> tag in else block as below...
{% if data %}
......
......
{% for key, value in data.items %}
{% for key2,value2 in value.items %}
....
....
{% endfor %}
{% endfor %}
{% else %}
# write your default <td> tag here which is shown when there is empty data dictionary
{% endif %}
And for iterate for loop only once you have to use forloop.first of django template as below...
{% for key, value in data.items %}
{% if forloop.first %}
{% for key2,value2 in value.items %}
....
....
{% endfor %}
{% endif %}
{% endfor %}

How to use Django Haystack whoosh search field in multiple application templates

I have implemented a working Django 1.6 haystack/whoosh search field following Mike Hibbert's tutorial:https://www.youtube.com/watch?v=B-n6_m66TmA. The implementation works in a twitter bootstrap search field in the navbar in the url 'search'. I'd like to use the implementation in several pages in my application but it doesn't work.
I've tried with implementing the search.html code in other pages with search bars but it changes the search url prefix from 'search/...' to the page url, e.g. to 'front/...' on the frontpage. I've also tried to include the search.html in other pages, both as the block content and with an include tag in the template but it hasn't worked.
# in app/templates/search/indexes/search.html
{% extends 'base_searches.html' %}
{% block content %}
<form method="get" action=".">
<table>
<tr><th><label for="id_q"></label></th><td><input type="text" id="id_q"
name="q" placeholder="Search..." class="form-control" /><button
class="btn btn-success" type="submit" value="Search"><spaclass="glyphicon
glyphicon-search"></span></button></td></tr>
<tr>
<td> </td>
{% if query %}
{% for result in page.object_list %}
<div class="alert alert-success" role="alert">
Hi, {{ user }}, here's the found database match for your search
<a href="{{ result.object.get_absolute_url }}">
{{result.object.title }}.</a></div>
{% empty %}
<div class="alert alert-info" role="alert">
<strong>Hi {{ user }}, there's no match found in the
database for your search !.</strong>
</div>
{% endfor %}
{% endif %}
<div class="col-xs-6 col-sm-3 sidebar-offcanvas" id="sidebar">
<!--/.sidebar-offcanvas-->
<!--/row-->
<hr>
<td>
</td>
</tr>
</table>
</form>
</body>
</html>
{% endblock %}
# in models.py for each indexed model field
def get_absolute_url(self):
return '%s' % self.id
# in app/templates/base_searches.html
<form class="navbar-form navbar-right" id="search">{% csrf_token %}
<center><h> <td colspan="1" id="content">{% block content %}}
{% endblock %} </center></td></h>
<ul id="search-results">
</ul>
</form>
in urls.py
from haystack.query import SearchQuerySet
url(r'^search/',include('haystack.urls'),name='haystack_search'),
# in search_indexes.py
from haystack import indexes
from app.models import Article
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text= indexes.CharField(document=True,use_template=True)
content = indexes.CharField(model_attr='description')
content_auto = indexes.EdgeNgramField(model_attr='title')
def get_model(self):
return Article
def index_queryset(self, using=None):
"""used when the entire index for model is updated """
return self.get_model().objects.all()
# in app/templates/search/indexes/appname/article_text.txt
{{ object.title }}
{{ object.content}}
How do I include the search.html in other pages, as I've included it in the navbar in base_searches.html, and maintain the prefix search/..searchresult for the get_absolut_url function for the search result object and not the url prefix for other pages that I'm trying to include it in, e.g. front/..searchresult ? when trying to implement it in the frontpage with url front/, or are there better ways to use the haystack whoosh search in search fields in multiple application pages ?
I have solved this problem by adding http://{{ request.get_host }}/search" to the search form action.
`<form method="get" action="http://{{ request.get_host }}/search"`
The action="." will reference to your current page and the request will be redirected to your current view. With adding the host URL to your action it will redirect your query to the search view no matter on which page you are.

Is it possible to create view with list of objects and forms to update?

I'm trying to solve my problem with django for last 2 days, I've searched many reddit posts/ git repos / stack questions and I've achieved nothing.
I'm learning django and doing a project to help me in my current job.
My goal is to make detail view of model "Partner" where I'll list all it's "PartnerMugs"
models.py
class Partner(models.Model):
partner_name = models.CharField(max_length=255)
class Meta:
ordering = ["partner_name"]
def __str__(self):
return self.partner_name
def get_absolute_url(self):
return reverse("partners:detail", kwargs={"pk":self.pk})
class PartnerMug(models.Model):
partner = models.ForeignKey('Partner', on_delete=models.CASCADE)
pattern = models.ForeignKey('patterns.Pattern', on_delete=models.CASCADE)
xs_amount = models.IntegerField(default=0)
xl_amount = models.IntegerField(default=0)
class Meta:
ordering = ["partner"]
def __str__(self):
return str(self.partner) + " " + str(self.pattern)
def get_absolute_url(self):
return reverse('partners:detail', args=[self.partner.pk])
The problem is that I have no idea how to put form for each "PartnerMug" object in my list. I tried to do something with inlineformset_factory, but I didn't find the way how to put it in my for loop.
form.py
class PartnerForm(forms.ModelForm):
class Meta:
model = Partner
fields = ['partner_name']
class MugAmountForm(forms.ModelForm):
class Meta:
model = PartnerMug
fields = ['xs_amount','xl_amount',]
MugAmountFormSet = inlineformset_factory(Partner, PartnerMug, form=MugAmountForm, extra=0)
Updated view.py:
view.py
def par_detail_view(request, pk=None):
obj = Partner(pk=pk)
mugsFormSet = inlineformset_factory(Partner, PartnerMug, form=MugAmountForm, extra=0)
if request.method == "POST":
mugsFormSet = mugsFormSet(request.POST, instance=obj)
if mugsFormSet.is_valid():
mugsFormSet.save()
else:
mugsFormSet = mugsFormSet(instance=obj)
return render(request, 'partners/pattern_function.html', {
'mugsFormSet':mugsFormSet,
'obj':obj
})
Updated template.html
template.html
{% extends "base.html" %}
{% block content %}
{% for partner_mugs in obj.partnermug_set.all %}
<div class="row">
<div class="col-md-4 text-center">
{% if partner_mugs.pattern.pattern_thumbnail %}
<img src="{{ partner_mugs.pattern.pattern_thumbnail.url }}" class="thumbnail">
{% endif %}
</div>
<div class="col-md-8 text-center">
<div class="row">
<div class="col-sm-12">
<h4>pattern:{{ partner_mugs.pattern }}</h4>
</div>
</div>
<div class="row">
<div class="col-md-6 text-center">
<p>small: {{ partner_mugs.xs_amount }}</p>
</div>
<div class="col-md-6 text-center">
<p>large: {{ partner_mugs.xl_amount }}</p>
</div>
</div>
</div>
</div>
<hr>
{% endfor %}
<form class="form-horizontal" action="" method="POST">
{% csrf_token %}
<fieldset>
<legend>Profile</legend>
<br>
{{ formset.management_form }}
<table class="table table-bordered table-hover table-condensed">
{% for form in mugsFormSet.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr class="{% cycle "row1" "row2" %}">
{% for field in form.visible_fields %}
<td>
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" value="save" class="btn" />
</fieldset>
</form>
{% endblock content %}
I'd like to put form for xs_amount in div :
<div class="col-md-6 text-center">
<p>Small: {{ partner_mugs.xs_amount }}</p>
</div>
And xl_amount in:
<div class="col-md-6 text-center">
<p>Large: {{ partner_mugs.xl_amount }}</p>
</div>
Both forms under the values.
Is it even possible to loop through objects and it's forms in the same time? All forms should be submited by one button in the same time.
result
On your views.py create a function linked to your url.
I am not able to re-write your code, but I think you may find my example useful:
def profile(request):
user = request.user
userform=UserForm(instance=user)
addressFormSet=inlineformset_factory(User, ProfileAddress, form=ProfileAddressForm ,can_delete=False,extra=1)
if request.method == "POST":
userform=UserForm(request.POST,instance=user)
addressFormSet = addressFormSet(request.POST, request.FILES, instance=user)
if userform.is_valid() and addressFormSet.is_valid() a:
userform.save()
addressFormSet.save()
else:
addressFormSet = addressFormSet(instance=user.profile)
return render(request, 'template.html', {
'userform':userform,
'addressFormSet':addressFormSet,
})
template.html
<form class="form-horizontal" action="" method="POST">
{% csrf_token %}
<fieldset>
<legend>Profile</legend>
{% include "form_snippet.html" with form=userform %}
{% include "inlineTableForm.html" with formset=addressFormSet %}
<input type="submit" value="save" class="btn" />
</fieldset>
</form>
inlineTableForm.html
<br>
{{ formset.management_form }}
<table class="table table-bordered table-hover table-condensed">
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr class="{% cycle "row1" "row2" %}">
{% for field in form.visible_fields %}
<td>
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I found solution to my problem. I used #Walucas inlineformset_factory and function view. And in "inlineTableForm.html" I used "form.instance" to get values of my objects:
<br>
{{ formset.management_form }}
<table class="table table-bordered table-hover table-condensed">
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
<th>Thumbnail:</th>
<th>Pattern:</th>
<th>xs:</th>
<th>xl:</th>
</tr>
</thead>
{% endif %}
<tr class="{% cycle "row1" "row2" %}">
<td><img src="{{ form.instance.pattern.pattern_thumbnail.url }}" class="thumbnail"></td>
<td>{{ form.instance.pattern }}</td>
<td>{{ form.xs_amount }}</td>
<td>{{ form.xl_amount }}</td>
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{{ form.errors.as_ul }}
</tr>
{% endfor %}
Now i have rows with each object thumbnail , pattern name and forms to change amount.
".instance" in formset was the key to understand all of this

Learning to use Jinja2 templates, missing URL values

I'm learning how to use Jinja2 templates (see code below). When I add an item to my form, I expect that the url will change to something like this.
http://localhost:8080/?food=steak&food=eggs&food=cheese
However, what ends up happening is that the first food will have a value, but everything else will be blank. It looks something like this:
http://localhost:8080/?food=asd&food=&food=
What am I doing wrong?
<form>
<h2>Add a Food</h2>
<input type="text" name="food">
{% if items %}
{% for items in items %}
<input type="hidden" name="food" value="{{item}}">
{% endfor %}
{% endif %}
<button>Add</button>
{% if items %}
<br>
<br>
<h2>Shopping List</h2>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endif %}
</form>
Here is the function to render the HTML:
class MainPage(Handler):
def get(self):
items = self.request.get_all("food")
self.render("shopping_list.html", items=items)
For item in items?
{% for item in items %}
<input type="hidden" name="food" value="{{item}}">
{% endfor %}
I'm not certain, but I think the issue is with your <button> tag. Try something like <button type='submit'>. I think your current button just doesn't do anything.
w3 documentation here

Categories

Resources