Merge remote-tracking branch 'origin/pr/285' into p285
This commit is contained in:
commit
10731b0fd8
15
.travis.yml
15
.travis.yml
@ -7,12 +7,21 @@ python:
|
|||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
env:
|
env:
|
||||||
- PYMONGO=dev
|
- PYMONGO=dev DJANGO=1.5.1
|
||||||
- PYMONGO=2.5
|
- PYMONGO=dev DJANGO=1.4.2
|
||||||
- PYMONGO=2.4.2
|
- PYMONGO=2.5 DJANGO=1.5.1
|
||||||
|
- PYMONGO=2.5 DJANGO=1.4.2
|
||||||
|
- PYMONGO=2.4.2 DJANGO=1.4.2
|
||||||
|
matrix:
|
||||||
|
exclude:
|
||||||
|
- python: "2.6"
|
||||||
|
env: PYMONGO=dev DJANGO=1.5.1
|
||||||
|
- python: "2.6"
|
||||||
|
env: PYMONGO=2.5 DJANGO=1.5.1
|
||||||
install:
|
install:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then cp /usr/lib/*/libz.so $VIRTUAL_ENV/lib/; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then cp /usr/lib/*/libz.so $VIRTUAL_ENV/lib/; fi
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install pil --use-mirrors ; true; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install pil --use-mirrors ; true; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install django==$DJANGO --use-mirrors ; true; fi
|
||||||
- if [[ $PYMONGO == 'dev' ]]; then pip install https://github.com/mongodb/mongo-python-driver/tarball/master; true; fi
|
- if [[ $PYMONGO == 'dev' ]]; then pip install https://github.com/mongodb/mongo-python-driver/tarball/master; true; fi
|
||||||
- if [[ $PYMONGO != 'dev' ]]; then pip install pymongo==$PYMONGO --use-mirrors; true; fi
|
- if [[ $PYMONGO != 'dev' ]]; then pip install pymongo==$PYMONGO --use-mirrors; true; fi
|
||||||
- python setup.py install
|
- python setup.py install
|
||||||
|
@ -42,6 +42,42 @@ The :mod:`~mongoengine.django.auth` module also contains a
|
|||||||
|
|
||||||
.. versionadded:: 0.1.3
|
.. versionadded:: 0.1.3
|
||||||
|
|
||||||
|
Custom User model
|
||||||
|
=================
|
||||||
|
Django 1.5 introduced `Custom user Models
|
||||||
|
<https://docs.djangoproject.com/en/dev/topics/auth/customizing/#auth-custom-user>`
|
||||||
|
which can be used as an alternative the Mongoengine authentication backend.
|
||||||
|
|
||||||
|
The main advantage of this option is that other components relying on
|
||||||
|
:mod:`django.contrib.auth` and supporting the new swappable user model are more
|
||||||
|
likely to work. For example, you can use the ``createsuperuser`` management
|
||||||
|
command as usual.
|
||||||
|
|
||||||
|
To enable the custom User model in Django, add ``'mongoengine.django.mongo_auth'``
|
||||||
|
in your ``INSTALLED_APPS`` and set ``'mongo_auth.MongoUser'`` as the custom user
|
||||||
|
user model to use. In your **settings.py** file you will have::
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
...
|
||||||
|
'django.contrib.auth',
|
||||||
|
'mongoengine.django.mongo_auth',
|
||||||
|
...
|
||||||
|
)
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = 'mongo_auth.MongoUser'
|
||||||
|
|
||||||
|
An additional ``MONGOENGINE_USER_DOCUMENT`` setting enables you to replace the
|
||||||
|
:class:`~mongoengine.django.auth.User` class with another class of your choice::
|
||||||
|
|
||||||
|
MONGOENGINE_USER_DOCUMENT = 'mongoengine.django.auth.User'
|
||||||
|
|
||||||
|
The custom :class:`User` must be a :class:`~mongoengine.Document` class, but
|
||||||
|
otherwise has the same requirements as a standard custom user model,
|
||||||
|
as specified in the `Django Documentation
|
||||||
|
<https://docs.djangoproject.com/en/dev/topics/auth/customizing/>`.
|
||||||
|
In particular, the custom class must define :attr:`USERNAME_FIELD` and
|
||||||
|
:attr:`REQUIRED_FIELDS` attributes.
|
||||||
|
|
||||||
Sessions
|
Sessions
|
||||||
========
|
========
|
||||||
Django allows the use of different backend stores for its sessions. MongoEngine
|
Django allows the use of different backend stores for its sessions. MongoEngine
|
||||||
|
@ -108,7 +108,7 @@ class Permission(Document):
|
|||||||
created for each Django model.
|
created for each Django model.
|
||||||
"""
|
"""
|
||||||
name = StringField(max_length=50, verbose_name=_('username'))
|
name = StringField(max_length=50, verbose_name=_('username'))
|
||||||
content_type = ReferenceField(ContentType)
|
content_type = ReferenceField(ContentType, dbref=True)
|
||||||
codename = StringField(max_length=100, verbose_name=_('codename'))
|
codename = StringField(max_length=100, verbose_name=_('codename'))
|
||||||
# FIXME: don't access field of the other class
|
# FIXME: don't access field of the other class
|
||||||
# unique_with=['content_type__app_label', 'content_type__model'])
|
# unique_with=['content_type__app_label', 'content_type__model'])
|
||||||
@ -150,7 +150,7 @@ class Group(Document):
|
|||||||
"""
|
"""
|
||||||
name = StringField(max_length=80, unique=True, verbose_name=_('name'))
|
name = StringField(max_length=80, unique=True, verbose_name=_('name'))
|
||||||
# permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
|
# permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
|
||||||
permissions = ListField(ReferenceField(Permission, verbose_name=_('permissions'), required=False))
|
permissions = ListField(ReferenceField(Permission, verbose_name=_('permissions'), required=False, dbref=True))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('group')
|
verbose_name = _('group')
|
||||||
@ -231,6 +231,9 @@ class User(Document):
|
|||||||
date_joined = DateTimeField(default=datetime_now,
|
date_joined = DateTimeField(default=datetime_now,
|
||||||
verbose_name=_('date joined'))
|
verbose_name=_('date joined'))
|
||||||
|
|
||||||
|
USERNAME_FIELD = 'username'
|
||||||
|
REQUIRED_FIELDS = ['email']
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
'allow_inheritance': True,
|
'allow_inheritance': True,
|
||||||
'indexes': [
|
'indexes': [
|
||||||
|
0
mongoengine/django/mongo_auth/__init__.py
Normal file
0
mongoengine/django/mongo_auth/__init__.py
Normal file
90
mongoengine/django/mongo_auth/models.py
Normal file
90
mongoengine/django/mongo_auth/models.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth.models import UserManager
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
MONGOENGINE_USER_DOCUMENT = getattr(
|
||||||
|
settings, 'MONGOENGINE_USER_DOCUMENT', 'mongoengine.django.auth.User')
|
||||||
|
|
||||||
|
|
||||||
|
class MongoUserManager(UserManager):
|
||||||
|
"""A User manager wich allows the use of MongoEngine documents in Django.
|
||||||
|
|
||||||
|
To use the manager, you must tell django.contrib.auth to use MongoUser as
|
||||||
|
the user model. In you settings.py, you need:
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
...
|
||||||
|
'django.contrib.auth',
|
||||||
|
'mongoengine.django.mongo_auth',
|
||||||
|
...
|
||||||
|
)
|
||||||
|
AUTH_USER_MODEL = 'mongo_auth.MongoUser'
|
||||||
|
|
||||||
|
Django will use the model object to access the custom Manager, which will
|
||||||
|
replace the original queryset with MongoEngine querysets.
|
||||||
|
|
||||||
|
By default, mongoengine.django.auth.User will be used to store users. You
|
||||||
|
can specify another document class in MONGOENGINE_USER_DOCUMENT in your
|
||||||
|
settings.py.
|
||||||
|
|
||||||
|
The User Document class has the same requirements as a standard custom user
|
||||||
|
model: https://docs.djangoproject.com/en/dev/topics/auth/customizing/
|
||||||
|
|
||||||
|
In particular, the User Document class must define USERNAME_FIELD and
|
||||||
|
REQUIRED_FIELDS.
|
||||||
|
|
||||||
|
`AUTH_USER_MODEL` has been added in Django 1.5.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def contribute_to_class(self, model, name):
|
||||||
|
super(MongoUserManager, self).contribute_to_class(model, name)
|
||||||
|
self.dj_model = self.model
|
||||||
|
self.model = self._get_user_document()
|
||||||
|
|
||||||
|
self.dj_model.USERNAME_FIELD = self.model.USERNAME_FIELD
|
||||||
|
username = models.CharField(_('username'), max_length=30, unique=True)
|
||||||
|
username.contribute_to_class(self.dj_model, self.dj_model.USERNAME_FIELD)
|
||||||
|
|
||||||
|
self.dj_model.REQUIRED_FIELDS = self.model.REQUIRED_FIELDS
|
||||||
|
for name in self.dj_model.REQUIRED_FIELDS:
|
||||||
|
field = models.CharField(_(name), max_length=30)
|
||||||
|
field.contribute_to_class(self.dj_model, name)
|
||||||
|
|
||||||
|
def _get_user_document(self):
|
||||||
|
try:
|
||||||
|
name = MONGOENGINE_USER_DOCUMENT
|
||||||
|
dot = name.rindex('.')
|
||||||
|
module = import_module(name[:dot])
|
||||||
|
return getattr(module, name[dot + 1:])
|
||||||
|
except ImportError:
|
||||||
|
raise ImproperlyConfigured("Error importing %s, please check "
|
||||||
|
"settings.MONGOENGINE_USER_DOCUMENT"
|
||||||
|
% name)
|
||||||
|
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return self.get_query_set().get(*args, **kwargs)
|
||||||
|
except self.model.DoesNotExist:
|
||||||
|
# ModelBackend expects this exception
|
||||||
|
raise self.dj_model.DoesNotExist
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_empty_query_set(self):
|
||||||
|
return self.model.objects.none()
|
||||||
|
|
||||||
|
def get_query_set(self):
|
||||||
|
return self.model.objects
|
||||||
|
|
||||||
|
|
||||||
|
class MongoUser(models.Model):
|
||||||
|
objects = MongoUserManager()
|
||||||
|
|
2
setup.py
2
setup.py
@ -57,7 +57,7 @@ if sys.version_info[0] == 3:
|
|||||||
extra_opts['packages'].append("tests")
|
extra_opts['packages'].append("tests")
|
||||||
extra_opts['package_data'] = {"tests": ["fields/mongoengine.png", "fields/mongodb_leaf.png"]}
|
extra_opts['package_data'] = {"tests": ["fields/mongoengine.png", "fields/mongodb_leaf.png"]}
|
||||||
else:
|
else:
|
||||||
extra_opts['tests_require'] = ['nose', 'coverage', 'blinker', 'django==1.4.2', 'PIL']
|
extra_opts['tests_require'] = ['nose', 'coverage', 'blinker', 'django>=1.4.2', 'PIL']
|
||||||
extra_opts['packages'] = find_packages(exclude=('tests',))
|
extra_opts['packages'] = find_packages(exclude=('tests',))
|
||||||
|
|
||||||
setup(name='mongoengine',
|
setup(name='mongoengine',
|
||||||
|
@ -14,8 +14,19 @@ try:
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
|
|
||||||
settings.configure(USE_TZ=True)
|
settings.configure(
|
||||||
|
USE_TZ=True,
|
||||||
|
INSTALLED_APPS=('django.contrib.auth', 'mongoengine.django.mongo_auth'),
|
||||||
|
AUTH_USER_MODEL=('mongo_auth.MongoUser'),
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.contrib.auth import authenticate, get_user_model
|
||||||
|
from mongoengine.django.auth import User
|
||||||
|
from mongoengine.django.mongo_auth.models import MongoUser, MongoUserManager
|
||||||
|
DJ15 = True
|
||||||
|
except Exception:
|
||||||
|
DJ15 = False
|
||||||
from django.contrib.sessions.tests import SessionTestsMixin
|
from django.contrib.sessions.tests import SessionTestsMixin
|
||||||
from mongoengine.django.sessions import SessionStore, MongoSession
|
from mongoengine.django.sessions import SessionStore, MongoSession
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
@ -156,6 +167,7 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
rendered = template.render(Context({'users': users}))
|
rendered = template.render(Context({'users': users}))
|
||||||
self.assertEqual(rendered, 'AB ABCD CD')
|
self.assertEqual(rendered, 'AB ABCD CD')
|
||||||
|
|
||||||
|
|
||||||
class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase):
|
class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase):
|
||||||
backend = SessionStore
|
backend = SessionStore
|
||||||
|
|
||||||
@ -184,5 +196,49 @@ class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase):
|
|||||||
session = SessionStore(key)
|
session = SessionStore(key)
|
||||||
self.assertTrue('test_expire' in session, 'Session has expired before it is expected')
|
self.assertTrue('test_expire' in session, 'Session has expired before it is expected')
|
||||||
|
|
||||||
|
|
||||||
|
class MongoAuthTest(unittest.TestCase):
|
||||||
|
user_data = {
|
||||||
|
'username': 'user',
|
||||||
|
'email': 'user@example.com',
|
||||||
|
'password': 'test',
|
||||||
|
}
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
if PY3:
|
||||||
|
raise SkipTest('django does not have Python 3 support')
|
||||||
|
if not DJ15:
|
||||||
|
raise SkipTest('mongo_auth requires Django 1.5')
|
||||||
|
connect(db='mongoenginetest')
|
||||||
|
User.drop_collection()
|
||||||
|
super(MongoAuthTest, self).setUp()
|
||||||
|
|
||||||
|
def test_user_model(self):
|
||||||
|
self.assertEqual(get_user_model(), MongoUser)
|
||||||
|
|
||||||
|
def test_user_manager(self):
|
||||||
|
manager = get_user_model()._default_manager
|
||||||
|
self.assertIsInstance(manager, MongoUserManager)
|
||||||
|
|
||||||
|
def test_user_manager_exception(self):
|
||||||
|
manager = get_user_model()._default_manager
|
||||||
|
self.assertRaises(MongoUser.DoesNotExist, manager.get,
|
||||||
|
username='not found')
|
||||||
|
|
||||||
|
def test_create_user(self):
|
||||||
|
manager = get_user_model()._default_manager
|
||||||
|
user = manager.create_user(**self.user_data)
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
db_user = User.objects.get(username='user')
|
||||||
|
self.assertEqual(user.id, db_user.id)
|
||||||
|
|
||||||
|
def test_authenticate(self):
|
||||||
|
get_user_model()._default_manager.create_user(**self.user_data)
|
||||||
|
user = authenticate(username='user', password='fail')
|
||||||
|
self.assertIsNone(user)
|
||||||
|
user = authenticate(username='user', password='test')
|
||||||
|
db_user = User.objects.get(username='user')
|
||||||
|
self.assertEqual(user.id, db_user.id)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user