django max and groupby together - django

I have a model which looks like this
player_info, game, score, creation_date
I want to fetch the records with the highest score of each player for a particular game.
Any help is appreciated.
EDIT:
class Game(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(max_length=1000)
logo = models.URLField()
resource_info = models.URLField()
cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=10)
modified_date = models.DateTimeField(auto_now_add=True)
developer_info = models.ForeignKey(User, related_name='uploaded_games', on_delete=models.CASCADE)
class Score(models.Model):
game_info = models.ForeignKey(Game, related_name='game_info',on_delete=models.CASCADE)
player_info = models.ForeignKey(User, related_name='player_info', on_delete=models.CASCADE)
last_played = models.DateTimeField(auto_now=True)
score = models.BigIntegerField(default=0)

If I understand correctly:
You want to filter your Scores by a Game.
And then you want to GROUP BY User and get the MAX score
The GROUP BY part is a bit tricky, but you can achieve it using values + annotate.
Try something like this:
from django.db.models import Max
Score.objects.filter(game_info=...)
.values('player_info').annotate(max=Max('score'))
More info an examples: https://docs.djangoproject.com/en/1.10/topics/db/aggregation/

Related

How to sort and filter queryset based on select_related in Django ORM

I have two tables in my models as show below:
class Coin(models.Model):
coin_id = models.CharField(max_length=100, primary_key=True, unique=True)
name = models.CharField(max_length=100, null=True, blank=True)
class Fundamental(models.Model):
coin_id = models.OneToOneField(Coin, to_field="coin_id", db_column="coin_id", on_delete=models.CASCADE)
market_cap = models.BigIntegerField(null=True, blank=True)
price = models.FloatField(null=True, blank=True)
Now I want to get the top 1000 coins sorted by market cap, or market cap range is between 1000-1000000.
coins = Coin.objects.select_related('fundamental').order_by('ticker__market_cap')[:1000]
I'm writing my query like this, but it is working for some of the coins, but if any coin doesnot exists, it shows the exception like
screener.models.Coin.fundamental.RelatedObjectDoesNotExist: Coin has no
fundamental.
Does anyone will help me to filter a query in a good way

Group By Django queryset by a foreignkey related field

I have a model Allotment
class Kit(models.Model):
kit_types = (('FLC', 'FLC'), ('FSC', 'FSC'), ('Crate', 'Crate'), ('PP Box', 'PP Box'))
kit_name = models.CharField(max_length=500, default=0)
kit_type = models.CharField(max_length=50, default=0, choices=kit_types, blank=True, null=True)
class AllotmentFlow(models.Model):
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
kit = models.ForeignKey(Kit, on_delete=models.CASCADE)
asked_quantity = models.IntegerField(default=0)
alloted_quantity = models.IntegerField(default=0)
class Allotment(models.Model):
transaction_no = models.IntegerField(default=0)
dispatch_date = models.DateTimeField(default=datetime.now)
send_from_warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
flows = models.ManyToManyField(AllotmentFlow)
For a stacked graph I am trying to get the data of different kit_type alloted in different months.
For that I have tried annotate but it isn't getting the desired results
dataset = Allotment.objects.all().annotate(
month=TruncMonth('dispatch_date')).values(
'month').annotate(dcount=Count('flows__kit__kit_type')).values('month', 'dcount')
Expected Output:
[{'month':xyz, 'kit_type':foo, count:123},...]
I am getting the month and count of kit type from above but how do I segregate it by kit_type?
having a field that represents your choice field names in this query is difficult
instead how about use the Count filter argument and annotate to get what you want
dataset = Allotment.objects.all().annotate(month=TruncMonth('dispatch_date')).values('month').annotate(
FLC_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="FLC")),
FSC_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="FSC")),
Crate_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="Crate")),
PP_Box_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="PP_Box")),
).values('month', 'FLC_count', 'FSC_count', 'Crate_count', 'PP_Box_count')

How to change field value dynamically depended on dropdown selection in django

