我为Django-CMS写了一个旋转木马插件,它显示了截图。底层模型有一些与轮播相关的参数(高度,动画风格等),以及ForeignKey
到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 %}
我的问题是:我想概括我的carousel插件,以便在其他项目中重用它,因此不依赖于Screenshot
模型。我可以用for
替换模板的include
循环的内容,以允许每个项目指定如何在轮播中显示项目。但是如何概括CarouselPluginModel
的{{1}}?
在任何特定的应用程序中,我只希望允许一种类型的模型(在我的示例中为ForeignKey
) - 我不希望管理控制台允许包含任何其他模型。
谢谢!
答案 0 :(得分: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 %}
最后,我会建议您使用的模型在其描述中包含id
,因为管理面板必须按ID选择,例如:
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)