From e8520fd0a934adf1fd2bc766fc0cc6efe15f4929 Mon Sep 17 00:00:00 2001 From: wuyu Date: Tue, 11 Oct 2016 17:59:42 +0800 Subject: [PATCH 01/24] xadmin for python3.4 change: force_unicode ==> force_text smart_unicode ==> smart_text unicode ==> smart_text --- .gitignore | 2 ++ demo_app/app/models.py | 17 +++++++++++------ demo_app/demo/settings.py | 7 +++++-- tests/runtests.py | 3 ++- tests/xtests/site/apps.py | 5 +++-- tests/xtests/view_base/apps.py | 5 +++-- xadmin/filters.py | 10 +++++----- xadmin/models.py | 16 +++++++++++----- xadmin/plugins/actions.py | 8 ++++---- xadmin/plugins/ajax.py | 4 ++-- xadmin/plugins/auth.py | 3 ++- xadmin/plugins/batch.py | 6 +++--- xadmin/plugins/bookmark.py | 17 +++++++++-------- xadmin/plugins/chart.py | 15 +++++++-------- xadmin/plugins/editable.py | 6 +++--- xadmin/plugins/export.py | 12 ++++++------ xadmin/plugins/inline.py | 3 ++- xadmin/plugins/multiselect.py | 10 +++++----- xadmin/plugins/relate.py | 8 ++++---- xadmin/plugins/wizard.py | 3 ++- xadmin/plugins/xversion.py | 22 +++++++++++----------- xadmin/sites.py | 6 ++++-- xadmin/templatetags/xadmin_tags.py | 8 ++++++-- xadmin/util.py | 25 ++++++++++++++++--------- xadmin/views/base.py | 13 ++++++------- xadmin/views/dashboard.py | 12 ++++++------ xadmin/views/delete.py | 10 +++++----- xadmin/views/detail.py | 12 ++++++------ xadmin/views/edit.py | 22 +++++++++++----------- xadmin/views/form.py | 2 +- xadmin/views/list.py | 10 +++++----- xadmin/widgets.py | 12 ++++++------ 32 files changed, 174 insertions(+), 140 deletions(-) diff --git a/.gitignore b/.gitignore index cccac58f3..68a5de545 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ xadmin/static/xadmin/bower_components/ .idea *~ demo_app/data.db + +TAGS diff --git a/demo_app/app/models.py b/demo_app/app/models.py index 32fef1113..5f2ddcc74 100644 --- a/demo_app/app/models.py +++ b/demo_app/app/models.py @@ -1,6 +1,7 @@ from django.db import models from django.contrib.auth.models import Group from django.conf import settings +from django.utils.encoding import python_2_unicode_compatible AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') @@ -22,7 +23,7 @@ ('mix', u"Mix"), ) - +@python_2_unicode_compatible class IDC(models.Model): name = models.CharField(max_length=64) description = models.TextField() @@ -35,7 +36,7 @@ class IDC(models.Model): create_time = models.DateField(auto_now=True) - def __unicode__(self): + def __str__(self): return self.name class Meta: @@ -43,6 +44,7 @@ class Meta: verbose_name_plural = verbose_name +@python_2_unicode_compatible class Host(models.Model): idc = models.ForeignKey(IDC) name = models.CharField(max_length=64) @@ -72,7 +74,7 @@ class Host(models.Model): administrator = models.ForeignKey(AUTH_USER_MODEL, verbose_name="Admin") - def __unicode__(self): + def __str__(self): return self.name class Meta: @@ -80,6 +82,7 @@ class Meta: verbose_name_plural = verbose_name +@python_2_unicode_compatible class MaintainLog(models.Model): host = models.ForeignKey(Host) maintain_type = models.CharField(max_length=32) @@ -88,7 +91,7 @@ class MaintainLog(models.Model): operator = models.CharField(max_length=16) note = models.TextField() - def __unicode__(self): + def __str__(self): return '%s maintain-log [%s] %s %s' % (self.host.name, self.time.strftime('%Y-%m-%d %H:%M:%S'), self.maintain_type, self.hard_type) @@ -97,6 +100,7 @@ class Meta: verbose_name_plural = verbose_name +@python_2_unicode_compatible class HostGroup(models.Model): name = models.CharField(max_length=32) @@ -108,10 +112,11 @@ class Meta: verbose_name = u"Host Group" verbose_name_plural = verbose_name - def __unicode__(self): + def __str__(self): return self.name +@python_2_unicode_compatible class AccessRecord(models.Model): date = models.DateField() user_count = models.IntegerField() @@ -121,5 +126,5 @@ class Meta: verbose_name = u"Access Record" verbose_name_plural = verbose_name - def __unicode__(self): + def __str__(self): return "%s Access Record" % self.date.strftime('%Y-%m-%d') diff --git a/demo_app/demo/settings.py b/demo_app/demo/settings.py index 87b76b1d3..916d0b8f9 100644 --- a/demo_app/demo/settings.py +++ b/demo_app/demo/settings.py @@ -3,8 +3,11 @@ import sys import os.path -reload(sys) -sys.setdefaultencoding('utf-8') +if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': + import imp + imp.reload(sys) + sys.setdefaultencoding('utf-8') + gettext = lambda s: s PROJECT_ROOT = os.path.join( diff --git a/tests/runtests.py b/tests/runtests.py index 3efe90c17..cffe257ca 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -6,6 +6,7 @@ import django from django.apps import AppConfig,apps +from django.utils.encoding import smart_text TEST_ROOT = os.path.realpath(os.path.dirname(__file__)) @@ -103,7 +104,7 @@ def teardown(state): # so that it will successfully remove temp trees containing # non-ASCII filenames on Windows. (We're assuming the temp dir # name itself does not contain non-ASCII characters.) - shutil.rmtree(unicode(TEMP_DIR)) + shutil.rmtree(smart_text(TEMP_DIR)) # Restore the old settings. for key, value in state.items(): setattr(settings, key, value) diff --git a/tests/xtests/site/apps.py b/tests/xtests/site/apps.py index 1ab4a5c31..3504ccdbe 100644 --- a/tests/xtests/site/apps.py +++ b/tests/xtests/site/apps.py @@ -1,8 +1,9 @@ #!/usr/bin/env python #coding:utf-8 import sys -if sys.getdefaultencoding()=='ascii': - reload(sys) +if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': + import imp + imp.reload(sys) sys.setdefaultencoding('utf-8') from django.apps import AppConfig diff --git a/tests/xtests/view_base/apps.py b/tests/xtests/view_base/apps.py index 6398388ca..b35885faf 100644 --- a/tests/xtests/view_base/apps.py +++ b/tests/xtests/view_base/apps.py @@ -1,8 +1,9 @@ #!/usr/bin/env python #coding:utf-8 import sys -if sys.getdefaultencoding()=='ascii': - reload(sys) +if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': + import imp + imp.reload(sys) sys.setdefaultencoding('utf-8') from django.apps import AppConfig diff --git a/xadmin/filters.py b/xadmin/filters.py index 6656578c3..47af94f0a 100644 --- a/xadmin/filters.py +++ b/xadmin/filters.py @@ -1,6 +1,6 @@ from django.db import models from django.core.exceptions import ImproperlyConfigured -from django.utils.encoding import smart_unicode +from django.utils.encoding import smart_text from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from django.template.loader import get_template @@ -192,7 +192,7 @@ def choices(self): } for lookup, title in self.field.flatchoices: yield { - 'selected': smart_unicode(lookup) == self.lookup_exact_val, + 'selected': smart_text(lookup) == self.lookup_exact_val, 'query_string': self.query_string({self.lookup_exact_name: lookup}), 'display': title, } @@ -408,7 +408,7 @@ def choices(self): } for pk_val, val in self.lookup_choices: yield { - 'selected': self.lookup_exact_val == smart_unicode(pk_val), + 'selected': self.lookup_exact_val == smart_text(pk_val), 'query_string': self.query_string({ self.lookup_exact_name: pk_val, }, [self.lookup_isnull_name]), @@ -494,7 +494,7 @@ def choices(self): } for val in self.lookup_choices: yield { - 'selected': smart_unicode(val) in self.lookup_in_val, + 'selected': smart_text(val) in self.lookup_in_val, 'query_string': self.query_string({self.lookup_in_name: ",".join([val]+self.lookup_in_val),}), 'remove_query_string': self.query_string({self.lookup_in_name: ",".join([v for v in self.lookup_in_val if v != val]),}), 'display': val, @@ -535,7 +535,7 @@ def choices(self): if val is None: include_none = True continue - val = smart_unicode(val) + val = smart_text(val) yield { 'selected': self.lookup_exact_val == val, 'query_string': self.query_string({self.lookup_exact_name: val}, diff --git a/xadmin/models.py b/xadmin/models.py index 32ef94f27..d880c82e6 100644 --- a/xadmin/models.py +++ b/xadmin/models.py @@ -8,7 +8,7 @@ from django.core.urlresolvers import NoReverseMatch, reverse from django.core.serializers.json import DjangoJSONEncoder from django.db.models.base import ModelBase -from django.utils.encoding import python_2_unicode_compatible, smart_text, smart_unicode +from django.utils.encoding import python_2_unicode_compatible, smart_text from django.db.models.signals import post_migrate from django.contrib.auth.models import Permission @@ -40,6 +40,8 @@ def add_view_permissions(sender, **kwargs): # check for all our view permissions after a syncdb post_migrate.connect(add_view_permissions) + +@python_2_unicode_compatible class Bookmark(models.Model): title = models.CharField(_(u'Title'), max_length=128) user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_(u"user"), blank=True, null=True) @@ -55,7 +57,7 @@ def url(self): base_url = base_url + '?' + self.query return base_url - def __unicode__(self): + def __str__(self): return self.title class Meta: @@ -77,9 +79,10 @@ def default(self, o): try: return super(JSONEncoder, self).default(o) except Exception: - return smart_unicode(o) + return smart_text(o) +@python_2_unicode_compatible class UserSettings(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_(u"user")) key = models.CharField(_('Settings Key'), max_length=256) @@ -91,7 +94,7 @@ def json_value(self): def set_json(self, obj): self.value = json.dumps(obj, cls=JSONEncoder, ensure_ascii=False) - def __unicode__(self): + def __str__(self): return "%s %s" % (self.user, self.key) class Meta: @@ -99,6 +102,7 @@ class Meta: verbose_name_plural = _('User Settings') +@python_2_unicode_compatible class UserWidget(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_(u"user")) page_id = models.CharField(_(u"Page"), max_length=256) @@ -126,13 +130,15 @@ def save(self, *args, **kwargs): except Exception: pass - def __unicode__(self): + def __str__(self): return "%s %s widget" % (self.user, self.widget_type) class Meta: verbose_name = _(u'User Widget') verbose_name_plural = _('User Widgets') + +@python_2_unicode_compatible class Log(models.Model): action_time = models.DateTimeField( _('action time'), diff --git a/xadmin/plugins/actions.py b/xadmin/plugins/actions.py index 0e9bf2921..fd8a2bf57 100644 --- a/xadmin/plugins/actions.py +++ b/xadmin/plugins/actions.py @@ -5,7 +5,7 @@ from django.http import HttpResponse, HttpResponseRedirect from django.template import loader from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _, ungettext from django.utils.text import capfirst @@ -24,7 +24,7 @@ def action_checkbox(obj): - return checkbox.render(ACTION_CHECKBOX_NAME, force_unicode(obj.pk)) + return checkbox.render(ACTION_CHECKBOX_NAME, force_text(obj.pk)) action_checkbox.short_description = mark_safe( '') action_checkbox.allow_tags = True @@ -102,9 +102,9 @@ def do_action(self, queryset): return None if len(queryset) == 1: - objects_name = force_unicode(self.opts.verbose_name) + objects_name = force_text(self.opts.verbose_name) else: - objects_name = force_unicode(self.opts.verbose_name_plural) + objects_name = force_text(self.opts.verbose_name_plural) if perms_needed or protected: title = _("Cannot delete %(name)s") % {"name": objects_name} diff --git a/xadmin/plugins/ajax.py b/xadmin/plugins/ajax.py index f6e21c3d6..b09bea21b 100644 --- a/xadmin/plugins/ajax.py +++ b/xadmin/plugins/ajax.py @@ -1,7 +1,7 @@ from collections import OrderedDict from django.forms.utils import ErrorDict from django.utils.html import escape -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from xadmin.sites import site from xadmin.views import BaseAdminPlugin, ListAdminView, ModelFormAdminView, DetailAdminView @@ -27,7 +27,7 @@ def get_list_display(self,list_display): def get_result_list(self, response): av = self.admin_view base_fields = self.get_list_display(av.base_list_display) - headers = dict([(c.field_name, force_unicode(c.text)) for c in av.result_headers( + headers = dict([(c.field_name, force_text(c.text)) for c in av.result_headers( ).cells if c.field_name in base_fields]) objects = [dict([(o.field_name, escape(str(o.value))) for i, o in diff --git a/xadmin/plugins/auth.py b/xadmin/plugins/auth.py index 9e8c927c4..e0389af51 100644 --- a/xadmin/plugins/auth.py +++ b/xadmin/plugins/auth.py @@ -8,6 +8,7 @@ from django.utils.decorators import method_decorator from django.http import HttpResponseRedirect from django.utils.html import escape +from django.utils.encoding import smart_text from django.utils.translation import ugettext as _ from django.views.decorators.debug import sensitive_post_parameters from django.forms import ModelMultipleChoiceField @@ -196,7 +197,7 @@ def get_context(self): helper.include_media = False self.form.helper = helper context.update({ - 'title': _('Change password: %s') % escape(unicode(self.obj)), + 'title': _('Change password: %s') % escape(smart_text(self.obj)), 'form': self.form, 'has_delete_permission': False, 'has_change_permission': True, diff --git a/xadmin/plugins/batch.py b/xadmin/plugins/batch.py index 769ede1b0..1964be1f5 100644 --- a/xadmin/plugins/batch.py +++ b/xadmin/plugins/batch.py @@ -5,7 +5,7 @@ from django.core.exceptions import PermissionDenied from django.forms.models import modelform_factory from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _, ugettext_lazy from xadmin.layout import FormHelper, Layout, Fieldset, Container, Col @@ -129,9 +129,9 @@ def do_action(self, queryset): self.form_obj.helper = helper count = len(queryset) if count == 1: - objects_name = force_unicode(self.opts.verbose_name) + objects_name = force_text(self.opts.verbose_name) else: - objects_name = force_unicode(self.opts.verbose_name_plural) + objects_name = force_text(self.opts.verbose_name_plural) context = self.get_context() context.update({ diff --git a/xadmin/plugins/bookmark.py b/xadmin/plugins/bookmark.py index da1c39ebd..aefbc5b64 100644 --- a/xadmin/plugins/bookmark.py +++ b/xadmin/plugins/bookmark.py @@ -1,22 +1,23 @@ -from django.template import loader -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext_lazy as _ -from django.utils.decorators import method_decorator -from django.views.decorators.csrf import csrf_protect from django.contrib.contenttypes.models import ContentType +from django.core.urlresolvers import reverse from django.db import transaction from django.db.models import Q from django.forms import ModelChoiceField from django.http import QueryDict +from django.template import loader +from django.utils.decorators import method_decorator +from django.utils.encoding import smart_text +from django.utils.translation import ugettext_lazy as _ +from django.views.decorators.csrf import csrf_protect +from xadmin.filters import FILTER_PREFIX, SEARCH_VAR +from xadmin.plugins.relate import RELATE_PREFIX from xadmin.plugins.utils import get_context_dict from xadmin.sites import site from xadmin.views import ModelAdminView, BaseAdminPlugin, ListAdminView from xadmin.views.list import COL_LIST_VAR, ORDER_VAR from xadmin.views.dashboard import widget_manager, BaseWidget, PartialBaseWidget -from xadmin.filters import FILTER_PREFIX, SEARCH_VAR -from xadmin.plugins.relate import RELATE_PREFIX from xadmin.models import Bookmark @@ -188,7 +189,7 @@ def setup(self): self.bookmark = bookmark if not self.title: - self.title = unicode(bookmark) + self.title = smart_text(bookmark) req = self.make_get_request("", data.items()) self.list_view = self.get_view_class( diff --git a/xadmin/plugins/chart.py b/xadmin/plugins/chart.py index 36907da65..e2b0a649a 100644 --- a/xadmin/plugins/chart.py +++ b/xadmin/plugins/chart.py @@ -1,22 +1,21 @@ +import calendar import datetime import decimal -import calendar -from django.template import loader -from django.http import HttpResponseNotFound from django.core.serializers.json import DjangoJSONEncoder -from django.http import HttpResponse -from django.utils.encoding import smart_unicode from django.db import models +from django.http import HttpResponse, HttpResponseNotFound +from django.template import loader from django.utils.http import urlencode +from django.utils.encoding import force_text, smart_text from django.utils.translation import ugettext_lazy as _, ugettext from xadmin.plugins.utils import get_context_dict from xadmin.sites import site from xadmin.views import BaseAdminPlugin, ListAdminView from xadmin.views.dashboard import ModelBaseWidget, widget_manager -from xadmin.util import lookup_field, label_for_field, force_unicode, json +from xadmin.util import lookup_field, label_for_field, json @widget_manager.register @@ -77,7 +76,7 @@ def default(self, o): try: return super(JSONEncoder, self).default(o) except Exception: - return smart_unicode(o) + return smart_text(o) class ChartsPlugin(BaseAdminPlugin): @@ -124,7 +123,7 @@ def get(self, request, name): self.y_fields = ( y_fields,) if type(y_fields) not in (list, tuple) else y_fields - datas = [{"data":[], "label": force_unicode(label_for_field( + datas = [{"data":[], "label": force_text(label_for_field( i, self.model, model_admin=self))} for i in self.y_fields] self.make_result_list() diff --git a/xadmin/plugins/editable.py b/xadmin/plugins/editable.py index 00c4c8ae0..1b49feb60 100644 --- a/xadmin/plugins/editable.py +++ b/xadmin/plugins/editable.py @@ -3,7 +3,7 @@ from django.db import models, transaction from django.forms.models import modelform_factory from django.http import Http404, HttpResponse -from django.utils.encoding import force_unicode, smart_unicode +from django.utils.encoding import force_text, smart_text from django.utils.html import escape, conditional_escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -71,7 +71,7 @@ def init_request(self, object_id, *args, **kwargs): if self.org_obj is None: raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % - {'name': force_unicode(self.opts.verbose_name), 'key': escape(object_id)}) + {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) def get_new_field_html(self, f): result = self.result_item(self.org_obj, f, {'is_display_first': @@ -92,7 +92,7 @@ def _get_new_field_html(self, field_name): allow_tags = True text = boolean_icon(value) else: - text = smart_unicode(value) + text = smart_text(value) else: if isinstance(f.rel, models.ManyToOneRel): field_val = getattr(self.org_obj, f.name) diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 860755640..6b4cbb00c 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -4,7 +4,7 @@ from django.http import HttpResponse from django.template import loader -from django.utils.encoding import force_unicode, smart_unicode +from django.utils.encoding import force_text, smart_text from django.utils.html import escape from django.utils.translation import ugettext as _ from django.utils.xmlutils import SimplerXMLGenerator @@ -75,7 +75,7 @@ def _get_objects(self, context): rows = context['results'] return [dict([ - (force_unicode(headers[i].text), self._format_value(o)) for i, o in + (force_text(headers[i].text), self._format_value(o)) for i, o in enumerate(filter(lambda c:getattr(c, 'export', False), r.cells))]) for r in rows] def _get_datas(self, context): @@ -83,7 +83,7 @@ def _get_datas(self, context): new_rows = [[self._format_value(o) for o in filter(lambda c:getattr(c, 'export', False), r.cells)] for r in rows] - new_rows.insert(0, [force_unicode(c.text) for c in context['result_headers'].cells if c.export]) + new_rows.insert(0, [force_text(c.text) for c in context['result_headers'].cells if c.export]) return new_rows def get_xlsx_export(self, context): @@ -95,7 +95,7 @@ def get_xlsx_export(self, context): model_name = self.opts.verbose_name book = xlsxwriter.Workbook(output) sheet = book.add_worksheet( - u"%s %s" % (_(u'Sheet'), force_unicode(model_name))) + u"%s %s" % (_(u'Sheet'), force_text(model_name))) styles = {'datetime': book.add_format({'num_format': 'yyyy-mm-dd hh:mm:ss'}), 'date': book.add_format({'num_format': 'yyyy-mm-dd'}), 'time': book.add_format({'num_format': 'hh:mm:ss'}), @@ -132,7 +132,7 @@ def get_xls_export(self, context): model_name = self.opts.verbose_name book = xlwt.Workbook(encoding='utf8') sheet = book.add_sheet( - u"%s %s" % (_(u'Sheet'), force_unicode(model_name))) + u"%s %s" % (_(u'Sheet'), force_text(model_name))) styles = {'datetime': xlwt.easyxf(num_format_str='yyyy-mm-dd hh:mm:ss'), 'date': xlwt.easyxf(num_format_str='yyyy-mm-dd'), 'time': xlwt.easyxf(num_format_str='hh:mm:ss'), @@ -193,7 +193,7 @@ def _to_xml(self, xml, data): self._to_xml(xml, value) xml.endElement(key) else: - xml.characters(smart_unicode(data)) + xml.characters(smart_text(data)) def get_xml_export(self, context): results = self._get_objects(context) diff --git a/xadmin/plugins/inline.py b/xadmin/plugins/inline.py index cf4629156..c85b5dc50 100644 --- a/xadmin/plugins/inline.py +++ b/xadmin/plugins/inline.py @@ -7,6 +7,7 @@ from django.template import loader from django.template.loader import render_to_string from django.contrib.auth import get_permission_codename +from django.utils.encoding import smart_text from crispy_forms.utils import TEMPLATE_PACK from xadmin.layout import FormHelper, Layout, flatatt, Container, Column, Field, Fieldset @@ -229,7 +230,7 @@ def instance_form(self, **kwargs): label = None if readonly_field in inst._meta.get_all_field_names(): label = inst._meta.get_field(readonly_field).verbose_name - value = unicode(getattr(inst, readonly_field)) + value = smart_text(getattr(inst, readonly_field)) elif inspect.ismethod(getattr(inst, readonly_field, None)): value = getattr(inst, readonly_field)() label = getattr(getattr(inst, readonly_field), 'short_description', readonly_field) diff --git a/xadmin/plugins/multiselect.py b/xadmin/plugins/multiselect.py index 29426a7fe..4fec7f2be 100644 --- a/xadmin/plugins/multiselect.py +++ b/xadmin/plugins/multiselect.py @@ -6,7 +6,7 @@ from django.db.models import ManyToManyField from django.forms.utils import flatatt from django.template import loader -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.html import escape, conditional_escape from django.utils.safestring import mark_safe from xadmin.util import vendor @@ -25,9 +25,9 @@ def __init__(self, verbose_name, is_stacked, attrs=None, choices=()): super(SelectMultipleTransfer, self).__init__(attrs, choices) def render_opt(self, selected_choices, option_value, option_label): - option_value = force_unicode(option_value) + option_value = force_text(option_value) return u'' % ( - escape(option_value), conditional_escape(force_unicode(option_label))), bool(option_value in selected_choices) + escape(option_value), conditional_escape(force_text(option_label))), bool(option_value in selected_choices) def render(self, name, value, attrs=None, choices=()): if attrs is None: @@ -39,14 +39,14 @@ def render(self, name, value, attrs=None, choices=()): value = [] final_attrs = self.build_attrs(attrs, name=name) - selected_choices = set(force_unicode(v) for v in value) + selected_choices = set(force_text(v) for v in value) available_output = [] chosen_output = [] for option_value, option_label in chain(self.choices, choices): if isinstance(option_label, (list, tuple)): available_output.append(u'' % - escape(force_unicode(option_value))) + escape(force_text(option_value))) for option in option_label: output, selected = self.render_opt( selected_choices, *option) diff --git a/xadmin/plugins/relate.py b/xadmin/plugins/relate.py index 7b08c25c0..2475b9c9f 100644 --- a/xadmin/plugins/relate.py +++ b/xadmin/plugins/relate.py @@ -3,7 +3,7 @@ from django.core.urlresolvers import reverse from django.db.models.options import PROXY_PARENTS -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.encoding import smart_str from django.utils.safestring import mark_safe from django.db.models.sql.query import LOOKUP_SEP @@ -78,7 +78,7 @@ def related_link(self, instance): field = rel.field rel_name = rel.get_related_field().name - verbose_name = force_unicode(opts.verbose_name) + verbose_name = force_text(opts.verbose_name) lookup_name = '%s__%s__exact' % (field.name, rel_name) link = ''.join(('
  • ', @@ -145,9 +145,9 @@ def get_brand_name(self): if len(self.to_objs) == 1: to_model_name = str(self.to_objs[0]) else: - to_model_name = force_unicode(self.to_model._meta.verbose_name) + to_model_name = force_text(self.to_model._meta.verbose_name) - return mark_safe(u"%s %s" % (to_model_name, force_unicode(self.opts.verbose_name_plural))) + return mark_safe(u"%s %s" % (to_model_name, force_text(self.opts.verbose_name_plural))) class BaseRelateDisplayPlugin(BaseAdminPlugin): diff --git a/xadmin/plugins/wizard.py b/xadmin/plugins/wizard.py index b370b622c..b2cb49337 100644 --- a/xadmin/plugins/wizard.py +++ b/xadmin/plugins/wizard.py @@ -13,6 +13,7 @@ from django.contrib.formtools.wizard.forms import ManagementForm from django.contrib.formtools.wizard.views import StepsHelper +from django.utils.encoding import smart_text from django.utils.module_loading import import_string from django.forms import ValidationError from django.forms.models import modelform_factory @@ -51,7 +52,7 @@ def get_form_list(self): self.wizard_form_list) > 0, 'at least one form is needed' for i, form in enumerate(self.wizard_form_list): - init_form_list[unicode(form[0])] = form[1] + init_form_list[smart_text(form[0])] = form[1] self._form_list = init_form_list diff --git a/xadmin/plugins/xversion.py b/xadmin/plugins/xversion.py index 9c7a9d008..ebe7118ea 100644 --- a/xadmin/plugins/xversion.py +++ b/xadmin/plugins/xversion.py @@ -8,7 +8,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text, smart_text from django.utils.safestring import mark_safe from django.utils.text import capfirst from django.utils.translation import ugettext as _ @@ -191,7 +191,7 @@ def get_context(self): "opts": opts, "app_label": opts.app_label, "model_name": capfirst(opts.verbose_name), - "title": _("Recover deleted %(name)s") % {"name": force_unicode(opts.verbose_name_plural)}, + "title": _("Recover deleted %(name)s") % {"name": force_text(opts.verbose_name_plural)}, "deleted": deleted, "changelist_url": self.model_admin_url("changelist"), }) @@ -235,9 +235,9 @@ def get_context(self): ).select_related("revision__user")) ] context.update({ - 'title': _('Change history: %s') % force_unicode(self.obj), + 'title': _('Change history: %s') % force_text(self.obj), 'action_list': action_list, - 'model_name': capfirst(force_unicode(opts.verbose_name_plural)), + 'model_name': capfirst(force_text(opts.verbose_name_plural)), 'object': self.obj, 'app_label': opts.app_label, "changelist_url": self.model_admin_url("changelist"), @@ -393,7 +393,7 @@ def init_request(self, object_id, version_id): DetailAdminView, self.model, object_id) self.org_obj = self.detail.obj self.version = get_object_or_404( - Version, pk=version_id, object_id=unicode(self.org_obj.pk)) + Version, pk=version_id, object_id=smart_text(self.org_obj.pk)) self.prepare_form() @@ -421,7 +421,7 @@ def get_form_helper(self): def get_context(self): context = super(RevisionView, self).get_context() context["title"] = _( - "Revert %s") % force_unicode(self.model._meta.verbose_name) + "Revert %s") % force_text(self.model._meta.verbose_name) return context @filter_hook @@ -438,7 +438,7 @@ def get_response(self): @filter_hook def post_response(self): self.message_user(_('The %(model)s "%(name)s" was reverted successfully. You may edit it again below.') % - {"model": force_unicode(self.opts.verbose_name), "name": unicode(self.new_obj)}, 'success') + {"model": force_text(self.opts.verbose_name), "name": smart_text(self.new_obj)}, 'success') return HttpResponseRedirect(self.model_admin_url('change', self.new_obj.pk)) @@ -475,7 +475,7 @@ def get_response(self): @filter_hook def post_response(self): self.message_user(_('The %(model)s "%(name)s" was recovered successfully. You may edit it again below.') % - {"model": force_unicode(self.opts.verbose_name), "name": unicode(self.new_obj)}, 'success') + {"model": force_text(self.opts.verbose_name), "name": smart_text(self.new_obj)}, 'success') return HttpResponseRedirect(self.model_admin_url('change', self.new_obj.pk)) @@ -521,7 +521,7 @@ def get_related_versions(self, obj, version, formset): related_versions = dict([(related_version.object_id, related_version) for related_version in revision_versions if ContentType.objects.get_for_id(related_version.content_type_id).model_class() == formset.model - and unicode(related_version.field_dict[fk_name]) == unicode(object_id)]) + and smart_text(related_version.field_dict[fk_name]) == smart_text(object_id)]) return related_versions def _hack_inline_formset_initial(self, revision_view, formset): @@ -532,9 +532,9 @@ def _hack_inline_formset_initial(self, revision_view, formset): revision_view.org_obj, revision_view.version, formset) formset.related_versions = related_versions for related_obj in formset.queryset: - if unicode(related_obj.pk) in related_versions: + if smart_text(related_obj.pk) in related_versions: initial.append( - related_versions.pop(unicode(related_obj.pk)).field_dict) + related_versions.pop(smart_text(related_obj.pk)).field_dict) else: initial_data = model_to_dict(related_obj) initial_data["DELETE"] = True diff --git a/xadmin/sites.py b/xadmin/sites.py index 292bc5ffe..9cbde739c 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -6,8 +6,10 @@ from django.views.decorators.cache import never_cache import inspect -reload(sys) -sys.setdefaultencoding("utf-8") +if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': + import imp + imp.reload(sys) + sys.setdefaultencoding("utf-8") class AlreadyRegistered(Exception): diff --git a/xadmin/templatetags/xadmin_tags.py b/xadmin/templatetags/xadmin_tags.py index 80ce1dbd9..13ec3bbc6 100644 --- a/xadmin/templatetags/xadmin_tags.py +++ b/xadmin/templatetags/xadmin_tags.py @@ -1,3 +1,4 @@ +import sys from django import template from django.template import Library from django.utils.safestring import mark_safe @@ -19,7 +20,10 @@ def view_block(context, block_name, *args, **kwargs): if hasattr(view, method_name) and callable(getattr(view, method_name)): block_func = getattr(view, method_name) result = block_func(context, nodes, *args, **kwargs) - if result and type(result) in (str, unicode): + if result and ( + isinstance(result, str) + or sys.version_info.major < 3 and isinstance(result, unicode) + ): nodes.append(result) if nodes: return mark_safe(''.join(nodes)) @@ -60,4 +64,4 @@ def do_blockcapture(parser, token): nodelist = parser.parse(('endblockcapture',)) parser.delete_first_token() - return BlockcaptureNode(nodelist, args) \ No newline at end of file + return BlockcaptureNode(nodelist, args) diff --git a/xadmin/util.py b/xadmin/util.py index 72fcf5424..8e62634a3 100644 --- a/xadmin/util.py +++ b/xadmin/util.py @@ -1,3 +1,4 @@ +import sys import django from django.db import models from django.db.models.sql.query import LOOKUP_SEP @@ -8,7 +9,7 @@ from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.text import capfirst -from django.utils.encoding import force_unicode, smart_unicode, smart_str +from django.utils.encoding import force_text, smart_text, smart_str from django.utils.translation import ungettext from django.core.urlresolvers import reverse from django.conf import settings @@ -55,7 +56,10 @@ def xstatic(*tags): else: raise e - if type(node) in (str, unicode): + if ( + isinstance(node, str) + or sys.version_info.major < 3 and isinstance(node, unicode) + ): files = node else: mode = 'dev' @@ -236,8 +240,8 @@ def model_format_dict(obj): else: opts = obj return { - 'verbose_name': force_unicode(opts.verbose_name), - 'verbose_name_plural': force_unicode(opts.verbose_name_plural) + 'verbose_name': force_text(opts.verbose_name), + 'verbose_name_plural': force_text(opts.verbose_name_plural) } @@ -276,8 +280,11 @@ def lookup_field(name, obj, model_admin=None): if callable(name): attr = name value = attr(obj) - elif (model_admin is not None and hasattr(model_admin, name) and - not name == '__str__' and not name == '__unicode__'): + elif ( + model_admin is not None + and hasattr(model_admin, name) + and name not in ('__str__', '__unicode__') + ): attr = getattr(model_admin, name) value = attr(obj) else: @@ -329,9 +336,9 @@ def display_for_field(value, field): elif isinstance(field, models.FloatField): return formats.number_format(value) elif isinstance(field.rel, models.ManyToManyRel): - return ', '.join([smart_unicode(obj) for obj in value.all()]) + return ', '.join([smart_text(obj) for obj in value.all()]) else: - return smart_unicode(value) + return smart_text(value) def display_for_value(value, boolean=False): @@ -348,7 +355,7 @@ def display_for_value(value, boolean=False): elif isinstance(value, (decimal.Decimal, float)): return formats.number_format(value) else: - return smart_unicode(value) + return smart_text(value) class NotRelationField(Exception): diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 44cb044fb..4da64decc 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -7,7 +7,6 @@ from inspect import getargspec from django import forms -from django.utils.encoding import force_unicode, force_text from django.apps import apps from django.conf import settings from django.contrib import messages @@ -19,7 +18,7 @@ from django.template import Context, Template from django.template.response import TemplateResponse from django.utils.decorators import method_decorator, classonlymethod -from django.utils.encoding import force_unicode, smart_unicode, smart_str +from django.utils.encoding import force_text, smart_text, smart_str from django.utils.http import urlencode from django.utils.itercompat import is_iterable from django.utils.safestring import mark_safe @@ -120,7 +119,7 @@ def default(self, o): try: return super(JSONEncoder, self).default(o) except Exception: - return smart_unicode(o) + return smart_text(o) class BaseAdminObject(object): @@ -344,7 +343,7 @@ def get_url(menu, had_urls): app_label = model._meta.app_label app_icon = None model_dict = { - 'title': unicode(capfirst(model._meta.verbose_name_plural)), + 'title': smart_text(capfirst(model._meta.verbose_name_plural)), 'url': self.get_model_url(model, "changelist"), 'icon': self.get_model_icon(model), 'perm': self.get_model_perm(model, 'view'), @@ -358,11 +357,11 @@ def get_url(menu, had_urls): nav_menu[app_key]['menus'].append(model_dict) else: # Find app title - app_title = unicode(app_label.title()) + app_title = smart_text(app_label.title()) if app_label.lower() in self.apps_label_title: app_title = self.apps_label_title[app_label.lower()] else: - app_title = unicode(apps.get_app_config(app_label).verbose_name) + app_title = smart_text(apps.get_app_config(app_label).verbose_name) #find app icon if app_label.lower() in self.apps_icons: app_icon = self.apps_icons[app_label.lower()] @@ -495,7 +494,7 @@ def get_context(self): "opts": self.opts, "app_label": self.app_label, "model_name": self.model_name, - "verbose_name": force_unicode(self.opts.verbose_name), + "verbose_name": force_text(self.opts.verbose_name), 'model_icon': self.get_model_icon(self.model), } context = super(ModelAdminView, self).get_context() diff --git a/xadmin/views/dashboard.py b/xadmin/views/dashboard.py index 569c938d7..bed4b3aa3 100644 --- a/xadmin/views/dashboard.py +++ b/xadmin/views/dashboard.py @@ -9,7 +9,7 @@ from django.template import loader from django.http import Http404 from django.test.client import RequestFactory -from django.utils.encoding import force_unicode, smart_unicode +from django.utils.encoding import force_text, smart_text from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -39,12 +39,12 @@ def render(self, name, value, attrs=None): final_attrs = self.build_attrs(attrs, name=name) final_attrs['class'] = 'nav nav-pills nav-stacked' output = [u'' % flatatt(final_attrs)] - options = self.render_options(force_unicode(value), final_attrs['id']) + options = self.render_options(force_text(value), final_attrs['id']) if options: output.append(options) output.append(u'') output.append('' % - (final_attrs['id'], name, force_unicode(value))) + (final_attrs['id'], name, force_text(value))) return mark_safe(u'\n'.join(output)) def render_option(self, selected_choice, widget, id): @@ -305,7 +305,7 @@ def prepare_value(self, value): def valid_value(self, value): value = self.prepare_value(value) for k, v in self.choices: - if value == smart_unicode(k): + if value == smart_text(k): return True return False @@ -637,7 +637,7 @@ def get_page_id(self): @filter_hook def get_title(self): - return self.title % force_unicode(self.obj) + return self.title % force_text(self.obj) def init_request(self, object_id, *args, **kwargs): self.obj = self.get_object(unquote(object_id)) @@ -647,7 +647,7 @@ def init_request(self, object_id, *args, **kwargs): if self.obj is None: raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % - {'name': force_unicode(self.opts.verbose_name), 'key': escape(object_id)}) + {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) @filter_hook def get_context(self): diff --git a/xadmin/views/delete.py b/xadmin/views/delete.py index 88ee93cca..42e79b76c 100644 --- a/xadmin/views/delete.py +++ b/xadmin/views/delete.py @@ -2,7 +2,7 @@ from django.db import transaction, router from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.html import escape from django.utils.translation import ugettext as _ from django.contrib.admin.utils import get_deleted_objects @@ -24,7 +24,7 @@ def init_request(self, object_id, *args, **kwargs): raise PermissionDenied if self.obj is None: - raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(self.opts.verbose_name), 'key': escape(object_id)}) + raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) using = router.db_for_write(self.model) @@ -68,7 +68,7 @@ def delete_model(self): def get_context(self): if self.perms_needed or self.protected: title = _("Cannot delete %(name)s") % {"name": - force_unicode(self.opts.verbose_name)} + force_text(self.opts.verbose_name)} else: title = _("Are you sure?") @@ -87,7 +87,7 @@ def get_context(self): def get_breadcrumb(self): bcs = super(DeleteAdminView, self).get_breadcrumb() bcs.append({ - 'title': force_unicode(self.obj), + 'title': force_text(self.obj), 'url': self.get_object_url(self.obj) }) item = {'title': _('Delete')} @@ -101,7 +101,7 @@ def get_breadcrumb(self): def post_response(self): self.message_user(_('The %(name)s "%(obj)s" was deleted successfully.') % - {'name': force_unicode(self.opts.verbose_name), 'obj': force_unicode(self.obj)}, 'success') + {'name': force_text(self.opts.verbose_name), 'obj': force_text(self.obj)}, 'success') if not self.has_view_permission(): return self.get_admin_url('index') diff --git a/xadmin/views/detail.py b/xadmin/views/detail.py index 46bfd7ce0..c0f881295 100644 --- a/xadmin/views/detail.py +++ b/xadmin/views/detail.py @@ -9,7 +9,7 @@ from django.http import Http404 from django.template import loader from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode, smart_unicode +from django.utils.encoding import force_text, smart_text from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -93,7 +93,7 @@ def init(self): self.allow_tags = True self.text = boolean_icon(value) else: - self.text = smart_unicode(value) + self.text = smart_text(value) else: if isinstance(f.rel, models.ManyToOneRel): self.text = getattr(self.obj, f.name) @@ -107,7 +107,7 @@ def init(self): def val(self): text = mark_safe( self.text) if self.allow_tags else conditional_escape(self.text) - if force_unicode(text) == '' or text == 'None' or text == EMPTY_CHANGELIST_VALUE: + if force_text(text) == '' or text == 'None' or text == EMPTY_CHANGELIST_VALUE: text = mark_safe( '%s' % EMPTY_CHANGELIST_VALUE) for wrap in self.wraps: @@ -143,7 +143,7 @@ def init_request(self, object_id, *args, **kwargs): if self.obj is None: raise Http404( _('%(name)s object with primary key %(key)r does not exist.') % - {'name': force_unicode(self.opts.verbose_name), 'key': escape(object_id)}) + {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) self.org_obj = self.obj @filter_hook @@ -232,7 +232,7 @@ def get(self, request, *args, **kwargs): @filter_hook def get_context(self): new_context = { - 'title': _('%s Detail') % force_unicode(self.opts.verbose_name), + 'title': _('%s Detail') % force_text(self.opts.verbose_name), 'form': self.form_obj, 'object': self.obj, @@ -250,7 +250,7 @@ def get_context(self): @filter_hook def get_breadcrumb(self): bcs = super(DetailAdminView, self).get_breadcrumb() - item = {'title': force_unicode(self.obj)} + item = {'title': force_text(self.obj)} if self.has_view_permission(): item['url'] = self.model_admin_url('detail', self.obj.pk) bcs.append(item) diff --git a/xadmin/views/edit.py b/xadmin/views/edit.py index d335dd4d0..eb87caff5 100644 --- a/xadmin/views/edit.py +++ b/xadmin/views/edit.py @@ -8,7 +8,7 @@ from django.forms.models import modelform_factory, modelform_defines_fields from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.html import escape from django.utils.text import capfirst, get_text_list from django.template import loader @@ -384,7 +384,7 @@ def get_form_datas(self): @filter_hook def get_context(self): new_context = { - 'title': _('Add %s') % force_unicode(self.opts.verbose_name), + 'title': _('Add %s') % force_text(self.opts.verbose_name), } context = super(CreateAdminView, self).get_context() context.update(new_context) @@ -393,7 +393,7 @@ def get_context(self): @filter_hook def get_breadcrumb(self): bcs = super(ModelFormAdminView, self).get_breadcrumb() - item = {'title': _('Add %s') % force_unicode(self.opts.verbose_name)} + item = {'title': _('Add %s') % force_text(self.opts.verbose_name)} if self.has_add_permission(): item['url'] = self.model_admin_url('add') bcs.append(item) @@ -417,8 +417,8 @@ def post_response(self): request = self.request msg = _( - 'The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(self.opts.verbose_name), - 'obj': "%s" % (self.model_admin_url('change', self.new_obj._get_pk_val()), force_unicode(self.new_obj))} + 'The %(name)s "%(obj)s" was added successfully.') % {'name': force_text(self.opts.verbose_name), + 'obj': "%s" % (self.model_admin_url('change', self.new_obj._get_pk_val()), force_text(self.new_obj))} if "_continue" in request.POST: self.message_user( @@ -426,7 +426,7 @@ def post_response(self): return self.model_admin_url('change', self.new_obj._get_pk_val()) if "_addanother" in request.POST: - self.message_user(msg + ' ' + (_("You may add another %s below.") % force_unicode(self.opts.verbose_name)), 'success') + self.message_user(msg + ' ' + (_("You may add another %s below.") % force_text(self.opts.verbose_name)), 'success') return request.path else: self.message_user(msg, 'success') @@ -452,7 +452,7 @@ def init_request(self, object_id, *args, **kwargs): if self.org_obj is None: raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % - {'name': force_unicode(self.opts.verbose_name), 'key': escape(object_id)}) + {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) # comm method for both get and post self.prepare_form() @@ -468,7 +468,7 @@ def get_form_datas(self): @filter_hook def get_context(self): new_context = { - 'title': _('Change %s') % force_unicode(self.org_obj), + 'title': _('Change %s') % force_text(self.org_obj), 'object_id': str(self.org_obj.pk), } context = super(UpdateAdminView, self).get_context() @@ -479,7 +479,7 @@ def get_context(self): def get_breadcrumb(self): bcs = super(ModelFormAdminView, self).get_breadcrumb() - item = {'title': force_unicode(self.org_obj)} + item = {'title': force_text(self.org_obj)} if self.has_change_permission(): item['url'] = self.model_admin_url('change', self.org_obj.pk) bcs.append(item) @@ -514,14 +514,14 @@ def post_response(self): pk_value = obj._get_pk_val() msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': - force_unicode(verbose_name), 'obj': force_unicode(obj)} + force_text(verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: self.message_user( msg + ' ' + _("You may edit it again below."), 'success') return request.path elif "_addanother" in request.POST: self.message_user(msg + ' ' + (_("You may add another %s below.") - % force_unicode(verbose_name)), 'success') + % force_text(verbose_name)), 'success') return self.model_admin_url('add') else: self.message_user(msg, 'success') diff --git a/xadmin/views/form.py b/xadmin/views/form.py index 38556e340..62002b997 100644 --- a/xadmin/views/form.py +++ b/xadmin/views/form.py @@ -7,7 +7,7 @@ from django.forms.models import modelform_factory from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.html import escape from django.template import loader from django.utils.translation import ugettext as _ diff --git a/xadmin/views/list.py b/xadmin/views/list.py index 0afe43b32..2b224bc64 100644 --- a/xadmin/views/list.py +++ b/xadmin/views/list.py @@ -5,7 +5,7 @@ from django.db import models from django.http import HttpResponseRedirect from django.template.response import SimpleTemplateResponse, TemplateResponse -from django.utils.encoding import force_unicode, smart_unicode +from django.utils.encoding import force_text, smart_text from django.utils.html import escape, conditional_escape from django.utils.safestring import mark_safe from django.utils.text import capfirst @@ -66,7 +66,7 @@ def __init__(self, field_name, row): def label(self): text = mark_safe( self.text) if self.allow_tags else conditional_escape(self.text) - if force_unicode(text) == '': + if force_text(text) == '': text = mark_safe(' ') for wrap in self.wraps: text = mark_safe(wrap % text) @@ -370,12 +370,12 @@ def get_context(self): """ Prepare the context for templates. """ - self.title = _('%s List') % force_unicode(self.opts.verbose_name) + self.title = _('%s List') % force_text(self.opts.verbose_name) model_fields = [(f, f.name in self.list_display, self.get_check_field_url(f)) for f in (list(self.opts.fields) + self.get_model_method_fields()) if f.name not in self.list_exclude] new_context = { - 'model_name': force_unicode(self.opts.verbose_name_plural), + 'model_name': force_text(self.opts.verbose_name_plural), 'title': self.title, 'cl': self, 'model_fields': model_fields, @@ -543,7 +543,7 @@ def result_item(self, obj, field_name, row): item.allow_tags = True item.text = boolean_icon(value) else: - item.text = smart_unicode(value) + item.text = smart_text(value) else: if isinstance(f.rel, models.ManyToOneRel): field_val = getattr(obj, f.name) diff --git a/xadmin/widgets.py b/xadmin/widgets.py index e7301b6eb..d3264243f 100644 --- a/xadmin/widgets.py +++ b/xadmin/widgets.py @@ -4,7 +4,7 @@ from itertools import chain from django import forms from django.forms.widgets import RadioFieldRenderer, RadioChoiceInput -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.safestring import mark_safe from django.utils.html import conditional_escape from django.utils.translation import ugettext as _ @@ -81,7 +81,7 @@ def render(self, name=None, value=None, attrs=None, choices=()): label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) else: label_for = '' - choice_label = conditional_escape(force_unicode(self.choice_label)) + choice_label = conditional_escape(force_text(self.choice_label)) if attrs.get('inline', False): return mark_safe(u'%s %s' % (label_for, self.tag(), choice_label)) else: @@ -99,7 +99,7 @@ def __getitem__(self, idx): return AdminRadioInput(self.name, self.value, self.attrs.copy(), choice, idx) def render(self): - return mark_safe(u'\n'.join([force_unicode(w) for w in self])) + return mark_safe(u'\n'.join([force_text(w) for w in self])) class AdminRadioSelect(forms.RadioSelect): @@ -114,7 +114,7 @@ def render(self, name, value, attrs=None, choices=()): final_attrs = self.build_attrs(attrs, name=name) output = [] # Normalize to strings - str_values = set([force_unicode(v) for v in value]) + str_values = set([force_text(v) for v in value]) for i, (option_value, option_label) in enumerate(chain(self.choices, choices)): # If an ID attribute was given, add a numeric index as a suffix, # so that the checkboxes don't all have the same ID attribute. @@ -126,9 +126,9 @@ def render(self, name, value, attrs=None, choices=()): cb = forms.CheckboxInput( final_attrs, check_test=lambda value: value in str_values) - option_value = force_unicode(option_value) + option_value = force_text(option_value) rendered_cb = cb.render(name, option_value) - option_label = conditional_escape(force_unicode(option_label)) + option_label = conditional_escape(force_text(option_label)) if final_attrs.get('inline', False): output.append(u'%s %s' % (label_for, rendered_cb, option_label)) From a1b10078378ee1253ff49572d8dbd423540e4366 Mon Sep 17 00:00:00 2001 From: wuyu Date: Tue, 11 Oct 2016 18:03:20 +0800 Subject: [PATCH 02/24] add python v3.4 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 87ff0c737..db8db128f 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ "Programming Language :: JavaScript", 'Programming Language :: Python', "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.4", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", From 8c128250cabe33f4d96bc37fe76e130578b7afaa Mon Sep 17 00:00:00 2001 From: wuyu Date: Tue, 11 Oct 2016 18:16:49 +0800 Subject: [PATCH 03/24] futurize --stage1 --- demo_app/app/adminx.py | 3 ++- tests/runtests.py | 1 + tests/xtests/site/tests.py | 3 ++- tests/xtests/view_base/adminx.py | 3 ++- tests/xtests/view_base/tests.py | 5 +++-- tests/xtests/view_base/urls.py | 3 ++- xadmin/adminx.py | 3 ++- xadmin/filters.py | 3 ++- xadmin/plugins/export.py | 2 +- xadmin/plugins/filters.py | 7 ++++--- xadmin/plugins/quickfilter.py | 2 +- xadmin/plugins/themes.py | 5 +++-- xadmin/util.py | 7 ++++--- xadmin/views/__init__.py | 17 +++++++++-------- xadmin/views/dashboard.py | 2 +- xadmin/views/detail.py | 3 ++- xadmin/views/edit.py | 3 ++- xadmin/views/form.py | 3 ++- xadmin/views/list.py | 3 ++- xadmin/views/website.py | 5 +++-- xadmin/widgets.py | 3 ++- 21 files changed, 52 insertions(+), 34 deletions(-) diff --git a/demo_app/app/adminx.py b/demo_app/app/adminx.py index 3e3c50de4..7048f886b 100644 --- a/demo_app/app/adminx.py +++ b/demo_app/app/adminx.py @@ -1,6 +1,7 @@ +from __future__ import absolute_import import xadmin from xadmin import views -from models import IDC, Host, MaintainLog, HostGroup, AccessRecord +from .models import IDC, Host, MaintainLog, HostGroup, AccessRecord from xadmin.layout import Main, TabHolder, Tab, Fieldset, Row, Col, AppendedText, Side from xadmin.plugins.inline import Inline from xadmin.plugins.batch import BatchChangeAction diff --git a/tests/runtests.py b/tests/runtests.py index cffe257ca..5bd6d5bf6 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import print_function import os import shutil import sys diff --git a/tests/xtests/site/tests.py b/tests/xtests/site/tests.py index db5ccb81a..808997f40 100644 --- a/tests/xtests/site/tests.py +++ b/tests/xtests/site/tests.py @@ -1,10 +1,11 @@ +from __future__ import absolute_import from django.http import HttpResponse from base import BaseTest from xadmin.sites import AdminSite from xadmin.views import BaseAdminView, BaseAdminPlugin, ModelAdminView, filter_hook -from models import ModelA +from .models import ModelA class ModelAAdmin(object): diff --git a/tests/xtests/view_base/adminx.py b/tests/xtests/view_base/adminx.py index 7db81e35f..b75fc8f8a 100644 --- a/tests/xtests/view_base/adminx.py +++ b/tests/xtests/view_base/adminx.py @@ -1,6 +1,7 @@ +from __future__ import absolute_import from xadmin.sites import AdminSite from xadmin.views import BaseAdminView, CommAdminView, ListAdminView -from models import ModelA, ModelB +from .models import ModelA, ModelB site = AdminSite('views_base') diff --git a/tests/xtests/view_base/tests.py b/tests/xtests/view_base/tests.py index a34da38cb..a779341f4 100644 --- a/tests/xtests/view_base/tests.py +++ b/tests/xtests/view_base/tests.py @@ -1,11 +1,12 @@ +from __future__ import absolute_import from django.contrib.auth.models import User from base import BaseTest from xadmin.views import BaseAdminView, BaseAdminPlugin, ModelAdminView, ListAdminView -from models import ModelA, ModelB -from adminx import site, ModelAAdmin, TestBaseView, TestCommView, TestAView, OptionA +from .models import ModelA, ModelB +from .adminx import site, ModelAAdmin, TestBaseView, TestCommView, TestAView, OptionA class BaseAdminTest(BaseTest): diff --git a/tests/xtests/view_base/urls.py b/tests/xtests/view_base/urls.py index 5f76a1c80..a6a3601ec 100644 --- a/tests/xtests/view_base/urls.py +++ b/tests/xtests/view_base/urls.py @@ -1,5 +1,6 @@ +from __future__ import absolute_import from django.conf.urls import patterns, include -from adminx import site +from .adminx import site urlpatterns = patterns('', (r'', include(site.urls)), diff --git a/xadmin/adminx.py b/xadmin/adminx.py index a22630107..e7a66e0ff 100644 --- a/xadmin/adminx.py +++ b/xadmin/adminx.py @@ -1,5 +1,6 @@ +from __future__ import absolute_import import xadmin -from models import UserSettings, Log +from .models import UserSettings, Log from xadmin.layout import * from django.utils.translation import ugettext_lazy as _, ugettext diff --git a/xadmin/filters.py b/xadmin/filters.py index 47af94f0a..b4da9b43c 100644 --- a/xadmin/filters.py +++ b/xadmin/filters.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.db import models from django.core.exceptions import ImproperlyConfigured from django.utils.encoding import smart_text @@ -17,7 +18,7 @@ FILTER_PREFIX = '_p_' SEARCH_VAR = '_q_' -from util import (get_model_from_relation, +from .util import (get_model_from_relation, reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value) diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 6b4cbb00c..845148c17 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -230,7 +230,7 @@ def get_response(self, response, context, *args, **kwargs): # View Methods def get_result_list(self, __): if self.request.GET.get('all', 'off') == 'on': - self.admin_view.list_per_page = sys.maxint + self.admin_view.list_per_page = sys.maxsize return __() def result_header(self, item, field_name, row): diff --git a/xadmin/plugins/filters.py b/xadmin/plugins/filters.py index 46a5903ec..21b0cf444 100644 --- a/xadmin/plugins/filters.py +++ b/xadmin/plugins/filters.py @@ -15,6 +15,7 @@ from xadmin.sites import site from xadmin.views import BaseAdminPlugin, ListAdminView from xadmin.util import is_related_field +from functools import reduce class IncorrectLookupParameters(Exception): @@ -128,7 +129,7 @@ def get_list_queryset(self, queryset): if spec and spec.has_output(): try: new_qs = spec.do_filte(queryset) - except ValidationError, e: + except ValidationError as e: new_qs = None self.admin_view.message_user(_("Filtering error: %s") % e.messages[0], 'error') if new_qs is not None: @@ -145,14 +146,14 @@ def get_list_queryset(self, queryset): for key, value in lookup_params.items(): use_distinct = ( use_distinct or lookup_needs_distinct(self.opts, key)) - except FieldDoesNotExist, e: + except FieldDoesNotExist as e: raise IncorrectLookupParameters(e) try: queryset = queryset.filter(**lookup_params) except (SuspiciousOperation, ImproperlyConfigured): raise - except Exception, e: + except Exception as e: raise IncorrectLookupParameters(e) query = self.request.GET.get(SEARCH_VAR, '') diff --git a/xadmin/plugins/quickfilter.py b/xadmin/plugins/quickfilter.py index b51a401e9..4b45fe97c 100644 --- a/xadmin/plugins/quickfilter.py +++ b/xadmin/plugins/quickfilter.py @@ -136,7 +136,7 @@ def get_list_queryset(self, queryset): if spec and spec.has_output(): try: new_qs = spec.do_filte(queryset) - except ValidationError, e: + except ValidationError as e: new_qs = None self.admin_view.message_user(_("Filtering error: %s") % e.messages[0], 'error') if new_qs is not None: diff --git a/xadmin/plugins/themes.py b/xadmin/plugins/themes.py index 534429f3a..cad5eaf38 100644 --- a/xadmin/plugins/themes.py +++ b/xadmin/plugins/themes.py @@ -1,4 +1,5 @@ #coding:utf-8 +from __future__ import print_function import urllib, httplib2 from django.template import loader from django.core.cache import cache @@ -68,8 +69,8 @@ def block_top_navmenu(self, context, nodes): {'name': t['name'], 'description': t['description'], 'css': t['cssMin'], 'thumbnail': t['thumbnail']} for t in watch_themes]) - except Exception, e: - print e + except Exception as e: + print(e) cache.set(THEME_CACHE_KEY, json.dumps(ex_themes), 24 * 3600) themes.extend(ex_themes) diff --git a/xadmin/util.py b/xadmin/util.py index 8e62634a3..bc4bbf519 100644 --- a/xadmin/util.py +++ b/xadmin/util.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys import django from django.db import models @@ -36,7 +37,7 @@ def xstatic(*tags): - from vendors import vendors + from .vendors import vendors node = vendors fs = [] @@ -46,7 +47,7 @@ def xstatic(*tags): try: for p in tag.split('.'): node = node[p] - except Exception, e: + except Exception as e: if tag.startswith('xadmin'): file_type = tag.split('.')[-1] if file_type in ('css', 'js'): @@ -191,7 +192,7 @@ def collect(self, objs, source_attr=None, **kwargs): self.add_edge(None, obj) try: return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) - except models.ProtectedError, e: + except models.ProtectedError as e: self.protected.update(e.protected_objects) def related_objects(self, related, objs): diff --git a/xadmin/views/__init__.py b/xadmin/views/__init__.py index c7db4ff58..9e21b9fc2 100644 --- a/xadmin/views/__init__.py +++ b/xadmin/views/__init__.py @@ -1,13 +1,14 @@ +from __future__ import absolute_import -from base import BaseAdminPlugin, BaseAdminView, CommAdminView, ModelAdminView, filter_hook, csrf_protect_m, BaseAdminObject +from .base import BaseAdminPlugin, BaseAdminView, CommAdminView, ModelAdminView, filter_hook, csrf_protect_m, BaseAdminObject -from list import ListAdminView -from edit import CreateAdminView, UpdateAdminView, ModelFormAdminView -from delete import DeleteAdminView -from detail import DetailAdminView -from form import FormAdminView -from dashboard import Dashboard, BaseWidget, widget_manager, ModelDashboard -from website import IndexView, LoginView, LogoutView, UserSettingView +from .list import ListAdminView +from .edit import CreateAdminView, UpdateAdminView, ModelFormAdminView +from .delete import DeleteAdminView +from .detail import DetailAdminView +from .form import FormAdminView +from .dashboard import Dashboard, BaseWidget, widget_manager, ModelDashboard +from .website import IndexView, LoginView, LogoutView, UserSettingView __all__ = ( 'BaseAdminObject', diff --git a/xadmin/views/dashboard.py b/xadmin/views/dashboard.py index bed4b3aa3..7aa9dafd5 100644 --- a/xadmin/views/dashboard.py +++ b/xadmin/views/dashboard.py @@ -558,7 +558,7 @@ def get_widgets(self): widget = user_widgets.get(int(wid)) if widget: ws.append(self.get_widget(widget)) - except Exception, e: + except Exception as e: import logging logging.error(e, exc_info=True) widgets.append(ws) diff --git a/xadmin/views/detail.py b/xadmin/views/detail.py index c0f881295..61b852c5f 100644 --- a/xadmin/views/detail.py +++ b/xadmin/views/detail.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy from crispy_forms.utils import TEMPLATE_PACK @@ -17,7 +18,7 @@ from xadmin.layout import FormHelper, Layout, Fieldset, Container, Column, Field, Col, TabHolder from xadmin.util import unquote, lookup_field, display_for_field, boolean_icon, label_for_field -from base import ModelAdminView, filter_hook, csrf_protect_m +from .base import ModelAdminView, filter_hook, csrf_protect_m # Text to display within change-list table cells if the value is blank. EMPTY_CHANGELIST_VALUE = _('Null') diff --git a/xadmin/views/edit.py b/xadmin/views/edit.py index eb87caff5..a840d5d05 100644 --- a/xadmin/views/edit.py +++ b/xadmin/views/edit.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy from crispy_forms.utils import TEMPLATE_PACK @@ -18,7 +19,7 @@ from xadmin.util import unquote from xadmin.views.detail import DetailAdminUtil -from base import ModelAdminView, filter_hook, csrf_protect_m +from .base import ModelAdminView, filter_hook, csrf_protect_m FORMFIELD_FOR_DBFIELD_DEFAULTS = { diff --git a/xadmin/views/form.py b/xadmin/views/form.py index 62002b997..86a6114c8 100644 --- a/xadmin/views/form.py +++ b/xadmin/views/form.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy from django import forms @@ -16,7 +17,7 @@ from xadmin.util import unquote from xadmin.views.detail import DetailAdminUtil -from base import CommAdminView, filter_hook, csrf_protect_m +from .base import CommAdminView, filter_hook, csrf_protect_m class FormAdminView(CommAdminView): form = forms.ModelForm diff --git a/xadmin/views/list.py b/xadmin/views/list.py index 2b224bc64..d18d56032 100644 --- a/xadmin/views/list.py +++ b/xadmin/views/list.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from collections import OrderedDict from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.paginator import InvalidPage, Paginator @@ -13,7 +14,7 @@ from xadmin.util import lookup_field, display_for_field, label_for_field, boolean_icon -from base import ModelAdminView, filter_hook, inclusion_tag, csrf_protect_m +from .base import ModelAdminView, filter_hook, inclusion_tag, csrf_protect_m # List settings ALL_VAR = 'all' diff --git a/xadmin/views/website.py b/xadmin/views/website.py index eb4bcf020..172b99d90 100644 --- a/xadmin/views/website.py +++ b/xadmin/views/website.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.utils.translation import ugettext as _ from django.contrib.auth import REDIRECT_FIELD_NAME from django.views.decorators.cache import never_cache @@ -5,8 +6,8 @@ from django.contrib.auth.views import logout from django.http import HttpResponse -from base import BaseAdminView, filter_hook -from dashboard import Dashboard +from .base import BaseAdminView, filter_hook +from .dashboard import Dashboard from xadmin.forms import AdminAuthenticationForm from xadmin.models import UserSettings from xadmin.layout import FormHelper diff --git a/xadmin/widgets.py b/xadmin/widgets.py index d3264243f..6636bfa55 100644 --- a/xadmin/widgets.py +++ b/xadmin/widgets.py @@ -1,6 +1,7 @@ """ Form Widget classes specific to the Django admin site. """ +from __future__ import absolute_import from itertools import chain from django import forms from django.forms.widgets import RadioFieldRenderer, RadioChoiceInput @@ -9,7 +10,7 @@ from django.utils.html import conditional_escape from django.utils.translation import ugettext as _ -from util import vendor +from .util import vendor class AdminDateWidget(forms.DateInput): From d801ac70a3a746955e08fe433e7cd70f1e127c40 Mon Sep 17 00:00:00 2001 From: wuyu Date: Tue, 11 Oct 2016 19:27:16 +0800 Subject: [PATCH 04/24] wait for modification --- xadmin/plugins/export.py | 8 ++++---- xadmin/sites.py | 3 ++- xadmin/views/base.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 845148c17..7ab1323b2 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -1,4 +1,4 @@ -import StringIO +import io import datetime import sys @@ -88,7 +88,7 @@ def _get_datas(self, context): def get_xlsx_export(self, context): datas = self._get_datas(context) - output = StringIO.StringIO() + output = io.StringIO() export_header = ( self.request.GET.get('export_xlsx_header', 'off') == 'on') @@ -125,7 +125,7 @@ def get_xlsx_export(self, context): def get_xls_export(self, context): datas = self._get_datas(context) - output = StringIO.StringIO() + output = io.StringIO() export_header = ( self.request.GET.get('export_xls_header', 'off') == 'on') @@ -197,7 +197,7 @@ def _to_xml(self, xml, data): def get_xml_export(self, context): results = self._get_objects(context) - stream = StringIO.StringIO() + stream = io.StringIO() xml = SimplerXMLGenerator(stream, "utf-8") xml.startDocument() diff --git a/xadmin/sites.py b/xadmin/sites.py index 9cbde739c..f4df49054 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -1,5 +1,6 @@ import sys from functools import update_wrapper +from future.utils import iteritems from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db.models.base import ModelBase @@ -308,7 +309,7 @@ def wrapper(*args, **kwargs): ] # Add in each model's views. - for model, admin_class in self._registry.iteritems(): + for model, admin_class in iteritems(self._registry): view_urls = [url( path, wrap( self.create_model_admin_view(clz, model, admin_class)), diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 4da64decc..631a4cde8 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -384,7 +384,7 @@ def get_url(menu, had_urls): for menu in nav_menu.values(): menu['menus'].sort(key=sortkeypicker(['order', 'title'])) - nav_menu = nav_menu.values() + nav_menu = list(nav_menu.values()) nav_menu.sort(key=lambda x: x['title']) site_menu.extend(nav_menu) From 0dfd836dab05470320cc613502f097364e6e7152 Mon Sep 17 00:00:00 2001 From: wy Date: Wed, 12 Oct 2016 21:38:25 +0800 Subject: [PATCH 05/24] fix error. --- error_info.txt | 11 +++++++++++ xadmin/plugins/export.py | 3 ++- xadmin/plugins/filters.py | 3 ++- xadmin/plugins/quickfilter.py | 3 ++- xadmin/views/base.py | 6 ++++-- 5 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 error_info.txt diff --git a/error_info.txt b/error_info.txt new file mode 100644 index 000000000..a847a238f --- /dev/null +++ b/error_info.txt @@ -0,0 +1,11 @@ +暂时无法解决的问题: + +1. 模板渲染时, 语言参数丢失. + ~/src/env/py3/lib/python3.4/site-packages/django/utils/translation/__init__.py + 临时解决办法: + 在get_language_info()中,增加2行: + def get_language_info(lang_code): + if not lang_code: + lang_code = 'en' + + diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 7ab1323b2..612469d7b 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -1,6 +1,7 @@ import io import datetime import sys +from future.utils import iteritems from django.http import HttpResponse from django.template import loader @@ -187,7 +188,7 @@ def _to_xml(self, xml, data): self._to_xml(xml, item) xml.endElement("row") elif isinstance(data, dict): - for key, value in data.iteritems(): + for key, value in iteritems(data): key = key.replace(' ', '_') xml.startElement(key, {}) self._to_xml(xml, value) diff --git a/xadmin/plugins/filters.py b/xadmin/plugins/filters.py index 21b0cf444..ff60d90c2 100644 --- a/xadmin/plugins/filters.py +++ b/xadmin/plugins/filters.py @@ -1,4 +1,5 @@ import operator +from future.utils import iteritems from xadmin import widgets from xadmin.plugins.utils import get_context_dict @@ -75,7 +76,7 @@ def lookup_allowed(self, lookup, value): def get_list_queryset(self, queryset): lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items() if smart_str(k).startswith(FILTER_PREFIX) and v != '']) - for p_key, p_val in lookup_params.iteritems(): + for p_key, p_val in iteritems(lookup_params): if p_val == "False": lookup_params[p_key] = False use_distinct = False diff --git a/xadmin/plugins/quickfilter.py b/xadmin/plugins/quickfilter.py index 4b45fe97c..e6caf6da8 100644 --- a/xadmin/plugins/quickfilter.py +++ b/xadmin/plugins/quickfilter.py @@ -3,6 +3,7 @@ @author: LAB_ADM ''' +from future.utils import iteritems from django.utils.translation import ugettext_lazy as _ from xadmin.filters import manager,MultiSelectFieldListFilter from xadmin.plugins.filters import * @@ -80,7 +81,7 @@ def lookup_allowed(self, lookup, value): def get_list_queryset(self, queryset): lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items() if smart_str(k).startswith(FILTER_PREFIX) and v != '']) - for p_key, p_val in lookup_params.iteritems(): + for p_key, p_val in iteritems(lookup_params): if p_val == "False": lookup_params[p_key] = False use_distinct = False diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 631a4cde8..c3cda64a1 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -153,8 +153,9 @@ def get_query_string(self, new_params=None, remove=None): if remove is None: remove = [] p = dict(self.request.GET.items()).copy() + arr_keys = list(p.keys()) for r in remove: - for k in p.keys(): + for k in arr_keys: if k.startswith(r): del p[k] for k, v in new_params.items(): @@ -171,8 +172,9 @@ def get_form_params(self, new_params=None, remove=None): if remove is None: remove = [] p = dict(self.request.GET.items()).copy() + arr_keys = list(p.keys()) for r in remove: - for k in p.keys(): + for k in arr_keys: if k.startswith(r): del p[k] for k, v in new_params.items(): From 37837866363a53620c3239561ba50e2338c050cb Mon Sep 17 00:00:00 2001 From: wy Date: Thu, 13 Oct 2016 07:53:24 +0800 Subject: [PATCH 06/24] =?UTF-8?q?=E4=BF=AE=E6=AD=A3tests/runtests.py?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- error_info.txt | 2 +- tests/runtests.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/error_info.txt b/error_info.txt index a847a238f..55804e31c 100644 --- a/error_info.txt +++ b/error_info.txt @@ -1,4 +1,4 @@ -暂时无法解决的问题: +xadmin for py3中, 暂时无法解决的问题: 1. 模板渲染时, 语言参数丢失. ~/src/env/py3/lib/python3.4/site-packages/django/utils/translation/__init__.py diff --git a/tests/runtests.py b/tests/runtests.py index 5bd6d5bf6..5f8677b25 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -34,9 +34,13 @@ def get_test_modules(): modules = [] for f in os.listdir(RUNTESTS_DIR): - if (f.startswith('__init__') or - f.startswith('.') or - f.startswith('sql') or not os.path.isdir(os.path.join(RUNTESTS_DIR, f))): + if ( + f.startswith('__init__') + or f.startswith('__pycache__') + or f.startswith('.') + or f.startswith('sql') + or not os.path.isdir(os.path.join(RUNTESTS_DIR, f)) + ): continue modules.append(f) return modules @@ -83,7 +87,6 @@ def setup(verbosity, test_labels): # Load all the test model apps. test_labels_set = set([label.split('.')[0] for label in test_labels]) test_modules = get_test_modules() - for module_name in test_modules: module_label = module_name # if the module was named on the command line, or From ddbb2a7f76099f544fc4d7c9fa9de70fa8b32be8 Mon Sep 17 00:00:00 2001 From: wy Date: Thu, 13 Oct 2016 08:04:26 +0800 Subject: [PATCH 07/24] deal with wait. --- error_info.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/error_info.txt b/error_info.txt index 55804e31c..a72f4c785 100644 --- a/error_info.txt +++ b/error_info.txt @@ -1,6 +1,6 @@ xadmin for py3中, 暂时无法解决的问题: -1. 模板渲染时, 语言参数丢失. +1. demo_app在渲染模板时, 语言参数丢失. ~/src/env/py3/lib/python3.4/site-packages/django/utils/translation/__init__.py 临时解决办法: 在get_language_info()中,增加2行: @@ -9,3 +9,14 @@ xadmin for py3中, 暂时无法解决的问题: lang_code = 'en' +2. demo_app中, + + File "/mnt/backup/data/src/code/Django/xadmin-wy/demo_app/../xadmin/filters.py", line 270, in __init__ + self.lookup_isnull_name: False +AttributeError: 'DateFieldListFilter' object has no attribute 'lookup_isnull_name' +[12/Oct/2016 18:54:52] "GET /app/accessrecord/chart/user_count/?_p_date__lt=2013-01-29&p=1&_p_date__gte=2013-01-08 HTTP/1.1" 500 15756 +[12/Oct/2016 18:54:52] "GET /favicon.ico HTTP/1.1" 404 6219 +^C(py3)u01@asus:~/src/env/py3/xadmin-wy/demo_app$ + + + From e9b95bca1088a8313c1d185e78a82a783b1f19fb Mon Sep 17 00:00:00 2001 From: wy Date: Sat, 15 Oct 2016 11:39:18 +0800 Subject: [PATCH 08/24] fix lang_code. --- error_info.txt | 11 ++--------- xadmin/plugins/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/error_info.txt b/error_info.txt index a72f4c785..5b88984de 100644 --- a/error_info.txt +++ b/error_info.txt @@ -1,14 +1,5 @@ xadmin for py3中, 暂时无法解决的问题: -1. demo_app在渲染模板时, 语言参数丢失. - ~/src/env/py3/lib/python3.4/site-packages/django/utils/translation/__init__.py - 临时解决办法: - 在get_language_info()中,增加2行: - def get_language_info(lang_code): - if not lang_code: - lang_code = 'en' - - 2. demo_app中, File "/mnt/backup/data/src/code/Django/xadmin-wy/demo_app/../xadmin/filters.py", line 270, in __init__ @@ -19,4 +10,6 @@ AttributeError: 'DateFieldListFilter' object has no attribute 'lookup_isnull_nam ^C(py3)u01@asus:~/src/env/py3/xadmin-wy/demo_app$ +3. 看到 xadmin-wy/xadmin/filters.py 的 DateFieldListFilter.__init__() + diff --git a/xadmin/plugins/utils.py b/xadmin/plugins/utils.py index 10df8daed..0b917c6fd 100644 --- a/xadmin/plugins/utils.py +++ b/xadmin/plugins/utils.py @@ -1,3 +1,4 @@ +import copy from django.template.context import RequestContext @@ -9,8 +10,7 @@ def get_context_dict(context): :return: dict """ if isinstance(context, RequestContext): - ctx = {} - map(ctx.update, context.dicts) + ctx = context.flatten() else: ctx = context return ctx From 990da9a7c3e5999e0c3d90d9a979ddabed3326df Mon Sep 17 00:00:00 2001 From: wy Date: Sat, 15 Oct 2016 22:59:55 +0800 Subject: [PATCH 09/24] =?UTF-8?q?=E9=99=A4=E5=B7=A6=E8=BE=B9=E6=A0=8F?= =?UTF-8?q?=E5=A4=96,=20=E5=9F=BA=E6=9C=AC=E6=B2=A1=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E4=BA=86.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- error_info.txt | 20 ++++++++------------ xadmin/filters.py | 21 +++++++++++++++------ xadmin/plugins/actions.py | 5 ++++- xadmin/plugins/filters.py | 17 +++++++++++++---- xadmin/plugins/quickfilter.py | 6 +++++- xadmin/views/base.py | 6 +++++- xadmin/views/list.py | 6 +++++- 7 files changed, 55 insertions(+), 26 deletions(-) diff --git a/error_info.txt b/error_info.txt index 5b88984de..bc5f98e78 100644 --- a/error_info.txt +++ b/error_info.txt @@ -1,15 +1,11 @@ xadmin for py3中, 暂时无法解决的问题: -2. demo_app中, - - File "/mnt/backup/data/src/code/Django/xadmin-wy/demo_app/../xadmin/filters.py", line 270, in __init__ - self.lookup_isnull_name: False -AttributeError: 'DateFieldListFilter' object has no attribute 'lookup_isnull_name' -[12/Oct/2016 18:54:52] "GET /app/accessrecord/chart/user_count/?_p_date__lt=2013-01-29&p=1&_p_date__gte=2013-01-08 HTTP/1.1" 500 15756 -[12/Oct/2016 18:54:52] "GET /favicon.ico HTTP/1.1" 404 6219 -^C(py3)u01@asus:~/src/env/py3/xadmin-wy/demo_app$ - - -3. 看到 xadmin-wy/xadmin/filters.py 的 DateFieldListFilter.__init__() - +3. 启动时报错. +xadmin/sites.py --> AdminSite.admin_view(): ... + view: + cacheable: False +the JSON object must be str, not 'bytes' +[15/Oct/2016 02:51:08] "GET / HTTP/1.1" 200 25380 + +4. 左边栏, 没有内容. diff --git a/xadmin/filters.py b/xadmin/filters.py index b4da9b43c..0c136cb76 100644 --- a/xadmin/filters.py +++ b/xadmin/filters.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +import sys from django.db import models from django.core.exceptions import ImproperlyConfigured from django.utils.encoding import smart_text @@ -46,8 +47,10 @@ def query_string(self, new_params=None, remove=None): return self.admin_view.get_query_string(new_params, remove) def form_params(self): - return self.admin_view.get_form_params( - remove=map(lambda k: FILTER_PREFIX + k, self.used_params.keys())) + arr = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) + if 2 < sys.version_info.major: + arr = list(arr) + return self.admin_view.get_form_params(remove=arr) def has_output(self): """ @@ -121,14 +124,20 @@ def __init__(self, field, request, params, model, admin_view, field_path): else: self.context_params["%s_val" % name] = '' - map(lambda kv: setattr( - self, 'lookup_' + kv[0], kv[1]), self.context_params.items()) + arr = map( + lambda kv: setattr(self, 'lookup_' + kv[0], kv[1]), + self.context_params.items() + ) + if 2 < sys.version_info.major: + list(arr) def get_context(self): context = super(FieldFilter, self).get_context() context.update(self.context_params) - context['remove_url'] = self.query_string( - {}, map(lambda k: FILTER_PREFIX + k, self.used_params.keys())) + obj = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) + if 2 < sys.version_info.major: + obj = list(obj) + context['remove_url'] = self.query_string({}, obj) return context def has_output(self): diff --git a/xadmin/plugins/actions.py b/xadmin/plugins/actions.py index fd8a2bf57..c16934159 100644 --- a/xadmin/plugins/actions.py +++ b/xadmin/plugins/actions.py @@ -1,3 +1,4 @@ +import sys from collections import OrderedDict from django import forms from django.core.exceptions import PermissionDenied @@ -227,6 +228,8 @@ def get_actions(self): # get_action might have returned None, so filter any of those out. actions = filter(None, actions) + if 2 < sys.version_info.major: + actions = list(actions) # Convert the actions into a OrderedDict keyed by name. actions = OrderedDict([ @@ -242,7 +245,7 @@ def get_action_choices(self): tuple (name, description). """ choices = [] - for ac, name, description, icon in self.actions.itervalues(): + for ac, name, description, icon in self.actions.values(): choice = (name, description % model_format_dict(self.opts), icon) choices.append(choice) return choices diff --git a/xadmin/plugins/filters.py b/xadmin/plugins/filters.py index ff60d90c2..ae01d8955 100644 --- a/xadmin/plugins/filters.py +++ b/xadmin/plugins/filters.py @@ -1,4 +1,5 @@ import operator +import sys from future.utils import iteritems from xadmin import widgets from xadmin.plugins.utils import get_context_dict @@ -140,8 +141,10 @@ def get_list_queryset(self, queryset): self.has_filters = bool(self.filter_specs) self.admin_view.filter_specs = self.filter_specs - self.admin_view.used_filter_num = len( - filter(lambda f: f.is_used, self.filter_specs)) + obj = filter(lambda f: f.is_used, self.filter_specs) + if 2 < sys.version_info.major: + obj = list(obj) + self.admin_view.used_filter_num = len(obj) try: for key, value in lookup_params.items(): @@ -191,10 +194,16 @@ def construct_search(field_name): # Media def get_media(self, media): - if bool(filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs)): + arr = filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs) + if 2 < sys.version_info.major: + arr = list(arr) + if bool(arr): media = media + self.vendor('datepicker.css', 'datepicker.js', 'xadmin.widget.datetime.js') - if bool(filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs)): + arr = filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs) + if 2 < sys.version_info.major: + arr = list(arr) + if bool(arr): media = media + self.vendor( 'select.js', 'select.css', 'xadmin.widget.select.js') return media + self.vendor('xadmin.plugin.filters.js') diff --git a/xadmin/plugins/quickfilter.py b/xadmin/plugins/quickfilter.py index e6caf6da8..cae51c463 100644 --- a/xadmin/plugins/quickfilter.py +++ b/xadmin/plugins/quickfilter.py @@ -3,6 +3,7 @@ @author: LAB_ADM ''' +import sys from future.utils import iteritems from django.utils.translation import ugettext_lazy as _ from xadmin.filters import manager,MultiSelectFieldListFilter @@ -147,7 +148,10 @@ def get_list_queryset(self, queryset): self.has_filters = bool(self.filter_specs) self.admin_view.quickfilter['filter_specs'] = self.filter_specs - self.admin_view.quickfilter['used_filter_num'] = len(filter(lambda f: f.is_used, self.filter_specs)) + obj = filter(lambda f: f.is_used, self.filter_specs) + if 2 < sys.version_info.major: + obj = list(obj) + self.admin_view.quickfilter['used_filter_num'] = len(obj) if use_distinct: return queryset.distinct() diff --git a/xadmin/views/base.py b/xadmin/views/base.py index c3cda64a1..1f89fa1a4 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -86,9 +86,13 @@ def wrap(func): def method(self, context, nodes, *arg, **kwargs): _dict = func(self, context, nodes, *arg, **kwargs) from django.template.loader import get_template, select_template + if 2 < sys.version_info.major: + cls_string = str + else: + cls_string = basestring if isinstance(file_name, Template): t = file_name - elif not isinstance(file_name, basestring) and is_iterable(file_name): + elif not isinstance(file_name, cls_string) and is_iterable(file_name): t = select_template(file_name) else: t = get_template(file_name) diff --git a/xadmin/views/list.py b/xadmin/views/list.py index d18d56032..203aae1a2 100644 --- a/xadmin/views/list.py +++ b/xadmin/views/list.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +import sys from collections import OrderedDict from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.paginator import InvalidPage, Paginator @@ -460,7 +461,10 @@ def result_header(self, field_name, row): if field_name in ordering_field_columns: sorted = True order_type = ordering_field_columns.get(field_name).lower() - sort_priority = ordering_field_columns.keys().index(field_name) + 1 + arr = ordering_field_columns.keys() + if 2 < sys.version_info.major: + arr = list(arr) + sort_priority = arr.index(field_name) + 1 th_classes.append('sorted %sending' % order_type) new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] From d610e06cbe5aa8271126de12a7f2332abefab519 Mon Sep 17 00:00:00 2001 From: wy Date: Sun, 16 Oct 2016 21:52:38 +0800 Subject: [PATCH 10/24] fix JSON error. --- error_info.txt | 8 +------- xadmin/plugins/themes.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/error_info.txt b/error_info.txt index bc5f98e78..f6484c646 100644 --- a/error_info.txt +++ b/error_info.txt @@ -1,11 +1,5 @@ xadmin for py3中, 暂时无法解决的问题: -3. 启动时报错. -xadmin/sites.py --> AdminSite.admin_view(): ... - view: - cacheable: False -the JSON object must be str, not 'bytes' -[15/Oct/2016 02:51:08] "GET / HTTP/1.1" 200 25380 - 4. 左边栏, 没有内容. + diff --git a/xadmin/plugins/themes.py b/xadmin/plugins/themes.py index cad5eaf38..6ab202eef 100644 --- a/xadmin/plugins/themes.py +++ b/xadmin/plugins/themes.py @@ -1,5 +1,6 @@ #coding:utf-8 from __future__ import print_function +import sys import urllib, httplib2 from django.template import loader from django.core.cache import cache @@ -45,10 +46,10 @@ def get_media(self, media): # Block Views def block_top_navmenu(self, context, nodes): - themes = [{'name': _(u"Default"), 'description': _( - u"Default bootstrap theme"), 'css': self.default_theme}, - {'name': _(u"Bootstrap2"), 'description': _(u"Bootstrap 2.x theme"), - 'css': self.bootstrap2_theme}] + themes = [ + {'name': _(u"Default"), 'description': _(u"Default bootstrap theme"), 'css': self.default_theme}, + {'name': _(u"Bootstrap2"), 'description': _(u"Bootstrap 2.x theme"), 'css': self.bootstrap2_theme}, + ] select_css = context.get('site_theme', self.default_theme) if self.user_themes: @@ -62,8 +63,10 @@ def block_top_navmenu(self, context, nodes): ex_themes = [] try: h = httplib2.Http() - resp, content = h.request("http://bootswatch.com/api/3.json", 'GET', \ - "", headers={"Accept": "application/json", "User-Agent": self.request.META['HTTP_USER_AGENT']}) + resp, content = h.request("http://bootswatch.com/api/3.json", 'GET', '', + headers={"Accept": "application/json", "User-Agent": self.request.META['HTTP_USER_AGENT']}) + if 2 < sys.version_info.major: + content = content.decode() watch_themes = json.loads(content)['themes'] ex_themes.extend([ {'name': t['name'], 'description': t['description'], From 37bd1ff7457e8dae194c457b0a095e869a07c011 Mon Sep 17 00:00:00 2001 From: wuyu Date: Mon, 17 Oct 2016 10:44:49 +0800 Subject: [PATCH 11/24] fix JSONEncoder.default() --- xadmin/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xadmin/models.py b/xadmin/models.py index d880c82e6..da5145641 100644 --- a/xadmin/models.py +++ b/xadmin/models.py @@ -67,10 +67,10 @@ class Meta: class JSONEncoder(DjangoJSONEncoder): def default(self, o): - if isinstance(o, datetime.date): - return o.strftime('%Y-%m-%d') - elif isinstance(o, datetime.datetime): + if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %H:%M:%S') + elif isinstance(o, datetime.date): + return o.strftime('%Y-%m-%d') elif isinstance(o, decimal.Decimal): return str(o) elif isinstance(o, ModelBase): From 0681d4109d42145643fbb78b757d207168aa0f75 Mon Sep 17 00:00:00 2001 From: wy Date: Tue, 18 Oct 2016 21:09:48 +0800 Subject: [PATCH 12/24] =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=B7=A6=E8=BE=B9=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- error_info.txt | 5 ----- xadmin/sites.py | 31 ++++++++++++++++++++----------- xadmin/views/base.py | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) delete mode 100644 error_info.txt diff --git a/.gitignore b/.gitignore index 68a5de545..bae85af2f 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ xadmin/static/xadmin/bower_components/ *~ demo_app/data.db -TAGS +TAGS* +*.swp diff --git a/error_info.txt b/error_info.txt deleted file mode 100644 index f6484c646..000000000 --- a/error_info.txt +++ /dev/null @@ -1,5 +0,0 @@ -xadmin for py3中, 暂时无法解决的问题: - -4. 左边栏, 没有内容. - - diff --git a/xadmin/sites.py b/xadmin/sites.py index f4df49054..820a0ef0e 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -298,26 +298,35 @@ def wrapper(*args, **kwargs): # Admin-site-wide views. urlpatterns = [ url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n') - ] + ] # Registed admin views # inspect[isclass]: Only checks if the object is a class. With it lets you create an custom view that # inherits from multiple views and have more of a metaclass. urlpatterns += [ - url(path, wrap(self.create_admin_view(clz_or_func)) if inspect.isclass(clz_or_func) and issubclass(clz_or_func, BaseAdminView) else include(clz_or_func(self)), - name=name) for path, clz_or_func, name in self._registry_views - ] + url( + path, + wrap(self.create_admin_view(clz_or_func)) + if inspect.isclass(clz_or_func) and issubclass(clz_or_func, BaseAdminView) + else include(clz_or_func(self)), + name=name + ) + for path, clz_or_func, name in self._registry_views + ] # Add in each model's views. for model, admin_class in iteritems(self._registry): - view_urls = [url( - path, wrap( - self.create_model_admin_view(clz, model, admin_class)), - name=name % (model._meta.app_label, model._meta.model_name)) - for path, clz, name in self._registry_modelviews] + view_urls = [ + url( + path, + wrap(self.create_model_admin_view(clz, model, admin_class)), + name=name % (model._meta.app_label, model._meta.model_name) + ) + for path, clz, name in self._registry_modelviews + ] urlpatterns += [ - url(r'^%s/%s/' % ( model._meta.app_label, model._meta.model_name), include(view_urls)) - ] + url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(view_urls)) + ] return urlpatterns diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 1f89fa1a4..6c34eace1 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -428,7 +428,7 @@ def filter_item(item): return item nav_menu = [filter_item(item) for item in menus if check_menu_permission(item)] - nav_menu = filter(lambda x:x, nav_menu) + nav_menu = list(filter(lambda x:x, nav_menu)) if not settings.DEBUG: self.request.session['nav_menu'] = json.dumps(nav_menu) From 5293238859b5c15adccba9b063c70742b7dfceba Mon Sep 17 00:00:00 2001 From: wy Date: Tue, 18 Oct 2016 21:15:08 +0800 Subject: [PATCH 13/24] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E7=BE=8E=E5=8C=96.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo_app/demo/settings.py | 18 ++++++++++++------ xadmin/filters.py | 40 ++++++++++++++++++++++++--------------- xadmin/plugins/utils.py | 1 - xadmin/sites.py | 2 ++ 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/demo_app/demo/settings.py b/demo_app/demo/settings.py index 916d0b8f9..ab477e486 100644 --- a/demo_app/demo/settings.py +++ b/demo_app/demo/settings.py @@ -8,10 +8,11 @@ imp.reload(sys) sys.setdefaultencoding('utf-8') -gettext = lambda s: s +from django.utils.translation import ugettext_lazy as _ PROJECT_ROOT = os.path.join( os.path.realpath(os.path.dirname(__file__)), os.pardir) +# PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DEBUG = True @@ -33,7 +34,7 @@ } # Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = '*' +ALLOWED_HOSTS = ['*'] # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name @@ -46,8 +47,8 @@ LANGUAGE_CODE = 'en-us' LANGUAGES = ( - ('en', gettext('English')), - ('zh-hans', gettext('Chinese')), + ('en', _('English')), + ('zh-hans', _('Chinese')), ) SITE_ID = 1 @@ -101,10 +102,12 @@ SECRET_KEY = '5=!nss_+^nvyyc_j(tdcf!7(_una*3gtw+_8v5jaa=)j0g^d_2' MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', + 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.locale.LocaleMiddleware', # Uncomment the next line for simple clickjacking protection: @@ -126,12 +129,15 @@ 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], - 'debug':DEBUG + 'debug': DEBUG, }, }, ] diff --git a/xadmin/filters.py b/xadmin/filters.py index 0c136cb76..ebe0c5cb3 100644 --- a/xadmin/filters.py +++ b/xadmin/filters.py @@ -168,22 +168,28 @@ def choices(self): for lookup, title in ( ('', _('All')), ('1', _('Yes')), - ('0', _('No'))): + ('0', _('No')), + ): yield { - 'selected': self.lookup_exact_val == lookup and not self.lookup_isnull_val, - 'query_string': self.query_string({ - self.lookup_exact_name: lookup, - }, [self.lookup_isnull_name]), - 'display': title, - } + 'selected': ( + self.lookup_exact_val == lookup + and not self.lookup_isnull_val + ), + 'query_string': self.query_string( + {self.lookup_exact_name: lookup}, + [self.lookup_isnull_name], + ), + 'display': title, + } if isinstance(self.field, models.NullBooleanField): yield { - 'selected': self.lookup_isnull_val == 'True', - 'query_string': self.query_string({ - self.lookup_isnull_name: 'True', - }, [self.lookup_exact_name]), - 'display': _('Unknown'), - } + 'selected': self.lookup_isnull_val == 'True', + 'query_string': self.query_string( + {self.lookup_isnull_name: 'True'}, + [self.lookup_exact_name], + ), + 'display': _('Unknown'), + } @manager.register @@ -211,11 +217,15 @@ def choices(self): @manager.register class TextFieldListFilter(FieldFilter): template = 'xadmin/filters/char.html' - lookup_formats = {'in': '%s__in','search': '%s__contains'} + lookup_formats = {'in': '%s__in', 'search': '%s__contains'} @classmethod def test(cls, field, request, params, model, admin_view, field_path): - return (isinstance(field, models.CharField) and field.max_length > 20) or isinstance(field, models.TextField) + return ( + isinstance(field, models.CharField) + and field.max_length > 20 + or isinstance(field, models.TextField) + ) @manager.register diff --git a/xadmin/plugins/utils.py b/xadmin/plugins/utils.py index 0b917c6fd..6bc7e7915 100644 --- a/xadmin/plugins/utils.py +++ b/xadmin/plugins/utils.py @@ -1,4 +1,3 @@ -import copy from django.template.context import RequestContext diff --git a/xadmin/sites.py b/xadmin/sites.py index 820a0ef0e..c6eee43de 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -198,6 +198,8 @@ def get_urls(self): cacheable=True. """ def inner(request, *args, **kwargs): + # print('xadmin/sites.py --> AdminSite.inner(): ...') + # print(u'\targs: {}\n\tkwargs: {}'.format(args, kwargs)) if not self.has_permission(request) and getattr(view, 'need_site_permission', True): return self.create_admin_view(self.login_view)(request, *args, **kwargs) return view(request, *args, **kwargs) From 8017ed2dd086fa7d97a6b35ffcd958514ece399f Mon Sep 17 00:00:00 2001 From: wy Date: Tue, 18 Oct 2016 22:18:12 +0800 Subject: [PATCH 14/24] fix --- xadmin/plugins/bookmark.py | 35 ++++++++++++++++++++++++++--------- xadmin/plugins/export.py | 3 ++- xadmin/plugins/inline.py | 4 +++- xadmin/plugins/relate.py | 7 +++++-- xadmin/plugins/xversion.py | 4 +++- xadmin/util.py | 6 ++++-- xadmin/views/base.py | 7 ++----- xadmin/views/delete.py | 9 +++++---- xadmin/views/detail.py | 11 ++++++++--- xadmin/views/edit.py | 9 +++++++-- xadmin/views/form.py | 4 +++- xadmin/views/list.py | 13 ++++++++----- 12 files changed, 76 insertions(+), 36 deletions(-) diff --git a/xadmin/plugins/bookmark.py b/xadmin/plugins/bookmark.py index aefbc5b64..3d612cec8 100644 --- a/xadmin/plugins/bookmark.py +++ b/xadmin/plugins/bookmark.py @@ -42,9 +42,17 @@ def get_context(self, context): bookmarks = [] - current_qs = '&'.join(['%s=%s' % (k, v) for k, v in sorted( - filter(lambda i: bool(i[1] and (i[0] in (COL_LIST_VAR, ORDER_VAR, SEARCH_VAR) or i[0].startswith(FILTER_PREFIX) - or i[0].startswith(RELATE_PREFIX))), self.request.GET.items()))]) + current_qs = '&'.join([ + '%s=%s' % (k, v) + for k, v in sorted(filter( + lambda i: bool(i[1] and ( + i[0] in (COL_LIST_VAR, ORDER_VAR, SEARCH_VAR) + or i[0].startswith(FILTER_PREFIX) + or i[0].startswith(RELATE_PREFIX) + )), + self.request.GET.items() + )) + ]) model_info = (self.opts.app_label, self.opts.model_name) has_selected = False @@ -55,8 +63,10 @@ def get_context(self, context): # local bookmarks for bk in self.list_bookmarks: title = bk['title'] - params = dict( - [(FILTER_PREFIX + k, v) for (k, v) in bk['query'].items()]) + params = dict([ + (FILTER_PREFIX + k, v) + for (k, v) in bk['query'].items() + ]) if 'order' in bk: params[ORDER_VAR] = '.'.join(bk['order']) if 'cols' in bk: @@ -65,7 +75,10 @@ def get_context(self, context): params[SEARCH_VAR] = bk['search'] def check_item(i): return bool(i[1]) or i[1] == False - bk_qs = '&'.join(['%s=%s' % (k, v) for k, v in sorted(filter(check_item, params.items()))]) + bk_qs = '&'.join([ + '%s=%s' % (k, v) + for k, v in sorted(filter(check_item, params.items())) + ]) url = list_base_url + '?' + bk_qs selected = (current_qs == bk_qs) @@ -208,9 +221,13 @@ def context(self, context): context['result_headers'] = [c for c in list_view.result_headers( ).cells if c.field_name in base_fields] - context['results'] = [[o for i, o in - enumerate(filter(lambda c:c.field_name in base_fields, r.cells))] - for r in list_view.results()] + context['results'] = [ + [o for i, o in enumerate(filter( + lambda c: c.field_name in base_fields, + r.cells + ))] + for r in list_view.results() + ] context['result_count'] = list_view.result_count context['page_url'] = self.bookmark.url diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 612469d7b..09be6cba8 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -165,7 +165,8 @@ def _format_csv_text(self, t): if isinstance(t, bool): return _('Yes') if t else _('No') t = t.replace('"', '""').replace(',', '\,') - if isinstance(t, basestring): + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(t, cls_str): t = '"%s"' % t return t diff --git a/xadmin/plugins/inline.py b/xadmin/plugins/inline.py index c85b5dc50..a307a9d63 100644 --- a/xadmin/plugins/inline.py +++ b/xadmin/plugins/inline.py @@ -1,5 +1,6 @@ import copy import inspect +import sys from django import forms from django.forms.formsets import all_valid, DELETION_FIELD_NAME from django.forms.models import inlineformset_factory, BaseInlineFormSet, modelform_defines_fields @@ -114,10 +115,11 @@ def get_attrs(self): def replace_field_to_value(layout, av): if layout: + cls_str = str if 2 < sys.version_info.major else basestring for i, lo in enumerate(layout.fields): if isinstance(lo, Field) or issubclass(lo.__class__, Field): layout.fields[i] = ShowField(av, *lo.fields, **lo.attrs) - elif isinstance(lo, basestring): + elif isinstance(lo, cls_str): layout.fields[i] = ShowField(av, lo) elif hasattr(lo, 'get_field_names'): replace_field_to_value(lo, av) diff --git a/xadmin/plugins/relate.py b/xadmin/plugins/relate.py index 2475b9c9f..ac622089b 100644 --- a/xadmin/plugins/relate.py +++ b/xadmin/plugins/relate.py @@ -1,4 +1,5 @@ # coding=UTF-8 +import sys from itertools import chain from django.core.urlresolvers import reverse @@ -206,7 +207,8 @@ def get_form_datas(self, datas): return datas def post_response(self, response): - if isinstance(response, basestring) and response != self.get_admin_url('index'): + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(response, cls_str) and response != self.get_admin_url('index'): return self._get_url(response) return response @@ -222,7 +224,8 @@ def block_after_fieldsets(self, context, nodes): class DeleteRelateDisplayPlugin(BaseRelateDisplayPlugin): def post_response(self, response): - if isinstance(response, basestring) and response != self.get_admin_url('index'): + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(response, cls_str) and response != self.get_admin_url('index'): return self._get_url(response) return response diff --git a/xadmin/plugins/xversion.py b/xadmin/plugins/xversion.py index ebe7118ea..cd1c9e58c 100644 --- a/xadmin/plugins/xversion.py +++ b/xadmin/plugins/xversion.py @@ -1,3 +1,4 @@ +import sys from crispy_forms.utils import TEMPLATE_PACK from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.models import ContentType @@ -563,7 +564,8 @@ def total_form_count_hack(count): if self.request.method == 'GET' and formset.helper and formset.helper.layout: helper = formset.helper - helper.filter(basestring).wrap(InlineDiffField) + cls_str = str if 2 < sys.version_info.major else basestring + helper.filter(cls_str).wrap(InlineDiffField) fake_admin_class = type(str('%s%sFakeAdmin' % (self.opts.app_label, self.opts.model_name)), (object, ), {'model': self.model}) for form in formset.forms: instance = form.instance diff --git a/xadmin/util.py b/xadmin/util.py index bc4bbf519..41542b7f2 100644 --- a/xadmin/util.py +++ b/xadmin/util.py @@ -129,7 +129,8 @@ def quote(s): quoting is slightly different so that it doesn't get automatically unquoted by the Web browser. """ - if not isinstance(s, basestring): + cls_str = str if 2 < sys.version_info.major else basestring + if not isinstance(s, cls_str): return s res = list(s) for i in range(len(res)): @@ -143,7 +144,8 @@ def unquote(s): """ Undo the effects of quote(). Based heavily on urllib.unquote(). """ - if not isinstance(s, basestring): + cls_str = str if 2 < sys.version_info.major else basestring + if not isinstance(s, cls_str): return s mychr = chr myatoi = int diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 6c34eace1..94b98535c 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -86,13 +86,10 @@ def wrap(func): def method(self, context, nodes, *arg, **kwargs): _dict = func(self, context, nodes, *arg, **kwargs) from django.template.loader import get_template, select_template - if 2 < sys.version_info.major: - cls_string = str - else: - cls_string = basestring + cls_str = str if 2 < sys.version_info.major else basestring if isinstance(file_name, Template): t = file_name - elif not isinstance(file_name, cls_string) and is_iterable(file_name): + elif not isinstance(file_name, cls_str) and is_iterable(file_name): t = select_template(file_name) else: t = get_template(file_name) diff --git a/xadmin/views/delete.py b/xadmin/views/delete.py index 42e79b76c..ffd2d9e0c 100644 --- a/xadmin/views/delete.py +++ b/xadmin/views/delete.py @@ -1,3 +1,4 @@ +import sys from django.core.exceptions import PermissionDenied from django.db import transaction, router from django.http import Http404, HttpResponseRedirect @@ -51,10 +52,10 @@ def post(self, request, object_id): self.delete_model() response = self.post_response() - if isinstance(response, basestring): - return HttpResponseRedirect(response) - else: - return response + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(response, cls_str): + response = HttpResponseRedirect(response) + return response @filter_hook def delete_model(self): diff --git a/xadmin/views/detail.py b/xadmin/views/detail.py index 61b852c5f..fc5603ae2 100644 --- a/xadmin/views/detail.py +++ b/xadmin/views/detail.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import copy +import sys from crispy_forms.utils import TEMPLATE_PACK from django import forms @@ -118,10 +119,14 @@ def val(self): def replace_field_to_value(layout, cb): for i, lo in enumerate(layout.fields): + if sys.version_info.major < 3: + cls_str = basestring + else: + cls_str = str if isinstance(lo, Field) or issubclass(lo.__class__, Field): layout.fields[i] = ShowField( cb, *lo.fields, attrs=lo.attrs, wrapper_class=lo.wrapper_class) - elif isinstance(lo, basestring): + elif sys.version_info.major < 3 and isinstance(lo, cls_str): layout.fields[i] = ShowField(cb, lo) elif hasattr(lo, 'get_field_names'): replace_field_to_value(lo, cb) @@ -215,8 +220,8 @@ def get_form_helper(self): layout = self.get_form_layout() replace_field_to_value(layout, self.get_field_result) helper.add_layout(layout) - helper.filter( - basestring, max_level=20).wrap(ShowField, admin_view=self) + cls_str = str if 2 < sys.version_info.major else basestring + helper.filter(cls_str, max_level=20).wrap(ShowField, admin_view=self) return helper @csrf_protect_m diff --git a/xadmin/views/edit.py b/xadmin/views/edit.py index a840d5d05..cd2cb079f 100644 --- a/xadmin/views/edit.py +++ b/xadmin/views/edit.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import copy +import sys from crispy_forms.utils import TEMPLATE_PACK from django import forms @@ -191,7 +192,10 @@ def get_model_form(self, **kwargs): @filter_hook def get_form_layout(self): layout = copy.deepcopy(self.form_layout) - fields = self.form_obj.fields.keys() + list(self.get_readonly_fields()) + arr = self.form_obj.fields.keys() + if 2 < sys.version_info.major: + arr = [k for k in arr] + fields = arr + list(self.get_readonly_fields()) if layout is None: layout = Layout(Container(Col('full', @@ -288,7 +292,8 @@ def post(self, request, *args, **kwargs): self.save_models() self.save_related() response = self.post_response() - if isinstance(response, basestring): + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(response, cls_str): return HttpResponseRedirect(response) else: return response diff --git a/xadmin/views/form.py b/xadmin/views/form.py index 86a6114c8..381a47c69 100644 --- a/xadmin/views/form.py +++ b/xadmin/views/form.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import copy +import sys from django import forms from django.contrib.contenttypes.models import ContentType @@ -111,7 +112,8 @@ def post(self, request, *args, **kwargs): if self.valid_forms(): self.save_forms() response = self.post_response() - if isinstance(response, basestring): + cls_str = str if 2 < sys.version_info.major else basestring + if isinstance(response, cls_str): return HttpResponseRedirect(response) else: return response diff --git a/xadmin/views/list.py b/xadmin/views/list.py index 203aae1a2..1804730b7 100644 --- a/xadmin/views/list.py +++ b/xadmin/views/list.py @@ -293,11 +293,14 @@ def get_ordering(self): or self._get_default_ordering()) if ORDER_VAR in self.params and self.params[ORDER_VAR]: # Clear ordering and used params - ordering = [pfx + self.get_ordering_field(field_name) for n, pfx, field_name in - map( - lambda p: p.rpartition('-'), - self.params[ORDER_VAR].split('.')) - if self.get_ordering_field(field_name)] + ordering = [ + pfx + self.get_ordering_field(field_name) + for n, pfx, field_name in map( + lambda p: p.rpartition('-'), + self.params[ORDER_VAR].split('.') + ) + if self.get_ordering_field(field_name) + ] # Ensure that the primary key is systematically present in the list of # ordering fields so we can guarantee a deterministic order across all From 4a576f5a07a94ad0951ed651c09f46413f290723 Mon Sep 17 00:00:00 2001 From: wuyu Date: Mon, 24 Oct 2016 11:30:35 +0800 Subject: [PATCH 15/24] add dependency package: future. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index d49b05b72..d04df08a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ django~=1.9.0 django-crispy-forms~=1.6.0 django-reversion~=2.0.0 django-formtools==1.0 +future==0.15.2 httplib2==0.9.2 From fcfc167d862572292e7186467b719d571c66e4a8 Mon Sep 17 00:00:00 2001 From: wy Date: Mon, 24 Oct 2016 11:35:08 +0800 Subject: [PATCH 16/24] add dependency package: future. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index d49b05b72..d04df08a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ django~=1.9.0 django-crispy-forms~=1.6.0 django-reversion~=2.0.0 django-formtools==1.0 +future==0.15.2 httplib2==0.9.2 From 38a4720608a1f7883bc2e533cc2ba498a311f8dc Mon Sep 17 00:00:00 2001 From: wy Date: Wed, 26 Oct 2016 20:36:30 +0800 Subject: [PATCH 17/24] fix /xadmin/userwidget/add/ --- xadmin/plugins/wizard.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/xadmin/plugins/wizard.py b/xadmin/plugins/wizard.py index b2cb49337..940c77f71 100644 --- a/xadmin/plugins/wizard.py +++ b/xadmin/plugins/wizard.py @@ -1,4 +1,5 @@ import re +import sys from collections import OrderedDict from django import forms from django.db import models @@ -42,7 +43,10 @@ class WizardFormPlugin(BaseAdminPlugin): def _get_form_prefix(self, step=None): if step is None: step = self.steps.current - return 'step_%d' % self.get_form_list().keys().index(step) + obj = self.get_form_list().keys() + if 2 < sys.version_info.major: + obj = [s for s in obj] + return 'step_%d' % obj.index(step) def get_form_list(self): if not hasattr(self, '_form_list'): @@ -85,8 +89,10 @@ def prepare_form(self, __): # form. (This makes stepping back a lot easier). wizard_goto_step = self.request.POST.get('wizard_goto_step', None) if wizard_goto_step and int(wizard_goto_step) < len(self.get_form_list()): - self.storage.current_step = self.get_form_list( - ).keys()[int(wizard_goto_step)] + obj = self.get_form_list().keys() + if 2 < sys.version_info.major: + obj = [s for s in obj] + self.storage.current_step = obj[int(wizard_goto_step)] self.admin_view.model_form = self.get_step_form() self.wizard_goto_step = True return @@ -280,10 +286,12 @@ def get_next_step(self, step=None): """ if step is None: step = self.steps.current - form_list = self.get_form_list() - key = form_list.keys().index(step) + 1 - if len(form_list.keys()) > key: - return form_list.keys()[key] + obj = self.get_form_list().keys() + if 2 < sys.version_info.major: + obj = [s for s in obj] + key = obj.index(step) + 1 + if len(obj) > key: + return obj[key] return None def get_prev_step(self, step=None): @@ -294,10 +302,12 @@ def get_prev_step(self, step=None): """ if step is None: step = self.steps.current - form_list = self.get_form_list() - key = form_list.keys().index(step) - 1 + obj = self.get_form_list().keys() + if 2 < sys.version_info.major: + obj = [s for s in obj] + key = obj.index(step) - 1 if key >= 0: - return form_list.keys()[key] + return obj[key] return None def get_step_index(self, step=None): @@ -307,7 +317,10 @@ def get_step_index(self, step=None): """ if step is None: step = self.steps.current - return self.get_form_list().keys().index(step) + obj = self.get_form_list().keys() + if 2 < sys.version_info.major: + obj = [s for s in obj] + return obj.index(step) def block_before_fieldsets(self, context, nodes): context.update(dict(self.storage.extra_data)) From 13b73e9710518ad32a0e4d1da3a13682dc88b473 Mon Sep 17 00:00:00 2001 From: wuyu Date: Fri, 28 Oct 2016 09:36:35 +0800 Subject: [PATCH 18/24] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E7=BE=8E=E5=8C=96=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo_app/app/adminx.py | 187 +++++++++++++++++++++++------------------ xadmin/sites.py | 2 - 2 files changed, 106 insertions(+), 83 deletions(-) diff --git a/demo_app/app/adminx.py b/demo_app/app/adminx.py index 7048f886b..43109d25b 100644 --- a/demo_app/app/adminx.py +++ b/demo_app/app/adminx.py @@ -10,12 +10,11 @@ class MainDashboard(object): widgets = [ [ {"type": "html", "title": "Test Widget", "content": "

    Welcome to Xadmin!

    Join Online Group:
    QQ Qun : 282936295

    "}, - {"type": "chart", "model": "app.accessrecord", 'chart': 'user_count', 'params': {'_p_date__gte': '2013-01-08', 'p': 1, '_p_date__lt': '2013-01-29'}}, - {"type": "list", "model": "app.host", 'params': { - 'o':'-guarantee_date'}}, + {"type": "chart", "model": "app.accessrecord", "chart": "user_count", "params": {"_p_date__gte": "2013-01-08", "p": 1, "_p_date__lt": "2013-01-29"}}, + {"type": "list", "model": "app.host", "params": {"o":"-guarantee_date"}}, ], [ - {"type": "qbutton", "title": "Quick Start", "btns": [{'model': Host}, {'model':IDC}, {'title': "Google", 'url': "http://www.google.com"}]}, + {"type": "qbutton", "title": "Quick Start", "btns": [{"model": Host}, {"model":IDC}, {"title": "Google", "url": "http://www.google.com"}]}, {"type": "addform", "model": MaintainLog}, ] ] @@ -31,134 +30,160 @@ class BaseSetting(object): class GlobalSetting(object): global_search_models = [Host, IDC] global_models_icon = { - Host: 'fa fa-laptop', IDC: 'fa fa-cloud' + Host: "fa fa-laptop", IDC: "fa fa-cloud" } - menu_style = 'default'#'accordion' + menu_style = "default"#"accordion" xadmin.sites.site.register(views.CommAdminView, GlobalSetting) class MaintainInline(object): model = MaintainLog extra = 1 - style = 'accordion' + style = "accordion" class IDCAdmin(object): - list_display = ('name', 'description', 'create_time') - list_display_links = ('name',) + list_display = ("name", "description", "create_time") + list_display_links = ("name",) wizard_form_list = [ - ('First\'s Form', ('name', 'description')), - ('Second Form', ('contact', 'telphone', 'address')), - ('Thread Form', ('customer_id',)) - ] + ("First's Form", ("name", "description")), + ("Second Form", ("contact", "telphone", "address")), + ("Thread Form", ("customer_id",)) + ] - search_fields = ['name'] - relfield_style = 'fk-select' + search_fields = ["name"] + relfield_style = "fk-select" reversion_enable = True actions = [BatchChangeAction, ] - batch_fields = ('contact', 'groups') + batch_fields = ("contact", "groups") class HostAdmin(object): def open_web(self, instance): - return "Open" % instance.ip + return """Open""" % instance.ip open_web.short_description = "Acts" open_web.allow_tags = True open_web.is_column = True - list_display = ('name', 'idc', 'guarantee_date', 'service_type', - 'status', 'open_web', 'description') - list_display_links = ('name',) + list_display = ( + "name", "idc", "guarantee_date", "service_type", "status", "open_web", + "description", + ) + list_display_links = ("name",) - raw_id_fields = ('idc',) - style_fields = {'system': "radio-inline"} + raw_id_fields = ("idc",) + style_fields = {"system": "radio-inline"} - search_fields = ['name', 'ip', 'description'] - list_filter = ['idc', 'guarantee_date', 'status', 'brand', 'model', - 'cpu', 'core_num', 'hard_disk', 'memory', ('service_type',xadmin.filters.MultiSelectFieldListFilter)] + search_fields = ["name", "ip", "description"] + list_filter = [ + "idc", "guarantee_date", "status", "brand", "model", "cpu", "core_num", + "hard_disk", "memory", ( + "service_type", + xadmin.filters.MultiSelectFieldListFilter, + ), + ] - list_quick_filter = ['service_type',{'field':'idc__name','limit':10}] - list_bookmarks = [{'title': "Need Guarantee", 'query': {'status__exact': 2}, 'order': ('-guarantee_date',), 'cols': ('brand', 'guarantee_date', 'service_type')}] - - show_detail_fields = ('idc',) + list_quick_filter = ["service_type",{"field":"idc__name","limit":10}] + list_bookmarks = [{ + "title": "Need Guarantee", + "query": {"status__exact": 2}, + "order": ("-guarantee_date",), + "cols": ("brand", "guarantee_date", "service_type"), + }] + + show_detail_fields = ("idc",) list_editable = ( - 'name', 'idc', 'guarantee_date', 'service_type', 'description') + "name", "idc", "guarantee_date", "service_type", "description", + ) save_as = True aggregate_fields = {"guarantee_date": "min"} - grid_layouts = ('table', 'thumbnails') + grid_layouts = ("table", "thumbnails") form_layout = ( Main( TabHolder( - Tab('Comm Fields', - Fieldset('Company data', - 'name', 'idc', - description="some comm fields, required" - ), + Tab( + "Comm Fields", + Fieldset( + "Company data", "name", "idc", + description="some comm fields, required", + ), Inline(MaintainLog), ), - Tab('Extend Fields', - Fieldset('Contact details', - 'service_type', - Row('brand', 'model'), - Row('cpu', 'core_num'), - Row(AppendedText( - 'hard_disk', 'G'), AppendedText('memory', "G")), - 'guarantee_date' - ), + Tab( + "Extend Fields", + Fieldset( + "Contact details", + "service_type", + Row("brand", "model"), + Row("cpu", "core_num"), + Row( + AppendedText("hard_disk", "G"), + AppendedText("memory", "G") + ), + "guarantee_date" + ), ), + ), ), - ), Side( - Fieldset('Status data', - 'status', 'ssh_port', 'ip' - ), + Fieldset("Status data", "status", "ssh_port", "ip"), + ) ) - ) inlines = [MaintainInline] reversion_enable = True - data_charts = { - "host_service_type_counts": {'title': u"Host service type count", "x-field": "service_type", "y-field": ("service_type",), - "option": { - "series": {"bars": {"align": "center", "barWidth": 0.8,'show':True}}, - "xaxis": {"aggregate": "count", "mode": "categories"}, - }, - }, - } + data_charts = {"host_service_type_counts": { + "title": u"Host service type count", + "x-field": "service_type", + "y-field": ("service_type",), + "option": { + "series": { + "bars": { + "align": "center", + "barWidth": 0.8, + "show": True, + }, + }, + "xaxis": { + "aggregate": "count", + "mode": "categories", + }, + }, + }} class HostGroupAdmin(object): - list_display = ('name', 'description') - list_display_links = ('name',) + list_display = ("name", "description") + list_display_links = ("name",) - search_fields = ['name'] - style_fields = {'hosts': 'checkbox-inline'} + search_fields = ["name"] + style_fields = {"hosts": "checkbox-inline"} class MaintainLogAdmin(object): list_display = ( - 'host', 'maintain_type', 'hard_type', 'time', 'operator', 'note') - list_display_links = ('host',) + "host", "maintain_type", "hard_type", "time", "operator", "note") + list_display_links = ("host",) - list_filter = ['host', 'maintain_type', 'hard_type', 'time', 'operator'] - search_fields = ['note'] + list_filter = ["host", "maintain_type", "hard_type", "time", "operator"] + search_fields = ["note"] form_layout = ( Col("col2", - Fieldset('Record data', - 'time', 'note', - css_class='unsort short_label no_title' + Fieldset("Record data", + "time", "note", + css_class="unsort short_label no_title" ), span=9, horizontal=True ), Col("col1", - Fieldset('Comm data', - 'host', 'maintain_type' + Fieldset("Comm data", + "host", "maintain_type" ), - Fieldset('Maintain details', - 'hard_type', 'operator' + Fieldset("Maintain details", + "hard_type", "operator" ), span=3 ) @@ -173,20 +198,20 @@ def avg_count(self, instance): avg_count.allow_tags = True avg_count.is_column = True - list_display = ('date', 'user_count', 'view_count', 'avg_count') - list_display_links = ('date',) + list_display = ("date", "user_count", "view_count", "avg_count") + list_display_links = ("date",) - list_filter = ['date', 'user_count', 'view_count'] + list_filter = ["date", "user_count", "view_count"] actions = None - aggregate_fields = {"user_count": "sum", 'view_count': "sum"} + aggregate_fields = {"user_count": "sum", "view_count": "sum"} refresh_times = (3, 5, 10) data_charts = { - "user_count": {'title': u"User Report", "x-field": "date", "y-field": ("user_count", "view_count"), "order": ('date',)}, - "avg_count": {'title': u"Avg Report", "x-field": "date", "y-field": ('avg_count',), "order": ('date',)}, - "per_month": {'title': u"Monthly Users", "x-field": "_chart_month", "y-field": ("user_count", ), + "user_count": {"title": u"User Report", "x-field": "date", "y-field": ("user_count", "view_count"), "order": ("date",)}, + "avg_count": {"title": u"Avg Report", "x-field": "date", "y-field": ("avg_count",), "order": ("date",)}, + "per_month": {"title": u"Monthly Users", "x-field": "_chart_month", "y-field": ("user_count", ), "option": { - "series": {"bars": {"align": "center", "barWidth": 0.8,'show':True}}, + "series": {"bars": {"align": "center", "barWidth": 0.8,"show":True}}, "xaxis": {"aggregate": "sum", "mode": "categories"}, }, }, diff --git a/xadmin/sites.py b/xadmin/sites.py index c6eee43de..820a0ef0e 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -198,8 +198,6 @@ def get_urls(self): cacheable=True. """ def inner(request, *args, **kwargs): - # print('xadmin/sites.py --> AdminSite.inner(): ...') - # print(u'\targs: {}\n\tkwargs: {}'.format(args, kwargs)) if not self.has_permission(request) and getattr(view, 'need_site_permission', True): return self.create_admin_view(self.login_view)(request, *args, **kwargs) return view(request, *args, **kwargs) From f105c30d6d2bd48d6e60b4fc294386374b04d2bb Mon Sep 17 00:00:00 2001 From: wy Date: Sun, 30 Oct 2016 05:34:30 +0800 Subject: [PATCH 19/24] Replace sys.version_info with six.PY3. --- demo_app/demo/settings.py | 3 ++- tests/xtests/site/apps.py | 3 ++- tests/xtests/view_base/apps.py | 3 ++- xadmin/filters.py | 8 ++++---- xadmin/plugins/actions.py | 4 ++-- xadmin/plugins/export.py | 3 ++- xadmin/plugins/filters.py | 8 ++++---- xadmin/plugins/inline.py | 4 ++-- xadmin/plugins/quickfilter.py | 4 ++-- xadmin/plugins/relate.py | 6 +++--- xadmin/plugins/themes.py | 4 ++-- xadmin/plugins/wizard.py | 12 ++++++------ xadmin/plugins/xversion.py | 4 ++-- xadmin/sites.py | 3 ++- xadmin/templatetags/xadmin_tags.py | 8 +++----- xadmin/util.py | 13 +++++-------- xadmin/views/base.py | 4 ++-- xadmin/views/delete.py | 4 ++-- xadmin/views/detail.py | 11 ++++------- xadmin/views/edit.py | 6 +++--- xadmin/views/form.py | 4 ++-- xadmin/views/list.py | 4 ++-- 22 files changed, 60 insertions(+), 63 deletions(-) diff --git a/demo_app/demo/settings.py b/demo_app/demo/settings.py index ab477e486..ba583a1bc 100644 --- a/demo_app/demo/settings.py +++ b/demo_app/demo/settings.py @@ -2,8 +2,9 @@ import sys import os.path +from django.utils import six -if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': +if six.PY2 and sys.getdefaultencoding()=='ascii': import imp imp.reload(sys) sys.setdefaultencoding('utf-8') diff --git a/tests/xtests/site/apps.py b/tests/xtests/site/apps.py index 3504ccdbe..37777566c 100644 --- a/tests/xtests/site/apps.py +++ b/tests/xtests/site/apps.py @@ -1,7 +1,8 @@ #!/usr/bin/env python #coding:utf-8 import sys -if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': +from django.utils import six +if six.PY2 and sys.getdefaultencoding()=='ascii': import imp imp.reload(sys) sys.setdefaultencoding('utf-8') diff --git a/tests/xtests/view_base/apps.py b/tests/xtests/view_base/apps.py index b35885faf..5b59ac85d 100644 --- a/tests/xtests/view_base/apps.py +++ b/tests/xtests/view_base/apps.py @@ -1,7 +1,8 @@ #!/usr/bin/env python #coding:utf-8 import sys -if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': +from django.utils import six +if six.PY2 and sys.getdefaultencoding()=='ascii': import imp imp.reload(sys) sys.setdefaultencoding('utf-8') diff --git a/xadmin/filters.py b/xadmin/filters.py index ebe0c5cb3..9eba01e99 100644 --- a/xadmin/filters.py +++ b/xadmin/filters.py @@ -1,5 +1,4 @@ from __future__ import absolute_import -import sys from django.db import models from django.core.exceptions import ImproperlyConfigured from django.utils.encoding import smart_text @@ -7,6 +6,7 @@ from django.utils import timezone from django.template.loader import get_template from django.template.context import Context +from django.utils import six from django.utils.safestring import mark_safe from django.utils.html import escape,format_html from django.utils.text import Truncator @@ -48,7 +48,7 @@ def query_string(self, new_params=None, remove=None): def form_params(self): arr = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) - if 2 < sys.version_info.major: + if six.PY3: arr = list(arr) return self.admin_view.get_form_params(remove=arr) @@ -128,14 +128,14 @@ def __init__(self, field, request, params, model, admin_view, field_path): lambda kv: setattr(self, 'lookup_' + kv[0], kv[1]), self.context_params.items() ) - if 2 < sys.version_info.major: + if six.PY3: list(arr) def get_context(self): context = super(FieldFilter, self).get_context() context.update(self.context_params) obj = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) - if 2 < sys.version_info.major: + if six.PY3: obj = list(obj) context['remove_url'] = self.query_string({}, obj) return context diff --git a/xadmin/plugins/actions.py b/xadmin/plugins/actions.py index c16934159..90eb744cd 100644 --- a/xadmin/plugins/actions.py +++ b/xadmin/plugins/actions.py @@ -1,4 +1,3 @@ -import sys from collections import OrderedDict from django import forms from django.core.exceptions import PermissionDenied @@ -6,6 +5,7 @@ from django.http import HttpResponse, HttpResponseRedirect from django.template import loader from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _, ungettext @@ -228,7 +228,7 @@ def get_actions(self): # get_action might have returned None, so filter any of those out. actions = filter(None, actions) - if 2 < sys.version_info.major: + if six.PY3: actions = list(actions) # Convert the actions into a OrderedDict keyed by name. diff --git a/xadmin/plugins/export.py b/xadmin/plugins/export.py index 09be6cba8..66c7950c9 100644 --- a/xadmin/plugins/export.py +++ b/xadmin/plugins/export.py @@ -5,6 +5,7 @@ from django.http import HttpResponse from django.template import loader +from django.utils import six from django.utils.encoding import force_text, smart_text from django.utils.html import escape from django.utils.translation import ugettext as _ @@ -165,7 +166,7 @@ def _format_csv_text(self, t): if isinstance(t, bool): return _('Yes') if t else _('No') t = t.replace('"', '""').replace(',', '\,') - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(t, cls_str): t = '"%s"' % t return t diff --git a/xadmin/plugins/filters.py b/xadmin/plugins/filters.py index ae01d8955..7e4b69f11 100644 --- a/xadmin/plugins/filters.py +++ b/xadmin/plugins/filters.py @@ -1,5 +1,4 @@ import operator -import sys from future.utils import iteritems from xadmin import widgets from xadmin.plugins.utils import get_context_dict @@ -10,6 +9,7 @@ from django.db.models.fields import FieldDoesNotExist from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS from django.template import loader +from django.utils import six from django.utils.encoding import smart_str from django.utils.translation import ugettext as _ @@ -142,7 +142,7 @@ def get_list_queryset(self, queryset): self.has_filters = bool(self.filter_specs) self.admin_view.filter_specs = self.filter_specs obj = filter(lambda f: f.is_used, self.filter_specs) - if 2 < sys.version_info.major: + if six.PY3: obj = list(obj) self.admin_view.used_filter_num = len(obj) @@ -195,13 +195,13 @@ def construct_search(field_name): # Media def get_media(self, media): arr = filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs) - if 2 < sys.version_info.major: + if six.PY3: arr = list(arr) if bool(arr): media = media + self.vendor('datepicker.css', 'datepicker.js', 'xadmin.widget.datetime.js') arr = filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs) - if 2 < sys.version_info.major: + if six.PY3: arr = list(arr) if bool(arr): media = media + self.vendor( diff --git a/xadmin/plugins/inline.py b/xadmin/plugins/inline.py index a307a9d63..2fbe5b19d 100644 --- a/xadmin/plugins/inline.py +++ b/xadmin/plugins/inline.py @@ -1,6 +1,5 @@ import copy import inspect -import sys from django import forms from django.forms.formsets import all_valid, DELETION_FIELD_NAME from django.forms.models import inlineformset_factory, BaseInlineFormSet, modelform_defines_fields @@ -8,6 +7,7 @@ from django.template import loader from django.template.loader import render_to_string from django.contrib.auth import get_permission_codename +from django.utils import six from django.utils.encoding import smart_text from crispy_forms.utils import TEMPLATE_PACK @@ -115,7 +115,7 @@ def get_attrs(self): def replace_field_to_value(layout, av): if layout: - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring for i, lo in enumerate(layout.fields): if isinstance(lo, Field) or issubclass(lo.__class__, Field): layout.fields[i] = ShowField(av, *lo.fields, **lo.attrs) diff --git a/xadmin/plugins/quickfilter.py b/xadmin/plugins/quickfilter.py index cae51c463..6222c34b4 100644 --- a/xadmin/plugins/quickfilter.py +++ b/xadmin/plugins/quickfilter.py @@ -3,8 +3,8 @@ @author: LAB_ADM ''' -import sys from future.utils import iteritems +from django.utils import six from django.utils.translation import ugettext_lazy as _ from xadmin.filters import manager,MultiSelectFieldListFilter from xadmin.plugins.filters import * @@ -149,7 +149,7 @@ def get_list_queryset(self, queryset): self.has_filters = bool(self.filter_specs) self.admin_view.quickfilter['filter_specs'] = self.filter_specs obj = filter(lambda f: f.is_used, self.filter_specs) - if 2 < sys.version_info.major: + if six.PY3: obj = list(obj) self.admin_view.quickfilter['used_filter_num'] = len(obj) diff --git a/xadmin/plugins/relate.py b/xadmin/plugins/relate.py index ac622089b..5bf2c65db 100644 --- a/xadmin/plugins/relate.py +++ b/xadmin/plugins/relate.py @@ -1,9 +1,9 @@ # coding=UTF-8 -import sys from itertools import chain from django.core.urlresolvers import reverse from django.db.models.options import PROXY_PARENTS +from django.utils import six from django.utils.encoding import force_text from django.utils.encoding import smart_str from django.utils.safestring import mark_safe @@ -207,7 +207,7 @@ def get_form_datas(self, datas): return datas def post_response(self, response): - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(response, cls_str) and response != self.get_admin_url('index'): return self._get_url(response) return response @@ -224,7 +224,7 @@ def block_after_fieldsets(self, context, nodes): class DeleteRelateDisplayPlugin(BaseRelateDisplayPlugin): def post_response(self, response): - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(response, cls_str) and response != self.get_admin_url('index'): return self._get_url(response) return response diff --git a/xadmin/plugins/themes.py b/xadmin/plugins/themes.py index 6ab202eef..ce6bbaba9 100644 --- a/xadmin/plugins/themes.py +++ b/xadmin/plugins/themes.py @@ -1,9 +1,9 @@ #coding:utf-8 from __future__ import print_function -import sys import urllib, httplib2 from django.template import loader from django.core.cache import cache +from django.utils import six from django.utils.translation import ugettext as _ from xadmin.sites import site from xadmin.models import UserSettings @@ -65,7 +65,7 @@ def block_top_navmenu(self, context, nodes): h = httplib2.Http() resp, content = h.request("http://bootswatch.com/api/3.json", 'GET', '', headers={"Accept": "application/json", "User-Agent": self.request.META['HTTP_USER_AGENT']}) - if 2 < sys.version_info.major: + if six.PY3: content = content.decode() watch_themes = json.loads(content)['themes'] ex_themes.extend([ diff --git a/xadmin/plugins/wizard.py b/xadmin/plugins/wizard.py index 940c77f71..9ddaac00a 100644 --- a/xadmin/plugins/wizard.py +++ b/xadmin/plugins/wizard.py @@ -1,5 +1,4 @@ import re -import sys from collections import OrderedDict from django import forms from django.db import models @@ -14,6 +13,7 @@ from django.contrib.formtools.wizard.forms import ManagementForm from django.contrib.formtools.wizard.views import StepsHelper +from django.utils import six from django.utils.encoding import smart_text from django.utils.module_loading import import_string from django.forms import ValidationError @@ -44,7 +44,7 @@ def _get_form_prefix(self, step=None): if step is None: step = self.steps.current obj = self.get_form_list().keys() - if 2 < sys.version_info.major: + if six.PY3: obj = [s for s in obj] return 'step_%d' % obj.index(step) @@ -90,7 +90,7 @@ def prepare_form(self, __): wizard_goto_step = self.request.POST.get('wizard_goto_step', None) if wizard_goto_step and int(wizard_goto_step) < len(self.get_form_list()): obj = self.get_form_list().keys() - if 2 < sys.version_info.major: + if six.PY3: obj = [s for s in obj] self.storage.current_step = obj[int(wizard_goto_step)] self.admin_view.model_form = self.get_step_form() @@ -287,7 +287,7 @@ def get_next_step(self, step=None): if step is None: step = self.steps.current obj = self.get_form_list().keys() - if 2 < sys.version_info.major: + if six.PY3: obj = [s for s in obj] key = obj.index(step) + 1 if len(obj) > key: @@ -303,7 +303,7 @@ def get_prev_step(self, step=None): if step is None: step = self.steps.current obj = self.get_form_list().keys() - if 2 < sys.version_info.major: + if six.PY3: obj = [s for s in obj] key = obj.index(step) - 1 if key >= 0: @@ -318,7 +318,7 @@ def get_step_index(self, step=None): if step is None: step = self.steps.current obj = self.get_form_list().keys() - if 2 < sys.version_info.major: + if six.PY3: obj = [s for s in obj] return obj.index(step) diff --git a/xadmin/plugins/xversion.py b/xadmin/plugins/xversion.py index cd1c9e58c..19b19e8bb 100644 --- a/xadmin/plugins/xversion.py +++ b/xadmin/plugins/xversion.py @@ -1,4 +1,3 @@ -import sys from crispy_forms.utils import TEMPLATE_PACK from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.models import ContentType @@ -9,6 +8,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text, smart_text from django.utils.safestring import mark_safe from django.utils.text import capfirst @@ -564,7 +564,7 @@ def total_form_count_hack(count): if self.request.method == 'GET' and formset.helper and formset.helper.layout: helper = formset.helper - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring helper.filter(cls_str).wrap(InlineDiffField) fake_admin_class = type(str('%s%sFakeAdmin' % (self.opts.app_label, self.opts.model_name)), (object, ), {'model': self.model}) for form in formset.forms: diff --git a/xadmin/sites.py b/xadmin/sites.py index 820a0ef0e..a7ed1325b 100644 --- a/xadmin/sites.py +++ b/xadmin/sites.py @@ -4,10 +4,11 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db.models.base import ModelBase +from django.utils import six from django.views.decorators.cache import never_cache import inspect -if sys.version_info.major < 3 and sys.getdefaultencoding()=='ascii': +if six.PY2 and sys.getdefaultencoding()=='ascii': import imp imp.reload(sys) sys.setdefaultencoding("utf-8") diff --git a/xadmin/templatetags/xadmin_tags.py b/xadmin/templatetags/xadmin_tags.py index 13ec3bbc6..ee0fc69c5 100644 --- a/xadmin/templatetags/xadmin_tags.py +++ b/xadmin/templatetags/xadmin_tags.py @@ -1,6 +1,6 @@ -import sys from django import template from django.template import Library +from django.utils import six from django.utils.safestring import mark_safe from xadmin.util import static, vendor as util_vendor @@ -16,14 +16,12 @@ def view_block(context, block_name, *args, **kwargs): nodes = [] method_name = 'block_%s' % block_name + cls_str = str if six.PY3 else basestring for view in [admin_view] + admin_view.plugins: if hasattr(view, method_name) and callable(getattr(view, method_name)): block_func = getattr(view, method_name) result = block_func(context, nodes, *args, **kwargs) - if result and ( - isinstance(result, str) - or sys.version_info.major < 3 and isinstance(result, unicode) - ): + if result and isinstance(result, cls_str): nodes.append(result) if nodes: return mark_safe(''.join(nodes)) diff --git a/xadmin/util.py b/xadmin/util.py index 41542b7f2..9a1ce7ab9 100644 --- a/xadmin/util.py +++ b/xadmin/util.py @@ -1,12 +1,11 @@ from __future__ import absolute_import -import sys import django from django.db import models from django.db.models.sql.query import LOOKUP_SEP from django.db.models.deletion import Collector from django.db.models.fields.related import ForeignObjectRel from django.forms.forms import pretty_name -from django.utils import formats +from django.utils import formats, six from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.text import capfirst @@ -43,6 +42,7 @@ def xstatic(*tags): fs = [] lang = get_language() + cls_str = str if six.PY3 else basestring for tag in tags: try: for p in tag.split('.'): @@ -57,10 +57,7 @@ def xstatic(*tags): else: raise e - if ( - isinstance(node, str) - or sys.version_info.major < 3 and isinstance(node, unicode) - ): + if isinstance(node, cls_str): files = node else: mode = 'dev' @@ -129,7 +126,7 @@ def quote(s): quoting is slightly different so that it doesn't get automatically unquoted by the Web browser. """ - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if not isinstance(s, cls_str): return s res = list(s) @@ -144,7 +141,7 @@ def unquote(s): """ Undo the effects of quote(). Based heavily on urllib.unquote(). """ - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if not isinstance(s, cls_str): return s mychr = chr diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 94b98535c..9c4e68e9a 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -1,4 +1,3 @@ -import sys import copy import functools import datetime @@ -17,6 +16,7 @@ from django.http import HttpResponse from django.template import Context, Template from django.template.response import TemplateResponse +from django.utils import six from django.utils.decorators import method_decorator, classonlymethod from django.utils.encoding import force_text, smart_text, smart_str from django.utils.http import urlencode @@ -86,7 +86,7 @@ def wrap(func): def method(self, context, nodes, *arg, **kwargs): _dict = func(self, context, nodes, *arg, **kwargs) from django.template.loader import get_template, select_template - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(file_name, Template): t = file_name elif not isinstance(file_name, cls_str) and is_iterable(file_name): diff --git a/xadmin/views/delete.py b/xadmin/views/delete.py index ffd2d9e0c..52c4e859e 100644 --- a/xadmin/views/delete.py +++ b/xadmin/views/delete.py @@ -1,8 +1,8 @@ -import sys from django.core.exceptions import PermissionDenied from django.db import transaction, router from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text from django.utils.html import escape from django.utils.translation import ugettext as _ @@ -52,7 +52,7 @@ def post(self, request, object_id): self.delete_model() response = self.post_response() - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(response, cls_str): response = HttpResponseRedirect(response) return response diff --git a/xadmin/views/detail.py b/xadmin/views/detail.py index fc5603ae2..2ce3b131e 100644 --- a/xadmin/views/detail.py +++ b/xadmin/views/detail.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import copy -import sys from crispy_forms.utils import TEMPLATE_PACK from django import forms @@ -11,6 +10,7 @@ from django.http import Http404 from django.template import loader from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text, smart_text from django.utils.html import escape from django.utils.safestring import mark_safe @@ -118,15 +118,12 @@ def val(self): def replace_field_to_value(layout, cb): + cls_str = str if six.PY3 else basestring for i, lo in enumerate(layout.fields): - if sys.version_info.major < 3: - cls_str = basestring - else: - cls_str = str if isinstance(lo, Field) or issubclass(lo.__class__, Field): layout.fields[i] = ShowField( cb, *lo.fields, attrs=lo.attrs, wrapper_class=lo.wrapper_class) - elif sys.version_info.major < 3 and isinstance(lo, cls_str): + elif isinstance(lo, cls_str): layout.fields[i] = ShowField(cb, lo) elif hasattr(lo, 'get_field_names'): replace_field_to_value(lo, cb) @@ -220,7 +217,7 @@ def get_form_helper(self): layout = self.get_form_layout() replace_field_to_value(layout, self.get_field_result) helper.add_layout(layout) - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring helper.filter(cls_str, max_level=20).wrap(ShowField, admin_view=self) return helper diff --git a/xadmin/views/edit.py b/xadmin/views/edit.py index cd2cb079f..8c5fef2f0 100644 --- a/xadmin/views/edit.py +++ b/xadmin/views/edit.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import copy -import sys from crispy_forms.utils import TEMPLATE_PACK from django import forms @@ -10,6 +9,7 @@ from django.forms.models import modelform_factory, modelform_defines_fields from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text from django.utils.html import escape from django.utils.text import capfirst, get_text_list @@ -193,7 +193,7 @@ def get_model_form(self, **kwargs): def get_form_layout(self): layout = copy.deepcopy(self.form_layout) arr = self.form_obj.fields.keys() - if 2 < sys.version_info.major: + if six.PY3: arr = [k for k in arr] fields = arr + list(self.get_readonly_fields()) @@ -292,7 +292,7 @@ def post(self, request, *args, **kwargs): self.save_models() self.save_related() response = self.post_response() - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(response, cls_str): return HttpResponseRedirect(response) else: diff --git a/xadmin/views/form.py b/xadmin/views/form.py index 381a47c69..04a2e5223 100644 --- a/xadmin/views/form.py +++ b/xadmin/views/form.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import copy -import sys from django import forms from django.contrib.contenttypes.models import ContentType @@ -9,6 +8,7 @@ from django.forms.models import modelform_factory from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse +from django.utils import six from django.utils.encoding import force_text from django.utils.html import escape from django.template import loader @@ -112,7 +112,7 @@ def post(self, request, *args, **kwargs): if self.valid_forms(): self.save_forms() response = self.post_response() - cls_str = str if 2 < sys.version_info.major else basestring + cls_str = str if six.PY3 else basestring if isinstance(response, cls_str): return HttpResponseRedirect(response) else: diff --git a/xadmin/views/list.py b/xadmin/views/list.py index 1804730b7..7fdb03f72 100644 --- a/xadmin/views/list.py +++ b/xadmin/views/list.py @@ -1,5 +1,4 @@ from __future__ import absolute_import -import sys from collections import OrderedDict from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.paginator import InvalidPage, Paginator @@ -7,6 +6,7 @@ from django.db import models from django.http import HttpResponseRedirect from django.template.response import SimpleTemplateResponse, TemplateResponse +from django.utils import six from django.utils.encoding import force_text, smart_text from django.utils.html import escape, conditional_escape from django.utils.safestring import mark_safe @@ -465,7 +465,7 @@ def result_header(self, field_name, row): sorted = True order_type = ordering_field_columns.get(field_name).lower() arr = ordering_field_columns.keys() - if 2 < sys.version_info.major: + if six.PY3: arr = list(arr) sort_priority = arr.index(field_name) + 1 th_classes.append('sorted %sending' % order_type) From 2ebfa4d13d727458a7e887b6d11dfed240195459 Mon Sep 17 00:00:00 2001 From: wy Date: Sun, 30 Oct 2016 05:56:08 +0800 Subject: [PATCH 20/24] fix isinstance() with datetime.datetime --- xadmin/views/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 9c4e68e9a..2bd3b9861 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -110,10 +110,10 @@ def method(self, context, nodes, *arg, **kwargs): class JSONEncoder(DjangoJSONEncoder): def default(self, o): - if isinstance(o, datetime.date): - return o.strftime('%Y-%m-%d') - elif isinstance(o, datetime.datetime): + if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %H:%M:%S') + elif isinstance(o, datetime.date): + return o.strftime('%Y-%m-%d') elif isinstance(o, decimal.Decimal): return str(o) else: From 4d45056a73285cb9dab698abbb094e39094b3c97 Mon Sep 17 00:00:00 2001 From: wuyu Date: Mon, 31 Oct 2016 08:54:54 +0800 Subject: [PATCH 21/24] add six package. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index d04df08a4..cb5940a30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ django-reversion~=2.0.0 django-formtools==1.0 future==0.15.2 httplib2==0.9.2 +six==1.10.0 From 97c03b64acf2adc86548fe3d4bb303a4aded2a7e Mon Sep 17 00:00:00 2001 From: wuyu Date: Sun, 18 Dec 2016 15:56:13 +0800 Subject: [PATCH 22/24] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E3=80=82=20=E5=9C=A8DEBUG=3DFalse=E6=97=B6=EF=BC=8Cjson.dumps(?= =?UTF-8?q?nav=5Fmenu)=E4=B8=8D=E8=83=BD=E5=BA=8F=E5=88=97=E5=8C=96lazy?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xadmin/views/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 2bd3b9861..7a70ad6de 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -19,6 +19,7 @@ from django.utils import six from django.utils.decorators import method_decorator, classonlymethod from django.utils.encoding import force_text, smart_text, smart_str +from django.utils.functional import Promise from django.utils.http import urlencode from django.utils.itercompat import is_iterable from django.utils.safestring import mark_safe @@ -116,6 +117,8 @@ def default(self, o): return o.strftime('%Y-%m-%d') elif isinstance(o, decimal.Decimal): return str(o) + elif isinstance(obj, Promise): + return force_text(obj) else: try: return super(JSONEncoder, self).default(o) @@ -428,7 +431,7 @@ def filter_item(item): nav_menu = list(filter(lambda x:x, nav_menu)) if not settings.DEBUG: - self.request.session['nav_menu'] = json.dumps(nav_menu) + self.request.session['nav_menu'] = json.dumps(nav_menu, cls=JSONEncoder, ensure_ascii=False) self.request.session.modified = True def check_selected(menu, path): From 3018cb809400a28380dcfe6cf39481c34454b1df Mon Sep 17 00:00:00 2001 From: wuyu Date: Sun, 18 Dec 2016 18:22:08 +0800 Subject: [PATCH 23/24] fix --- xadmin/views/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xadmin/views/base.py b/xadmin/views/base.py index 7a70ad6de..a238b80ff 100644 --- a/xadmin/views/base.py +++ b/xadmin/views/base.py @@ -117,8 +117,8 @@ def default(self, o): return o.strftime('%Y-%m-%d') elif isinstance(o, decimal.Decimal): return str(o) - elif isinstance(obj, Promise): - return force_text(obj) + elif isinstance(o, Promise): + return force_text(o) else: try: return super(JSONEncoder, self).default(o) From 6ac2e7b9ac9124d86ce5371a0221515ee58bf7db Mon Sep 17 00:00:00 2001 From: wuyu Date: Tue, 20 Dec 2016 15:32:17 +0800 Subject: [PATCH 24/24] fix urllib.unquote --- xadmin/plugins/themes.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/xadmin/plugins/themes.py b/xadmin/plugins/themes.py index ce6bbaba9..8ae23c101 100644 --- a/xadmin/plugins/themes.py +++ b/xadmin/plugins/themes.py @@ -1,6 +1,6 @@ #coding:utf-8 from __future__ import print_function -import urllib, httplib2 +import httplib2 from django.template import loader from django.core.cache import cache from django.utils import six @@ -9,6 +9,11 @@ from xadmin.models import UserSettings from xadmin.views import BaseAdminPlugin, BaseAdminView from xadmin.util import static, json +import six +if six.PY2: + import urllib +else: + import urllib.parse THEME_CACHE_KEY = 'xadmin_themes' @@ -32,7 +37,11 @@ def _get_theme(self): except Exception: pass if '_theme' in self.request.COOKIES: - return urllib.unquote(self.request.COOKIES['_theme']) + if six.PY2: + func = urllib.unquote + else: + func = urllib.parse.unquote + return func(self.request.COOKIES['_theme']) return self.default_theme def get_context(self, context):