Metadata-Version: 2.0
Name: django-getorcreateplus
Version: 0.1.0
Summary: Mixins to cache, force and/or use non-atomic Model.objects.get_or_create() calls.
Home-page: https://github.com/f0r4y312/django-getorcreateplus
Author: Vimal Aravindashan
Author-email: vimal.aravindashan@gmail.com
License: Apache-2.0
Keywords: django get_or_create update_or_create get create update cache atomic non-atomic
Platform: any
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 1.8
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Requires-Dist: django (>=1.8,<2)

======================
Django GetOrCreatePlus
======================

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

.. code:: python

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

.. code:: python

    # 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'),
    }


