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?

+3


source to share


3 answers


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

.

+1


source


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')

      

0


source


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]

      

0


source







All Articles