I've been searching Google, but couldn't find a simple answer to this problem:
I have a django models that stores students information and three other models like this:
class Level(models.Model):
name = models.CharField(max_length=50)
class Pricing(models.Model):
level = models.ForeignKey(Level, on_delete=models.PROTECT)
price = models.PositiveSmallIntegerField(default=0)
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.PROTECT)
level = models.ForeignKey(Level, on_delete=models.CASCADE)
date_enrolled = models.DateField()
price = models.PositiveSmallIntegerField(default=0)
I want the Enrollment.price field to be populated dynamically depending on Enrollment.level field value. In javascript, it amounts to setting an event listener to Enrollement.level, but I can't find the equivalent in django.
hi you can modify your save method to fill automatically field price from Level model
Enrollment.level
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.PROTECT)
level = models.ForeignKey(Level, on_delete=models.CASCADE)
date_enrolled = models.DateField()
price = models.PositiveSmallIntegerField()
def save(self,*args,**kwargs):
self.price = Pricing.objects.get(level=self.level).price
super().save(*args,*kwargs)
but I recommend to rewrite your model like above example because its simple and you can access to price of every level directly
like Enrollment.level.price
class Level(models.Model):
level = models.CharField(max_length=50,unique=True)
price = models.PositiveSmallIntegerField(default=0)
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.PROTECT)
level = models.ForeignKey(Level, on_delete=models.CASCADE)
date_enrolled = models.DateField()
I hope it helped you

How to annotate a field from a related model to queryset?

I have two models:
Lot:
class Lot(models.Model):
name = models.CharField(max_length=150, db_index=True, unique=True)
step = models.DecimalField(max_digits=2, decimal_places=2)
and Bid:
class Bid(models.Model):
auction = models.ForeignKey('Lot', on_delete=models.CASCADE)
user_id = models.ForeignKey(User, on_delete=models.CASCADE, to_field='username')
value = models.DecimalField(max_digits=5, decimal_places=2)
Every instance of Lot can have a few Bids, however any instance of Bid is only related to a particular Lot.
I have a working annotation for Lot that gives me the max_bid and next_bid values:
self.auc_set = Lot.objects.annotate(max_bid=Max('bid__value'), next_bid=(Max('bid__value') + F('step')))
And what i can't achieve is getting 3 annotated fields: max_bid, next_bid and last_bidder.
Something like:
self.auc_set = Lot.objects.annotate(max_bid=Max('bid__value'), next_bid=(Max('bid__value') + F('step')), last_bidder=F(bid_set).get('auction_id'= F('id'), 'value'=max_bid)['user_id'])
but working.
Update:
The problem would be solved if i knew how to pass the 'id' from Lot.objects.annotate to the Bid.objects.get part:
auc_set = Lot.objects.annotate(last_bidder=Bid.objects.get(auction_id__exact='need_to_put_something_here', value=Max('value').user_id)

Filter by ForeignKey backwards and forwards

I have 3 model classes:
class Team(models.Model):
name = models.CharField(max_length=100, default="", blank=True, null=True)
number = models.IntegerField()
class Position(models.Model):
match = models.ForeignKey('Match')
color = models.CharField(max_length=5)
number = models.IntegerField()
team = models.ForeignKey('Team')
class Match(models.Model):
type = models.CharField(max_length=3)
number = models.IntegerField()
red_score = models.IntegerField(default=0)
blue_score = models.IntegerField(default=0)
match_events = models.TextField(max_length=1000)
Using the models as they are right now, how would I able to get a list of Matches a Team has won (i.e. if the Team belongs to a red Position, add it to the list if its Match has a red_score > blue_score)
Sorry if that's confusing. I can try to clarify if you have any specific questions.
Thanks!
Simplest way to do this:
Match.objects.filter(position__color='red', red_score__gt=F('blue_score'))
You may want to move Position model to the bottom, to remove apostrophes from foreign key related models names.
This is as well very good example to use ManyToMany relation:
class Team(models.Model):
name = models.CharField(max_length=100, default="", blank=True, null=True)
number = models.IntegerField()
class Match(models.Model):
type = models.CharField(max_length=3)
number = models.IntegerField()
red_score = models.IntegerField(default=0)
blue_score = models.IntegerField(default=0)
match_events = models.TextField(max_length=1000)
teams = models.ManyToManyField(Team, through='Position',
related_name='matches')
class Position(models.Model):
match = models.ForeignKey(Match)
color = models.CharField(max_length=5)
number = models.IntegerField()
team = models.ForeignKey(Team)
In this case, you will get few more options to simplify data access, e.g.:
if team is your actual team and match single match selected somewhere earlier in the code, this is valid:
team.matches.filter(red_score__gt=F('blue_score')) # all won matches of this team
match.teams.all() # teams involved in this match