Call Django function with argument in html - django

I am pretty new to django and try to call a django function in html to display how many objects of 'Akte' is in the respective 'Charge' object, but somehow I am missing the right way to do it.
models.py:
class Charge(models.Model):
STATI = (
('O','Offen'),
('G','Geschlossen'),
)
"Projektnr = models.CharField(max_length=30)"
Containernr = models.CharField(max_length=30)
Plombennr = models.CharField(max_length=30)
status = models.CharField(max_length=1, choices=STATI)
def __str__(self):
return self.Containernr
class Akte(models.Model):
Aktenbarcode = models.CharField(max_length=30)
"Eincheckdatum = models.datetime()"
user = models.CharField(max_length=30)
containerId = models.ForeignKey(Charge,on_delete=models.CASCADE)
kundennr = models.CharField(max_length=30)
Startdatum = models.DateField(auto_now_add=True)
def __str__(self):
return self.Aktenbarcode
and this is my views.py:
def tabelle(request):
assert isinstance(request, HttpRequest)
charge_list = Charge.objects.all()
return render(
request,
'app/tabelle.html',
{
'charge_list':charge_list,
}
)
def anzahl(containernr):
return {'anzahl': Akte.objects.filter(containerId__Containernr==containernr).count }
and here is the html code:
{% extends "app/ats.html" %}
{% block content %}
{% if not user.is_anonymous %}
<div style="margin-left:10%;color:white;"><a style="color:white"href="{% url 'home'%}">Home</a> ><a style="color:white"> Tabellenübersicht</a></div>
<div>
<table>
<tr>
<th>Containernummer</th>
<th>Status</th>
<th>Anzahl Akten</th>
<th>Plombennummer</th>
<th></th>
</tr>
{%for Charge in charge_list%}
<tr>
<td>{{Charge.Containernr}}</td>
<td>{{Charge.status}}</td>
<td>{% anzahl Charge.Containernr %}</td>
<td>{{Charge.Plombennr}}</td>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
{% endblock %}
when I try it, I always get this error:
TemplateSyntaxError at /tabelle
Invalid block tag on line 19: 'anzahl(Charge.Containernr)', expected 'empty' or 'endfor'. Did you forget to register or load this tag?
what is the right way to solve this problem?

You can't call methods with arguments in the template. But you don't need to here; to get the count of Akte for that Charge you can do:
{{ Charge.akte_set.count }}
An even better - and much more efficient - approach is to get this data in the original query in your view, via annotation:
from django.db.models import Count
def tabelle(request):
charge_list = Charge.objects.all().annotate(akte_count=Count('akte'))
and now in your template you can do:
{{ Charge.akte_count }}

Related

How to display django model column values horizontally on django template

my issue is displaying the model data on django template horizontally. I have a model named "Main" with 3 columns. When I display on the template it looks like this-
I want to filter it by category that will look like this-
Main.objects.filter(category='food')
My goal is to show the category name on the template with the price horizontally on the side with plus signs. It should look something like this-
food= 8+10+11
I tried for...in loop both on template and on views.py both failed. Tried something like this- print(f"{i.category}={i.price}+") with for loop. Didn't work.
output+=f'{i.price}+' with a for loop, holding it in a variable and display that variable on template. Different combinations of those, all failed.
Since += is mainly for integers, I tried with i.price without turning it into a string, failed.
Most answers I found here on "displaying model data horizontally on Django template" are about using css to display form elements side by side,which I know how to do and not exactly my problem.
Can anyone point me to the right direction?
Here is my models.py
class Main(models.Model):
name = models.CharField(max_length = 60, blank = True)
category = models.CharField(max_length = 60, blank = True)
price = models.CharField(max_length = 60, blank = True)
def __str__(self):
return self.name
views.py -
def products(request):
products = Main.objects.all()
context = {'products':products}
return render(request, 'myapp/index.html', context)
and the HTML template -
<div class="card card-body">
<table class="table">
<tr>
<th>Product</th>
<th>Category</th>
<th>Price</th>
</tr>
{% for i in products %}
<tr>
<td>{{i.name}}</td>
<td>{{i.category}}</td>
<td>{{i.price}}</td>
</tr>
{% endfor %}
</table>
</div>
Not the entire template but you get the idea. Very basic.
You can do it like this:
views.py:
def products(request):
foods = Main.objects.filter(category='food').values_lis('category', flat=True)
return render(request, 'myapp/index.html', {'foods': foods})
index.html:
<div class="card card-body">
<p> food:
<span>
{% for food in foods %}
{{ food }} {% if not forloop.last %}+{% endif %}
{% endfor %}
</span>
</p>
</div>

