Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Implement a polymorphic asset library. #1

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
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
15 changes: 15 additions & 0 deletions icekit/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import JsonResponse
from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _
from polymorphic.admin import PolymorphicChildModelFilter
from polymorphic.admin import PolymorphicParentModelAdmin

from icekit import models
Expand Down Expand Up @@ -166,5 +168,18 @@ class MediaCategoryAdmin(admin.ModelAdmin):
pass


class AssetParentAdmin(PolymorphicParentModelAdmin):
base_model = models.Asset
list_display = ['title', 'get_admin_thumbnail', 'get_child_type', 'caption', ]
list_display_links = ['title']
filter_horizontal = ['categories', ]
list_filter = [PolymorphicChildModelFilter, 'categories']
search_fields = ['title', 'caption', 'admin_notes']
polymorphic_list = True

def get_child_models(self):
return [import_string(kls) for kls in settings.ASSET_CLASSES]

admin.site.register(models.Asset, AssetParentAdmin)
admin.site.register(models.Layout, LayoutAdmin)
admin.site.register(models.MediaCategory, MediaCategoryAdmin)
29 changes: 29 additions & 0 deletions icekit/migrations/0007_asset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('icekit', '0006_auto_20150911_0744'),
]

operations = [
migrations.CreateModel(
name='Asset',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(help_text='The title is shown in the "title" attribute', max_length=255, blank=True)),
('caption', models.TextField(blank=True)),
('admin_notes', models.TextField(help_text='Internal notes for administrators only.', blank=True)),
('categories', models.ManyToManyField(related_name='icekit_asset_related', to='icekit.MediaCategory', blank=True)),
('polymorphic_ctype', models.ForeignKey(related_name='polymorphic_icekit.asset_set+', editable=False, to='contenttypes.ContentType', null=True)),
],
options={
'abstract': False,
},
),
]
43 changes: 43 additions & 0 deletions icekit/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import six
from django.db import models
from django.utils.translation import ugettext_lazy as _
from fluent_contents.models import ContentItem
from polymorphic.models import PolymorphicModel

from . import abstract_models, managers


Expand All @@ -15,3 +21,40 @@ class MediaCategory(abstract_models.AbstractMediaCategory):
A categorisation model for Media assets.
"""
pass


class Asset(PolymorphicModel):
"""
A static asset available for use on a CMS page.
"""
title = models.CharField(
max_length=255,
blank=True,
help_text=_('The title is shown in the "title" attribute'),
)
caption = models.TextField(
blank=True,
)
categories = models.ManyToManyField(
'icekit.MediaCategory',
blank=True,
related_name='%(app_label)s_%(class)s_related',
)
admin_notes = models.TextField(
blank=True,
help_text=_('Internal notes for administrators only.'),
)

def get_admin_thumbnail(self, width=150, height=150):
raise NotImplementedError
get_admin_thumbnail.short_description = "thumbnail"

def get_child_type(self):
return self.polymorphic_ctype
get_child_type.short_description = 'type'

def get_uses(self):
return [item.parent.get_absolute_url() for item in self.assetitem_set().all()]

def __str__(self):
return self.title
40 changes: 19 additions & 21 deletions icekit/plugins/image/abstract_models.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,53 @@
from django.core.exceptions import ValidationError
from django.template import Context
from django.template.loader import render_to_string
from django.utils import six
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.db import models
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from fluent_contents.models import ContentItem
from icekit.models import Asset


@python_2_unicode_compatible
class AbstractImage(models.Model):
class AbstractImage(Asset):
"""
A reusable image.
"""
image = models.ImageField(
upload_to='uploads/images/',
verbose_name=_('Image field'),
)
title = models.CharField(
max_length=255,
blank=True,
help_text=_('Can be included in captions'),
)
alt_text = models.CharField(
max_length=255,
help_text=_("A description of the image for users who don't see images. Leave blank if the image has no informational value."),
blank=True,
)
caption = models.TextField(
blank=True,
)
categories = models.ManyToManyField(
'icekit.MediaCategory',
blank=True,
related_name='%(app_label)s_%(class)s_related',
)
admin_notes = models.TextField(
blank=True,
help_text=_('Internal notes for administrators only.'),
)
is_active = models.BooleanField(
default=True,
)

class Meta:
abstract = True

def clean(self):
if not (self.title or self.alt_text):
raise ValidationError("You must specify either title or alt text")

class Meta:
abstract = True
def get_admin_thumbnail(self, width=150, height=150):
try:
from easy_thumbnails.files import get_thumbnailer
except ImportError:
return 'Thumbnail error: easy_thumbnails not installed'
try:
thumbnailer = get_thumbnailer(self.image)
thumbnail = thumbnailer.get_thumbnail({'size': (width, height)})
return format_html('<img class="thumbnail" src="{0}" />'.format(thumbnail.url))
except Exception as ex:
return 'Thumbnail exception: {0}'.format(ex)

def __str__(self):
return self.title or self.alt_text
Expand Down Expand Up @@ -95,7 +93,7 @@ def caption(self):
@caption.setter
def caption(self, value):
"""
If the caption property is assigned, make it use the
If the caption property is assigned to make it use the
`caption_override` field.

