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モデルに依存しません。テンプレートのforループの内容を に置き換えて、include各プロジェクトがアイテムをカルーセルに表示する方法を指定できるようにします。しかし、どうすれば を一般化できるでしょCarouselPluginModelForeignKeyか?

特定のアプリケーションでは、1 つのタイプのモデルのみを許可する必要があります (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 %}

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)
于 2013-06-28T01:36:44.563 に答える