2012-05-15 2 views
3

J'ai une action d'administration qui ressemble à ceci:Django - En utilisant l'expression F(), mais obtenir la mise à jour non atomique

def process(modeladmin, request, queryset): 
    for reservation in queryset: 
     if not reservation.processed: 
      reservation.processed = True 
      reservation.save() 
      item = reservation.item 
      item.available = F('available') - reservation.quantity 
      item.save() 

Ainsi, l'administrateur peut traiter un reservation d'un item. Chaque fois qu'il le fait, le reservation est marqué comme étant traité, et le nombre de items disponible est diminué de la quantité spécifiée dans le reservation. Comme il arrive pour toutes les actions d'administration, l'administrateur peut traiter plusieurs fois reservations à la fois. Tout va bien si le reservations ont tous différents items. Mais si deux reservations partagent un item, le nombre de items disponibles est seulement diminué de la quantité spécifiée dans le dernier reservation traité.

Je pensais que F() expressions étaient juste pour ce cas: je veux faire beaucoup de changements à item et de les augmenter ou diminuer un attribut sur item sans courir dans des conditions de course. Qu'est-ce que je rate?

+0

Comment le détectez-vous? Rappelez-vous que vous devez appeler get() pour obtenir la nouvelle valeur ... –

+0

Je regarde la valeur de item.available dans l'admin après le traitement des réservations! :-) – Andrea

+0

Est-ce que les éléments obtiennent 'select_related' dans le jeu de requêtes? – okm

Répondre

-1

expressions F() sont pour une utilisation dans une requête, par exemple, lorsque vous voulez faire dans SQL:

SELECT * FROM foo WHERE foo_col = bar_col 

Tu ferais:

Foo.objects.filter(foo_col=F('bar_col')) 

En tout cas, votre L'exigence selon laquelle un élément ne doit être réduit que selon la dernière réservation effectuée signifie que vous devez être un peu créatif en ce qui concerne la façon dont vous faites une boucle dans les réservations. Une option consisterait à ordonner le jeu de queues par identifiant d'article, et chaque fois que l'identifiant «change», ajustez le montant disponible en fonction de la dernière réservation de cet article.

+0

Ce n'est pas vrai. Les expressions F() sont utilisées chaque fois que vous voulez faire référence à un champ sur le même modèle. Cela peut être fait pour diverses raisons, y compris la comparaison et la mise à jour. Le code que j'ai posté ** devrait ** entraîner une requête pour diminuer 'item.available' par' reservation.quantity', plutôt que de récupérer la valeur de 'item-available' et de l'insérer de nouveau.Mais apparemment, je fais quelque chose de mal, car cela ne fonctionne pas comme prévu – Andrea

+0

Par ailleurs, le fait que "un élément ne devrait être diminué en fonction de la dernière réservation faite" est le problème auquel je suis confronté, pas une exigence! Il devrait être diminué en fonction de toutes les réserves, sauf si celles-ci sont déjà traitées – Andrea

1

Ce n'est pas vraiment la façon dont vous utiliseriez l'objet F. Une fois que vous séparez les étapes de la récupération de l'épargne, vous êtes en essence explicitement non-atomique.

Vous devez utiliser update pour que, si l'élément partie doit être:

Item.objects.filter(id=reservation.item.id).update(available=F('available')-reservation.quantity) 

ou quelque chose de similaire.

Questions connexes