Связывание и получение данных из моделей Django в тексте, введенном пользователем - PullRequest
7 голосов
/ 07 апреля 2011

Я ищу функциональность, похожую на ту, которую предоставляет Semantic MediaWiki. Короче говоря, я бы хотел, чтобы пользователь в произвольном текстовом поле мог выполнять следующие действия (я делаю разметку на ходу).

* Привет всем, не забывайте, что у нас [[:: AfricanSwallow.count]] африканские ласточки на нашей земле.

* Знаете ли вы, что Гарри, Европейская ласточка, взял с собой [[:: EuropeanSwallow.get (name = "harry"). Coconuts.count]] кокосовые орехи с собой?

В дополнение к этим функциям я хотел бы иметь возможность автозаполнения в строке - возможно, когда пользователь начнет печатать.

Я могу сделать все эти вещи, но я надеюсь, что некоторые или все они были сделаны. Есть идеи, если это так?

Ответы [ 2 ]

1 голос
/ 23 мая 2011

Я думаю, что-то подобное возможно, но сделать его универсальным (разрешить полный доступ только для чтения к ORM) было бы очень трудно сделать безопасным способом.

Вот несколько идей:

Ограничить действия заранее заданным набором явно помеченных методов в пользовательском классе менеджера.Например:

from django.db import models

class MarkupAccessManager(models.Manager):
    def count(self):
        return super(MarkupAccessManager, self).count()
    count.expose_to_markup = True


class AfricanSwallow(models.Model):
    objects = MarkupAccessManager()

Чтобы обратиться к моделям из разметки, вы можете воспользоваться структурой django.contrib.contenttypes, и теги могут иметь следующий формат: app_label.model_name action или app_label.model_name action arg1 arg2.

В зависимости от языка разметки, который вы выбираете, вы можете использовать пользовательские теги (если они есть в языке), теги шаблонов Django или обычные регулярные выражения.Как только вы получите содержимое тега, вы можете заменить его выводом указанного метода:

from django.contrib.contenttypes.models import ContentType

def replace_tag(tag):
    """
    'birds.africanswallow count' => birds.models.AfricanSwallow.objects.count()

    """
    bits = tag.split()
    model_ref = bits[0]
    action = bits[1]
    args = bits[2:]
    try:
        ct = ContentType.objects.get_by_natural_key(*model_ref.split('.'))
    except ContentType.DoesNotExist:
        return 'Invalid model reference.'

    model = ct.model_class()

    method = getattr(model._base_manager, action, None)
    if not method or not method.expose_to_markup:
        return 'Invalid action.'

    return method(*args)

Чтобы обеспечить автозаполнение, что-то в этом духе поможет вам составить список всехдоступные опции:

from django.db.models.loading import get_models
from django.contrib.contenttypes.models import ContentType


def model_refs():
    for model in get_models():
        if isinstance(model._base_manager, MarkupAccessManager):
            ct = ContentType.objects.get_for_model(model)
            yield '%s.%s' % (ct.app_label, ct.model)



def actions():
    for attr_name in dir(MarkupAccessManager):
        attr = getattr(MarkupAccessManager, attr_name)
        if attr.expose_to_markup:
            yield attr.__name__

Я не проверял код.Надеюсь, это немного поможет.

0 голосов
/ 18 мая 2011

Наиболее элегантным решением было бы создать компилятор , который позволит выполнять только определенные команды.Узнать больше @ http://en.wikibooks.org/wiki/Compiler_Construction

Другой способ - использовать exec () , но , вам следует избегать этого , поскольку это приводит к большим проблемам с безопасностью в вашем приложении.Вы всегда можете сначала попытаться проанализировать строку (для правильного синтаксиса), но это все равно будет возможной уязвимостью.

...