繁体   English   中英

如何从另一个Django模型不可知地链接任何对象/模型?

[英]How to agnostically link any object/Model from another Django Model?

我正在写一个基于Django的简单CMS。 大多数内容管理系统都依赖于使用具有一个或多个可编辑区域的模板在固定的页面上,在固定的URL上。 要具有可编辑的区域,您需要一个页面。 为了让系统计算出哪个页面,您需要URL。

当您不再处理“页面”(那些FlatPages页面或其他内容),而是其他模型的实例时,就会出现问题。 例如,如果我有一个产品模型,则可能希望创建一个详细信息页面,其中包含多个可编辑区域。

可以将这些区域构建到模型中,但就我而言,有多个模型,并且要显示多少数据有很大差异。

因此,我想在模板级别构建CMS,并根据“页面”实例或其使用的模型指定一个块(可编辑区域)。

我有个想法,也许可以像这样在页面上转储自定义模板标签:

{% block unique_object "unique placeholder name" %}

然后将根据传入的两个参数找到一个“块”。一个示例:

<h1>{{ product_instance.name }}</h1>
{% block product_instance "detail: product short description" %}
{% block product_instance "detail: product video" %}
{% block product_instance "detail: product long description" %}

听起来很脏吧? 好吧,我遇到的问题是如何为区域创建“密钥”,以便可以拉出正确的块? 我将处理一个完全未知的对象(它可以是“页面”对象,URL,模型实例,甚至可以是船</fg> )。

其他Django微型应用程序必须执行此操作。 您可以使用django-tagging标记任何内容,对吗? 我试图了解它是如何工作的,但是我正在画空白。

所以,首先,我生气了吗? 假设我没有,而且这似乎是一个相对理智的想法,那么我应该如何将对象+字符串链接到块/可编辑区域?

注意:编辑将在页面上完成因此让用户编辑区域没有真正的问题。 我将不必在管理员中进行任何反向超级巨无霸。 我最终的梦想是允许第三个参数指定这是哪种内容区域(文本,图像,视频等)。 如果您对此有任何评论,我很高兴阅读它们!

django-tagging使用Django的contenttypes框架。 文档在解释方面做得比我做得更好,但是最简单的描述是“可以指向任何其他模型的通用外键”。

这可能是您要寻找的,但是从您的描述看来,您似乎也想做一些与其他现有项目非常相似的事情:

  • django-flatblocks (“ ...的行为类似于django.contrib.flatpages,但对于页面的一部分;就像您希望在主要内容旁边显示的可编辑帮助框一样。”)

  • django-better-chunks (“您可以将其看作是少量可重复使用内容的平面,您可能希望将其插入模板并通过管理界面进行管理。”

等等。 如果它们相似,那么它们将为您提供一个很好的起点。

您想要一种在给定特定对象的情况下在通用模板上显示一些特定于对象的内容的方法,对吗?

为了同时支持模型和其他对象,我们需要两个中间模型。 一种用于处理字符串,另一种用于处理模型。 我们可以用一个模型来做,但是性能较低。 这些模型将提供内容和字符串/模型之间的链接。

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

CONTENT_TYPE_CHOICES = (
    ("video", "Video"),
    ("text", "Text"),
    ("image", "Image"),
)

def _get_template(name, type):
    "Returns a list of templates to load given a name and a type"
    return ["%s_%s.html" % (type, name), "%s.html" % name, "%s.html" % type]

class ModelContentLink(models.Model):
    key = models.CharField(max_length=255) # Or whatever you find appropriate
    type = models.CharField(max_length=31, choices= CONTENT_TYPE_CHOICES)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey('content_type', 'object_id')

    def get_template(self):
        model_name = self.object.__class__.__name__.lower()
        return _get_template(model_name, self.type)

class StringContentLink(models.Model):
    key = models.CharField(max_length=255) # Or whatever length you find appropriate
    type = models.CharField(max_length=31, choices= CONTENT_TYPE_CHOICES)
    content = models.TextField()

    def get_template(self):
        return _get_template(self.content, self.type)

现在,我们只需要一个模板标签即可捕获这些模板,然后尝试加载由模型的get_template()方法提供的模板。 我的时间有些紧迫,所以我将其留在此处并在约1小时内进行更新。 让我知道您是否认为这种方法不错。

使用contenttypes框架来实现您正在描述的查找策略非常简单:

class Block(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey() # not actually used here, but may be handy
    key = models.CharField(max_length=255)
    ... other fields ...

    class Meta:
       unique_together = ('content_type', 'object_id', 'key')

def lookup_block(object, key):
    return Block.objects.get(content_type=ContentType.objects.get_for_model(object),
                             object_id=object.pk,
                             key=key)

@register.simple_tag
def block(object, key)
   block = lookup_block(object, key)
   ... generate template content using 'block' ...

要知道的一个Block.objects.get是,您不能使用Block.objects.get调用中的object字段,因为它不是真正的数据库字段。 您必须使用content_typeobject_id

我将模型称为Block ,但是如果在某些情况下,一个以上的唯一(object, key)元组映射到同一块,则它实际上可能是一个中间模型,该模型本身对您实际的Block模型或模型具有一个ForeignKey Van Gale提到的助手应用程序中的适当模型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM