Как агностически связать любой объект / модель с другой моделью Django? - PullRequest
1 голос
/ 09 июня 2009

Я пишу простую CMS на основе Django. Большинство систем управления контентом полагаются на наличие фиксированной страницы, фиксированного 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, верно? Я пытался понять, как это работает, но я рисую пробелы.

Так, во-первых, я сумасшедший? И если предположить, что нет, и это выглядит как относительно разумная идея для продолжения, то как мне связать объект + строку с блоком / редактируемой областью?

Примечание: редактирование будет выполнено на странице , поэтому нет никакой реальной проблемы позволить пользователям редактировать зоны. Мне не нужно делать никаких обратных действий в админке. Моя конечная мечта - позволить третьему аргументу указать, что это за область контента (текст, изображение, видео и т. Д.). Если у вас есть какие-либо комментарии по этому поводу, я буду рад их прочитать!

Ответы [ 3 ]

6 голосов
/ 09 июня 2009

django-tagging использует фреймворк Django contenttypes . Документы объясняют это гораздо лучше, чем я, но самое простое описание этого было бы «универсальный внешний ключ, который может указывать на любую другую модель».

Это может быть то, что вы ищете, но из вашего описания также звучит так, как будто вы хотите сделать что-то очень похожее на некоторые другие существующие проекты:

  • django-flatblocks ("... действует как django.contrib.flatpages, но для частей страницы; как редактируемое окно справки, которое вы хотите показать рядом с основное содержание. ")

  • django-better-chunks («Думайте об этом как о плоских страницах для небольших кусков повторно используемого контента, которые вы, возможно, захотите вставить в свои шаблоны и управлять из интерфейса администратора . ")

и так далее. Если они похожи, то они станут для вас хорошей отправной точкой.

2 голосов
/ 03 августа 2009

Довольно просто использовать инфраструктуру 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' ...

Нужно знать, что вы не можете использовать поле object в вызове Block.objects.get, потому что это не настоящее поле базы данных. Вы должны использовать content_type и object_id.

Я назвал модель Block, но если у вас есть несколько случаев, когда более одного уникального кортежа (object, key) отображается на один и тот же блок, на самом деле это может быть промежуточная модель, которая сама имеет ForeignKey для вашего фактического Block модель или соответствующая модель в приложении-помощнике, подобном тем, о которых упоминал Ван Гейл.

2 голосов
/ 29 июля 2009

Требуется способ отображения некоторого специфичного для объекта содержимого в общем шаблоне, если указан конкретный объект, верно?

Для поддержки как моделей, так и других объектов нам нужны две промежуточные модели; один для обработки строк, а другой для работы с моделями. Мы могли бы сделать это с одной моделью, но это менее производительно. Эти модели будут обеспечивать связь между содержимым и строкой / моделью.

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 час. Дайте мне знать, если вы считаете, что такой подход кажется нормальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...