web-dev-qa-db-fra.com

Django Query utilisant .order_by () et .latest ()

J'ai un modèle:

class MyModel(models.Model):
   creation_date = models.DateTimeField(auto_now_add = True, editable=False)

   class Meta:
      get_latest_by = 'creation_date'

J'ai eu une question à mon avis qui a fait ce qui suit:

instances = MyModel.objects.all().order_by('creation_date')

Et puis plus tard, je voulais instances.latest(), mais cela ne me donnait pas le bon exemple, mais en fait le premier exemple. Ce n'est que lorsque j'ai défini order_by sur -creation_date ou que j'ai effectivement supprimé order_by de la requête, .latest() m'a donné l'instance correcte. Cela se produit également lorsque je teste cela manuellement à l’aide de python manage.py Shell plutôt que dans la vue.

Donc, ce que j'ai fait maintenant est dans la méta du modèle, j'ai répertorié order_by = ['creation_date'] et je ne l'ai pas utilisé dans la requête, et cela fonctionne.

Je me serais attendu à ce que .latest() renvoie toujours l'instance la plus récente en fonction d'un champ (date) (heure). Quelqu'un peut-il me dire s'il est correct que .latest() se comporte étrangement lorsque vous utilisez order_by dans la requête?

38
Heyl1

J'aurais pensé que .latest () renverrait toujours l'instance la plus récente en fonction d'un champ (date) (heure). 

La documentation dit que 

Si la variable Meta de votre modèle spécifie get_latest_by, vous pouvez laisser l'argument field_name à latest(). Django utilisera le champ spécifié dans get_latest_by par défaut.

Cela signifie simplement que lorsque vous déclenchez MyModel.objects.latest(), vous obtiendrez la dernière instance en fonction du champ date/heure. Et lorsque j'ai testé votre code en utilisant des exemples de données, c'est effectivement le cas.

Et puis plus tard, je voulais instances.latest (), mais cela ne me donnait pas l'instance correcte, mais plutôt la première instance.

Vous avez mal compris le fonctionnement de latest(). Lorsqu'il est appelé sur MyModel.objects, il retourne La dernière instance de table. Lorsqu'il est appelé sur un queryset, latest renvoie le premier objet dans le queryset. Votre ensemble de requêtes était composé de toutes les instances de MyModel ordonnées par creation_date par ordre croissant. Il est donc naturel que latest de ce queryset retourne la première ligne du queryset. Il se trouve d'ailleurs que cette ligne est la plus ancienne de la table.

Une façon de mieux comprendre consiste à afficher la requête déclenchée pour latest.

Cas 1: 

from Django.db import connection
MyModel.objects.latest()
print connection.queries[-1]['sql']

Cela imprime:

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM 
"app_mymodel" ORDER BY "app_mymodel"."creation_date" DESC LIMIT 1

Notez le classement par creation_date DESC et la clause LIMIT. Le premier est grâce à get_latest_by alors que le dernier est la contribution de latest

Maintenant, cas 2:

MyModel.objects.order_by('creation_date').latest()
print connection.queries[-1]['sql']

empreintes

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM 
"app_mymodel" ORDER BY "app_mymodel"."creation_date" ASC LIMIT 1

Notez que la commande a été modifiée en creation_date ASC. Ceci est le résultat du order_by explicite. La LIMIT est ajoutée, plus tard, avec la permission de latest

Voyons également le cas 3: où vous spécifiez explicitement le field_name pour objects.latest().

MyModel.objects.latest('id')
print connection.queries[-1]['sql']

spectacles

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM "app_mymodel"
ORDER BY "app_mymodel"."id" DESC LIMIT 1
67
Manoj Govindan

Je suppose que ceci est un bug connu dans Django qui a été corrigé après la publication de la version 1.3.

Cela a fonctionné pour moi

latestsetuplist = SetupTemplate.objects.order_by('-creationTime')[:10][::1]
0
Manish Gupta