Add value_decorator into SequenceField

Allows post processing of the calculated counter value.
This commit is contained in:
Ross Lawley 2012-11-07 13:20:34 +00:00
parent 1986e82783
commit 99fe1da345
4 changed files with 50 additions and 15 deletions

View File

@ -4,6 +4,7 @@ Changelog
Changes in 0.8 Changes in 0.8
============== ==============
- Updated SequenceFields to allow post processing of the calculated counter value (MongoEngine/mongoengine#141)
- Added clean method to documents for pre validation data cleaning (MongoEngine/mongoengine#60) - Added clean method to documents for pre validation data cleaning (MongoEngine/mongoengine#60)
- Added support setting for read prefrence at a query level (MongoEngine/mongoengine#157) - Added support setting for read prefrence at a query level (MongoEngine/mongoengine#157)
- Added _instance to EmbeddedDocuments pointing to the parent (MongoEngine/mongoengine#139) - Added _instance to EmbeddedDocuments pointing to the parent (MongoEngine/mongoengine#139)

View File

@ -57,6 +57,13 @@ you will need to declare :attr:`allow_inheritance` in the meta data like so:
meta = {'allow_inheritance': True} meta = {'allow_inheritance': True}
SequenceFields
--------------
:class:`~mongoengine.fields.SequenceField`s now inherit from `BaseField` to
allow flexible storage of the calculated value. As such MIN and MAX settings
are no longer handled.
0.6 to 0.7 0.6 to 0.7
========== ==========

View File

@ -1329,7 +1329,7 @@ class GeoPointField(BaseField):
self.error('Both values in point must be float or int') self.error('Both values in point must be float or int')
class SequenceField(IntField): class SequenceField(BaseField):
"""Provides a sequental counter see: """Provides a sequental counter see:
http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-SequenceNumbers http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-SequenceNumbers
@ -1341,15 +1341,26 @@ class SequenceField(IntField):
cluster of machines, it is easier to create an object ID than have cluster of machines, it is easier to create an object ID than have
global, uniformly increasing sequence numbers. global, uniformly increasing sequence numbers.
Use any callable as `value_decorator` to transform calculated counter into
any value suitable for your needs, e.g. string or hexadecimal
representation of the default integer counter value.
.. versionadded:: 0.5 .. versionadded:: 0.5
.. versionchanged:: 0.8 added `value_decorator`
""" """
_auto_gen = True _auto_gen = True
COLLECTION_NAME = 'mongoengine.counters'
VALUE_DECORATOR = int
def __init__(self, collection_name=None, db_alias=None, def __init__(self, collection_name=None, db_alias=None,
sequence_name=None, *args, **kwargs): sequence_name=None, value_decorator=None, *args, **kwargs):
self.collection_name = collection_name or 'mongoengine.counters' self.collection_name = collection_name or self.COLLECTION_NAME
self.db_alias = db_alias or DEFAULT_CONNECTION_NAME self.db_alias = db_alias or DEFAULT_CONNECTION_NAME
self.sequence_name = sequence_name self.sequence_name = sequence_name
self.value_decorator = (callable(value_decorator) and
value_decorator or self.VALUE_DECORATOR)
return super(SequenceField, self).__init__(*args, **kwargs) return super(SequenceField, self).__init__(*args, **kwargs)
def generate(self): def generate(self):
@ -1364,24 +1375,16 @@ class SequenceField(IntField):
update={"$inc": {"next": 1}}, update={"$inc": {"next": 1}},
new=True, new=True,
upsert=True) upsert=True)
return counter['next'] return self.value_decorator(counter['next'])
def __get__(self, instance, owner): def __get__(self, instance, owner):
value = super(SequenceField, self).__get__(instance, owner)
if instance is None: if value is None and instance._initialised:
return self
if not instance._data:
return
value = instance._data.get(self.name)
if not value and instance._initialised:
value = self.generate() value = self.generate()
instance._data[self.name] = value instance._data[self.name] = value
instance._mark_as_changed(self.name) instance._mark_as_changed(self.name)
return int(value) if value else None return value
def __set__(self, instance, value): def __set__(self, instance, value):

View File

@ -1,5 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import with_statement from __future__ import with_statement
import sys
sys.path[0:0] = [""]
import datetime import datetime
import os import os
import unittest import unittest
@ -2184,6 +2187,27 @@ class FieldTest(unittest.TestCase):
c = self.db['mongoengine.counters'].find_one({'_id': 'animal.id'}) c = self.db['mongoengine.counters'].find_one({'_id': 'animal.id'})
self.assertEqual(c['next'], 10) self.assertEqual(c['next'], 10)
def test_sequence_field_value_decorator(self):
class Person(Document):
id = SequenceField(primary_key=True, value_decorator=str)
name = StringField()
self.db['mongoengine.counters'].drop()
Person.drop_collection()
for x in xrange(10):
p = Person(name="Person %s" % x)
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]
self.assertEqual(ids, map(str, range(1, 11)))
c = self.db['mongoengine.counters'].find_one({'_id': 'person.id'})
self.assertEqual(c['next'], 10)
def test_generic_embedded_document(self): def test_generic_embedded_document(self):
class Car(EmbeddedDocument): class Car(EmbeddedDocument):
name = StringField() name = StringField()