2013-06-23 7 views
3

У меня есть две основные модели - Command и Flow. Потоки могут содержать ряд команд или других вложенных потоков. Таким образом, любой данный поток может иметь список дочерних элементов, которые являются типами Step или Flow. (Это похоже на файлы и каталоги, которые можно моделировать в файловой системе.)Моделирование иерархических данных в django с типами полиморфных узлов

Я попытался смоделировать это с использованием ContentTypes, общих отношений и mptt (что не позволяет использовать общие типы контента AFAIK), но имеет не имел успеха. Вот мои основные модели:

class Step(models.Model): 
    parent  = models.ForeignKey('Step', null=True) 
    name  = models.CharField(max_length=100) 
    start_time = models.DateTimeField(null=True) 
    end_time = models.DateTimeField(null=True) 
    state  = models.CharField(max_length=1, default='u') 

class Flow(Step): 
    type = models.CharField(max_length=1) 

    def getChildren(self): 
     # todo: the steps returned here need to be sorted by their order in the flow 
     return Step.objects.filter(parent_id=self.parent_id) 

    def run(self): 
     for child in self.getChildren(): 
      print("DEBUG: run method processing a {0}".format(child.__class__.__name__)) 
      # if this is a flow, run it 
      # else if it's a command, execute it 

class Command(Step): 
    exec_string = models.TextField() 

Я хочу, чтобы иметь возможность создавать потоки в моем приложении, опрашивать ребенок, а затем обработать каждый ребенок по-разному в зависимости от его типа

(команды получают казнены, потоки получают рекурсивно обрабатывается).

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

Edit: Я хотел бы добавить, что я использую Python 3.3 и Django Dev (будет называться 1.6)

+0

Возможно, вы ищете 'abstract' https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes –

+0

Я не понимаю, как, но я бы приветствовал пример, который соответствовал бы моим требованиям. Я использовал абстрактные классы, и поля Foreign Key не могут указывать на них (что имеет смысл), поэтому потребуется что-то еще. – Jorvis

+1

Если «Поток может иметь список дочерних элементов, которые являются типами Step или Flow», как Flow знает, какой порядок обрабатывать их? Выполняет ли он все шаги сначала, или они чередуются? Кажется, что поток должен каким-то образом их упорядочить. –

ответ

3

Наконец-то я нашел ответ через некоторую большую помощь в IRC и хотел поделиться им на тот случай, если кто-то другой проблема.

Единственное, что я должен был в конечном итоге изменить, это Flow.getChildren().

def getChildren(self): 
    # Get a list of all the attrs relating to Child models. 
    child_attrs = dict(
     (rel.var_name, rel.get_cache_name()) 
     for rel in Step._meta.get_all_related_objects() 
     if issubclass(rel.field.model, Step) and isinstance(rel.field, models.OneToOneField) 
    ) 

    objs = [] 
    for obj in self.children.all().select_related(*child_attrs.keys()): 
     # Try to find any children... 
     for child in child_attrs.values(): 
      sobj = obj.__dict__.get(child) 
      if sobj is not None: 
       break 
     objs.append(sobj) 
    return objs 

Если кто-то имеет более чистое решение, которое я хотел бы видеть его, тем более, что это, кажется, как много работы что-то кажется, что система должна обрабатывать более непосредственно.

0

Дело в том, что выскакивает у меня есть «возвращение Step.objects.filter (parent_id = self.parent_id)». Я считаю, что это должно быть «return Step.objects.filter (parent__pk = self.parent.pk)»

+0

Фильтрация на самом деле не была проблемой и возвращала правильные объекты. Самая большая проблема заключается в том, что они возвращались как объекты Step, а не их подклассы. Я получил решение, хотя и опубликую его через мгновение. – Jorvis