last record in django models database - python

i am trying to do this:
i have a table of rating records of locations. in this table, one location can also have multiple rating scores. but i want to restrict the search only to the last record of same locations. for example:
one location with id=1 has 3 rating scores: 1, 2, 4. now when user searchs for rating score 2, this location should NOT appear, because its last record is 4.
EDIT
there are two tables(django models): location and rating.
can i do this:
all_locations = Location.objects.all()
then in template. locations_rating is a related_name for foreignkey locationID in rating table.
{% for location in all_locations %}
{{ location.locations_rating }}
{% endfor %}

models.py
class Location(models.Model):
locationname = models.CharField(max_length=100)
def __unicode__(self):
return self.locationname
def latest(self):
return Rating.objects.values('rating').filter(von_location=self).order_by('-id')[0]
class Rating(models.Model):
von_location = models.ForeignKey(Location,related_name="locations_rate")
rating = models.IntegerField()
def __unicode__(self):
return "{0}".format(self.rating)
views.py
all_locs = Location.objects.all()
template
{% for location in all_locs %}
{{ location.locationname }} - {{ location.latest.rating }}<br/>
{% endfor %}

This is pure guessing, but can you do something like this?
Rating.objects.filter(location_id=1).order_by(id).reverse()[0]

Ahh, I misinterpreted the question. Here's a not very efficient way to do what you're asking:
locations = Location.objects.all();
filtered = []
for location in locations:
try:
r = Rating.objects.filter(location=location).order_by(-id).[0]
if r.rating = 2:
filtered.append(location)
except Exception as ex:
pass

Related

display sum per user elegantly in django

trying to display the final mark per student. But instead of just showing the result of sum , it displays a chunk of query set: for example:
Annie <QuerySet [{'studName': None, 'attendance__sum': 3}, {'studName': 1, 'attendance__sum': 2}, {'studName': 2, 'attendance__sum': 1}]>
and same goes to the rest of the students.
I would like to display it like :
Annie 2
Benny 3
Charlie 4
My view:
def attStudName(request):
studentName = MarkAtt.objects.all()
mark = MarkAtt.objects.values('studName').annotate(Sum('attendance'))
context = {
'studentName' : studentName,
'mark' : mark
}
return render(request,'show-name.html',context)
My template:
{% for y in mark %}
{% for x in studentName %}
<p>{{x.studName}}</p> <p> {{mark}}</p>
{% endfor %}
{% endfor %}
How do i display each student name with their own mark accordingly? And how do i display the mark without the
Edited:
Model.py:
class Namelist(models.Model):
name = models.CharField(max_length=100)
program = models.CharField(max_length=10)
year = models.IntegerField(default=1)
studType = models.CharField(max_length=15)
courseType = models.CharField(max_length=15)
nationality = models.CharField(max_length=20)
VMSAcc = models.CharField(max_length=30)
classGrp = models.ForeignKey('GroupInfo', on_delete=models.SET_NULL, null=True)
class MarkAtt(models.Model):
studName = models.ForeignKey(Namelist,on_delete=models.SET_NULL,blank=True, null=True, default=None)
classGrp = models.ForeignKey(GroupInfo, on_delete=models.SET_NULL, null=True)
currentDate = models.DateField(default=now())
week = models.IntegerField(default=1)
attendance = models.IntegerField(default=100) #1 is present
Thank you in advance.
The below should return a queryset with student names and marks. Two separate queries should not be needed.
students = MarkAtt.objects.values('studName').annotate(mark=Sum('attendance'))
If studName is a foreign key, do this .values('studName__name')
Then in your context you can just add:
context = {
students = students
}
You can then loop through students in you template and display data as:
<p>{{x.studName}}</p> <p> {{x.mark}}</p>
You are overcomplicating things. Given the following simple context:
students = MarkAtt.objects.values('studName').annotate(mark=Sum('attendance'))
context = {
'students' : students,
}
you can do in the template:
{% for student in students %}
<p>{{student.studName}}</p> <p> {{ student.mark}}</p>
{% endfor %}

Django 2 distinct model field items

I am trying to get a list of distinct items in a field of a module and then display all the items associated with that field.
For example, in a school administration system there is a school module and a student model. Each student has a color associated with them as a 'color' field. I want to create a page where the page lists all the distinct colors in the school and then under each color a list of students that belong to that color.
Would I write this function in views?
Here is what I have so far in views.py:
class SchoolColorDetailView(DetailView):
model=models.School
template_name='school_app/school_color_detail.html'
def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs)
context['colors']=Student.objects.all().order_by('color').distinct('color')
This will get me a list of all colors (but not by school). Is there any way to only get the colors by school and then all the students associated with that color? Do I have to create a dictionary for this?
Any help would be appreciated.
Thanks!
Update:
Here are the models:
class School(models.Model):
name = models.CharField(max_length=256)
principal = models.CharField(max_length=256)
location = models.CharField(max_length=256)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("school_app:school_detail",kwargs={'pk':self.pk})
class Student(models.Model):
name = models.CharField(max_length=256)
color = models.CharField(max_length=256)
school = models.ForeignKey(School,related_name='students', on_delete="Protect")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("school_app:student_detail",kwargs={'pk':self.pk})
Second update:
I am trying to make a template that looks something like this (not sure the best way to do that):
{% for color in colors %}
<ul>
<li>{{color}}
{% for student in color %}
<ul>
<li>{{student}}</li>
</ul>
{% endfor %}
</li>
</ul>
{% endfor %}
Change
context['colors']=Student.objects.all(
).order_by('color').distinct('color')
to
context['colors']=self.student_set.all(
).order_by('color').distinct('color')

