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ť.