diff --git a/ox/django/api/actions.py b/ox/django/api/actions.py index 54c5ee3..8579080 100644 --- a/ox/django/api/actions.py +++ b/ox/django/api/actions.py @@ -11,7 +11,7 @@ from ...utils import json def autodiscover(): # Register api actions from all installed apps - from django.utils.importlib import import_module + from importlib import import_module from django.utils.module_loading import module_has_submodule for app in settings.INSTALLED_APPS: if app != 'api': diff --git a/ox/django/api/urls.py b/ox/django/api/urls.py index 460da84..5346a98 100644 --- a/ox/django/api/urls.py +++ b/ox/django/api/urls.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from django.conf.urls import patterns +from django.conf.urls import url import views import actions actions.autodiscover() -urlpatterns = patterns("", - (r'^$', views.api), -) +urlpatterns = [ + url(r'^$', views.api), +] diff --git a/ox/django/decorators.py b/ox/django/decorators.py index 84e5faf..98aa9dd 100644 --- a/ox/django/decorators.py +++ b/ox/django/decorators.py @@ -26,7 +26,7 @@ def admin_required_json(function=None): """ def _wrapped_view(request, *args, **kwargs): - if request.user.is_authenticated() and request.user.get_profile().get_level() == 'admin': + if request.user.is_authenticated() and request.user.profile.get_level() == 'admin': return function(request, *args, **kwargs) return render_to_json_response({'status': {'code': 403, 'text': 'permission denied'}}) return wraps(function)(_wrapped_view) diff --git a/ox/django/fields.py b/ox/django/fields.py index 83e11f0..9270468 100644 --- a/ox/django/fields.py +++ b/ox/django/fields.py @@ -2,6 +2,7 @@ # vi:si:et:sw=4:sts=4:ts=4 import time import datetime +import copy from django.db import models from django.utils import datetime_safe @@ -45,20 +46,15 @@ def from_json(json_object): return json_object class DictField(models.TextField): - """DictField is a textfield that contains JSON-serialized dictionaries.""" - - # Used so to_python() is called - __metaclass__ = models.SubfieldBase _type = dict def loads(self, value): return json.loads(value, object_hook=from_json) def dumps(self, obj): - return json.dumps(obj, default=to_json) + return json.dumps(obj, default=to_json, ensure_ascii=False) - def to_python(self, value): - # django 1.7 + def from_db_value(self, value, expression, connection, context): if value is None: return value if isinstance(value, self._type): @@ -71,10 +67,6 @@ class DictField(models.TextField): assert isinstance(value, self._type) return value - def from_db_value(self, value, expression, connection, context): - # django 1.8 - return self.to_python(value) - def get_prep_value(self, value): if isinstance(value, self._type): value = self.dumps(value) @@ -83,9 +75,15 @@ class DictField(models.TextField): value = models.TextField.get_prep_value(self, value) return value + def get_default(self): + if self.has_default(): + if callable(self.default): + return self.default() + return copy.deepcopy(self.default) + return super(DictField, self).get_default() class TupleField(DictField): - _type = tuple + _type = (tuple, list) def loads(self, value): value = DictField.loads(self, value) diff --git a/ox/django/query.py b/ox/django/query.py index 216f1e1..38ab9a6 100644 --- a/ox/django/query.py +++ b/ox/django/query.py @@ -20,31 +20,21 @@ class Model(models.Model): objects = Manager() ''' -class SQLCompiler(SQLCompiler): +class NullLastSQLCompiler(SQLCompiler): - def get_ordering(self): - result, group_by = super(SQLCompiler, self).get_ordering() - if self.query.nulls_last and len(result): - if self.connection.vendor == 'sqlite': - _result = [] - for r in result: - if r.endswith(' DESC'): - _r = r[:-len(' DESC')] - elif r.endswith(' ASC'): - _r = r[:-len(' ASC')] - _result.append(_r + ' IS NULL') - _result.append(r) + def get_order_by(self): + result = super(NullLastSQLCompiler, self).get_order_by() + if self.query.nulls_last and result \ + and self.connection.vendor == 'postgresql': + return [(expr, (sql + ' NULLS LAST', params, is_ref)) + for (expr, (sql, params, is_ref)) in result] + return result - result = _result - else: - result = map(lambda e: e + ' NULLS LAST', result) - return result, group_by - -class Query(Query): +class NullsLastQuery(Query): nulls_last = False def clone(self, *args, **kwargs): - obj = super(Query, self).clone(*args, **kwargs) + obj = super(NullsLastQuery, self).clone(*args, **kwargs) obj.nulls_last = self.nulls_last return obj @@ -53,18 +43,13 @@ class Query(Query): raise ValueError("Need either using or connection") if using: connection = connections[using] - # Check that the compiler will be able to execute the query - for alias, aggregate in self.aggregate_select.items(): - connection.ops.check_aggregate_support(aggregate) - - return SQLCompiler(self, connection, using) - + return NullLastSQLCompiler(self, connection, using) class QuerySet(django.db.models.query.QuerySet): def __init__(self, model=None, query=None, using=None, **kwargs): super(QuerySet, self).__init__(model=model, query=query, using=None, **kwargs) - self.query = query or Query(self.model) + self.query = query or NullsLastQuery(self.model) def order_by(self, *args, **kwargs): nulls_last = kwargs.pop('nulls_last', False)