mirror of
https://github.com/jazzband/django-categories.git
synced 2026-03-16 22:30:24 +00:00
pep8 cleanup
This commit is contained in:
parent
fa470df0a7
commit
0d254eca63
12 changed files with 161 additions and 145 deletions
|
|
@ -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',)
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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 <head>")
|
||||
|
||||
|
||||
|
||||
@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"
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ urlpatterns = patterns('django.views.generic.list_detail',
|
|||
|
||||
urlpatterns += patterns('categories.views',
|
||||
url(r'^(?P<path>.+)/$', 'category_detail', name='categories_category'),
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue