Atomické get_or_create v djangu
Pozor na funkciu get_or_create v djangu. Navonok sa síce tvári atomicky, ale v skutočnosti môže nastať situácia keď sa vytvoria 2 objekty s rovnakými atribútmi.
Predstavme si, že chceme zaznamenávať štatistiky pre každú URL adresu webu. Štatistiky budú ukladané v ORM modeli PageStatistics
. Model bude definovaný nasledovne:
from django.db import models class PageStatistics(models.Model): path = model.CharField(max_length=255) access_count = models.IntegerField(default=0)
Pri každom zobrazení stránky sa spustí nasledujúci kód:
stat = PageStatistics.objects.get_or_create(path=request.META['path']) stat.access_count += 1 stat.save()
Nový riadok v tabuľke sa vytvára až pri volaní metódy save
. Ak sa ešte pred zavolaním save
v inom vlákne spustí get_or_create
vytvoria sa 2 samostatné objekty štatistík s rovnakou URL adresou.
Atomickosť sa dá od verzie django 1.6 dosiahnuť pomerne elegantným kódom:
from django.db import transaction from django.db.models import F ... path = request.META['path'] try: stat = PageStatistics.objects.get(path=path) except PageStatistics.DoesNotExist: with transaction.atomic(): stat = PageStatistics(path=path) stat.save() PageStatistics.objects.filter(pk=stat.pk).update(access_count=F('access_count') + 1)
Pre pridávanie komentárov sa musíte prihlásiť.