How to request the previous elements of a given criterion
Here is the model
class Player(models.Model):
name = models.CharField()
class ShootingAttempt(models.Model):
player = models.ForeignKey(Player, related_name='shooting_attempts')
is_scored = models.BooleanField()
point = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_add_now=True)
Implementation:
jordan = Player.objects.create(name='Michael Jordan')
attempt1 = ShootingAttempt(player=jordan, is_scored=False)
attempt2 = ShootingAttempt(player=jordan, is_scored=False)
attempt3 = ShootingAttempt(player=jordan, is_scored=True, point=3)
attempt4 = ShootingAttempt(player=jordan, is_scored=False)
attempt5 = ShootingAttempt(player=jordan, is_scored=True, point=3)
attempt6 = ShootingAttempt(player=jordan, is_scored=True, point=3)
Now, how can I query the previous is_scored=False
one if a given ShootingAttempt where pk = 5, presumably for try5, using a named player Micheal Jordan
? This will give the result:[attempt4]
Means Jordan has 1 miss before successfully completing 3 points in 5th attempt
If given ShootingAttempt
where pk=3
(try3) it will return
[attempt1, attempt2]
means Jordan has 2 misses before successfully deflating the first 3 points
And if given pk=6
it will return nothing because there is no existing is_scored=False
between the latter is_scored=True
and pk=6
(try6)
Means Jordan hasn't missed before digging another 3 points
Every shooting attempt can be missed and I would like to receive the final misses of every successful shot.
Is there any job?
source to share
These are the steps I would prefer.
Get the id of the desired instance is_scored=True
ShootingAttempt
. Say id1
And you can get another instance is_scored=True
ShootingAttempt
using .filter(id__lt=id1).aggregate(id2=Max('id'))
this will return you {id2: some_id} which has is_scored=True
and is below id1.
id2 = ShootingAttempt.objects.all().filter(id__lt=id1).aggregate(id2=Max('id'))['id2']
Finally, you can - .filter(id__gt=id2).filter(id__lte=id1)
, which will return the query with False
and last True
.
source to share
You can use order_by
in your request. For example:
last_false = ShootingAttempt.objects.filter(is_scored=False).order_by('-created_at')[0]
Part of the filter selects those objects with a "False" score, after which they are ordered downward, finally selecting the first item ( [0]
).
You can also set the filter with your player in the same way:
last_false = ShootingAttempt.objects.filter(player=jordan).filter(is_scored=False).order_by('-created_at')[0]
Edit:
If you want all previous attempts had attempted ID, you can also filter by means of pk
using __lt
:
last_false = ShootingAttempt.objects.filter(player=jordan).filter(is_scored=False).filter(pk__lt=<shootingattempt>).order_by('-created_at')
source to share
Work around.
attempts = ShootingAttempt.objects.filter(player=jordan)[:pk]
n = len(attempts)
actual_attempts = [] if attempts[n-1].is_scored == True else
[attempts[n-1]]
n -= 1
while n and attempts[n-1].is_scored == False:
actual_attempts.append(attempts[n-1])
n -= 1
actual_attempts = actual_attempts[::-1]
source to share