Django formset only adding one form

OK, so this is my first time using formsets. I am trying to create a table that I can dynamically add rows to and fill out each row, then submit and have Django put them all in the database. Every time I submit it only adds the first form.
File views.py:
#main_context_wrapper
def bacteriaForm2(request,context):
if not request.user.is_authenticated():
#If user isn't authenticated, then just redirect to login
return HttpResponseRedirect('/login/')
BacteriaFormSet = formset_factory(BacteriaForm)
if request.POST:
bacteriaformset = BacteriaFormSet(request.POST, request.FILES)
if bacteriaformset.is_valid():
context["error"] = ""
for form in bacteriaformset:
form.save()
return HttpResponseRedirect('/')
else:
context["error"] = "validation"
context["bacteriaformset"] = BacteriaFormSet
context.update(csrf(request))
return render_to_response('bacteriaForm.html', context)
else:
#The request was a GET, add the form to the context
context["bacteriaformset"] = BacteriaFormSet()
#Add all siteInfo objects to allow for dynamic site info drop down menus
siteInfo = SiteInfo.objects.all()
context["siteInfo"] = siteInfo
return render(request, "bacteriaForm.html", context)
Template:
{% extends "inherited/main.html" %}
{% block content %}
<h1> Bacteria Entry Form </h1>
<form action='/bacteriaForm/' method="post">{% csrf_token %}
{{bacteriaformset.management_form}}
{% if error == "validation" %}
<div class="alert alert-danger">
<p>
<strong>Error: </strong>Form not completed properly.
</p>
</div>
{% endif %}
<table id="id_forms_table">
<tr>
{% for field in bacteriaformset.forms.0 %}
{% if not field.is_hidden %}
<th>{{ field.label }}</th>
{% endif %}
{% endfor %}
</tr>
{% for f in bacteriaformset.management_form %}
{{ f }}
{% endfor %}
{% for f in bacteriaformset.forms %}
<tr id="{{ f.prefix }}-row" class="dynamic-form">
{% for field in f %}
{% if not field.is_hidden %}
<td>
{{ field.errors }}
{{ field }}
</td>
{% else %}
<td valign="bottom">{{ field }}</
{% endif %}
{% endfor %}
<td{% if forloop.first %} class="hidden"{% endif %}>
<a id="remove-{{ form.prefix }}-row" href="javascript:void(0)" class="delete-row">delete</a>
</td>
</tr>
{% endfor %}
<tr>
<td colspan="4">add property</td>
</tr>
</table>
<div>
<input type="submit" value="submit" />
</div>
</form>
<script>
$(function () {
$('.add-row').click(function() {
return addForm(this, 'form');
});
$('.delete-row').click(function() {
return deleteForm(this, 'form');
});
});
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
var row = $('.dynamic-form:first').clone(true).get(0);
$(row).removeAttr('id').insertAfter($('.dynamic- form:last')).children('.hidden').removeClass('hidden');
$(row).children().not(':last').children().each(function() {
updateElementIndex(this, prefix, formCount);
$(this).val('');
});
$(row).find('.delete-row').click(function() {
deleteForm(this, prefix);
});
$('#id_' + prefix + '-TOTAL_FORMS').val(formCount + 1);
return false;
}
function deleteForm(btn, prefix) {
$(btn).parents('.dynamic-form').remove();
var forms = $('.dynamic-form');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).children().not(':last').children().each(function() {
updateElementIndex(this, prefix, i);
});
}
return false;
}
$("#id_date").datepicker();
</script>
{% endblock %}
File Models.py
class BacteriaEntry(models.Model):
"""
A bacteria entry contains information about a test set's
bacteria levels at a specific time. BacteriaEntry utilizes the
Djano model.
"""
siteNumber = models.IntegerField()
date = models.DateField()
sampleNumber = models.IntegerField(primary_key=True)
ecoliRawCount = models.IntegerField(null=True)
ecoli = models.DecimalField(decimal_places=10, max_digits=20, null=True)
ecoliException = models.IntegerField(null=True)
coliformRawCount = models.IntegerField(null=True)
coliform = models.DecimalField(decimal_places=10, max_digits=20, null=True)
coliformException = models.IntegerField(null=True)
comments = models.CharField(max_length=2000, null=True)
"""Returns the sample number of the Bacteria Entry"""
def __unicode__(self):
return smart_unicode(self.sampleNumber)
Here is some post data
<QueryDict: {u'form-0-date': [u'02/24/2014'], u'form-0-comments': [u'65'], u'form- MAX_NUM_FORMS': [u'1000', u'1000'], u'form-0-coliformRawCount': [u'5'],
u'form-0-coliform': [u'65'], u'form-0-ecoliException': [u'56'], u'form-TOTAL_FORMS': [u'1', u'1'], u'form-0-sampleNumber': [u'1554'], u'form-0-ecoliRawC
ount': [u'35'], u'form-0-coliformException': [u'56'], u'form-INITIAL_FORMS': [u'0', u'0'], u'csrfmiddlewaretoken': [u'VSnaJCW6R9z8iEKib46cHuBJ6AKTPPUT'],
u'form-0-ecoli': [u'51'], u'form-0-siteNumber': [u'100']}>
I'm not exactly sure where my problem is. I have spent a lot of time trying to figure this out. I am not sure what is wrong.
You're not printing formset.non_form_errors, or form.non_field_errors in any of the child forms, in your template - there's probably something in one of those that is causing validation to fail.
I should also point out that there is no need to instantiate the form separately from the formset. It makes no sense to create a separate BacteriaForm instance and pass it to the template, then validate it on post: that's what the formset is for, after all.
I'm a bit confused with this, not sure why you need both a Form and a FormSet, especially because the FormSet contains the same Forms as is the separate Form...
But if that is the case, then you should use prefix on the Form and/or on the FromSet:
bacteriaForm = BacteriaForm(request.POST, prefix='the_one_bacteria')
bacteriaformset = BacteriaFormSet(request.POST, request.FILES, prefix='bacterias')
and also in the else: part of the View.
Pardon my plural.

