Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include LICENSE.rst
include README.rst
recursive-include shop_simplecategories/templates *
recursive-include shop_simplecategories/locale *
32 changes: 31 additions & 1 deletion shop_simplecategories/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
from shop_simplecategories.models import Category
from django import forms
from django.utils.translation import ugettext_lazy as _
from sorl.thumbnail.admin.current import AdminImageWidget
from sorl.thumbnail.fields import ImageField
from django.db.models import ManyToManyField
from shop.models import Product

class ProductWithCategoryForm(forms.ModelForm):
categories = forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -32,5 +36,31 @@ def save(self, commit=True):

return product

class CategoryAdminForm(forms.ModelForm):
class Meta(object):
model = Category

admin.site.register(Category)
products = forms.ModelMultipleChoiceField(
queryset = Product.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name=_('products'),
is_stacked=False
)
)

class CategoryAdmin(admin.ModelAdmin):
fieldsets = [
['', {'fields': ['name', 'slug', 'parent_category', 'order', 'image']}],
[_('Products'), {'fields': ['products'], 'classes': ('collapse',)}],
[_('Description'), {'fields': ['description'], 'classes': ('collapse',)}]
]
list_display = ['admin_thumbnail', 'name', 'parent_category', 'order']
list_editable = ['order']
formfield_overrides = {
ImageField: {'widget': AdminImageWidget},
}
form = CategoryAdminForm
prepopulated_fields = {'slug': ['name']}

admin.site.register(Category, CategoryAdmin)
12 changes: 12 additions & 0 deletions shop_simplecategories/cms_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8

from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _

class ShopCategoriesApp(CMSApp):
name = _("Shop categories App")
urls = ["shop_simplecategories.urls"]

apphook_pool.register(ShopCategoriesApp)
9 changes: 9 additions & 0 deletions shop_simplecategories/context_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8

__author__ = 'zeus'

from models import Category

def root_categories(request):
return {'ROOT_CATEGORIES': Category.objects.filter(parent_category=None)}
Binary file modified shop_simplecategories/locale/ru/LC_MESSAGES/django.mo
Binary file not shown.
48 changes: 37 additions & 11 deletions shop_simplecategories/locale/ru/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-23 14:04+0400\n"
"POT-Creation-Date: 2011-06-30 11:36+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand All @@ -18,22 +18,48 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%"
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"

#: models.py:22
msgid "category"
msgstr "категория"

#: models.py:23
#: admin.py:17 models.py:33
msgid "categories"
msgstr "категрии"

#: models.py:31
msgid "Parent category"
msgstr "Родительская категория"
#: admin.py:47
msgid "products"
msgstr "Продукты"

#: models.py:36
#: admin.py:55 models.py:46
msgid "Products"
msgstr "Продукты"

#: models.py:38
#: admin.py:56
msgid "Description"
msgstr "Описание"

#: cms_app.py:9
#, fuzzy
msgid "Shop categories App"
msgstr "категории"

#: models.py:32
msgid "category"
msgstr "категория"

#: models.py:41
msgid "Parent category"
msgstr "Родительская категория"

#: models.py:48
msgid "Ordering"
msgstr "Порядок"

#: models.py:49
msgid "Cover"
msgstr "Обложка"

#: models.py:77
msgid "Thumbnail"
msgstr "Миниатюра"

#: simplecategories_plugins/cms_plugins.py:14
#: simplecategories_plugins/models.py:12
msgid "Categories"
msgstr "Категории"
52 changes: 52 additions & 0 deletions shop_simplecategories/migrations/0003_addimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

def forwards(self, orm):

# Adding field 'Category.image'
db.add_column('shop_simplecategories_category', 'image', self.gf('sorl.thumbnail.fields.ImageField')(max_length=100, null=True, blank=True), keep_default=False)


def backwards(self, orm):

# Deleting field 'Category.image'
db.delete_column('shop_simplecategories_category', 'image')


models = {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'shop.product': {
'Meta': {'object_name': 'Product'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_shop.product_set'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
'unit_price': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '12', 'decimal_places': '2'})
},
'shop_simplecategories.category': {
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'parent_category': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['shop_simplecategories.Category']"}),
'products': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'categories'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['shop.Product']"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'})
}
}

complete_apps = ['shop_simplecategories']
53 changes: 53 additions & 0 deletions shop_simplecategories/migrations/0004_add_description.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

def forwards(self, orm):

