Compare commits

...

27 Commits

Author SHA1 Message Date
Ross Lawley
2a34358abc Updated connection refs #474 2012-03-27 01:47:17 +01:00
Ross Lawley
fd2bb8ea45 Merge pull request #474 from samuelclay/patch-1
The port is defaulted in to conn_settings, so discard the port since hos...
2012-03-26 17:17:26 -07:00
Ross Lawley
98e5daa0e0 Added mostlystatic to the AUTHORS 2012-03-27 00:49:34 +01:00
Samuel Clay
ad2e119282 The port is defaulted in to conn_settings, so discard the port since hosts_or_uri must be used. 2012-03-26 16:48:37 -07:00
Ross Lawley
c20c30d8d1 Merge pull request #471 from mostlystatic/master
Simple fix to unknown connection alias error message
2012-03-26 16:47:46 -07:00
mostlystatic
66d215c9c1 Fix for unknown connection alias error message. 2012-03-24 20:01:40 +00:00
Ross Lawley
bbdd15161a 0.6.3 release 2012-03-24 19:06:08 +00:00
Ross Lawley
ea9dc8cfb8 Merge branch 'master' of github.com:hmarr/mongoengine 2012-03-24 19:03:44 +00:00
Ross Lawley
6bd2ccc9bf UPdated authors 2012-03-24 19:03:24 +00:00
Ross Lawley
56327c6b58 Merge pull request #470 from arbaal/master
Patches for Django 1.4 compability
2012-03-24 12:02:44 -07:00
Nils Hasenbanck
712e8a51e4 Merge branch 'master' of github.com:arbaal/mongoengine
Conflicts:
	mongoengine/django/sessions.py

Signed-off-by: Nils Hasenbanck <nils@hasenbanck.de>
2012-03-24 19:49:02 +01:00
Nils Hasenbanck
421f324f9e Fixed the exception when saving a new session
The session was not created for some reason. Now it is.

Signed-off-by: Nils Hasenbanck <nils@hasenbanck.de>
2012-03-24 19:43:01 +01:00
Nils Hasenbanck
8fe4a70299 Fixed the exception when saving a new session
Signed-off-by: Nils Hasenbanck <nils@hasenbanck.de>
2012-03-24 19:24:42 +01:00
Nils Hasenbanck
3af6d0dbfd Replaces deprecated hasher with new django 1.4 hasher
This way we can even use the new hasher configuration
django 1.4 provides.

Signed-off-by: Nils Hasenbanck <nils@hasenbanck.de>
2012-03-24 11:08:00 +01:00
Nils Hasenbanck
e2bef076d3 Fixed the session backend for django 1.4
Signed-off-by: Nils Hasenbanck <nils@hasenbanck.de>
2012-03-24 11:07:37 +01:00
Ross Lawley
f1e7b97a93 Updated changelog 2012-03-22 15:48:54 +00:00
Ross Lawley
0f420abc8e Added test for listfields containing embedded documents
Added Adam to the authors - thanks for the patch
fixes #466
2012-03-22 15:44:22 +00:00
Ross Lawley
3b5b715567 Merge branch 'dev' of https://github.com/aparrish/mongoengine into 466 2012-03-22 15:32:45 +00:00
Adam Parrish
520051af25 preparing values in a ListField won't mangle embedded documents any more 2012-03-21 11:03:49 -07:00
Ross Lawley
fd18a48608 Rst fix 2012-03-15 16:36:04 +00:00
Ross Lawley
64860c6287 Fix signals documentation 2012-03-15 16:27:31 +00:00
Ross Lawley
58635b24ba Updated changelog 2012-03-12 10:35:02 +00:00
Ross Lawley
bd1572f11a Fixed upgrade docs and instructions 2012-03-12 10:31:51 +00:00
Ross Lawley
65591c7727 Version Bump 2012-03-08 12:40:07 +00:00
Ross Lawley
61411bb259 Doc updates 2012-03-05 12:26:44 +00:00
Ross Lawley
fcdb0eff8f Added for read the docs 2012-03-05 12:21:53 +00:00
Ross Lawley
30d9347272 Updated readme 2012-03-05 12:20:59 +00:00
15 changed files with 89 additions and 44 deletions

View File

@@ -98,3 +98,5 @@ that much better:
* Chris Williams * Chris Williams
* Robert Kajic * Robert Kajic
* Jacob Peddicord * Jacob Peddicord
* Nils Hasenbanck
* mostlystatic

