我正在使用Django 1.4和django-CMS 2.3。
我有apphooks的几个应用程序,我想在django-CMS中能够引用 应用程序的对象。
为了建立可持续的链接,我正在尝试使用django-CMS菜单或通用外键找到一个插件。
如果不存在这样的情况,那么最好的通用外键应用是什么?我刚刚使用django.contrib.contenttypes创建了一个小插件,它限制了使用get_absolute_url
方法选择模型,但它很糟糕。
感谢。
答案 0 :(得分:3)
我刚碰到你的问题。我最近为几个项目实现了类似的东西,这就是我根据Adam Alton所做的工作所做的:http://adamalton.co.uk/blog/displaying-django-genericforeignkey-as-single-form-field/
这是不一个CMSPlugin,但是,我知道这并没有直接回答这个问题,而是我所拥有的,我希望它可以帮助其他人寻找类似的溶液击>
概述,我的模型中定义了“横幅”类型,代表客户网站首页上的横幅。每个横幅都可以链接到其他内容。在这些情况下,链接目标可以是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)
然后,您可以通过调用获取目标对象的URL
{% if banner.destination %}{{ banner.destination.get_absolute_url }}{% endif %}
在你的模板中。
运行良好,不应过于难以在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)