0

我为 Django-CMS 编写了一个显示屏幕截图的轮播插件。底层模型有一些与轮播相关的参数(高度、动画风格等),以及一个ForeignKeyto ScreenshotGroup

class ScreenshotGroup(models.Model):
    name = models.CharField(max_length=60)
    screenshots = models.ManyToManyField(Screenshot, through="ScreenshotGroupMember")

class Screenshot(models.Model):
    name = models.CharField(max_length=60)
    desc = models.TextField(_("description"), blank=True)
    img = models.ImageField(upload_to='img/')

class CarouselPluginModel(CMSPlugin):
    group = models.ForeignKey(ScreenshotGroup)
    height = models.IntegerField()
    ...

轮播的视图方法包含:

context['item_list'] = instance.group.screenshots.all()

(其实因为我用的是Django-CMS,所以在cms_plugins.py render方法里,不是view方法里。)

该模板通过以下方式引用屏幕截图字段:

{% for item in item_list %}
    {{ item.name }}
    {{ item.desc }}
    ...{{ item.img }}...
{% endfor %}

我的问题是:我想概括我的轮播插件以在其他项目中重用它,所以这不依赖于Screenshot模型。我可以用 an 替换模板for循环的内容,include以允许每个项目指定如何在轮播中显示项目。但是我如何概括CarouselPluginModel's ForeignKey

在任何特定应用程序中,我只希望允许一种类型的模型(ScreenshotGroup在我的示例中) - 我不希望管理控制台允许包含任何其他模型。

谢谢!

4

1 回答 1

2

基于 karthikr 建议的通用外键思想,这是我采用的完整解决方案。拼图的其他部分是:

  • 使用一个条目settings.py来限制在这个通用外键中允许哪些模型;
  • 嗅探所选模型的多对多字段;
  • {% include "carousel_item.html" %}在模板中使用来概括项目显示。我将在应用程序中提供默认实现,但这样最终用户不必遵守我预先定义的字段。

models.py

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.conf import settings

allowed_models = getattr(settings, 'ALLOWED_MODELS_IN_CAROUSEL', [])
# must be a list of dictionaries with keys: app_label and model, e.g:
# ALLOWED_MODELS_IN_CAROUSEL=[{'app_label':'myapp', 'model':'screenshotgroup'},]

fk_models = None
if allowed_models:
    # don't like this repetition - how can I improve this?
    fk_models = models.Q(app_label = allowed_models[0]['app_label'].lower(), 
                         model = allowed_models[0]['model'].lower())
    for m in allowed_models[1:]:
        fk_models = fk_models | models.Q(app_label = m['app_label'].lower(),
                                         model = m['model'].lower())

class CarouselPluginModel(CMSPlugin):
    content_type = models.ForeignKey(ContentType, limit_choices_to = fk_models)
    object_id = models.PositiveIntegerField()
    content_group = generic.GenericForeignKey('content_type', 'object_id')
    ...

视图需要在所选模型中找到 ManyToManyField,例如:

if instance.content_group and instance.content_group._meta.many_to_many:
    m2m_fieldname = instance.content_group._meta.many_to_many[0].name
    context['item_list'] = getattr(instance.content_group, m2m_fieldname).all()

该模板可能如下所示:

{% for item in item_list %}
    {% include "carousel_item.html" %}
{% endfor %}

And finally I'll include a recommendation that the model you use include its id in its description, since the admin panel will have to choose it by id, e.g:

class ScreenshotGroup(models.Model):
    name = models.CharField(max_length=60)
    screenshots = models.ManyToManyField(Screenshot, through="ScreenshotGroupMember")
    def __unicode__(self):
        return u"{0} (id {1})".format(self.name, self.id)
于 2013-06-28T01:36:44.563 回答