Skip to content

Commit

Permalink
Merge pull request #12 from idlead/master
Browse files Browse the repository at this point in the history
Restructuring and EnumField
  • Loading branch information
rozza committed Jun 27, 2014
2 parents 9cf13ca + 141dfd1 commit 5e63e05
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 148 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.pyc
build/
venv/
3 changes: 3 additions & 0 deletions extras_mongoengine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import fields

__all__ = ('fields')
76 changes: 76 additions & 0 deletions extras_mongoengine/django_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import os
import datetime

from mongoengine.base import BaseField
from mongoengine.python_support import str_types

from django.db.models.fields.files import FieldFile
from django.core.files.base import File
from django.core.files.storage import default_storage

from django.utils.encoding import force_str, force_text


class LocalStorageFileField(BaseField):

proxy_class = FieldFile

def __init__(self,
size=None,
name=None,
upload_to='',
storage=None,
**kwargs):
self.size = size
self.storage = storage or default_storage
self.upload_to = upload_to
if callable(upload_to):
self.generate_filename = upload_to
super(LocalStorageFileField, self).__init__(**kwargs)

def __get__(self, instance, owner):
if instance is None:
return self

file = instance._data.get(self.name)

if isinstance(file, str_types) or file is None:
attr = self.proxy_class(instance, self, file)
instance._data[self.name] = attr

return instance._data[self.name]

def __set__(self, instance, value):
key = self.name
if isinstance(value, File) and not isinstance(value, FieldFile):
file = instance._data.get(self.name)
if file:
try:
file.delete()
except:
pass
# Create a new proxy object as we don't already have one
file_copy = self.proxy_class(instance, self, value.name)
file_copy.file = value
instance._data[key] = file_copy
else:
instance._data[key] = value

instance._mark_as_changed(key)

def get_directory_name(self):
return os.path.normpath(force_text(
datetime.datetime.now().strftime(force_str(self.upload_to))))

def get_filename(self, filename):
return os.path.normpath(
self.storage.get_valid_name(os.path.basename(filename)))

def generate_filename(self, instance, filename):
return os.path.join(
self.get_directory_name(), self.get_filename(filename))

def to_mongo(self, value):
if isinstance(value, self.proxy_class):
return value.name
return value
111 changes: 111 additions & 0 deletions extras_mongoengine/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from datetime import timedelta
from mongoengine.base import BaseField
from mongoengine.fields import IntField, StringField, EmailField


class TimedeltaField(BaseField):
"""A timedelta field.
Looks to the outside world like a datatime.timedelta, but stores
in the database as an integer (or float) number of seconds.
"""
def validate(self, value):
if not isinstance(value, (timedelta, int, float)):
self.error(u'cannot parse timedelta "%r"' % value)

def to_mongo(self, value):
return self.prepare_query_value(None, value)

def to_python(self, value):
return timedelta(seconds=value)

def prepare_query_value(self, op, value):
if value is None:
return value
if isinstance(value, timedelta):
return self.total_seconds(value)
if isinstance(value, (int, float)):
return value

@staticmethod
def total_seconds(value):
"""Implements Python 2.7's datetime.timedelta.total_seconds()
for backwards compatibility with Python 2.5 and 2.6.
"""
try:
return value.total_seconds()
except AttributeError:
return (value.days * 24 * 3600) + \
(value.seconds) + \
(value.microseconds / 1000000.0)


class LowerStringField(StringField):
def __set__(self, instance, value):
value = self.to_python(value)
return super(LowerStringField, self).__set__(instance, value)

def to_python(self, value):
if value:
value = value.lower()
return value

def prepare_query_value(self, op, value):
value = value.lower() if value else value
return super(LowerStringField, self).prepare_query_value(op, value)


class LowerEmailField(LowerStringField):

def validate(self, value):
if not EmailField.EMAIL_REGEX.match(value):
self.error('Invalid Mail-address: %s' % value)
super(LowerEmailField, self).validate(value)


class EnumField(object):
"""
A class to register Enum type (from the package enum34) into mongo
:param choices: must be of :class:`enum.Enum`: type
and will be used as possible choices
"""

def __init__(self, enum, *args, **kwargs):
self.enum = enum
kwargs['choices'] = [choice for choice in enum]
super(EnumField, self).__init__(*args, **kwargs)

def __get_value(self, enum):
return enum.value if hasattr(enum, 'value') else enum

def to_python(self, value):
return self.enum(super(EnumField, self).to_python(value))

def to_mongo(self, value):
return self.__get_value(value)

def prepare_query_value(self, op, value):
return super(EnumField, self).prepare_query_value(
op, self.__get_value(value))

def validate(self, value):
return super(EnumField, self).validate(self.__get_value(value))

def _validate(self, value, **kwargs):
return super(EnumField, self)._validate(
self.enum(self.__get_value(value)), **kwargs)


class IntEnumField(EnumField, IntField):
"""A variation on :class:`EnumField` for only int containing enumeration.
"""
pass


class StringEnumField(EnumField, StringField):
"""A variation on :class:`EnumField` for only string containing enumeration.
"""
pass
139 changes: 0 additions & 139 deletions fields/fields.py

This file was deleted.

1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
unittest2
django
mongoengine
10 changes: 10 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python
from distutils.core import setup

setup(name='extras_mongoengine',
version='0.1',
description='MongoEngine Extras - Field Types and any other wizardry.',
url='https://github.com/MongoEngine/extras-mongoengine/',
install_requires=['mongoengine>=0.8.6'],
packages=['extras_mongoengine'],
)
Empty file added tests/__init__.py
Empty file.
Loading

0 comments on commit 5e63e05

Please sign in to comment.