Tweaked SequenceField so that it doesn't increment on creation.
[refs #238]
This commit is contained in:
parent
5eb895b952
commit
5834fa840c
1
AUTHORS
1
AUTHORS
@ -4,3 +4,4 @@ Deepak Thukral <iapain@yahoo.com>
|
|||||||
Florian Schlachter <flori@n-schlachter.de>
|
Florian Schlachter <flori@n-schlachter.de>
|
||||||
Steve Challis <steve@stevechallis.com>
|
Steve Challis <steve@stevechallis.com>
|
||||||
Ross Lawley <ross.lawley@gmail.com>
|
Ross Lawley <ross.lawley@gmail.com>
|
||||||
|
Wilson Júnior <wilsonpjunior@gmail.com>
|
||||||
|
@ -5,6 +5,7 @@ Changelog
|
|||||||
Changes in dev
|
Changes in dev
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
- Added SequenceField - for creating sequential counters
|
||||||
- Added update() convenience method to a document
|
- Added update() convenience method to a document
|
||||||
- Added cascading saves - so changes to Referenced documents are saved on .save()
|
- Added cascading saves - so changes to Referenced documents are saved on .save()
|
||||||
- Added select_related() support
|
- Added select_related() support
|
||||||
|
@ -587,7 +587,8 @@ class BaseDocument(object):
|
|||||||
|
|
||||||
# Set any get_fieldname_display methods
|
# Set any get_fieldname_display methods
|
||||||
self.__set_field_display()
|
self.__set_field_display()
|
||||||
|
# Flag initialised
|
||||||
|
self._initialised = True
|
||||||
signals.post_init.send(self.__class__, document=self)
|
signals.post_init.send(self.__class__, document=self)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
@ -880,30 +880,46 @@ class GeoPointField(BaseField):
|
|||||||
|
|
||||||
|
|
||||||
class SequenceField(IntField):
|
class SequenceField(IntField):
|
||||||
|
"""Provides a sequental counter.
|
||||||
|
|
||||||
|
..note:: Although traditional databases often use increasing sequence
|
||||||
|
numbers for primary keys. In MongoDB, the preferred approach is to
|
||||||
|
use Object IDs instead. The concept is that in a very large
|
||||||
|
cluster of machines, it is easier to create an object ID than have
|
||||||
|
global, uniformly increasing sequence numbers.
|
||||||
|
|
||||||
|
.. versionadded:: 0.5
|
||||||
|
"""
|
||||||
|
def __init__(self, collection_name=None, *args, **kwargs):
|
||||||
|
self.collection_name = collection_name or 'mongoengine.counters'
|
||||||
|
return super(SequenceField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def generate_new_value(self):
|
def generate_new_value(self):
|
||||||
"""
|
"""
|
||||||
Generate and Increment counter
|
Generate and Increment the counter
|
||||||
"""
|
"""
|
||||||
sequence_id = "{0}.{1}".format(self.owner_document._get_collection_name(),
|
sequence_id = "{0}.{1}".format(self.owner_document._get_collection_name(),
|
||||||
self.name)
|
self.name)
|
||||||
collection = _get_db()['mongoengine.counters']
|
collection = _get_db()[self.collection_name]
|
||||||
counter = collection.find_and_modify(query={"_id": sequence_id},
|
counter = collection.find_and_modify(query={"_id": sequence_id},
|
||||||
update={"$inc" : {"next": 1}},
|
update={"$inc": {"next": 1}},
|
||||||
new=True,
|
new=True,
|
||||||
upsert=True)
|
upsert=True)
|
||||||
return counter['next']
|
return counter['next']
|
||||||
|
|
||||||
def __get__(self, instance, owner):
|
def __get__(self, instance, owner):
|
||||||
if not instance._data:
|
|
||||||
return
|
|
||||||
|
|
||||||
if instance is None:
|
if instance is None:
|
||||||
return self
|
return self
|
||||||
|
if not instance._data:
|
||||||
|
return
|
||||||
value = instance._data.get(self.name)
|
value = instance._data.get(self.name)
|
||||||
|
if not value and instance._initialised:
|
||||||
if not value:
|
|
||||||
value = self.generate_new_value()
|
value = self.generate_new_value()
|
||||||
instance._data[self.name] = value
|
instance._data[self.name] = value
|
||||||
|
return value
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if value is None:
|
||||||
|
value = self.generate_new_value()
|
||||||
return value
|
return value
|
||||||
|
@ -1379,20 +1379,7 @@ class FieldTest(unittest.TestCase):
|
|||||||
self.assertEqual(d2.data, {})
|
self.assertEqual(d2.data, {})
|
||||||
self.assertEqual(d2.data2, {})
|
self.assertEqual(d2.data2, {})
|
||||||
|
|
||||||
|
|
||||||
def test_sequence_field(self):
|
def test_sequence_field(self):
|
||||||
class Person(Document):
|
|
||||||
id = SequenceField(primary_key=True)
|
|
||||||
|
|
||||||
self.db['mongoengine.counters'].drop()
|
|
||||||
Person.drop_collection()
|
|
||||||
p = Person()
|
|
||||||
p.save()
|
|
||||||
|
|
||||||
p = Person.objects.first()
|
|
||||||
self.assertEqual(p.id, 1)
|
|
||||||
|
|
||||||
def test_multiple_sequence_field(self):
|
|
||||||
class Person(Document):
|
class Person(Document):
|
||||||
id = SequenceField(primary_key=True)
|
id = SequenceField(primary_key=True)
|
||||||
name = StringField()
|
name = StringField()
|
||||||
@ -1404,18 +1391,76 @@ class FieldTest(unittest.TestCase):
|
|||||||
p = Person(name="Person %s" % x)
|
p = Person(name="Person %s" % x)
|
||||||
p.save()
|
p.save()
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
ids = [i.id for i in Person.objects]
|
ids = [i.id for i in Person.objects]
|
||||||
self.assertEqual(ids, range(1, 11))
|
self.assertEqual(ids, range(1, 11))
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
def test_multiple_sequence_fields(self):
|
||||||
|
class Person(Document):
|
||||||
|
id = SequenceField(primary_key=True)
|
||||||
|
counter = SequenceField()
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
self.db['mongoengine.counters'].drop()
|
||||||
|
Person.drop_collection()
|
||||||
|
|
||||||
for x in xrange(10):
|
for x in xrange(10):
|
||||||
p = Person(name="Person %s" % x)
|
p = Person(name="Person %s" % x)
|
||||||
p.save()
|
p.save()
|
||||||
|
|
||||||
ids = [i.id for i in Person.objects]
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
self.assertEqual(ids, range(1, 21))
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
ids = [i.id for i in Person.objects]
|
||||||
|
self.assertEqual(ids, range(1, 11))
|
||||||
|
|
||||||
|
counters = [i.counter for i in Person.objects]
|
||||||
|
self.assertEqual(counters, range(1, 11))
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
def test_multiple_sequence_fields_on_docs(self):
|
||||||
|
|
||||||
|
class Animal(Document):
|
||||||
|
id = SequenceField(primary_key=True)
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
id = SequenceField(primary_key=True)
|
||||||
|
|
||||||
|
self.db['mongoengine.counters'].drop()
|
||||||
|
Animal.drop_collection()
|
||||||
|
Person.drop_collection()
|
||||||
|
|
||||||
|
for x in xrange(10):
|
||||||
|
a = Animal(name="Animal %s" % x)
|
||||||
|
a.save()
|
||||||
|
p = Person(name="Person %s" % x)
|
||||||
|
p.save()
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'animal.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
ids = [i.id for i in Person.objects]
|
||||||
|
self.assertEqual(ids, range(1, 11))
|
||||||
|
|
||||||
|
id = [i.id for i in Animal.objects]
|
||||||
|
self.assertEqual(id, range(1, 11))
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
|
c = self.db['mongoengine.counters'].find_one({'_id': 'animal.id'})
|
||||||
|
self.assertEqual(c['next'], 10)
|
||||||
|
|
||||||
counter = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
|
|
||||||
self.assertEqual(counter['next'], 20)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user