Наследование модели Django с настраиваемыми тегами включения - PullRequest
5 голосов
/ 03 июня 2009

Я постараюсь максимально упростить это. Допустим, у меня есть следующее:

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 для ссылки на всех людей.

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

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 %}
...

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

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

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

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

Ответы [ 4 ]

5 голосов
/ 03 июня 2009

См. этот ответ , чтобы узнать, как получить эффективный подобъект типа объекта person после запроса таблицы Person.

Как только у вас это получится, вы сможете устранить большую часть сложности тегов шаблона, используя полиморфизм. Если вы хотите отображать каждый тип человека с помощью другого шаблона, присвойте этому шаблону имя класса-атрибута модели или даже просто создайте имя шаблона на основе имени модели (используя person._meta.module_name). Один простой тег шаблона должен быть в состоянии охватить все случаи, даже не зная каких-либо подробностей о том, какие подклассы существуют. РЕДАКТИРОВАТЬ Этот отдельный тег не может быть зарегистрирован с помощью декоратора 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 будет отображаться с использованием worker.html, а Retired - с использованием retired.html и т. Д. Если определенный шаблон для подтипа не найден, он возвращается к стандартному person.html.

2 голосов
/ 03 июня 2009

Воспользуйтесь преимуществами фреймворка Django для определения типов вашей модели.

См. Этот фрагмент: Наследственное понимание модели ребенка и использование предложения Карла Мейера в комментариях (заверните назначение в "if not self.id:")

0 голосов
/ 03 июня 2009

Используйте этот фрагмент для метода модели 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

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

0 голосов
/ 03 июня 2009

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

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 (), чтобы найти тип объекта при создании, и сохраняю его в этом поле.

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

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