Revert addition of UpdateOrCreateMixin; reaches 100% test coverage.

This commit is contained in:
Carl Meyer 2013-01-27 14:16:58 -08:00
parent 63a9f461fa
commit 246fb81813
5 changed files with 3 additions and 145 deletions

View file

@ -14,9 +14,6 @@ tip (unreleased)
- Removed deprecated ``ChoiceEnum``, ``InheritanceCastModel``,
``InheritanceCastManager``, and ``manager_from``.
- Added ``UpdateOrCreateMixin`` for custom queryset subclasses. Thanks Antti
Kaihola.
- Fixed pickling of ``PassThroughManager``. Thanks Rinat Shigapov.
- Set ``use_for_related_fields = True`` on ``QueryManager``.

View file

@ -389,34 +389,3 @@ directly on the manager::
Post.objects.by_author(user=request.user).unpublished()
UpdateOrCreateMixin
===================
`Ticket #3182`_ in Django's bug tracker suggests
an ``update_or_create()`` method for managers and querysets.
The method works in a similar way as ``get_or_create()``,
but in addition to returning an object if it's found in the database,
it updates the object's fields according to the ``defaults`` keyword argument.
.. _`Ticket #3182`: https://code.djangoproject.com/ticket/3182
Use this mixin in a custom ``QuerySet`` subclass, and create a corresponding
manager with ``PassThroughManager``::
from datetime import datetime
from django.db import models
from django.db.models.query import QuerySet
from model_utils.managers import UpdateOrCreateMixin
class PostQuerySet(QuerySet, UpdateOrCreateMixin):
pass
class Post(models.Model):
user = models.ForeignKey(User)
published = models.DateTimeField()
objects = PassThroughManager.for_queryset_class(PostQuerySet)()
Post.objects.update_or_create(user=request.user,
defaults={'published': datetime.now()})

View file

@ -153,42 +153,3 @@ def create_pass_through_manager_for_queryset_class(base, queryset_cls):
def unpickle_pass_through_manager_for_queryset_class(base, queryset_cls):
cls = create_pass_through_manager_for_queryset_class(base, queryset_cls)
return cls.__new__(cls)
class UpdateOrCreateMixin(object):
def update_or_create(self, **kwargs):
"""
Looks up an object with the given kwargs, creating one if necessary.
If the object already exists, then its fields are updated with the
values passed in the defaults dictionary.
Returns a tuple of (object, created), where created is a boolean
specifying whether an object was created.
See https://code.djangoproject.com/ticket/3182
"""
assert kwargs, \
'update_or_create() must be passed at least one keyword argument'
defaults = kwargs.pop('defaults', {})
lookup = kwargs.copy()
for f in self.model._meta.fields:
if f.attname in lookup:
lookup[f.name] = lookup.pop(f.attname)
self._for_write = True
sid = transaction.savepoint(using=self.db)
try:
obj = self.get(**lookup)
create = False
except self.model.DoesNotExist:
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
obj = self.model(**params)
create = True
for attname, value in defaults.items():
setattr(obj, attname, value)
try:
obj.save(force_insert=create, using=self.db)
transaction.savepoint_commit(sid, using=self.db)
return obj, create
except IntegrityError:
transaction.savepoint_rollback(sid, using=self.db)
exc_info = sys.exc_info()
raise exc_info[1], None, exc_info[2]

View file

@ -2,7 +2,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils.models import TimeStampedModel, StatusModel, TimeFramedModel
from model_utils.managers import QueryManager, InheritanceManager, PassThroughManager, UpdateOrCreateMixin
from model_utils.managers import QueryManager, InheritanceManager, PassThroughManager
from model_utils.fields import SplitField, MonitorField
from model_utils import Choices
@ -215,22 +215,3 @@ class Spot(models.Model):
owner = models.ForeignKey(Dude, related_name='spots_owned')
objects = PassThroughManager.for_queryset_class(SpotQuerySet)()
class PersonQuerySet(models.query.QuerySet, UpdateOrCreateMixin):
pass
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
birthday = models.DateField()
objects = PassThroughManager(PersonQuerySet)
def __str__(self):
return '%s %s, Birthday: %s' % (self.first_name, self.last_name,
self.birthday)
class Meta:
ordering = ('last_name',)

View file

@ -2,7 +2,7 @@ from __future__ import with_statement
import pickle
from datetime import date, datetime, timedelta
from datetime import datetime, timedelta
from django.db import models
from django.db.models.fields import FieldDoesNotExist
@ -18,8 +18,7 @@ from model_utils.tests.models import (
InheritanceManagerTestParent, InheritanceManagerTestChild1,
InheritanceManagerTestChild2, TimeStamp, Post, Article, Status,
StatusPlainTuple, TimeFrame, Monitored, StatusManagerAdded,
TimeFrameManagerAdded, Dude, SplitFieldAbstractParent, Car, Spot,
Person)
TimeFrameManagerAdded, Dude, SplitFieldAbstractParent, Car, Spot)
@ -576,52 +575,3 @@ class CreatePassThroughManagerTests(TestCase):
pickled_qs = pickle.dumps(qs)
unpickled_qs = pickle.loads(pickled_qs)
self.assertEqual(unpickled_qs.secured().count(), 1)
class UpdateOrCreateTests(TestCase):
def test_update_or_create(self):
Person.objects.create(
first_name='John', last_name='Lennon', birthday=date(1940, 10, 9)
)
p, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon', defaults={
'birthday': date(1970, 10, 9)
}
)
self.assertFalse(created)
self.assertEqual(Person.objects.count(), 1)
self.assertEqual(Person.objects.get().birthday, date(1970, 10, 9))
p, created = Person.objects.update_or_create(
first_name='George', last_name='Harrison', defaults={
'birthday': date(1943, 2, 25)
}
)
self.assertTrue(created)
self.assertEqual(Person.objects.count(), 2)
# If we execute the exact same statement, it won't create a Person.
p, created = Person.objects.update_or_create(
first_name='George', last_name='Harrison', defaults={
'birthday': date(1943, 2, 25)
}
)
self.assertFalse(created)
self.assertEqual(Person.objects.count(), 2)
# update_or_create() can take an empty 'defaults' parameter, but in
# this situation behaves exactly like get_or_create(). This is useful
# if you are building the 'defaults' dictionary dynamically.
p, created = Person.objects.update_or_create(
first_name='George', last_name='Harrison', defaults={}
)
self.assertFalse(created)
# A different name with an empty 'defaults'.
p, created = Person.objects.update_or_create(
first_name='John', last_name='Smith', birthday=date(1950, 2, 10),
defaults={}
)
self.assertTrue(created)
self.assertEqual(Person.objects.count(), 3)