pep8 cleanup

This commit is contained in:
Corey Oordt 2012-07-12 19:24:55 -04:00
parent fa470df0a7
commit 0d254eca63
12 changed files with 161 additions and 145 deletions

View file

@ -32,7 +32,7 @@ if RELATION_MODELS:
class CategoryAdminForm(CategoryBaseAdminForm):
class Meta:
model = Category
def clean_alternate_title(self):
if self.instance is None or not self.cleaned_data['alternate_title']:
return self.cleaned_data['name']
@ -48,7 +48,7 @@ class CategoryAdmin(CategoryBaseAdmin):
'fields': ('parent', 'name', 'thumbnail', 'active')
}),
('Meta Data', {
'fields': ('alternate_title', 'alternate_url', 'description',
'fields': ('alternate_title', 'alternate_url', 'description',
'meta_keywords', 'meta_extra'),
'classes': ('collapse',),
}),
@ -57,10 +57,10 @@ class CategoryAdmin(CategoryBaseAdmin):
'classes': ('collapse',),
}),
)
if RELATION_MODELS:
inlines = [InlineCategoryRelation,]
inlines = [InlineCategoryRelation, ]
class Media:
js = (JAVASCRIPT_URL + 'genericcollections.js',)

View file

@ -16,6 +16,7 @@ from mptt.managers import TreeManager
from .editor.tree_editor import TreeEditor
from .settings import ALLOW_SLUG_CHANGE, SLUG_TRANSLITERATOR
class CategoryManager(models.Manager):
"""
A manager that adds an "active()" method for all active categories
@ -32,44 +33,44 @@ class CategoryBase(MPTTModel):
This base model includes the absolute bare bones fields and methods. One
could simply subclass this model and do nothing else and it should work.
"""
parent = TreeForeignKey('self',
blank=True,
null=True,
related_name="children",
parent = TreeForeignKey('self',
blank=True,
null=True,
related_name="children",
verbose_name='Parent')
name = models.CharField(max_length=100)
slug = models.SlugField()
active = models.BooleanField(default=True)
objects = CategoryManager()
tree = TreeManager()
def save(self, *args, **kwargs):
"""
While you can activate an item without activating its descendants,
It doesn't make sense that you can deactivate an item and have its
It doesn't make sense that you can deactivate an item and have its
decendants remain active.
"""
if not self.slug:
self.slug = slugify(SLUG_TRANSLITERATOR(self.name))[:50]
super(CategoryBase, self).save(*args, **kwargs)
if not self.active:
for item in self.get_descendants():
if item.active != self.active:
item.active = self.active
item.save()
def __unicode__(self):
ancestors = self.get_ancestors()
return ' > '.join([force_unicode(i.name) for i in ancestors]+[self.name,])
return ' > '.join([force_unicode(i.name) for i in ancestors] + [self.name, ])
class Meta:
abstract = True
unique_together = ('parent', 'name')
ordering = ('tree_id', 'lft')
class MPTTMeta:
order_insertion_by = 'name'
@ -79,11 +80,11 @@ class CategoryBaseAdminForm(forms.ModelForm):
if self.instance is None or not ALLOW_SLUG_CHANGE:
self.cleaned_data['slug'] = slugify(self.cleaned_data['name'])
return self.cleaned_data['slug'][:50]
def clean(self):
super(CategoryBaseAdminForm, self).clean()
opts = self._meta
# Validate slug is valid in that level
kwargs = {}
if self.cleaned_data.get('parent', None) is None:
@ -91,14 +92,14 @@ class CategoryBaseAdminForm(forms.ModelForm):
else:
kwargs['parent__pk'] = int(self.cleaned_data['parent'].id)
this_level_slugs = [c['slug'] for c in opts.model.objects.filter(
**kwargs).values('id','slug'
**kwargs).values('id', 'slug'
) if c['id'] != self.instance.id]
if self.cleaned_data['slug'] in this_level_slugs:
raise forms.ValidationError("The slug must be unique among "
"the items at its level.")
# Validate Category Parent
# Make sure the category doesn't set itself or any of its children as
# Make sure the category doesn't set itself or any of its children as
# its parent.
decendant_ids = self.instance.get_descendants().values_list('id', flat=True)
if self.cleaned_data.get('parent', None) is None or self.instance.id is None:
@ -117,35 +118,36 @@ class CategoryBaseAdmin(TreeEditor, admin.ModelAdmin):
list_display = ('name', 'active')
search_fields = ('name',)
prepopulated_fields = {'slug': ('name',)}
actions = ['activate', 'deactivate']
def get_actions(self, request):
actions = super(CategoryBaseAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def deactivate(self, request, queryset):
"""
Set active to False for selected items
"""
selected_cats = self.model.objects.filter(
pk__in=[int(x) for x in request.POST.getlist('_selected_action')])
for item in selected_cats:
if item.active:
item.active = False
item.save()
item.children.all().update(active=False)
deactivate.short_description = "Deactivate selected categories and their children"
def activate(self, request, queryset):
"""
Set active to True for selected items
"""
selected_cats = self.model.objects.filter(
pk__in=[int(x) for x in request.POST.getlist('_selected_action')])
for item in selected_cats:
item.active = True
item.save()

View file

@ -8,4 +8,4 @@ if STATIC_URL == None:
STATIC_URL = settings.MEDIA_URL
MEDIA_PATH = getattr(settings, 'EDITOR_MEDIA_PATH', '%seditor/' % STATIC_URL)
TREE_INITIAL_STATE = getattr(settings, 'EDITOR_TREE_INITIAL_STATE', 'collapsed')
TREE_INITIAL_STATE = getattr(settings, 'EDITOR_TREE_INITIAL_STATE', 'collapsed')

View file

@ -11,15 +11,16 @@ import django
import settings
class TreeEditorQuerySet(QuerySet):
"""
The TreeEditorQuerySet is a special query set used only in the TreeEditor
ChangeList page. The only difference to a regular QuerySet is that it
will enforce:
(a) The result is ordered in correct tree order so that
the TreeAdmin works all right.
(b) It ensures that all ancestors of selected items are included
in the result set, so the resulting tree display actually
makes sense.
@ -41,20 +42,20 @@ class TreeEditorQuerySet(QuerySet):
p.id not in include_pages:
ancestor_id_list = p.get_ancestors().values_list('id', flat=True)
include_pages.update(ancestor_id_list)
if include_pages:
qs = qs | self.model._default_manager.filter(id__in=include_pages)
qs = qs.distinct()
for obj in super(TreeEditorQuerySet, qs).iterator():
yield obj
# Although slicing isn't nice in a tree, it is used in the deletion action
# in the admin changelist. This causes github issue #25
# def __getitem__(self, index):
# return self # Don't even try to slice
def get(self, *args, **kwargs):
"""
Quick and dirty hack to fix change_view and delete_view; they use
@ -65,54 +66,56 @@ class TreeEditorQuerySet(QuerySet):
"""
return self.model._default_manager.get(*args, **kwargs)
class TreeChangeList(ChangeList):
def _get_default_ordering(self):
if django.VERSION[1] < 4:
return '', '' #('tree_id', 'lft')
return '', '' # ('tree_id', 'lft')
else:
return []
def get_ordering(self, request=None, queryset=None):
if django.VERSION[1] < 4:
return '', '' #('tree_id', 'lft')
return '', '' # ('tree_id', 'lft')
else:
return []
def get_query_set(self, *args, **kwargs):
qs = super(TreeChangeList, self).get_query_set(*args, **kwargs).order_by('tree_id', 'lft')
return qs
class TreeEditor(admin.ModelAdmin):
list_per_page = 999999999 # We can't have pagination
list_max_show_all = 200 # new in django 1.4
list_per_page = 999999999 # We can't have pagination
list_max_show_all = 200 # new in django 1.4
class Media:
css = {'all':(settings.MEDIA_PATH + "jquery.treeTable.css",)}
css = {'all': (settings.MEDIA_PATH + "jquery.treeTable.css", )}
js = []
js.extend((settings.MEDIA_PATH + "jquery.treeTable.js",))
js.extend((settings.MEDIA_PATH + "jquery.treeTable.js", ))
def __init__(self, *args, **kwargs):
super(TreeEditor, self).__init__(*args, **kwargs)
self.list_display = list(self.list_display)
if 'action_checkbox' in self.list_display:
self.list_display.remove('action_checkbox')
opts = self.model._meta
self.change_list_template = [
'admin/%s/%s/editor/tree_editor.html' % (opts.app_label, opts.object_name.lower()),
'admin/%s/editor/tree_editor.html' % opts.app_label,
'admin/editor/tree_editor.html',
]
def get_changelist(self, request, **kwargs):
"""
Returns the ChangeList class for use on the changelist page.
"""
return TreeChangeList
def old_changelist_view(self, request, extra_context=None):
"The 'change list' admin view for this model."
from django.contrib.admin.views.main import ERROR_FLAG
@ -137,15 +140,15 @@ class TreeEditor(admin.ModelAdmin):
try:
if django.VERSION[1] < 4:
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page,self.list_editable, self)
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_editable, self)
else:
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_max_show_all,
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_max_show_all,
self.list_editable, self)
cl = TreeChangeList(*params)
except IncorrectLookupParameters:
@ -238,7 +241,7 @@ class TreeEditor(admin.ModelAdmin):
else:
selection_note_all = ungettext('%(total_count)s selected',
'All %(total_count)s selected', cl.result_count)
context.update({
'module_name': force_unicode(opts.verbose_name_plural),
'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
@ -253,7 +256,7 @@ class TreeEditor(admin.ModelAdmin):
'admin/%s/change_list.html' % app_label,
'admin/change_list.html'
], context, context_instance=context_instance)
def changelist_view(self, request, extra_context=None, *args, **kwargs):
"""
Handle the changelist view, the django view for the model instances
@ -267,7 +270,7 @@ class TreeEditor(admin.ModelAdmin):
request, extra_context, *args, **kwargs)
else:
return self.old_changelist_view(request, extra_context)
def queryset(self, request):
"""
Returns a QuerySet of all model instances that can be edited by the

View file

@ -3,8 +3,12 @@ Provides compatibility with Django 1.1
Copied from django.contrib.admin.util
"""
from django.forms.forms import pretty_name
from django.db import models
from django.db.models.related import RelatedObject
from django.utils.encoding import force_unicode, smart_unicode, smart_str
from django.utils import formats
def lookup_field(name, obj, model_admin=None):
opts = obj._meta
@ -81,10 +85,11 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
else:
return label
def display_for_field(value, field):
from django.contrib.admin.templatetags.admin_list import _boolean_icon
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
if field.flatchoices:
return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE)
# NullBooleanField needs special-case null-handling, so it comes

