Skip to main content

Mixins to cache, force and/or use non-atomic Model.objects.get_or_create() calls.

Project description

Django GetOrCreatePlus is a set of queryset mixins to create custom querysets that can:

  • Cache results of get_or_create() or update_or_create()

  • Always use get_or_create() when get() calls are made

  • Allow non-atomic get_or_create() to avoid nested transaction points

Quick start

# models.py

from django.db import models
from django.core.cache import caches
from getorcreateplus import CachedGetOrCreateMixin, AlwaysGetOrCreateMixin, NonAtomicGetOrCreateMixin


# sample for CachedGetOrCreateMixin (see below for changes to be made in settings.py)
class CachedQuerySet(CachedGetOrCreateMixin, models.QuerySet):
    pass

class CachedManager(models.manager.BaseManager.from_queryset(CachedQuerySet)):
    use_for_related_fields = True

class CachedImmutableModel(models.Model):
    foo = models.CharField(max_length=8)
    bar = models.IntegerField(null=True)

    objects = CachedManager()


obj1, _ = CachedImmutableModel.objects.get_or_create(foo='FooBar') # fetches from db
obj2, _ = CachedImmutableModel.objects.get_or_create(foo='FooBar') # hits cache


class CachedMutableObject(models.Model):
    foo = models.CharField(max_length=8)
    bar = models.IntegerField(null=True)

    objects = CachedManager()

    def save(self, **kwargs):
        cache = caches[self._meta.model_name]
        cache.delete(self.pk)
        return super(CachedMutableObject, self).save(**kwargs)


obj1, _ = CachedMutableModel.objects.get_or_create(foo='FooBar') # fetches from db
obj1.bar = 1
obj1.save() # invalidate object cache
obj2, _ = CachedMutableModel.objects.get_or_create(foo='FooBar') # fetches from db
obj3, _ = CachedMutableModel.objects.get_or_create(foo='FooBar') # hits cache


# sample for NonAtomicGetOrCreateMixin
class NonAtomicQuerySet(NonAtomicGetOrCreateMixin, models.QuerySet):
    pass

class NonAtomicManager(models.manager.BaseManager.from_queryset(NonAtomicQuerySet)):
    use_for_related_fields = True

class ParentQuerySet(NonAtomicQuerySet):
    def create(self, **kwargs):
       children = kwargs.pop('children', [])
       parent = super(ParentQuerySet, self).create(**kwargs)
       for child in children:
           parent.children.get_or_create(**child)
       return parent

class ParentManager(models.manager.BaseManager.from_queryset(ParentQuerySet)):
    use_for_related_fields = True

class ParentModel(models.Model):
    foo = models.CharField(max_length=8)

    objects = ParentManager()

class ChildModel(models.Model):
    parent = models.ForeignKey(Parent, related_name='children')
    bar = models.CharField(max_length=8)

    objects = NonAtomicManager()


from django.db import transaction

with transaction.atomic():
    parent, _ = ParentModel.objects.get_or_create(foo='Foo', defaults={children: [{bar: 'Bar'}, {bar: 'Baz'}]})


# samples for combining mixins CachedGetOrCreateMixin, AlwaysGetOrCreateMixin, NonAtomicGetOrCreateMixin
class NonAtomicAlwaysQuerySet(NonAtomicGetOrCreateMixin, AlwaysGetOrCreateMixin, models.QuerySet):
    pass

class AlwaysCachedQuerySet(AlwaysGetOrCreateMixin, CachedGetOrCreateMixin, models.QuerySet):
    pass

class PlusQuerySet(CachedGetOrCreateMixin, AlwaysGetOrCreateMixin, NonAtomicGetOrCreateMixin, models.QuerySet):
    pass

CachedGetOrCreateMixin uses Django caches. The keys are cached to the default cache, and the objects are cached using alias model._meta.model_name.

NOTE: If you have models by the same name in different apps both using CachedGetOrCreateMixin, this will fail.

# settings.py
# assuming use of django-connection-url (shameless self-plug)

import connection_url

CACHES = {
    'default': connection_url.config('locmem:///'),
    'cachedimmutablemodel': connection_url.config('REDIS_URL'),
    'cachedmutablemodel': connection_url.config('MEMCACHED_URL'),
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

django_getorcreateplus-0.1.0-py2-none-any.whl (5.9 kB view details)

Uploaded Python 2

File details

Details for the file django_getorcreateplus-0.1.0-py2-none-any.whl.

File metadata

File hashes

Hashes for django_getorcreateplus-0.1.0-py2-none-any.whl
Algorithm Hash digest
SHA256 c6514fc3e88b6585ad3eec0fac2252a3a956216610e3b08a3cb2f4a4f3695a45
MD5 9f50e3d2366cdde89af35fbca9562c8e
BLAKE2b-256 d9da6d19644d51f488321f28f4433a443fa4bddfaa42e9887622b4707fe51837

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page