2009-06-03 2 views
5

Я попытаюсь упростить это как можно больше. Допустим, у меня есть следующие:Наследование модели Django с пользовательским включением_tags

models.py

class Person(models.Model): 
    name = models.CharField(max_length=255) 

    def getRealPerson(self): 
     # is there a better way to do this? 
     ret = None 
     try: 
      ret = self.worker 
     except: 
      try: 
       ret = self.retired 
      except: 
       ret = self 
     return ret 
class Worker(Person): 
    salary = models.IntegerField(default=0) 

class Retired(Person): 
    age = models.IntegerField() 

пример на самом деле не имеет значения, что я хочу, просто пойти со мной здесь. Цель этого заключается в том, что у меня может быть таблица «Мастер-личность» для ссылки на всех людей.

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

people.html
{% load people_extras %} 
{% for person in people %} 
    {% show_person person %} 
{% endfor %} 

people_extras.py - templatetags

from django import template 

@register.inclusion_tag('worker.html') 
def show_worker(person): 
    return {'person':person} 

@register.inclusion_tag('worker.html') 
def show_retired(person): 
    return {'person':person} 

#How do I write this function and use it as the show_person person tag? 
from project.app.models import Worker, Retired 
def show_person(person): 
    person = person.getRealPerson(): 
    if isinstance(person, Worker): 
     return show_worker # yes, this doesn't work. 

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

Я не мог понять, как это сделать с помощью шаблона {% ifequal%} как это:

{% ifequal person.getRealPerson.__class__.__name__ "Worker" %} 
    {% show_worker %} 
... 

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

Я думаю, что в конечном итоге я хотел бы иметь возможность использовать общий вид для этого также и для объекта Person.

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

Я уже давно застрял здесь в течение дня ... мог действительно использовать толчок.

ответ

5

См. this answer, чтобы получить эффективный способ подбора подтипа подходящего лица после запроса в таблице Person.

После того, как вы работаете, вы сможете устранить большую часть сложности ваших тегов шаблонов, используя полиморфизм. Если вы хотите отображать тип каждого человека с использованием другого шаблона, сделайте этот шаблонный атрибут атрибутом класса модели или даже просто создайте имя шаблона на основе имени модели (используя person._meta.module_name). Один простой тег шаблона должен затем охватывать все случаи, даже не зная каких-либо подробностей о том, какие подклассы существуют. EDIT Этот единственный тег не может быть зарегистрирован с помощью декоратора include_tag, так как вам нужно будет определить имя шаблона динамически. Но это легко написать, используя simple_tag декоратора:

@register.simple_tag 
def show_person(person): 
    t = template.loader.select_template(["%s.html" % person._meta.module_name, 
             "person.html") 
    return t.render({'person': person}) 

Это будет рендерить работник с помощью worker.html, отставной с помощью retired.html и т.д. Если конкретный шаблон для подтипа не найден, он падает обратно по умолчанию person.html.

+0

I 'немного запутался в реализации пользовательского шаблона. testperson.cast() возвращает правильный под-объект, но как я могу использовать его при вызове правильного include_tag. То, как я устанавливал это выше, show_person не может быть вызван (он не зарегистрирован). – lostincode

+0

Вот что я обратился во втором абзаце. Отредактировано, надеюсь, сделать его более ясным. –

2

Воспользуйтесь функцией contenttypes framework от Django, чтобы идентифицировать ваши типы моделей.

Смотрите этот фрагмент кода: Child aware model inheritance и использовать Carl Meyer's предложение в комментариях (оберните назначение в «if not self.id:»)

+0

Или посмотрите этот ответ: http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the- name/929982 # 929982 –

+1

Также обратите внимание, что rix зафиксировал свой фрагмент на основе моего предложения, поэтому больше не нужно указывать комментарий. –

+0

О, о, я был в хвосте всепожирающего, и почему-то мой мозг не регистрировал self.pk is self.id :) –

0

Я использую метод, который я взломал вместе быстро на данный момент сделать очень похожую работу. У меня есть много моделей, наследующих от основной «базовой» модели - я могу получить доступ ко всему в моей базе данных по уникальному коду (мы называем это «код go»). Чтобы узнать ребенка родительского объекта, я сделать что-то вроде этого:

def get_child_types(self): 
    return [ c.__name__.lower() for c in self.__subclasses__() ] 

def get_child(self): 
    for type in self.get_child_types(): 
     try: 
      o = self.__getattribute__(type) 
     except: 
      pass 
     else: 
      return o 

Я знаю, что это грязно, но он отлично работает. Я храню «тип» объекта в денормализованном поле в родительской объектной модели, поэтому мне только нужно «найти» его один раз, что уменьшает количество обращений к базе данных и работу процессора. Затем я просто переопределяю save(), чтобы найти тип объекта при создании, и сохраните его в этом поле.

Надеюсь, это поможет!

+0

Это имеет общую правильную идею, но это сложнее (и медленнее) чем это должно быть. Во время создания вы уже знаете правильный тип, поэтому вам не нужно его искать, перебирая список типов и проверяя их. См. Http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982 –

0

Используйте этот фрагмент кода для getRealPerson() метод Person модели:

def getRealPerson(self): 
    from django.db.models.fields.related import OneToOneRel 
    from django.core.exceptions import ObjectDoesNotExist 
    for related in self._meta.get_all_related_objects(): 
     rel_opts_name = related.get_accessor_name() 
     if isinstance(related.field.rel, OneToOneRel): 
      try: 
       sub_obj = getattr(self, rel_opts_name) 
      except ObjectDoesNotExist: 
       pass 
      else: 
       return sub_obj 

Это вернет вам первый связанный объект (либо работник или отставной).