mirror of
https://github.com/jazzband/django-categories.git
synced 2026-03-16 22:30:24 +00:00
commit
75b1496d90
31 changed files with 186 additions and 143 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -14,3 +14,4 @@ MANIFEST
|
|||
dist/
|
||||
.venv
|
||||
example/media/
|
||||
.tox/
|
||||
|
|
|
|||
33
.travis.yml
33
.travis.yml
|
|
@ -1,16 +1,23 @@
|
|||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
env:
|
||||
- DJANGO_VERSION=1.6.11
|
||||
- DJANGO_VERSION=1.7.7
|
||||
- DJANGO_VERSION=1.8
|
||||
install:
|
||||
- pip install Django==$DJANGO_VERSION
|
||||
- pip install -e .
|
||||
- pip install South
|
||||
script:
|
||||
- ./example/manage.py test categories --settings='settings-testing'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- master
|
||||
|
||||
env:
|
||||
- TOXENV=py27-django18
|
||||
- TOXENV=py27-django19
|
||||
- TOXENV=py34-django18
|
||||
- TOXENV=py34-django19
|
||||
- TOXENV=py35-django18
|
||||
- TOXENV=py35-django19
|
||||
|
||||
install:
|
||||
- pip install tox
|
||||
|
||||
script:
|
||||
- tox -e $TOXENV
|
||||
|
||||
after_success:
|
||||
- pip install codecov
|
||||
- codecov -e TOXENV
|
||||
|
|
|
|||
|
|
@ -29,4 +29,4 @@ def register():
|
|||
try:
|
||||
register()
|
||||
except Exception as e:
|
||||
print e
|
||||
print(e)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from .settings import MODEL_REGISTRY
|
|||
|
||||
class NullTreeNodeChoiceField(forms.ModelChoiceField):
|
||||
"""A ModelChoiceField for tree nodes."""
|
||||
def __init__(self, level_indicator=u'---', *args, **kwargs):
|
||||
def __init__(self, level_indicator='---', *args, **kwargs):
|
||||
self.level_indicator = level_indicator
|
||||
super(NullTreeNodeChoiceField, self).__init__(*args, **kwargs)
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ class NullTreeNodeChoiceField(forms.ModelChoiceField):
|
|||
Creates labels which represent the tree level of each node when
|
||||
generating option labels.
|
||||
"""
|
||||
return u'%s %s' % (self.level_indicator * getattr(
|
||||
return '%s %s' % (self.level_indicator * getattr(
|
||||
obj, obj._mptt_meta.level_attr), obj)
|
||||
if RELATION_MODELS:
|
||||
from .models import CategoryRelation
|
||||
|
|
@ -68,8 +68,8 @@ class CategoryAdmin(CategoryBaseAdmin):
|
|||
if REGISTER_ADMIN:
|
||||
admin.site.register(Category, CategoryAdmin)
|
||||
|
||||
for model, modeladmin in admin.site._registry.items():
|
||||
if model in MODEL_REGISTRY.values() and modeladmin.fieldsets:
|
||||
for model, modeladmin in list(admin.site._registry.items()):
|
||||
if model in list(MODEL_REGISTRY.values()) and modeladmin.fieldsets:
|
||||
fieldsets = getattr(modeladmin, 'fieldsets', ())
|
||||
fields = [cat.split('.')[2] for cat in MODEL_REGISTRY if MODEL_REGISTRY[cat] == model]
|
||||
# check each field to see if already defined
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ def handle_class_prepared(sender, **kwargs):
|
|||
sender_app = sender._meta.app_label
|
||||
sender_name = sender._meta.model_name
|
||||
|
||||
for key, val in FK_REGISTRY.items():
|
||||
for key, val in list(FK_REGISTRY.items()):
|
||||
app_name, model_name = key.split('.')
|
||||
if app_name == sender_app and sender_name == model_name:
|
||||
registry.register_model(app_name, sender, 'ForeignKey', val)
|
||||
|
||||
for key, val in M2M_REGISTRY.items():
|
||||
for key, val in list(M2M_REGISTRY.items()):
|
||||
app_name, model_name = key.split('.')
|
||||
if app_name == sender_app and sender_name == model_name:
|
||||
registry.register_model(app_name, sender, 'ManyToManyField', val)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ with customizable metadata and its own name space.
|
|||
from django.contrib import admin
|
||||
from django.db import models
|
||||
from django import forms
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mptt.models import MPTTModel
|
||||
|
|
@ -29,6 +29,7 @@ class CategoryManager(models.Manager):
|
|||
return self.get_queryset().filter(active=True)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class CategoryBase(MPTTModel):
|
||||
"""
|
||||
This base model includes the absolute bare bones fields and methods. One
|
||||
|
|
@ -63,9 +64,9 @@ class CategoryBase(MPTTModel):
|
|||
item.active = self.active
|
||||
item.save()
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
ancestors = self.get_ancestors()
|
||||
return ' > '.join([force_unicode(i.name) for i in ancestors] + [self.name, ])
|
||||
return ' > '.join([force_text(i.name) for i in ancestors] + [self.name, ])
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "admin/change_list.html" %}
|
||||
{% load admin_list i18n admin_tree_list %}
|
||||
{% load admin_list i18n admin_tree_list_tags %}
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ from django.db import models
|
|||
from django.template import Library
|
||||
from django.contrib.admin.templatetags.admin_list import result_headers, _boolean_icon
|
||||
try:
|
||||
from django.contrib.admin.util import lookup_field, display_for_field, label_for_field
|
||||
from django.contrib.admin.utils import lookup_field, display_for_field, label_for_field
|
||||
except ImportError:
|
||||
from categories.editor.utils import lookup_field, display_for_field, label_for_field
|
||||
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.encoding import smart_unicode, force_unicode
|
||||
from django.utils.encoding import smart_text, force_text
|
||||
from django.utils.html import escape, conditional_escape
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
|
@ -21,6 +20,15 @@ if settings.IS_GRAPPELLI_INSTALLED:
|
|||
TREE_LIST_RESULTS_TEMPLATE = 'admin/editor/grappelli_tree_list_results.html'
|
||||
|
||||
|
||||
def get_empty_value_display(cl):
|
||||
if hasattr(cl.model_admin, 'get_empty_value_display'):
|
||||
return cl.model_admin.get_empty_value_display()
|
||||
else:
|
||||
# Django < 1.9
|
||||
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
|
||||
return EMPTY_CHANGELIST_VALUE
|
||||
|
||||
|
||||
def items_for_tree_result(cl, result, form):
|
||||
"""
|
||||
Generates the actual list of data.
|
||||
|
|
@ -32,7 +40,7 @@ def items_for_tree_result(cl, result, form):
|
|||
try:
|
||||
f, attr, value = lookup_field(field_name, result, cl.model_admin)
|
||||
except (AttributeError, ObjectDoesNotExist):
|
||||
result_repr = EMPTY_CHANGELIST_VALUE
|
||||
result_repr = get_empty_value_display(cl)
|
||||
else:
|
||||
if f is None:
|
||||
if django.VERSION[1] == 4:
|
||||
|
|
@ -44,7 +52,7 @@ def items_for_tree_result(cl, result, form):
|
|||
allow_tags = True
|
||||
result_repr = _boolean_icon(value)
|
||||
else:
|
||||
result_repr = smart_unicode(value)
|
||||
result_repr = smart_text(value)
|
||||
# Strip HTML tags in the resulting text, except if the
|
||||
# function has an "allow_tags" attribute set to True.
|
||||
if not allow_tags:
|
||||
|
|
@ -53,7 +61,7 @@ def items_for_tree_result(cl, result, form):
|
|||
result_repr = mark_safe(result_repr)
|
||||
else:
|
||||
if value is None:
|
||||
result_repr = EMPTY_CHANGELIST_VALUE
|
||||
result_repr = get_empty_value_display(cl)
|
||||
if isinstance(f.rel, models.ManyToOneRel):
|
||||
result_repr = escape(getattr(result, f.name))
|
||||
else:
|
||||
|
|
@ -71,7 +79,7 @@ def items_for_tree_result(cl, result, form):
|
|||
except (AttributeError, ObjectDoesNotExist):
|
||||
pass
|
||||
|
||||
if force_unicode(result_repr) == '':
|
||||
if force_text(result_repr) == '':
|
||||
result_repr = mark_safe(' ')
|
||||
# If list_display_links not defined, add the link tag to the first field
|
||||
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
|
||||
|
|
@ -88,13 +96,13 @@ def items_for_tree_result(cl, result, form):
|
|||
else:
|
||||
attr = pk
|
||||
value = result.serializable_value(attr)
|
||||
result_id = repr(force_unicode(value))[1:]
|
||||
result_id = repr(force_text(value))[1:]
|
||||
first = False
|
||||
if django.VERSION[1] < 4:
|
||||
yield mark_safe(u'<%s%s>%s<a href="%s"%s>%s</a></%s>' % \
|
||||
yield mark_safe('<%s%s>%s<a href="%s"%s>%s</a></%s>' % \
|
||||
(table_tag, row_class, checkbox_value, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
|
||||
else:
|
||||
yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
|
||||
yield mark_safe('<%s%s><a href="%s"%s>%s</a></%s>' % \
|
||||
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
|
||||
|
||||
else:
|
||||
|
|
@ -103,12 +111,12 @@ def items_for_tree_result(cl, result, form):
|
|||
# can provide fields on a per request basis
|
||||
if form and field_name in form.fields:
|
||||
bf = form[field_name]
|
||||
result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf))
|
||||
result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
|
||||
else:
|
||||
result_repr = conditional_escape(result_repr)
|
||||
yield mark_safe(u'<td%s>%s</td>' % (row_class, result_repr))
|
||||
yield mark_safe('<td%s>%s</td>' % (row_class, result_repr))
|
||||
if form and not form[cl.model._meta.pk.name].is_hidden:
|
||||
yield mark_safe(u'<td>%s</td>' % force_unicode(form[cl.model._meta.pk.name]))
|
||||
yield mark_safe('<td>%s</td>' % force_text(form[cl.model._meta.pk.name]))
|
||||
|
||||
|
||||
class TreeList(list):
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from django.shortcuts import render_to_response
|
|||
|
||||
import django
|
||||
|
||||
import settings
|
||||
from . import settings
|
||||
|
||||
|
||||
class TreeEditorQuerySet(QuerySet):
|
||||
|
|
@ -125,7 +125,7 @@ class TreeEditor(admin.ModelAdmin):
|
|||
"The 'change list' admin view for this model."
|
||||
from django.contrib.admin.views.main import ERROR_FLAG
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ungettext
|
||||
opts = self.model._meta
|
||||
app_label = opts.app_label
|
||||
|
|
@ -162,7 +162,7 @@ class TreeEditor(admin.ModelAdmin):
|
|||
# parameter via the query string. If wacky parameters were given and
|
||||
# the 'invalid=1' parameter was already in the query string, something
|
||||
# is screwed up with the database, so display an error page.
|
||||
if ERROR_FLAG in request.GET.keys():
|
||||
if ERROR_FLAG in list(request.GET.keys()):
|
||||
return render_to_response(
|
||||
'admin/invalid_setup.html', {'title': _('Database error')})
|
||||
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
|
||||
|
|
@ -199,15 +199,15 @@ class TreeEditor(admin.ModelAdmin):
|
|||
|
||||
if changecount:
|
||||
if changecount == 1:
|
||||
name = force_unicode(opts.verbose_name)
|
||||
name = force_text(opts.verbose_name)
|
||||
else:
|
||||
name = force_unicode(opts.verbose_name_plural)
|
||||
name = force_text(opts.verbose_name_plural)
|
||||
msg = ungettext(
|
||||
"%(count)s %(name)s was changed successfully.",
|
||||
"%(count)s %(name)s were changed successfully.",
|
||||
changecount) % {'count': changecount,
|
||||
'name': name,
|
||||
'obj': force_unicode(obj)}
|
||||
'obj': force_text(obj)}
|
||||
self.message_user(request, msg)
|
||||
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
|
@ -248,7 +248,7 @@ class TreeEditor(admin.ModelAdmin):
|
|||
'All %(total_count)s selected', cl.result_count)
|
||||
|
||||
context.update({
|
||||
'module_name': force_unicode(opts.verbose_name_plural),
|
||||
'module_name': force_text(opts.verbose_name_plural),
|
||||
'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
|
||||
'selection_note_all': selection_note_all % {'total_count': cl.result_count},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Provides compatibility with Django 1.1
|
||||
|
||||
Copied from django.contrib.admin.util
|
||||
Copied from django.contrib.admin.utils
|
||||
"""
|
||||
from django.forms.forms import pretty_name
|
||||
from django.db import models
|
||||
|
|
@ -11,6 +11,7 @@ from django.utils.translation import get_date_formats
|
|||
from django.utils.text import capfirst
|
||||
from django.utils import dateformat
|
||||
from django.utils.html import escape
|
||||
import collections
|
||||
|
||||
|
||||
def lookup_field(name, obj, model_admin=None):
|
||||
|
|
@ -20,7 +21,7 @@ def lookup_field(name, obj, model_admin=None):
|
|||
except models.FieldDoesNotExist:
|
||||
# For non-field values, the value is either a method, property or
|
||||
# returned via a callable.
|
||||
if callable(name):
|
||||
if isinstance(name, collections.Callable):
|
||||
attr = name
|
||||
value = attr(obj)
|
||||
elif (model_admin is not None and hasattr(model_admin, name) and
|
||||
|
|
@ -29,7 +30,7 @@ def lookup_field(name, obj, model_admin=None):
|
|||
value = attr(obj)
|
||||
else:
|
||||
attr = getattr(obj, name)
|
||||
if callable(attr):
|
||||
if isinstance(attr, collections.Callable):
|
||||
value = attr()
|
||||
else:
|
||||
value = attr
|
||||
|
|
@ -57,12 +58,12 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
|
|||
except models.FieldDoesNotExist:
|
||||
if name == "__unicode__":
|
||||
label = force_unicode(model._meta.verbose_name)
|
||||
attr = unicode
|
||||
attr = str
|
||||
elif name == "__str__":
|
||||
label = smart_str(model._meta.verbose_name)
|
||||
attr = str
|
||||
else:
|
||||
if callable(name):
|
||||
if isinstance(name, collections.Callable):
|
||||
attr = name
|
||||
elif model_admin is not None and hasattr(model_admin, name):
|
||||
attr = getattr(model_admin, name)
|
||||
|
|
@ -76,7 +77,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
|
|||
|
||||
if hasattr(attr, "short_description"):
|
||||
label = attr.short_description
|
||||
elif callable(attr):
|
||||
elif isinstance(attr, collections.Callable):
|
||||
if attr.__name__ == "<lambda>":
|
||||
label = "--"
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ class Command(BaseCommand):
|
|||
|
||||
from categories.migration import drop_field
|
||||
if len(args) != 3:
|
||||
print "You must specify an Application name, a Model name and a Field name"
|
||||
print("You must specify an Application name, a Model name and a Field name")
|
||||
|
||||
drop_field(*args)
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ class Command(BaseCommand):
|
|||
|
||||
for file_path in file_paths:
|
||||
if not os.path.isfile(file_path):
|
||||
print "File %s not found." % file_path
|
||||
print("File %s not found." % file_path)
|
||||
continue
|
||||
f = file(file_path, 'r')
|
||||
f = open(file_path, 'r')
|
||||
data = f.readlines()
|
||||
f.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
from django.db import connection, transaction
|
||||
from django.apps import apps
|
||||
|
|
@ -47,7 +47,7 @@ def migrate_app(sender, *args, **kwargs):
|
|||
|
||||
app_name = app_config.label
|
||||
|
||||
fields = [fld for fld in registry._field_registry.keys() if fld.startswith(app_name)]
|
||||
fields = [fld for fld in list(registry._field_registry.keys()) if fld.startswith(app_name)]
|
||||
|
||||
sid = transaction.savepoint()
|
||||
for fld in fields:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.core.files.storage
|
||||
|
|
@ -20,15 +20,15 @@ class Migration(migrations.Migration):
|
|||
('name', models.CharField(max_length=100, verbose_name='name')),
|
||||
('slug', models.SlugField(verbose_name='slug')),
|
||||
('active', models.BooleanField(default=True, verbose_name='active')),
|
||||
('thumbnail', models.FileField(storage=django.core.files.storage.FileSystemStorage(), null=True, upload_to=b'uploads/categories/thumbnails', blank=True)),
|
||||
('thumbnail', models.FileField(storage=django.core.files.storage.FileSystemStorage(), null=True, upload_to='uploads/categories/thumbnails', blank=True)),
|
||||
('thumbnail_width', models.IntegerField(null=True, blank=True)),
|
||||
('thumbnail_height', models.IntegerField(null=True, blank=True)),
|
||||
('order', models.IntegerField(default=0)),
|
||||
('alternate_title', models.CharField(default=b'', help_text=b'An alternative title to use on pages with this category.', max_length=100, blank=True)),
|
||||
('alternate_url', models.CharField(help_text=b'An alternative URL to use instead of the one derived from the category hierarchy.', max_length=200, blank=True)),
|
||||
('alternate_title', models.CharField(default='', help_text='An alternative title to use on pages with this category.', max_length=100, blank=True)),
|
||||
('alternate_url', models.CharField(help_text='An alternative URL to use instead of the one derived from the category hierarchy.', max_length=200, blank=True)),
|
||||
('description', models.TextField(null=True, blank=True)),
|
||||
('meta_keywords', models.CharField(default=b'', help_text=b'Comma-separated keywords for search engines.', max_length=255, blank=True)),
|
||||
('meta_extra', models.TextField(default=b'', help_text=b'(Advanced) Any additional HTML to be placed verbatim in the <head>', blank=True)),
|
||||
('meta_keywords', models.CharField(default='', help_text='Comma-separated keywords for search engines.', max_length=255, blank=True)),
|
||||
('meta_extra', models.TextField(default='', help_text='(Advanced) Any additional HTML to be placed verbatim in the <head>', blank=True)),
|
||||
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
|
|
@ -47,7 +47,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('object_id', models.PositiveIntegerField(verbose_name='object id')),
|
||||
('relation_type', models.CharField(help_text="A generic text field to tag a relation, like 'leadphoto'.", max_length=b'200', null=True, verbose_name='relation type', blank=True)),
|
||||
('relation_type', models.CharField(help_text="A generic text field to tag a relation, like 'leadphoto'.", max_length='200', null=True, verbose_name='relation type', blank=True)),
|
||||
('category', models.ForeignKey(verbose_name='category', to='categories.Category')),
|
||||
('content_type', models.ForeignKey(verbose_name='content type', to='contenttypes.ContentType')),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.encoding import force_text
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from functools import reduce
|
||||
try:
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
except ImportError:
|
||||
|
|
@ -63,7 +64,7 @@ class Category(CategoryBase):
|
|||
except NoReverseMatch:
|
||||
prefix = '/'
|
||||
ancestors = list(self.get_ancestors()) + [self, ]
|
||||
return prefix + '/'.join([force_unicode(i.slug) for i in ancestors]) + '/'
|
||||
return prefix + '/'.join([force_text(i.slug) for i in ancestors]) + '/'
|
||||
|
||||
if RELATION_MODELS:
|
||||
def get_related_content_type(self, content_type):
|
||||
|
|
@ -133,7 +134,7 @@ class CategoryRelation(models.Model):
|
|||
object_id = models.PositiveIntegerField(verbose_name=_('object id'))
|
||||
content_object = GenericForeignKey('content_type', 'object_id')
|
||||
relation_type = models.CharField(verbose_name=_('relation type'),
|
||||
max_length="200",
|
||||
max_length=200,
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text=_("A generic text field to tag a relation, like 'leadphoto'."))
|
||||
|
|
@ -141,7 +142,7 @@ class CategoryRelation(models.Model):
|
|||
objects = CategoryRelationManager()
|
||||
|
||||
def __unicode__(self):
|
||||
return u"CategoryRelation"
|
||||
return "CategoryRelation"
|
||||
|
||||
try:
|
||||
from south.db import db # South is required for migrating. Need to check for it
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
These functions handle the adding of fields to other models
|
||||
"""
|
||||
from django.db.models import FieldDoesNotExist, ForeignKey, ManyToManyField
|
||||
import fields
|
||||
from . import fields
|
||||
# from settings import self._field_registry, self._model_registry
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
|
@ -32,7 +32,7 @@ class Registry(object):
|
|||
|
||||
app_label = app
|
||||
|
||||
if isinstance(field_definitions, basestring):
|
||||
if isinstance(field_definitions, str):
|
||||
field_definitions = [field_definitions]
|
||||
elif not isinstance(field_definitions, collections.Iterable):
|
||||
raise ImproperlyConfigured(_('Field configuration for %(app)s should '
|
||||
|
|
@ -64,7 +64,7 @@ class Registry(object):
|
|||
extra_params = {'to': 'categories.Category', 'blank': True}
|
||||
if field_type != 'ManyToManyField':
|
||||
extra_params['null'] = True
|
||||
if isinstance(fld, basestring):
|
||||
if isinstance(fld, str):
|
||||
field_name = fld
|
||||
elif isinstance(fld, dict):
|
||||
if 'name' in fld:
|
||||
|
|
@ -119,15 +119,15 @@ def _process_registry(registry, call_func):
|
|||
Given a dictionary, and a registration function, process the registry
|
||||
"""
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models.loading import get_model
|
||||
from django.apps import apps
|
||||
|
||||
for key, value in registry.items():
|
||||
model = get_model(*key.split('.'))
|
||||
for key, value in list(registry.items()):
|
||||
model = apps.get_model(*key.split('.'))
|
||||
if model is None:
|
||||
raise ImproperlyConfigured(_('%(key)s is not a model') % {'key': key})
|
||||
if isinstance(value, (tuple, list)):
|
||||
for item in value:
|
||||
if isinstance(item, basestring):
|
||||
if isinstance(item, str):
|
||||
call_func(model, item)
|
||||
elif isinstance(item, dict):
|
||||
field_name = item.pop('name')
|
||||
|
|
@ -135,7 +135,7 @@ def _process_registry(registry, call_func):
|
|||
else:
|
||||
raise ImproperlyConfigured(_("%(settings)s doesn't recognize the value of %(key)s") %
|
||||
{'settings': 'CATEGORY_SETTINGS', 'key': key})
|
||||
elif isinstance(value, basestring):
|
||||
elif isinstance(value, str):
|
||||
call_func(model, value)
|
||||
elif isinstance(value, dict):
|
||||
field_name = value.pop('name')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import collections
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
'ALLOW_SLUG_CHANGE': False,
|
||||
|
|
@ -18,9 +19,9 @@ DEFAULT_SETTINGS = {
|
|||
DEFAULT_SETTINGS.update(getattr(settings, 'CATEGORIES_SETTINGS', {}))
|
||||
|
||||
if DEFAULT_SETTINGS['SLUG_TRANSLITERATOR']:
|
||||
if callable(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR']):
|
||||
if isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], collections.Callable):
|
||||
pass
|
||||
elif isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], basestring):
|
||||
elif isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], str):
|
||||
from django.utils.importlib import import_module
|
||||
bits = DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'].split(".")
|
||||
module = import_module(".".join(bits[:-1]))
|
||||
|
|
|
|||
|
|
@ -11,22 +11,22 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar
|
|||
from .models import Category
|
||||
from .registration import registry
|
||||
import sys
|
||||
import StringIO
|
||||
import io
|
||||
|
||||
org_stderror = sys.stderr
|
||||
sys.stderr = StringIO.StringIO() # south will print out errors to stderr
|
||||
sys.stderr = io.StringIO() # south will print out errors to stderr
|
||||
try:
|
||||
from south.db import db
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured(_('%(dependency)s must be installed for this command to work') %
|
||||
{'dependency': 'South'})
|
||||
# pull the information from the registry
|
||||
if isinstance(app, basestring):
|
||||
if isinstance(app, str):
|
||||
app_name = app
|
||||
else:
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
|
||||
fields = [fld for fld in registry._field_registry.keys() if fld.startswith(app_name)]
|
||||
fields = [fld for fld in list(registry._field_registry.keys()) if fld.startswith(app_name)]
|
||||
# call the south commands to add the fields/tables
|
||||
for fld in fields:
|
||||
app_name, model_name, field_name = fld.split('.')
|
||||
|
|
@ -43,14 +43,14 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar
|
|||
db.add_column(table_name, field_name, registry._field_registry[fld], keep_default=False)
|
||||
db.commit_transaction()
|
||||
if verbosity:
|
||||
print (_('Added ForeignKey %(field_name)s to %(model_name)s') %
|
||||
{'field_name': field_name, 'model_name': model_name})
|
||||
except DatabaseError, e:
|
||||
print((_('Added ForeignKey %(field_name)s to %(model_name)s') %
|
||||
{'field_name': field_name, 'model_name': model_name}))
|
||||
except DatabaseError as e:
|
||||
db.rollback_transaction()
|
||||
if "already exists" in str(e):
|
||||
if verbosity > 1:
|
||||
print (_('ForeignKey %(field_name)s to %(model_name)s already exists') %
|
||||
{'field_name': field_name, 'model_name': model_name})
|
||||
print((_('ForeignKey %(field_name)s to %(model_name)s already exists') %
|
||||
{'field_name': field_name, 'model_name': model_name}))
|
||||
else:
|
||||
sys.stderr = org_stderror
|
||||
raise e
|
||||
|
|
@ -66,14 +66,14 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar
|
|||
db.create_unique(table_name, ['%s_id' % model_name, 'category_id'])
|
||||
db.commit_transaction()
|
||||
if verbosity:
|
||||
print (_('Added Many2Many table between %(model_name)s and %(category_table)s') %
|
||||
{'model_name': model_name, 'category_table': 'category'})
|
||||
except DatabaseError, e:
|
||||
print((_('Added Many2Many table between %(model_name)s and %(category_table)s') %
|
||||
{'model_name': model_name, 'category_table': 'category'}))
|
||||
except DatabaseError as e:
|
||||
db.rollback_transaction()
|
||||
if "already exists" in str(e):
|
||||
if verbosity > 1:
|
||||
print (_('Many2Many table between %(model_name)s and %(category_table)s already exists') %
|
||||
{'model_name': model_name, 'category_table': 'category'})
|
||||
print((_('Many2Many table between %(model_name)s and %(category_table)s already exists') %
|
||||
{'model_name': model_name, 'category_table': 'category'}))
|
||||
else:
|
||||
sys.stderr = org_stderror
|
||||
raise e
|
||||
|
|
@ -98,23 +98,23 @@ def drop_field(app_name, model_name, field_name):
|
|||
fld = '%s.%s.%s' % (app_name, model_name, field_name)
|
||||
|
||||
if isinstance(registry._field_registry[fld], CategoryFKField):
|
||||
print (_('Dropping ForeignKey %(field_name)s from %(model_name)s') %
|
||||
{'field_name': field_name, 'model_name': model_name})
|
||||
print((_('Dropping ForeignKey %(field_name)s from %(model_name)s') %
|
||||
{'field_name': field_name, 'model_name': model_name}))
|
||||
try:
|
||||
db.start_transaction()
|
||||
table_name = mdl._meta.db_table
|
||||
db.delete_column(table_name, field_name)
|
||||
db.commit_transaction()
|
||||
except DatabaseError, e:
|
||||
except DatabaseError as e:
|
||||
db.rollback_transaction()
|
||||
raise e
|
||||
elif isinstance(registry._field_registry[fld], CategoryM2MField):
|
||||
print (_('Dropping Many2Many table between %(model_name)s and %(category_table)s') %
|
||||
{'model_name': model_name, 'category_table': 'category'})
|
||||
print((_('Dropping Many2Many table between %(model_name)s and %(category_table)s') %
|
||||
{'model_name': model_name, 'category_table': 'category'}))
|
||||
try:
|
||||
db.start_transaction()
|
||||
db.delete_table(table_name, cascade=False)
|
||||
db.commit_transaction()
|
||||
except DatabaseError, e:
|
||||
except DatabaseError as e:
|
||||
db.rollback_transaction()
|
||||
raise e
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from django import template
|
||||
from django.db.models import get_model
|
||||
from django.apps import apps
|
||||
from django.template import (Node, TemplateSyntaxError, VariableDoesNotExist)
|
||||
from django.template.base import FilterExpression
|
||||
from django.utils.six import string_types
|
||||
from categories.base import CategoryBase
|
||||
from categories.models import Category
|
||||
from mptt.utils import drilldown_tree_for_node
|
||||
|
|
@ -30,8 +31,8 @@ def get_cat_model(model):
|
|||
Return a class from a string or class
|
||||
"""
|
||||
try:
|
||||
if isinstance(model, basestring):
|
||||
model_class = get_model(*model.split("."))
|
||||
if isinstance(model, string_types):
|
||||
model_class = apps.get_model(*model.split("."))
|
||||
elif issubclass(model, CategoryBase):
|
||||
model_class = model
|
||||
if model_class is None:
|
||||
|
|
@ -119,13 +120,13 @@ def get_category_drilldown(parser, token):
|
|||
'{%% %(tagname)s category_obj as varname %%}.'
|
||||
if len(bits) == 4:
|
||||
if bits[2] != 'as':
|
||||
raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]}
|
||||
raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]})
|
||||
if bits[2] == 'as':
|
||||
varname = bits[3].strip("'\"")
|
||||
model = "categories.category"
|
||||
if len(bits) == 6:
|
||||
if bits[2] not in ('using', 'as') or bits[4] not in ('using', 'as'):
|
||||
raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]}
|
||||
raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]})
|
||||
if bits[2] == 'as':
|
||||
varname = bits[3].strip("'\"")
|
||||
model = bits[5].strip("'\"")
|
||||
|
|
@ -266,7 +267,7 @@ def get_top_level_categories(parser, token):
|
|||
|
||||
def get_latest_objects_by_category(category, app_label, model_name, set_name,
|
||||
date_field='pub_date', num=15):
|
||||
m = get_model(app_label, model_name)
|
||||
m = apps.get_model(app_label, model_name)
|
||||
if not isinstance(category, CategoryBase):
|
||||
category = Category.objects.get(slug=str(category))
|
||||
children = category.children.all()
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@
|
|||
# test mixed
|
||||
import os
|
||||
|
||||
from django.test import TestCase
|
||||
from django.conf import settings
|
||||
from django.test import TestCase, override_settings
|
||||
from categories.models import Category
|
||||
from categories.management.commands.import_categories import Command
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
from categories.registration import _process_registry, registry
|
||||
|
||||
|
||||
@override_settings(INSTALLED_APPS=(app for app in settings.INSTALLED_APPS if app != 'django.contrib.flatpages'))
|
||||
class CategoryImportTest(TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class CategoryRegistrationTest(TestCase):
|
|||
}
|
||||
_process_registry(FK_REGISTRY, registry.register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()])
|
||||
|
||||
def test_foreignkey_dict(self):
|
||||
FK_REGISTRY = {
|
||||
|
|
@ -27,7 +27,7 @@ class CategoryRegistrationTest(TestCase):
|
|||
}
|
||||
_process_registry(FK_REGISTRY, registry.register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()])
|
||||
|
||||
def test_foreignkey_list(self):
|
||||
FK_REGISTRY = {
|
||||
|
|
@ -37,13 +37,13 @@ class CategoryRegistrationTest(TestCase):
|
|||
}
|
||||
_process_registry(FK_REGISTRY, registry.register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()])
|
||||
|
||||
if django.VERSION[1] >= 7:
|
||||
def test_new_foreignkey_string(self):
|
||||
registry.register_model('flatpages', 'flatpage', 'ForeignKey', 'category')
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()])
|
||||
|
||||
|
||||
class Categorym2mTest(TestCase):
|
||||
|
|
@ -53,6 +53,6 @@ class Categorym2mTest(TestCase):
|
|||
}
|
||||
_process_registry(M2M_REGISTRY, registry.register_m2m)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,40 +28,40 @@ class CategoryTagsTest(TestCase):
|
|||
Test that we can properly retrieve a category.
|
||||
"""
|
||||
# display_path_as_ul
|
||||
rock_resp = u'<ul><li><a href="/categories/">Top</a></li></ul>'
|
||||
rock_resp = '<ul><li><a href="/categories/">Top</a></li></ul>'
|
||||
resp = self.render_template('{% load category_tags %}{% display_path_as_ul "/Rock" %}')
|
||||
resp = re.sub(r'\n$', "", resp)
|
||||
self.assertEqual(resp, rock_resp)
|
||||
|
||||
# display_drilldown_as_ul
|
||||
expected_resp = u'<ul><li><a href="/categories/">Top</a><ul><li><a href="/categories/world/">World</a><ul><li><strong>Worldbeat</strong><ul><li><a href="/categories/world/worldbeat/afrobeat/">Afrobeat</a></li></ul></li></ul></li></ul></li></ul>'
|
||||
expected_resp = '<ul><li><a href="/categories/">Top</a><ul><li><a href="/categories/world/">World</a><ul><li><strong>Worldbeat</strong><ul><li><a href="/categories/world/worldbeat/afrobeat/">Afrobeat</a></li></ul></li></ul></li></ul></li></ul>'
|
||||
resp = self.render_template('{% load category_tags %}'
|
||||
'{% display_drilldown_as_ul "/World/Worldbeat" "categories.category" %}')
|
||||
resp = re.sub(r'\n$', "", resp)
|
||||
self.assertEqual(resp, expected_resp)
|
||||
|
||||
# breadcrumbs
|
||||
expected_resp = u'<a href="/categories/world/">World</a> > Worldbeat'
|
||||
expected_resp = '<a href="/categories/world/">World</a> > Worldbeat'
|
||||
resp = self.render_template('{% load category_tags %}'
|
||||
'{% breadcrumbs "/World/Worldbeat" " > " "categories.category" %}')
|
||||
self.assertEqual(resp, expected_resp)
|
||||
|
||||
# get_top_level_categories
|
||||
expected_resp = u'Avant-garde|Blues|Country|Easy listening|Electronic|Hip hop/Rap music|Jazz|Latin|Modern folk|Pop|Reggae|Rhythm and blues|Rock|World|'
|
||||
expected_resp = 'Avant-garde|Blues|Country|Easy listening|Electronic|Hip hop/Rap music|Jazz|Latin|Modern folk|Pop|Reggae|Rhythm and blues|Rock|World|'
|
||||
resp = self.render_template('{% load category_tags %}'
|
||||
'{% get_top_level_categories using "categories.category" as varname %}'
|
||||
'{% for item in varname %}{{ item }}|{% endfor %}')
|
||||
self.assertEqual(resp, expected_resp)
|
||||
|
||||
# get_category_drilldown
|
||||
expected_resp = u"World|World > Worldbeat|"
|
||||
expected_resp = "World|World > Worldbeat|"
|
||||
resp = self.render_template('{% load category_tags %}'
|
||||
'{% get_category_drilldown "/World" using "categories.category" as var %}'
|
||||
'{% for item in var %}{{ item }}|{% endfor %}')
|
||||
self.assertEqual(resp, expected_resp)
|
||||
|
||||
# recursetree
|
||||
expected_resp = u'<ul><li>Country<ul><li>Country pop<ul><li>Urban Cowboy</li></ul></li></ul></li><li>World<ul><li>Worldbeat<ul></ul></li></ul></li></ul>'
|
||||
expected_resp = '<ul><li>Country<ul><li>Country pop<ul><li>Urban Cowboy</li></ul></li></ul></li><li>World<ul><li>Worldbeat<ul></ul></li></ul></li></ul>'
|
||||
ctxt = {'nodes': Category.objects.filter(name__in=("Worldbeat", "Urban Cowboy"))}
|
||||
resp = self.render_template('{% load category_tags %}'
|
||||
'<ul>{% recursetree nodes|tree_queryset %}<li>{{ node.name }}'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
from .models import Category
|
||||
from . import views
|
||||
|
||||
try:
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
|
@ -15,12 +16,12 @@ categorytree_dict = {
|
|||
'queryset': Category.objects.filter(level=0)
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
urlpatterns = (
|
||||
url(
|
||||
r'^$', ListView.as_view(**categorytree_dict), name='categories_tree_list'
|
||||
),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('categories.views',
|
||||
url(r'^(?P<path>.+)/$', 'category_detail', name='categories_category'),
|
||||
urlpatterns += (
|
||||
url(r'^(?P<path>.+)/$', views.category_detail, name='categories_category'),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -63,14 +63,14 @@ class CategoryDetailView(DetailView):
|
|||
|
||||
def get_object(self, **kwargs):
|
||||
if self.path_field not in self.kwargs:
|
||||
raise AttributeError(u"Category detail view %s must be called with "
|
||||
u"a %s." % self.__class__.__name__, self.path_field)
|
||||
raise AttributeError("Category detail view %s must be called with "
|
||||
"a %s." % self.__class__.__name__, self.path_field)
|
||||
if self.queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
try:
|
||||
return get_category_for_path(self.kwargs[self.path_field], self.model.objects.all())
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404(_(u"No %(verbose_name)s found matching the query") %
|
||||
raise Http404(_("No %(verbose_name)s found matching the query") %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
def get_template_names(self):
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ source_suffix = '.rst'
|
|||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Django Categories'
|
||||
copyright = u'2010-2012, Corey Oordt'
|
||||
project = 'Django Categories'
|
||||
copyright = '2010-2012, Corey Oordt'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
|
@ -175,8 +175,8 @@ htmlhelp_basename = 'DjangoCategoriesdoc'
|
|||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'DjangoCategories.tex', u'Django Categories Documentation',
|
||||
u'CoreyOordt', 'manual'),
|
||||
('index', 'DjangoCategories.tex', 'Django Categories Documentation',
|
||||
'CoreyOordt', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ APP = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
|||
PROJ_ROOT = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.insert(0, APP)
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@domain.com'),
|
||||
|
|
@ -66,11 +65,6 @@ STATICFILES_FINDERS = (
|
|||
|
||||
SECRET_KEY = 'bwq#m)-zsey-fs)0#4*o=2z(v5g!ei=zytl9t-1hesh4b&-u^d'
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
|
|
@ -81,9 +75,16 @@ MIDDLEWARE_CLASSES = (
|
|||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')),
|
||||
)
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'APP_DIRS': True,
|
||||
'DIRS': [os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates'))],
|
||||
'OPTIONS': {
|
||||
'debug': DEBUG,
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
if django.VERSION[1] > 5:
|
||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from models import SimpleText, SimpleCategory
|
||||
from .models import SimpleText, SimpleCategory
|
||||
from django.contrib import admin
|
||||
|
||||
from categories.admin import CategoryBaseAdmin, CategoryBaseAdminForm
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class SimpleTest(TestCase):
|
|||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.failUnlessEqual(1 + 1, 2)
|
||||
self.assertEqual(1 + 1, 2)
|
||||
|
||||
__test__ = {"doctest": """
|
||||
Another way to test that 1 + 1 is equal to 2.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from django.conf.urls import patterns, include
|
||||
from django.conf.urls import include, url
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
from django.views.static import serve
|
||||
|
||||
admin.autodiscover()
|
||||
|
||||
|
||||
|
|
@ -9,7 +11,7 @@ import os
|
|||
|
||||
ROOT_PATH = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
urlpatterns = patterns('',
|
||||
urlpatterns = (
|
||||
# Example:
|
||||
# (r'^sample/', include('sample.foo.urls')),
|
||||
|
||||
|
|
@ -18,18 +20,18 @@ urlpatterns = patterns('',
|
|||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
||||
# Uncomment the next line to enable the admin:
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
(r'^categories/', include('categories.urls')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^categories/', include('categories.urls')),
|
||||
#(r'^cats/', include('categories.urls')),
|
||||
|
||||
(r'^static/categories/(?P<path>.*)$', 'django.views.static.serve',
|
||||
url(r'^static/categories/(?P<path>.*)$', serve,
|
||||
{'document_root': ROOT_PATH + '/categories/media/categories/'}),
|
||||
|
||||
# (r'^static/editor/(?P<path>.*)$', 'django.views.static.serve',
|
||||
# {'document_root': ROOT_PATH + '/editor/media/editor/',
|
||||
# 'show_indexes':True}),
|
||||
|
||||
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
|
||||
url(r'^static/(?P<path>.*)$', serve,
|
||||
{'document_root': os.path.join(ROOT_PATH, 'example', 'static')}),
|
||||
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
django-mptt>=0.6,<0.7
|
||||
django-mptt>=0.8,<0.9
|
||||
unicode-slugify==0.1.1
|
||||
|
|
|
|||
14
tox.ini
Normal file
14
tox.ini
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py27-django{18,19},
|
||||
py34-django{18,19},
|
||||
py35-django{18,19},
|
||||
|
||||
[testenv]
|
||||
deps=
|
||||
django19: Django==1.9.2
|
||||
django18: Django==1.8.9
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
commands=
|
||||
{toxinidir}/example/manage.py test --settings='settings-testing' categories
|
||||
Loading…
Reference in a new issue