:param value: The caption value to be saved.
Expand Down
16 changes: 3 additions & 13 deletions icekit/plugins/image/admin.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
from django.contrib import admin

from icekit.utils.admin.mixins import ThumbnailAdminMixin
from polymorphic.admin import PolymorphicChildModelAdmin

from . import models


class ImageAdmin(ThumbnailAdminMixin, admin.ModelAdmin):
list_display = ['thumbnail', 'title', 'alt_text',]
list_display_links = ['alt_text', 'thumbnail']
filter_horizontal = ['categories', ]
list_filter = ['categories',]
search_fields = ['title', 'alt_text', 'caption', 'admin_notes', 'image']

class ImageAdmin(PolymorphicChildModelAdmin):
base_model = models.Image
change_form_template = 'image/admin/change_form.html'

# ThumbnailAdminMixin attributes
thumbnail_field = 'image'
thumbnail_options = {
'size': (150, 150),
}

admin.site.register(models.Image, ImageAdmin)
72 changes: 72 additions & 0 deletions icekit/plugins/image/migrations/0009_assets_20161013_1124.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


def create_assets(apps, schema_editor):
# We need to create a new asset for each image
Image = apps.get_model('icekit_plugins_image', 'Image')
Asset = apps.get_model('icekit', 'Asset')
for image in Image.objects.all():
# Create a new asset
asset = Asset()
asset.admin_notes = image.admin_notes
asset.caption = image.caption
asset.title = image.title
asset.save()
asset.categories.add(*image.categories.all())

# Set the asset_ptr on the image
image.asset_ptr = asset
image.save()


class Migration(migrations.Migration):

dependencies = [
('icekit', '0007_asset'),
('icekit_plugins_image', '0008_auto_20160920_2114'),
('icekit', '0006_auto_20150911_0744'),
]

operations = [
# Add the ForeignKey first as not the primary key so we can fake it
migrations.AddField(
model_name='image',
name='asset_ptr',
field=models.OneToOneField(parent_link=True, auto_created=True, default=1, serialize=False, to='icekit.Asset'),
preserve_default=False,
),
# Create asset links for existing images
migrations.RunPython(
create_assets
),
migrations.RemoveField(
model_name='image',
name='admin_notes',
),
migrations.RemoveField(
model_name='image',
name='caption',
),
migrations.RemoveField(
model_name='image',
name='categories',
),
migrations.RemoveField(
model_name='image',
name='id',
),
migrations.RemoveField(
model_name='image',
name='title',
),
# Make asset_ptr the primary key
migrations.AlterField(
model_name='image',
name='asset_ptr',
field=models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='icekit.Asset'),
preserve_default=False,
),
]
2 changes: 2 additions & 0 deletions icekit/project/settings/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,8 @@

MIDDLEWARE_CLASSES += ('icekit.publishing.middleware.PublishingMiddleware', )

ASSET_CLASSES = ('icekit.plugins.image.models.Image',)

# MASTER PASSWORD #############################################################

AUTHENTICATION_BACKENDS += ('master_password.auth.ModelBackend', )
Expand Down