django filter a regroup within a forloop

I have a model called Subtopic. One of my templates runs a forloop on an object, returning a different field for each cell of a table row.
Two of the table cells look up a field which is a ManytoMany foreign key, both to the same foreign model, Resource. I want each to display different results, based on the value of a boolean field within the Resource model.
What you see below is currently working fine, but doesn't attempt to filter by the boolean field.
models.py:
class ICTResourceManager(models.Manager):
def get_query_set(self):
return super(ICTResourceManager, self).get_query_set().filter('is_ict': True)
class NonICTResourceManager(models.Manager):
def get_query_set(self):
return super(NonICTResourceManager, self).get_query_set().filter('is_ict': False)
class Resource(models.Model):
subtopics = models.ManyToManyField(Subtopic)
external_site = models.ForeignKey(ExternalSite)
link_address = models.URLField(max_length=200, unique=True, verify_exists=False)
requires_login = models.BooleanField()
is_ict = models.BooleanField()
flags = models.ManyToManyField(Flag, blank=True)
comment = models.TextField()
def __unicode__(self):
return u'%s %s' % (self.external_site, self.link_address)
objects = models.Manager()
ict_objects = ICTResourceManager()
nonict_objects = NonICTResourceManager()
class Meta:
ordering = ['external_site', 'link_address']
views.py:
def view_ks5topic(request, modulecode, topicshortname):
listofsubtopics = Subtopic.objects.filter(topic__module__code__iexact = modulecode, topic__shortname__iexact = topicshortname)
themodule = Module.objects.get(code__iexact = modulecode)
thetopic = Topic.objects.get(module__code__iexact = modulecode, shortname__iexact = topicshortname)
return render_to_response('topic_page.html', locals())
My template:
{% for whatever in listofsubtopics %}
<tr>
<td>
{{ whatever.objective_html|safe }}
<p>
{% if request.user.is_authenticated %}
{% with 'objective' as column %}
{% include "edit_text.html" %}
{% endwith %}
{% else %}
{% endif %}
</td>
<td>
{% regroup whatever.resource_set.all by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
</tr>
{% endfor %}
As you can see, I've added extra managers to the model to do the filtering for me, but when I replace the appropriate lines in the template, I just get blanks. I have tried: for external_site.ict_objects in resource_list and for item.ict_objects in resource_list and <a href="{{ item.ict_objects.link_address }}">. If this were in the view I could probably do the filter just by .filter('is_ict': True), but with this being inside a forloop I don't know where to do the filtering.
I also tried writing regroup whatever.resource_set.filter('is_ict': True) in the template, but the syntax for regrouping seems to use resource_set.all rather than resource_set.all() (and I don't know why) so the filter text doesn't work here.
Turns out it was possible to do it using a custom template filter. The original efforts to filter within the template weren't working, given that as is well documented the template language is not a fully-fledged python environment. My original question remains open for anyone who knows an alternative method that more directly addresses the question I was originally asking, but here's how I did it:
myapp_extras.py:
from django import template
register = template.Library()
def ict(value, arg):
"filters on whether the is_ict Boolean is true"
return value.filter(is_ict=arg)
register.filter('ict', ict)
My template, note the use of the custom filter in line 2:
<td>
{% regroup whatever.resource_set.all|ict:1 by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
After this I was able to remove the additional custom managers from the model.
One further question, when filtering for the boolean is_ict field, I found that I had to use filter(is_ict=1) and filter(is_ict=0). Is that the only way to refer to a True or False value?

accessing foreignKey inside the template

well it's quiet simple.
2 models with ManyToMany relation:
class Artist(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True,
help_text='Uniq value for artist page URL, created from name')
birth_name = models.CharField(max_length=100, blank=True)
class Song(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True,
help_text='Unique value for product page URL, create from name.')
youtube_link = models.URLField(blank=False)
artists = models.ManyToManyField(Artist)
my view suppose to display latest 5 songs:
def songs(request, template_name="artists/songs.html"):
song_list = Song.objects.all().order_by('-created_at')[:5]
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
and the problem is in the template... i want to display the artist name
but just dont realy know how to do it, i tried:
{% for song in song_list %}
{{ artists__name }} - {{ song.title }}
{% endfor %}
would appreciate any help !
Try changing your template code to:
{% for song in song_list %}
{% for artist in song.artists.all %}
{{ artist.name }} - {{ song.title }}
{% endfor %}
{% endfor %}
artists is another type of manager, so you have to iterate through artists.all and print the name attribute of each element.
Well, I worked on above solution of Mr #Dominic Rodger, but because am using Django version 3.2 it did not worked for me. Therefore, the problem may remain the same but according to how Django version changes, the way to solve them sometimes become different. If you're using Django 3.x use below solution.
In views.py
def songs(request):
song_list = Song.objects.all().order_by('-created_at')[:5]
song_list = {'song_list':song_list}
return render(request, 'artists/songs.html', song_list)
In your HTML Template use code below
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Artist - Song Title</th>
</tr>
</thead>
<tbody>
{% for song in song_list %}
</tr>
<td>{{ song.artist.name }} - {{ song.title }}</td>
<tr>
{% endfor %}
</tbody>
</table>
In urls.py
path('songs/', views.songs, name='songs'),
If you're running source code from localhost, then type on your browser http://127.0.0.1:8000/songs/
Thank you ....

Django Models absolute url - what am i doing wrong

I am trying to set up links to a view that allows to edit objects, in previous view.
Model:
class List(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
type = models.PositiveIntegerField(choices=TYPE_DICT)
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('EditList', None, {'list_id':self.id} )
View:
lists = List.objects.filter(user=request.user)
array = []
for list in lists:
ListDict = {'Name':list.name, 'type':types[str(list.type)], 'edit':list }
array.append(ListDict)
context = { 'array':array,}
Template:
{% for dict in array %}
<tr>
{% for key,value in dict.items %}
{% ifequal key 'edit' %}
<td>{{ key }}</td><td>{{ value.name }}</td>
{% else %}
<td>{{ key }}: </td><td>{{ value }}</td>
{% endifequal %}
{% endfor %}
</tr>
{% endfor %}
and urls conf:
urlpatterns = patterns('tst.list.views',
(r'^$', 'list'),
(r'^edit/(?P<list_id>\d+)/$', 'EditList')
,
What this line with link gives me is http://localhost/list/ as url, not http://localhost/list/edit/[objectid]/
Can anyone please tell me what am i doing wrong?
Alan
If you had wanted to do it for an unnamed urlconf, you just needed to pass the whole import string:
#models.permalink
def get_absolute_url(self):
return ('yourproject.yourapp.views.EditList', None, {'list_id':self.id} )
I also suggest you follow the PEP8 naming conventions for functions.
Ok. I got it working. What i needed to do ,was to give name to this view. When i changed my urlconf to this:
url(r'^edit/(?P<list_id>\d+)/$', 'EditList', name = 'EditList'),
Then everything started working.