# Adding field 'Category.description'
db.add_column('shop_simplecategories_category', 'description', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)


def backwards(self, orm):

# Deleting field 'Category.description'
db.delete_column('shop_simplecategories_category', 'description')


models = {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'shop.product': {
'Meta': {'object_name': 'Product'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_shop.product_set'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
'unit_price': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '12', 'decimal_places': '2'})
},
'shop_simplecategories.category': {
'Meta': {'ordering': "['order']", 'object_name': 'Category'},
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'parent_category': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['shop_simplecategories.Category']"}),
'products': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'categories'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['shop.Product']"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'})
}
}

complete_apps = ['shop_simplecategories']
75 changes: 71 additions & 4 deletions shop_simplecategories/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,41 @@
from django.db import models
from shop.models.productmodel import Product
from django.utils.translation import ugettext_lazy as _
from sorl.thumbnail import ImageField, get_thumbnail
from sorl.thumbnail.helpers import ThumbnailError
from django.conf import settings
import uuid
import os

class CategoryManager(models.Manager):
def root_categories(self):
return self.filter(parent_category__isnull=True)


def get_file_path(instance, filename):
ext = filename.split('.')[-1]
filename = "%s.%s" % (uuid.uuid4(), ext)
return os.path.join(getattr(settings, 'CATEGORY_IMAGE_UPLOAD_TO', 'categories/'), filename)

def rec(arr):
output = []
for i in arr:
output.append(i)
if hasattr(i, 'sub_categories'):
subs = rec(i.sub_categories)
i.IN = True
subs[-1].OUT = True
output += subs
return output

class Category(models.Model):
'''
"""
This should be a node in a tree (mptt?) structure representing categories
of products.
Ideally, this should be usable as a tag cloud too (tags are just categories
that are not in a tree structure). The display logic should be handle on a
per-site basis
'''
"""

class Meta(object):
verbose_name = _("category")
Expand All @@ -36,7 +57,10 @@ class Meta(object):
verbose_name=_('Products'),
)
order = models.IntegerField(verbose_name=_('Ordering'), default=0)
image = ImageField(verbose_name=_('Cover'), upload_to=get_file_path, null=True, blank=True)
objects = CategoryManager()

description = models.TextField(blank=True, null=True)

def __unicode__(self):
return self.name
Expand All @@ -45,11 +69,54 @@ def get_absolute_url(self):
return reverse('category_detail', args=[self.slug])

def get_products(self):
'''
"""
Gets the products belonging to this category (not recursively)
'''
"""
return self.products.all()

def get_child_categories(self):
return Category.objects.filter(parent_category=self)

def get_parents_as_tree(self, max_depth=10, add_childrens=False):
root_cats = []
if add_childrens:
root_cats = list(Category.objects.filter(parent_category=self))
current_category = self
while max_depth:
max_depth -= 1
if max_depth <=0:
break
# Collect siblings
level_categories = list(
Category.objects.filter(parent_category=current_category.parent_category)
)
# Set active level
for c in level_categories:
if current_category == c:
c.active = True
if root_cats:
c.sub_categories = root_cats
break
root_cats = level_categories
if not current_category.parent_category:
break
current_category = current_category.parent_category
return root_cats

def get_parents_as_list(self, max_depth=10):
return rec(self.get_parents_as_tree(max_depth))

def get_tree_as_list(self, max_depth=10):
return rec(self.get_parents_as_tree(add_childrens=True))

def admin_thumbnail(self):
try:
return '<img src="%s">' % get_thumbnail(self.image, '50x50', crop='center').url
except IOError:
return 'IOError'
except ThumbnailError, ex:
return 'ThumbnailError, %s' % ex.message

admin_thumbnail.short_description = _('Thumbnail')
admin_thumbnail.allow_tags = True

5 changes: 5 additions & 0 deletions shop_simplecategories/simplecategories_plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8

__author__ = 'zeus'

22 changes: 22 additions & 0 deletions shop_simplecategories/simplecategories_plugins/cms_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8

__author__ = 'zeus'


from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from models import CategoriesPlugin
from django.utils.translation import ugettext_lazy as _

class CategoryPlugin(CMSPluginBase):
model = CategoriesPlugin
name = _('Categories')
render_template = "cms/plugins/categories.html"
text_enabled = True

def render(self, context, instance, placeholder):
context.update({'category_list': instance.categories.all()})
return context

plugin_pool.register_plugin(CategoryPlugin)
Loading