5. Foreign Key Woes class Profile(models.Model): name = models.CharField(max_length=64) class Image(models.Model): profile = models.ForeignKey(Profile) >>> p = Profile.objects.create(name='andy') >>> i = Image.objects.create(profile=p) >>> p.delete() >>> Image.objects.filter(profile=p) []
6. Foreign Key Woes class Profile(models.Model): name = models.CharField(max_length=64) icon = models.ForeignKey(Image, null=True) class Image(models.Model): pass >>> i = Image.objects.create() >>> p = Profile.objects.create(name='andy', icon=i) >>> i.delete() >>> Profile.objects.filter(name='andy') [] # WTF ?!?!?!?!?!?
7.
8. Main Ticket: #7539 First Reported: 6/25/2008 !!! Duplicate Tickets: #10262, #6870, #12382, #12166
9. NullableForeignKey from whiskey.core import NullableForeignKey class Profile(models.Model): name = models.CharField(max_length=64) icon = NullableForeignKey(Image) class Image(models.Model): pass >>> i = Image.objects.create() >>> p = Profile.objects.create(name='andy', icon=i) >>> i.delete() >>> Profile.objects.filter(name='andy') >>> [<Profile: Profile object>] >>> print Profile.objects.filter(name='andy')[0].icon None
10. Concurrency Issues def like(request, pk): m = MyObject.objects.get(pk=pk) m.likes += 1 m.save() return HttpResponse('') What happens if two requests come in at the same time?
11. Django "F" Expressions New in Django 1.1 from django.db.models import F def like(request, pk): m = MyObject.objects.get(pk=pk) m.likes = F('likes') + 1 m.save() return HttpResponse('')
12. .save() Updates All Fields from django.db.models import F def like(request, pk): m = MyObject.objects.get(pk=pk) m.likes = F('likes') + 1 m.save() # race condition with "hates" return HttpResponse('') def hate(request, pk): m = MyObject.objects.get(pk=pk) m.hates = F('hates') + 1 m.save() # race condition with "likes" return HttpResponse('')
13. QuerySet.update() from django.db.models import F def like(request, pk): MyObject.objects.filter(pk=pk).update( likes=F('likes') + 1) return HttpResponse('') def hate(request, pk): MyObject.objects.filter(pk=pk).update( likes=F('hates') + 1) return HttpResponse('') That's a lot of typing. What about ORM cache invalidation?
14. Even Easier from whiskey.core import update def like(request, pk): m = MyObject.objects.get(pk=pk) update(m, likes=F('likes') + 1) return HttpResponse('') def hate(request, pk): m = MyObject.objects.get(pk=pk) update(m, hates=F('hates') + 1) return HttpResponse('')