たまたまあなたの質問に出くわしました。私は最近、いくつかのプロジェクトに同様のものを実装しました。ここで説明されている Adam Alton の作業に基づいて私が行ったことは次のとおりです。 -分野/
ただし、これはCMSPluginではないため、これが質問に直接答えないことはわかっていますが、私が持っているものであり、同様のソリューションを探している他の人に役立つことを願っています.
概要として、顧客のサイトのフロント ページのバナーを表す "Banner" タイプをモデルで定義しています。各バナーは他のコンテンツにリンクできます。このような場合、リンク先は Django-CMS ページ、または他の多くのタイプのいずれかになります。すべてに get_absolute_url メソッドが定義されていますが、これを決定するためにイントロスペクションを使用していません。ここに表示されるすべてのタイプに get_absolute_url を実装しただけです。とにかく、ここに行きます:
まず、Banner の単純なモデルを次に示します。
class Banner(models.Model):
short_name = models.CharField(max_length=64, unique=True)
html = models.TextField()
link_text = models.CharField(max_length=128, default='Learn more')
destination_type = models.ForeignKey(ContentType, null=True, blank=True,
limit_choices_to={"model__in": ("Page", "Project", "Person", "Client")}
)
destination_id = models.PositiveIntegerField(null=True, blank=True)
destination = generic.GenericForeignKey('destination_type', 'destination_id')
published = models.BooleanField(blank=True, default=False)
def __unicode__(self):
return self.short_name
これが私のforms.pyです:
import re
from django.forms import ModelForm, ChoiceField
from cms.models import Page
from django.contrib.contenttypes.models import ContentType
from apps.your_application.models import Project, Person, Client
class BannerAdminForm(ModelForm):
class Meta:
model = Banner
fields = ("short_name", "html", "link_text", "destination", "link_hash", "published",)
# GenericForeignKey form field, will hold combined object_type and object_id
destination = ChoiceField(required=False) # Note the 'required=False' here.
def __init__(self, *args, **kwargs):
super(BannerAdminForm, self).__init__(*args, **kwargs)
# Combine object_type and object_id into a single 'destination' field
# Get all the objects that we want the user to be able to choose from
# Note: The user is going to locate these by name, so we should
# alphabetize all of these
available_objects = list(Page.objects.all().order_by('title_set__title'))
available_objects += list(Project.objects.all().order_by('title'))
available_objects += list(Person.objects.all().order_by('name'))
available_objects += list(Client.objects.all().order_by('name'))
# Now create our list of choices for the <select> field
object_choices = []
object_choices.append(["", "--"])
for obj in available_objects:
type_class = ContentType.objects.get_for_model(obj.__class__)
type_id = type_class.id
obj_id = obj.id
form_value = "type:%s-id:%s" % (type_id, obj_id) # e.g."type:12-id:3"
display_text = "%s : %s" % (str(type_class), str(obj)) # E.g. "Client : Apple, Inc."
object_choices.append([form_value, display_text])
self.fields['destination'].choices = object_choices
# If there is an existing value, pre-select it
if self.instance.destination:
type_class = ContentType.objects.get_for_model(self.instance.destination.__class__)
type_id = type_class.id
obj_id = self.instance.destination.id
current_value = "type:%s-id:%s" % (type_id, obj_id)
self.fields['destination'].initial = current_value
def save(self, *args, **kwargs):
try:
#get object_type and object_id values from combined destination field
object_string = self.cleaned_data['destination']
matches = re.match("type:(\d+)-id:(\d+)", object_string).groups()
object_type_id = matches[0] # get 45 from "type:45-id:38"
object_id = matches[1] # get 38 from "type:45-id:38"
object_type = ContentType.objects.get(id=object_type_id)
self.cleaned_data['destination_type'] = object_type_id
self.cleaned_data['destination_id'] = object_id
self.instance.destination_id = object_id
self.instance.destination_type = object_type
except:
# If anything goes wrong, leave it blank,
# This is also the case for when '--' is chosen
# In the drop-down (tsk, tsk, bad code style =/)
self.cleaned_data['destination_type'] = None
self.cleaned_data['destination_id'] = None
self.instance.destination_id = None
self.instance.destination_type = None
return super(BannerAdminForm, self).save(*args, **kwargs)
{% if banner.destination %}{{ banner.destination.get_absolute_url }}{% endif %}
その後、テンプレートを呼び出して、宛先オブジェクトの URL を取得でき
ます。
うまく機能し、CMSPlugin で使用するのが難しくないはずです。

編集: 実際、CMSPlugin フォームとまったく同じものを実装しました。本質的にゼロの違いがあります。次のように、cms_plugins.py ファイルのプラグイン クラスにフォームを追加することを忘れないでください。
class CMSBannerPlugin(CMSPluginBase):
form = BannerAdminForm # <==== Don't forget this part
model = Banner
name = _("Banner Plugin")
render_template = "apps/your_application/_banner.html"
def render(self, context, instance, placeholder):
...
return context
plugin_pool.register_plugin(CMSBannerPlugin)