Output calculations to template - django

I want to perform row level math on a model and display the results in the template. The database has a row for each company per day.
class MyModel(models.Model):
company = model.CharField(...
daily_target = model.PositiveSmallIntger(...
actual = model.PositiveSmallIntger(...
date = model.DateField(...
In the template I'd want to display the result of 100 * actual / daily_target for the logged-in company. I have no problem doing this in the python interpreter but am confused about how to do this with views & templates.

You could add a property to the model:
class MyModel(models.Model):
company = model.CharField(...
daily_target = model.PositiveSmallIntger(...
actual = model.PositiveSmallIntger(...
...
#property
def pct_target(self):
return 100. * self.actual / self.daily_target
Then in your template:
{% for item in queryset %}
{{ item.pct_target }}
{% endfor %}
The disadvantage of this is that you cannot filter or order the queryset by the property. Another option would be to annotate your queryset with the calculated field.

Related

How to get total sum based on the date__year?

Here in the template I am iterating MyModel objects. Now in the template I want to get the total sum of integer fields for the particular year.
I don't know how I can I use these three functions in order to get the total sum of field? Or there might be any better approach ?
model
class MyModel(models.Model):
date = models.DateField()
field1 = models.DecimalField(default=0.0)
field2 = models.DecimalField(default=0.0)
views
def get_total_field1(year):
return MyModel.objects.filter(date__year=year).annotate(total=Sum('field1'))['total']
def get_total_field2(year):
return MyModel.objects.filter(date__year=year).annotate(total=Sum('field2'))['total']
def get_total(year):
return get_total_field1() + get_total_field2()
class MyView(ListView):
model = MyModel
template_name = 'my_template.html'
template
{% for obj in objs %}
<tr>
<td>{{obj.date|date:'Y'}}</td>
<td>Field 1 total sum for obj.date </td>
<td>Field 2 total sum for obj.date</td>
<td>Field 1 total + field2 total </td>
{% endfor %}
Templates are for displaying data. Calculations are more like business logic that should go to Python code. So my advice - calculate everything you need in the code (for "sum" see .annotate() Django method) and then just display pre-calculated variables in your templates.
In your example I would move "get_total_field1" and other methods into the model itself as property, then you can just do
obj.get_total_field1 in your template.

How to get list of object(equipement) for each object (intervention) manytomany relationship in django

models equipement :
class Equipement(models.Model):
nom_equipement=models.CharField(max_length=60)
qte_stock=models.IntegerField()
panne=models.ManyToManyField(Panne)
models intervention :
class Intervention(models.Model):
Titre_intervention = models.TextField(max_length=255)
date_intervention = models.DateField(auto_now_add=True)
type_panne = models.ForeignKey(Panne,on_delete=models.CASCADE)
etat = models.CharField(max_length=30)
description = models.TextField(max_length=255)
image = models.ImageField(blank=True,null=True,upload_to='medial/%Y/%m/%D')
equipements = models.ManyToManyField(Equipement)
clients = models.ForeignKey(Client,on_delete=models.CASCADE,default=True)
models intervention with relationship manytomany :
so when I add a new "intervention" it will add to table of association
I need to list all equipment of each intervention this is my view :
def mes_intervention(request):
if 'id_client' in request.session:
get_idClient=request.session['id_client']
Interv_client = Intervention.objects.all().filter(clients=get_idClient)
context = {
'intervention':Interv_client
}
return render(request, 'clients/mes-intervention.html',context)
and this is where I list all intervention into template html
As a side note, you have plurals and singulars a bit mixed up. A foreign key points to one model:
client = models.ForeignKey(Client,on_delete=models.CASCADE,default=True) # singular
A queryset returns multiple objects:
context = { 'interventions': Interv_client}
While you cannot call functions in templates with arguments, you can invoke object methods without arguments. So, you can in fact do this:
{% for item in interventions %}
...
{% for equipment in item.equipements.all %}
{{ equipment.qte_stock }}
{% endfor %}
{% endfor %}

Django - What is the most efficient way to query the average ratings for a list of objects?

I have a simple Product and Rating class like so:
class Product(models.Model):
name = ...
price = ...
class Rating(models.Model):
product = models.ForeignKey("Product", ...)
score = models.PositiveSmallIntegerField(...)
Now I want to get a list all products and the average rating for each product. Simply getting all products is easy:
product_list = Product.objects.all()
If I have a single product and I want to get the average rating for that single product:
product = get_object_or_404(Product, pk=product_id)
ratings = Rating.objects.filter(product=product)
product_avg_rating = ratings.aggregate((Avg("score")))
But let's assume I want to list all products and their average rating. This sounds like it's quite resource/compute heavy. So what is the best way to solve this? Should I make a class method for the Product class that just returns the average, so I can then call this in the template:
{{ product.get_average_rating }}
Or is there a better way to do this? I'm not quite sure what to do here and need some guidance.
Thank you so much in advance!
EDIT: I think I wasn't clear enough with my explanation, so here's an actual example. Let's say I have a query set, filtered by the slug (which is just a searchterm):
products = Product.objects.filter(tags__name__in=[slug])
Now how can I add the average rating to EACH SINGLE product so that I can do this in the template:
{% for product in products %}
{{ product.avg_rating_score }}
{% endfor %}
You can annotate your Product in the first query, so that it will only take one query to obtain the average, like:
product = get_object_or_404(
Product.object.annotate(avg_score=Avg('rating__score')),
pk=product_id
)
This will result in a single Product that contains an extra attribute (only for this specific QuerySet!), in the template, we thus can render it with:
{{ product.avg_score }}
The query that it does is:
SELECT product.*, AVG(rating.score) AS avg_score
FROM product
LEFT OUTER JOIN rating ON product.id = rating.product_id
WHERE product.id = product_id

Django 1.7.7 get object count in template through double relation

I have 3 models, Entry model and Category model, and I have created intermediate model CategoryEntry.
class Entry(models.Model):
entry_text = models.TextField()
class Category(models.Model):
user = models.ForeignKey(User)
category_text = models.CharField(max_length=200)
entries = models.ManyToManyField(Entry, through='CategoryEntry')
class CategoryEntry(models.Model):
category = models.ForeignKey(Category, related_name="related_entry_categories")
entry = models.ForeignKey(Entry)
viewed = models.BooleanField(default=False)
How can I get in template Users total Entry count.
For example I can get total users Category count with
{{ user.category_set.count }}
So I tried many different ways, but don't get how to follow next relation
{{ user.category_set.entries.count}}
{{ user.category_set.categoryentry_set.count}}
{{ user.category_set.all.categoryentry_set.count}}
{{ user.category_set.related_entry_categories.count }}
Is this even possible (good thing to do) to count in template? Or is there better way?
Thanks!
your queries don't make sense because category_set is a collection of objects rather than a single object, so you cannot simply ask for category_set.entries.count
first you have to think about what you want... do you want:
individual count of entries for each category in category_set?
or total count of entries across all categories in category_set?
For the former you need to annotate the queryset. this will have to be done in the view rather than template because the method needs arguments:
from django.db.models import Count
user_categories = user.category_set.annotate(entry_count=Count('entries'))
# then pass the user_categories queryset into your template along with user
you can then iterate over user_categories in the template to display individual counts:
{% for category in user_categories %}
No. of entries: {{ category.entry_count }}
{% endfor %}
For the latter you can use aggregate, again in the view:
from django.db.models import Count
total = user.category_set.aggregate(entry_count=Count('entries'))
# note that aggregate method returns a dict:
print total['entry_count']
# then pass total['entry_count'] as a value into your template along with user

How do I get the foreign key values of a form in a template?

So Im trying to create a similar panel like django admin and while I have my tables set up with query information and filters, Im trying to copy the "editable" option by creating fields that can be edited in the table. My problem is lets say I have models:
class model1(model.Models):
name = CharField(max_length = 20)
phone = IntegerField(max_length = 20)
def __unicode__(self):
return (#I Just return the name and phone number as a string here)
class model2(model.Models):
name = ForeignKeyFeild(model1)
team = CharField(max_length = 20)
If I set up a modelformset factory like so in a view:
qset = model2.objects.all()
fset = modelformset_factory(model2)
form = fset(queryset = qset)
In templates how can I show the value of 'phone' from model1?
When I render the form in the template:
{% for f in form %}
{{f.team.value}} # this gives me the value without an input field
{{f.name.phone.value}} # this however renders nothing and that's what I'm trying to find out
{%endfor%}
Also How can I make it so that {{f.name.value}} shows me the unicode string and not the actual numerical value (ID)?
How can I make the {{f.name.phone}} which is information from the table where it holds a foreign_key show?
If not is there a better way of doing this?
The original model object is available as the instance attribute of the form:
{% for f in form %}
{{ f.instance.team }}
{{ f.instance.name.phone }}
{% endfor %}