Django queryset optimisation: Reverse lookup on _set with filter

I have these models and I need to do some calculations and present them to the user. I render approx 2-3k of rows which results in 4k queries done to the DB (shown from debug toolbar). Is there any way to optimize this? I've tried with prefetch_related but it just adds another query on top of 4k already that are being done..
class Cart(models.Model):
name = models.CharField(max_length=15)
user = models.OneToOneField(User)
def sum_for_this(self, taxtype, tax):
return self.carttax_set.filter(tax__type__name=taxtype,
tax__tax=tax).aggregate(
sum=Coalesce(Sum('tax_amount'), Value('0'))
).get('sum')
class TaxType(models.Model):
name = models.CharField(max_length=10)
class Tax(models.Model):
name = models.CharField(max_length=100)
type = models.ForeignKey(TaxType)
tax = models.DecimalField()
class CartTax(models.Model):
cart = models.ForeignKey(Cart)
tax = models.ForeignKey(Tax)
base = models.IntegerField()
tax_amount = models.IntegerField()
What I do in template is:
{% for cart in cartlist %}
{{ cart.sum_for_this }}
{% endfor %}
I've tried with this but no effect:
Cart.objects.prefetch_related('carttax_set').all()
That method def sum_for_this is doing all the queries..
Try to use annotate with conditional expressions. Your query will look like this:
from django.db.models import Q, F, Sum, Case, When, IntegerField
from django.db.models.functions import Coalesce
cartlist = Cart.objects.annotate(
sum=Coalesce(Sum(Case(
When(Q(carttax__tax__type__name=taxtype) & Q(carttax__tax__tax=tax), then=F('carttax__tax_amount')),
output_field=IntegerField()
)), 0)
)
And in template:
{% for cart in cartlist %}
{{ cart.sum }}
{% endfor %}

Why choice field displays keys instead of values in django queryset?

I have a Choice Field in my models.py
models.py
STATUS = (
('closed_issue', 'Closed Issue'),
('open_ssue', 'Open Issue'),
('pending', 'Pending'),
)
class Issue(models.Model):
name = models.CharField(max_length=45)
status = models.CharField(max_length=50, choices=STATUS)
views.py
def Issues(resuest):
issues = Issue.objects.all()
template
{% for issue in issues %}
{{ issue.status }}
{% endfor %}
Output
closed_issue
open_issue
It displays the keys of the choice field instead of values
I want the values to be displayed in the template. Is there a way to get the values instead of keys?
Thanks for any help.
Of course there is a way:
{{ issue.get_status_display }}
In order to get the values of the STATUSes you must use a name convention get_<field_name>_display(). More on this here.

Iterating 2 querysets in Django html?

I have two querysets. My first Queryset (services) has all of my service objects. My second Queryset (rating_values) has all of my rating values, where each index corresponds to the index in the services Queryset. For example services[1] corresponds with rating_values[1].
How do I loop through these two queries in an html page in django so so that I can display the service name along with the corresponding rating value?
To be clear, services contains service objects and rating_values contains decimal values. I pass the variables like this:
return render_to_response('services/display_services.html', {'user': request.user, 'services':services, 'rating_values': rating_values })
I would like to do something like this:
{% for service in services %}
<p> {{service.service_name}} : {{ corresponding rating_value}} </p>
Edit
Here is my Service model:
class Service(models.Model):
user_id= models.IntegerField(default=1)
service_name = models.CharField(max_length=100)
address = models.CharField(max_length=200)
def __str__(self): # __unicode__ on Python 2
return self.service_name
Here is my Rating Model:
class Rating(models.Model):
service_id= models.IntegerField(default=1)
service_name= models.CharField(max_length=200)
number_of_ratings = models.IntegerField()
total_rating_value = models.IntegerField()
rating_average = models.FloatField()
def __str__(self): # __unicode__ on Python 2
return self.service_name
Just to answer the original question as well.
If you for some reason don't want a database relation between the models, you could convert the querysets to lists and zip them in the view, turning the querysets to a list of tuples.
view:
return render_to_response(
'services/display_services.html',
context_instance={
'user': request.user,
'services_and_ratings': zip(
services.all(),
rating_values.all()
)
}
)
template:
{% for service, rating in services_and_ratings %}
<p> {{ service.service_name }} : {{ rating.rating_average }} </p>
You can establish the relationship right in the model.
class Rating(models.Model):
service= models.OneToOneField(Service, primary_key=True)
service_name= models.CharField(max_length=200)
number_of_ratings = models.IntegerField()
total_rating_value = models.IntegerField()
rating_average = models.FloatField()
....
You can then pass services and get the corresponding ratings..
{% for service in services %}
<p> {{service.service_name}} : {{ service.rating.rating_average }} </p>

Categories