Django aggregate with associated values - django

I have a models.py like so:
class ScoreCard(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
created = models.DateTimeField(default=datetime.now)
score = models.IntegerField()
holes = models.IntegerField(
default=9
)
handicap = models.IntegerField(default=0)
class UserProfile(User):
...
def get_nine_stats(self, course):
nine_stats = ScoreCard.objects.filter(course=course) \
.filter(holes=9) \
.aggregate(Avg('score'), Max('score'), Min('score'))
return nine_stats
This is fine and returns almost what I need - a dict of max, min and avg. However, I really want those values with the associated created fields. Is this possible using the aggregate method?

Related

how to access to property in view(django)

I'm beginner and I need some solution
First, I have Racket and Detail class.
class Racket(models.Model):
name = models.CharField(max_length=20)
class RacketDetail(models.Model):
racket = models.OneToOneField(Racket, related_name='detail', on_delete=models.CASCADE)
adminReview = models.TextField()
adminPower = models.FloatField(default=0)
adminSpin = models.FloatField(default=0)
adminManeuverability = models.FloatField(default=0)
adminStability = models.FloatField(default=0)
adminComfort = models.FloatField(default=0)
#property
def adminAvgScore(self):
scoreAvg = (
self.adminPower +
self.adminSpin +
self.adminManeuverability +
self.adminStability +
self.adminComfort
) / 5
return round(scoreAvg, 2)
Second, I want to rander list using the #property(adminAvgScore), so I made view like this.
def racketMain(request: HttpRequest):
getRacket = Racket.objects.all().order_by('detail__adminAvgScore')
return render(request, "racket/racketMain.html", {'racketItems': getRacket, })
Unfortunally when I use 'RacketDetail' class's column I can access all column except 'adminAvgScore' using by "order_by('detail__".
If I use like "order_by('detail__adminAvgScore')" then Django show to me error "Unsupported lookup 'adminAvgScore' for BigAutoField or join on the field not permitted."
How can I solve it? Or should I think in a different way?
You cannot use property with Query as Property is Function. You can use annotate and aggregate combination to get the result as your property function but inside a query.Something like this will do the trick.
from django.db.models import F, Sum, FloatField, Avg
Model.objects.filter(...)\
.values('id')\
.annotate(subtotal=Sum(...math here..., output_field=FloatField()))\
.aggregate(total=Avg(F('subtotal')))

Accessing foreign key attributes for arithmetics in django rest framework

I'm trying to calculate the length of a house relative to some adjacent neighborhoods, such that, house_size / (neighborhood[0].length + neighborhood[1].length...):
class House(models.Model):
house_id = models.CharField(max_length=256, primary_key=True)
size = models.IntegerField()
neighborhood = models.ManyToManyField('neighborhood', through='HouseNeighborhoodLink')
class Neighborhood(models.Model):
length = models.IntegerField()
I created a table to assign several neighborhoods with a house. Also, houses can be assigned to several adjacent neighborhoods:
class HouseNeighborhoodLink(models.Model):
house = models.ForeignKey(House, on_delete=models.DO_NOTHING)
neighborhood = models.ForeignKey(Neighborhood, on_delete=models.DO_NOTHING)
Serializers:
class LengthFromNeighborhoodSerializer(serializers.ModelSerializer):
class Meta:
model = Neighborhood
fields = ['length']
class HouseCoverageOfNeighborhood(serializers.ModelSerializer):
Neighborhood = LengthFromNeighborhoodSerializer(read_only=True)
class Meta:
model = HouseNeighborhoodLink
fields = ['house_id', 'Neighborhood']
I'm stuck in the three dots (...), where I want to access the length attribute of all neighborhoods and then calculate the proportion to a house. I'm not sure how to access the length of each neighborhood from HouseNeighborhoodLink table:
class HouseCoverageDetail(generics.ListAPIView):
queryset = HouseNeighborhoodLink.objects.all()
serializer_class = HouseCoverageOfNeighborhood
def get_queryset(self):
house_id = self.kwargs['house_id']
neighborhood = self.queryset.filter(house_id=house_id)
...
return result
Chack this
class HouseCoverageOfNeighborhood(serializers.ModelSerializer):
Neighborhood = LengthFromNeighborhoodSerializer(many=True,read_only=True)
class Meta:
model = HouseNeighborhoodLink
fields = ['house_id', 'Neighborhood']

django - improve performance of __in queryset in M2M filtering

I have a models that has a M2M relationship to another model.
These are my models:
class Catalogue(models.Model):
city = models.CharField(db_index=True,max_length=100, null=True)
district = models.CharField(db_index=True,max_length=100, null=True)
type = models.ManyToManyField(Type, db_index=True)
datetime = models.CharField(db_index=True, max_length=100, null=True)
class Type(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
And this is views.py:
class all_ads(generic.ListView):
paginate_by = 12
template_name = 'new_list_view_grid-card.html'
def get_queryset(self):
city_district = self.request.GET.getlist('city_district')
usage = self.request.GET.get('usage')
status = self.request.GET.get('status')
last2week = datetime.datetime.now() - datetime.timedelta(days=14)
status = status.split(',')
if usage:
usage = usage.split(',')
else:
usage = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31']
intersections = list(set(status).intersection(usage))
type_q = (Q(type__in=intersections) & Q(type__isnull=False))
result = models.Catalogue.objects.filter(
Q(datetime__gte=last2week) &
type_q &
((reduce(operator.or_, (Q(city__contains=x) for x in city_district)) & Q(city__isnull=False)) |
(reduce(operator.or_, (Q(district__contains=x) for x in city_district)) & Q(district__isnull=False)))
).distinct().order_by('-datetime').prefetch_related('type')
return result
I want to filter MySQL db with some queries and return result in a listview.
It works good on a small database, but with large database it takes over 10 seconds to return results. If I delete type_q query, It takes 2 seconds (reduce 10 second!).
How can I improve performance of __in queryset?
It looks like type_q itself is not really the culprit, but acts as a multiplier, since now we make a LEFT OUTER JOIN, and thus the __contains runs over all combinations. This is thus more a peculiarity of two filters that work together
We can omit this with:
cat_ids = list(Catalogue.objects.filter(
Q(*[Q(city__contains=x) for x in city_district], _connector=Q.OR) |
Q(*[Q(district__contains=x) for x in city_district], _connector=Q.OR)
).values_list('pk', flat=True))
result = models.Catalogue.objects.filter(
Q(datetime__gte=last2week),
type_q,
pk__in=cat_ids
).distinct().order_by('-datetime').prefetch_related('type')
Some database (MySQL is known to not optimize a subquery very well), can even do that with a subquery with. So here we do not materialize the list, but let Django work with a subquery:
cat_ids = Catalogue.objects.filter(
Q(*[Q(city__contains=x) for x in city_district], _connector=Q.OR) |
Q(*[Q(district__contains=x) for x in city_district], _connector=Q.OR)
).values_list('pk', flat=True)
result = models.Catalogue.objects.filter(
Q(datetime__gte=last2week),
type_q,
pk__in=cat_ids
).distinct().order_by('-datetime').prefetch_related('type')

Building up subqueries of derived django fields

I have a few transformations I need to perform on my table before I aggregate.
I need to multiply transaction_type (which is either 1 or -1) by amount to yield a signed_amount. Then I need to sum all signed_amounts by primary_category (which is a foreign key to secondary category which is a foreign key of my table).
DEBIT = -1
CREDIT = 1
TRANSACTION_TYPE_CHOICES = (
(DEBIT, 'debit'),
(CREDIT, 'credit'),
)
class Transaction(models.Model):
amount = models.DecimalField(max_digits=7, decimal_places=2)
transaction_type = models.IntegerField(choices=TRANSACTION_TYPE_CHOICES)
secondary_category = models.ForeignKey(Secondary_Category)
class Primary_Category(models.Model):
name = models.CharField("Category Name", max_length=30)
category = models.ForeignKey(Primary_Category_Bucket)
class Secondary_Category(models.Model):
name = models.CharField("Category Name", max_length=30)
primary_category = models.ForeignKey(Primary_Category)
I'm stuck on the first bit though.
from django.db.models import Sum, Count, F
original_transactions = Transaction.objects.all()
original_transactions.signed_amount = F('transaction_type') * F('amount')
for transaction in original_transactions:
print transaction.signed_amount
When I try to sanity check that signed_amount is being calculated, I get an error that 'Transaction' object has no attribute 'signed_amount'. I don't want to save signed_amount to the database. I just want to generate it as derived field so I can calculate my totals.
How do I calculate this derived field and subsequently aggregate by primary_category.name?
User python decorator property on a method for class Transaction:
class Transaction(models.Model):
amount = models.DecimalField(max_digits=7, decimal_places=2)
transaction_type = models.IntegerField(choices=TRANSACTION_TYPE_CHOICES)
secondary_category = models.ForeignKey(Secondary_Category)
#property
def signed_amount(self):
return self.amount * self.transaction_type
Then for each Transaction object you can do transaction.signed_amount.
I'm not sure if the aggregation part could be done using queries, but if you don't have that many PrimaryCategory, then python would be good enough to achieve it.
Or you can do this.
all_transactions = Transaction.objects.all().order_by('secondary_category__primary_category_id')
sum = 0
if all_transactions:
primary_category_id = all_transactions[0].secondary_category.primary_category_id
for transaction in all_transactions:
if primary_category_id == transaction.secondary_category.primary_category_id:
sum += (transaction.amount * transaction_type)
else:
sum = (transaction.amount * transaction_type)
print sum

Django model field relating to a few models

Imagine a 5x5 grid (map), every field of it represents a certain object (it can be a monster, a tree etc.)
So, here we have:
class Field(Model):
x = y = PositiveIntegerField()
content = ...(?)
Here the problem arises. Here is the alternative, but I think this way is too messy, especially if I have many different content ids.
class Field(Model):
x = y = PositiveIntegerField()
content = PositiveIntegerField()
monster_rel = ForeignKey(Monster, null=True, blank=True)
building_rel = ForeignKey(Monster, null=True, blank=True)
nature_obj_rel = ForeignKey(Monster, null=True, blank=True)
and then in a view:
f = Field.objects.get(pk=1)
if f.content == 1:
print "Monster %s of level %d" % (f.monster_rel.name, f.monster_rel.level)
elif f.content == 2:
print "This is a %s" % f.building_rel.type
...
Is there a better solution for this?
EDIT
I would like fields like:
content_id = IntegerField()
content_rel = FieldRelatedToModelByContentId()
Well, sounds like generic relations is exactly what you're looking for.