View File

@@ -2,6 +2,18 @@
Changelog Changelog
========= =========
Changes in 0.6.X
================
- updated replicasetconnection - pop port if exists
- bug fix for unknown connection alias error message
Changes in 0.6.3
================
- Updated sessions for Django 1.4
- Bug fix for updates where listfields contain embedded documents
- Bug fix for collection naming and mixins
Changes in 0.6.2 Changes in 0.6.2
================ ================
- Updated documentation for ReplicaSet connections - Updated documentation for ReplicaSet connections

View File

@@ -2,6 +2,8 @@
Using MongoEngine with Django Using MongoEngine with Django
============================= =============================
.. note :: Updated to support Django 1.4
Connecting Connecting
========== ==========
In your **settings.py** file, ignore the standard database settings (unless you In your **settings.py** file, ignore the standard database settings (unless you

View File

@@ -5,15 +5,13 @@ Signals
.. versionadded:: 0.5 .. versionadded:: 0.5
.. note::
Signal support is provided by the excellent `blinker`_ library and Signal support is provided by the excellent `blinker`_ library and
will gracefully fall back if it is not available. will gracefully fall back if it is not available.
<<<<<<< HEAD
The following document signals exist in MongoEngine and are pretty self explanatory:
=======
The following document signals exist in MongoEngine and are pretty self-explanatory: The following document signals exist in MongoEngine and are pretty self-explanatory:
>>>>>>> master
* `mongoengine.signals.pre_init` * `mongoengine.signals.pre_init`
* `mongoengine.signals.post_init` * `mongoengine.signals.post_init`

View File

@@ -76,7 +76,7 @@ To upgrade use a Mixin class to set meta like so ::
class MyAceDocument(Document, BaseMixin): class MyAceDocument(Document, BaseMixin):
pass pass
MyAceDocument._get_collection_name() == myacedocument MyAceDocument._get_collection_name() == "myacedocument"
Alternatively, you can rename your collections eg :: Alternatively, you can rename your collections eg ::

View File

@@ -12,7 +12,7 @@ from signals import *
__all__ = (document.__all__ + fields.__all__ + connection.__all__ + __all__ = (document.__all__ + fields.__all__ + connection.__all__ +
queryset.__all__ + signals.__all__) queryset.__all__ + signals.__all__)
VERSION = (0, 6, 1) VERSION = (0, 6, 3)
def get_version(): def get_version():

View File

@@ -478,13 +478,18 @@ class DocumentMetaclass(type):
attrs.update(dict([(k, v) for k, v in base.__dict__.items() attrs.update(dict([(k, v) for k, v in base.__dict__.items()
if issubclass(v.__class__, BaseField)])) if issubclass(v.__class__, BaseField)]))
# Handle simple mixin's with meta
if hasattr(base, 'meta') and not isinstance(base, DocumentMetaclass):
meta = attrs.get('meta', {})
meta.update(base.meta)
attrs['meta'] = meta
for p_base in base.__bases__: for p_base in base.__bases__:
#optimize :-) #optimize :-)
if p_base in (object, BaseDocument): if p_base in (object, BaseDocument):
continue continue
attrs.update(_get_mixin_fields(p_base)) attrs.update(_get_mixin_fields(p_base))
return attrs return attrs
metaclass = attrs.get('__metaclass__') metaclass = attrs.get('__metaclass__')
@@ -498,6 +503,7 @@ class DocumentMetaclass(type):
simple_class = True simple_class = True
for base in bases: for base in bases:
# Include all fields present in superclasses # Include all fields present in superclasses
if hasattr(base, '_fields'): if hasattr(base, '_fields'):
doc_fields.update(base._fields) doc_fields.update(base._fields)
@@ -526,7 +532,8 @@ class DocumentMetaclass(type):
simple_class = False simple_class = False
doc_class_name = '.'.join(reversed(class_name)) doc_class_name = '.'.join(reversed(class_name))
meta = attrs.get('_meta', attrs.get('meta', {})) meta = attrs.get('_meta', {})
meta.update(attrs.get('meta', {}))
if 'allow_inheritance' not in meta: if 'allow_inheritance' not in meta:
meta['allow_inheritance'] = True meta['allow_inheritance'] = True

View File

@@ -86,7 +86,7 @@ def get_connection(alias=DEFAULT_CONNECTION_NAME, reconnect=False):
if alias not in _connections: if alias not in _connections:
if alias not in _connection_settings: if alias not in _connection_settings:
msg = 'Connection with alias "%s" has not been defined' msg = 'Connection with alias "%s" has not been defined' % alias
if alias == DEFAULT_CONNECTION_NAME: if alias == DEFAULT_CONNECTION_NAME:
msg = 'You have not defined a default connection' msg = 'You have not defined a default connection'
raise ConnectionError(msg) raise ConnectionError(msg)
@@ -105,11 +105,13 @@ def get_connection(alias=DEFAULT_CONNECTION_NAME, reconnect=False):
for slave_alias in conn_settings['slaves']: for slave_alias in conn_settings['slaves']:
slaves.append(get_connection(slave_alias)) slaves.append(get_connection(slave_alias))
conn_settings['slaves'] = slaves conn_settings['slaves'] = slaves
conn_settings.pop('read_preference') conn_settings.pop('read_preference', None)
connection_class = Connection connection_class = Connection
if 'replicaSet' in conn_settings: if 'replicaSet' in conn_settings:
conn_settings['hosts_or_uri'] = conn_settings.pop('host', None) conn_settings['hosts_or_uri'] = conn_settings.pop('host', None)
# Discard port since it can't be used on ReplicaSetConnection
conn_settings.pop('port', None)
connection_class = ReplicaSetConnection connection_class = ReplicaSetConnection
try: try:
_connections[alias] = connection_class(**conn_settings) _connections[alias] = connection_class(**conn_settings)

View File

@@ -1,23 +1,14 @@
from mongoengine import * from mongoengine import *
from django.utils.hashcompat import md5_constructor, sha_constructor
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.hashers import check_password, make_password
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import datetime import datetime
REDIRECT_FIELD_NAME = 'next' REDIRECT_FIELD_NAME = 'next'
def get_hexdigest(algorithm, salt, raw_password):
raw_password, salt = smart_str(raw_password), smart_str(salt)
if algorithm == 'md5':
return md5_constructor(salt + raw_password).hexdigest()
elif algorithm == 'sha1':
return sha_constructor(salt + raw_password).hexdigest()
raise ValueError('Got unknown password algorithm type in password')
class User(Document): class User(Document):
"""A User document that aims to mirror most of the API specified by Django """A User document that aims to mirror most of the API specified by Django
at http://docs.djangoproject.com/en/dev/topics/auth/#users at http://docs.djangoproject.com/en/dev/topics/auth/#users
@@ -34,7 +25,7 @@ class User(Document):
email = EmailField(verbose_name=_('e-mail address')) email = EmailField(verbose_name=_('e-mail address'))
password = StringField(max_length=128, password = StringField(max_length=128,
verbose_name=_('password'), verbose_name=_('password'),
help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>.")) help_text=_("Use '[algo]$[iterations]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
is_staff = BooleanField(default=False, is_staff = BooleanField(default=False,
verbose_name=_('staff status'), verbose_name=_('staff status'),
help_text=_("Designates whether the user can log into this admin site.")) help_text=_("Designates whether the user can log into this admin site."))
@@ -75,11 +66,7 @@ class User(Document):
assigning to :attr:`~mongoengine.django.auth.User.password` as the assigning to :attr:`~mongoengine.django.auth.User.password` as the
password is hashed before storage. password is hashed before storage.
""" """
from random import random self.password = make_password(raw_password)
algo = 'sha1'
salt = get_hexdigest(algo, str(random()), str(random()))[:5]
hash = get_hexdigest(algo, salt, raw_password)
self.password = '%s$%s$%s' % (algo, salt, hash)
self.save() self.save()
return self return self
@@ -89,8 +76,7 @@ class User(Document):
:attr:`~mongoengine.django.auth.User.password` as the password is :attr:`~mongoengine.django.auth.User.password` as the password is
hashed before storage. hashed before storage.
""" """
algo, salt, hash = self.password.split('$') return check_password(raw_password, self.password)
return hash == get_hexdigest(algo, salt, raw_password)
@classmethod @classmethod
def create_user(cls, username, password, email=None): def create_user(cls, username, password, email=None):

View File

@@ -41,7 +41,7 @@ class SessionStore(SessionBase):
def create(self): def create(self):
while True: while True:
self.session_key = self._get_new_session_key() self._session_key = self._get_new_session_key()
try: try:
self.save(must_create=True) self.save(must_create=True)
except CreateError: except CreateError:
@@ -51,7 +51,9 @@ class SessionStore(SessionBase):
return return
def save(self, must_create=False): def save(self, must_create=False):
s = MongoSession(session_key=self.session_key) if self._session_key is None:
self.create()
s = MongoSession(session_key=self._session_key)
s.session_data = self.encode(self._get_session(no_load=must_create)) s.session_data = self.encode(self._get_session(no_load=must_create))
s.expire_date = self.get_expiry_date() s.expire_date = self.get_expiry_date()
try: try:

View File

@@ -8,7 +8,7 @@ import uuid
from bson import Binary, DBRef, SON, ObjectId from bson import Binary, DBRef, SON, ObjectId
from base import (BaseField, ComplexBaseField, ObjectIdField, from base import (BaseField, ComplexBaseField, ObjectIdField,
ValidationError, get_document) ValidationError, get_document, BaseDocument)
from queryset import DO_NOTHING, QuerySet from queryset import DO_NOTHING, QuerySet
from document import Document, EmbeddedDocument from document import Document, EmbeddedDocument
from connection import get_db, DEFAULT_CONNECTION_NAME from connection import get_db, DEFAULT_CONNECTION_NAME
@@ -497,6 +497,7 @@ class ListField(ComplexBaseField):
def prepare_query_value(self, op, value): def prepare_query_value(self, op, value):
if self.field: if self.field:
if op in ('set', 'unset') and (not isinstance(value, basestring) if op in ('set', 'unset') and (not isinstance(value, basestring)
and not isinstance(value, BaseDocument)
and hasattr(value, '__iter__')): and hasattr(value, '__iter__')):
return [self.field.prepare_query_value(op, v) for v in value] return [self.field.prepare_query_value(op, v) for v in value]
return self.field.prepare_query_value(op, value) return self.field.prepare_query_value(op, value)

View File

@@ -5,7 +5,7 @@
%define srcname mongoengine %define srcname mongoengine
Name: python-%{srcname} Name: python-%{srcname}
Version: 0.6.2 Version: 0.6.3
Release: 1%{?dist} Release: 1%{?dist}
Summary: A Python Document-Object Mapper for working with MongoDB Summary: A Python Document-Object Mapper for working with MongoDB

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
pymongo

View File

@@ -96,7 +96,7 @@ class DocumentTest(unittest.TestCase):
# Ensure Document isn't treated like an actual document # Ensure Document isn't treated like an actual document
self.assertFalse(hasattr(Document, '_fields')) self.assertFalse(hasattr(Document, '_fields'))
def test_collection_name(self): def test_collection_naming(self):
"""Ensure that a collection with a specified name may be used. """Ensure that a collection with a specified name may be used.
""" """
@@ -157,11 +157,12 @@ class DocumentTest(unittest.TestCase):
} }
class BaseDocument(Document, BaseMixin): class BaseDocument(Document, BaseMixin):
pass meta = {'allow_inheritance': True}
class MyDocument(BaseDocument): class MyDocument(BaseDocument):
pass pass
self.assertEquals('mydocument', OldMixinNamingConvention._get_collection_name())
self.assertEquals('basedocument', MyDocument._get_collection_name())
def test_get_superclasses(self): def test_get_superclasses(self):
"""Ensure that the correct list of superclasses is assembled. """Ensure that the correct list of superclasses is assembled.

View File

@@ -1518,6 +1518,37 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
def test_set_list_embedded_documents(self):
class Author(EmbeddedDocument):
name = StringField()
class Message(Document):
title = StringField()
authors = ListField(EmbeddedDocumentField('Author'))
Message.drop_collection()
message = Message(title="hello", authors=[Author(name="Harry")])
message.save()
Message.objects(authors__name="Harry").update_one(
set__authors__S=Author(name="Ross"))
message = message.reload()
self.assertEquals(message.authors[0].name, "Ross")
Message.objects(authors__name="Ross").update_one(
set__authors=[Author(name="Harry"),
Author(name="Ross"),
Author(name="Adam")])
message = message.reload()
self.assertEquals(message.authors[0].name, "Harry")
self.assertEquals(message.authors[1].name, "Ross")
self.assertEquals(message.authors[2].name, "Adam")
def test_order_by(self): def test_order_by(self):
"""Ensure that QuerySets may be ordered. """Ensure that QuerySets may be ordered.
""" """