View file

@ -2,6 +2,7 @@ from django.db.models import ForeignKey, ManyToManyField
from .models import Category
class CategoryM2MField(ManyToManyField):
def __init__(self, **kwargs):
if 'to' in kwargs:

View file

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""
@ -8,7 +9,7 @@ class Command(BaseCommand):
args = "[appname ...]"
can_import_settings = True
requires_model_validation = False
def handle(self, *args, **options):
"""
Alter the tables
@ -17,7 +18,7 @@ class Command(BaseCommand):
from south.db import db
except ImportError:
raise ImproperlyConfigured("South must be installed for this command to work")
from categories.migration import migrate_app
from categories import model_registry
if args:

View file

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""
@ -8,7 +9,7 @@ class Command(BaseCommand):
args = "appname modelname fieldname"
can_import_settings = True
requires_model_validation = False
def handle(self, *args, **options):
"""
Alter the tables
@ -17,10 +18,9 @@ class Command(BaseCommand):
from south.db import db
except ImportError:
raise ImproperlyConfigured("South must be installed for this command to work")
from categories.migration import drop_field
from categories import model_registry
if len(args) != 3:
print "You must specify an Application name, a Model name and a Field name"
drop_field(*args)

View file

@ -5,18 +5,19 @@ from django.db import transaction
from categories.models import Category
from categories.settings import SLUG_TRANSLITERATOR
class Command(BaseCommand):
"""Import category trees from a file."""
help = "Imports category tree(s) from a file. Sub categories must be indented by the same multiple of spaces or tabs."
args = "file_path [file_path ...]"
def get_indent(self, string):
"""
Look through the string and count the spaces
"""
indent_amt = 0
if string[0] == '\t':
return '\t'
for char in string:
@ -24,7 +25,7 @@ class Command(BaseCommand):
indent_amt += 1
else:
return ' ' * indent_amt
@transaction.commit_on_success
def make_category(self, string, parent=None, order=1):
"""
@ -42,20 +43,20 @@ class Command(BaseCommand):
parent.rght = cat.rght + 1
parent.save()
return cat
def parse_lines(self, lines):
"""
Do the work of parsing each line
"""
indent = ''
level = 0
if lines[0][0] == ' ' or lines[0][0] == '\t':
raise CommandError("The first line in the file cannot start with a space or tab.")
# This keeps track of the current parents at a given level
current_parents = {0: None}
for line in lines:
if len(line) == 0:
continue
@ -65,18 +66,18 @@ class Command(BaseCommand):
elif not line[0] in indent:
raise CommandError("You can't mix spaces and tabs for indents")
level = line.count(indent)
current_parents[level] = self.make_category(line, parent=current_parents[level-1])
current_parents[level] = self.make_category(line, parent=current_parents[level - 1])
else:
# We are back to a zero level, so reset the whole thing
current_parents = {0: self.make_category(line)}
current_parents[0]._tree_manager.rebuild()
def handle(self, *file_paths, **options):
"""
Handle the basic import
"""
import os
for file_path in file_paths:
if not os.path.isfile(file_path):
print "File %s not found." % file_path
@ -84,6 +85,5 @@ class Command(BaseCommand):
f = file(file_path, 'r')
data = f.readlines()
f.close()
self.parse_lines(data)

View file

@ -7,16 +7,17 @@ from django.core.files.storage import get_storage_class
from django.utils.translation import ugettext_lazy as _
from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH,
from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH,
THUMBNAIL_STORAGE)
from .base import CategoryBase
STORAGE = get_storage_class(THUMBNAIL_STORAGE)
class Category(CategoryBase):
thumbnail = models.FileField(
upload_to=THUMBNAIL_UPLOAD_PATH,
upload_to=THUMBNAIL_UPLOAD_PATH,
null=True, blank=True,
storage=STORAGE(),)
thumbnail_width = models.IntegerField(blank=True, null=True)
@ -28,8 +29,8 @@ class Category(CategoryBase):
max_length=100,
help_text="An alternative title to use on pages with this category.")
alternate_url = models.CharField(
blank=True,
max_length=200,
blank=True,
max_length=200,
help_text="An alternative URL to use instead of the one derived from "
"the category hierarchy.")
description = models.TextField(blank=True, null=True)
@ -43,20 +44,19 @@ class Category(CategoryBase):
default="",
help_text="(Advanced) Any additional HTML to be placed verbatim "
"in the &lt;head&gt;")
@property
def short_title(self):
return self.name
def get_absolute_url(self):
"""Return a path"""
if self.alternate_url:
return self.alternate_url
prefix = reverse('categories_tree_list')
ancestors = list(self.get_ancestors()) + [self,]
ancestors = list(self.get_ancestors()) + [self, ]
return prefix + '/'.join([force_unicode(i.slug) for i in ancestors]) + '/'
if RELATION_MODELS:
def get_related_content_type(self, content_type):
"""
@ -64,13 +64,13 @@ class Category(CategoryBase):
"""
return self.categoryrelation_set.filter(
content_type__name=content_type)
def get_relation_type(self, relation_type):
"""
Get all relations of the specified relation type
"""
return self.categoryrelation_set.filter(relation_type=relation_type)
def save(self, *args, **kwargs):
if self.thumbnail:
from django.core.files.images import get_image_dimensions
@ -81,23 +81,25 @@ class Category(CategoryBase):
width, height = get_image_dimensions(self.thumbnail.file, close=True)
else:
width, height = None, None
self.thumbnail_width = width
self.thumbnail_height = height
super(Category, self).save(*args, **kwargs)
class Meta(CategoryBase.Meta):
verbose_name_plural = 'categories'
class MPTTMeta:
order_insertion_by = ('order', 'name')
if RELATIONS:
CATEGORY_RELATION_LIMITS = reduce(lambda x,y: x|y, RELATIONS)
CATEGORY_RELATION_LIMITS = reduce(lambda x, y: x | y, RELATIONS)
else:
CATEGORY_RELATION_LIMITS = []
class CategoryRelationManager(models.Manager):
def get_content_type(self, content_type):
"""
@ -105,7 +107,7 @@ class CategoryRelationManager(models.Manager):
"""
qs = self.get_query_set()
return qs.filter(content_type__name=content_type)
def get_relation_type(self, relation_type):
"""
Get all the items of the given relationship type related to this item.
@ -113,6 +115,7 @@ class CategoryRelationManager(models.Manager):
qs = self.get_query_set()
return qs.filter(relation_type=relation_type)
class CategoryRelation(models.Model):
"""Related category item"""
category = models.ForeignKey(Category)
@ -120,13 +123,13 @@ class CategoryRelation(models.Model):
ContentType, limit_choices_to=CATEGORY_RELATION_LIMITS)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
relation_type = models.CharField(_("Relation Type"),
max_length="200",
blank=True,
relation_type = models.CharField(_("Relation Type"),
max_length="200",
blank=True,
null=True,
help_text=_("A generic text field to tag a relation, like 'leadphoto'."))
objects = CategoryRelationManager()
def __unicode__(self):
return u"CategoryRelation"

View file

@ -13,4 +13,4 @@ urlpatterns = patterns('django.views.generic.list_detail',
urlpatterns += patterns('categories.views',
url(r'^(?P<path>.+)/$', 'category_detail', name='categories_category'),
)
)

View file

@ -10,20 +10,21 @@ from django.utils.translation import ugettext_lazy as _
from .models import Category
from .settings import CACHE_VIEW_LENGTH
@cache_page(CACHE_VIEW_LENGTH)
def category_detail(request, path,
def category_detail(request, path,
template_name='categories/category_detail.html', extra_context={}):
path_items = path.strip('/').split('/')
if len(path_items) >= 2:
category = get_object_or_404(Category,
slug__iexact = path_items[-1],
level = len(path_items)-1,
slug__iexact=path_items[-1],
level=len(path_items) - 1,
parent__slug__iexact=path_items[-2])
else:
category = get_object_or_404(Category,
slug__iexact = path_items[-1],
level = len(path_items)-1)
slug__iexact=path_items[-1],
level=len(path_items) - 1)
templates = []
while path_items:
templates.append('categories/%s.html' % '_'.join(path_items))
@ -31,7 +32,7 @@ def category_detail(request, path,
templates.append(template_name)
context = RequestContext(request)
context.update({'category':category})
context.update({'category': category})
if extra_context:
context.update(extra_context)
return HttpResponse(select_template(templates).render(context))
@ -41,13 +42,13 @@ def get_category_for_path(path, queryset=Category.objects.all()):
path_items = path.strip('/').split('/')
if len(path_items) >= 2:
queryset = queryset.filter(
slug__iexact = path_items[-1],
level = len(path_items)-1,
slug__iexact=path_items[-1],
level=len(path_items) - 1,
parent__slug__iexact=path_items[-2])
else:
queryset = queryset.filter(
slug__iexact = path_items[-1],
level = len(path_items)-1)
slug__iexact=path_items[-1],
level=len(path_items) - 1)
return queryset.get()
try:
@ -72,13 +73,13 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
raise AttributeError(u"Category detail view %s must be called with "
u"a %s." % self.__class__.__name__, self.path_field)
if self.queryset is None:
queryset = self.get_queryset()
queryset = self.get_queryset()
try:
return get_category_for_path(self.kwargs[self.path_field])
except ObjectDoesNotExist:
raise Http404(_(u"No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
def get_template_names(self):
names = []
path_items = self.kwargs[self.path_field].strip('/').split('/')
@ -88,16 +89,14 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
names.extend(super(CategoryDetailView, self).get_template_names())
return names
class CategoryRelatedDetail(DetailView):
path_field = 'category_path'
object_name_field = None
def get_object(self, **kwargs):
queryset = super(CategoryRelatedDetail, self).get_queryset()
category = get_category_for_path(self.kwargs[self.path_field])
return queryset.get(category=category,slug=self.kwargs[self.slug_field])
return queryset.get(category=category, slug=self.kwargs[self.slug_field])
def get_template_names(self):
names = []
@ -106,22 +105,22 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
if self.object_name_field:
path_items.append(getattr(self.object, self.object_name_field))
while path_items:
names.append( '%s/category_%s_%s%s.html' % (opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s_%s%s.html' % (
opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
path_items.pop()
names.append('%s/category_%s%s.html' % (opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s%s.html' % (
opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.extend(super(CategoryRelatedDetail, self).get_template_names())
return names
class CategoryRelatedList(ListView):
path_field = 'category_path'
def get_queryset(self):
@ -135,15 +134,17 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
opts = self.object_list.model._meta
path_items = self.kwargs[self.path_field].strip('/').split('/')
while path_items:
names.append( '%s/category_%s_%s%s.html' % (opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s_%s%s.html' % (
opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
path_items.pop()
names.append('%s/category_%s%s.html' % (opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s%s.html' % (
opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.extend(super(CategoryRelatedList, self).get_template_names())
return names