简体   繁体   English

Django模型继承w / custom inclusion_tags

[英]Django model inheritance w/ custom inclusion_tags

I'm gonna try and simplify this as much as possible. 我会尽可能地尝试简化这个。 Lets say i have the following: 可以说我有以下内容:

models.py 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()

The example doesn't really matter for what I want, just go with me here. 这个例子对我想要的东西并不重要,请跟我一起去。 The purpose of this is so I can have a master Person table to reference all people. 这样做的目的是让我可以有一个主人员表来引用所有人。

Ideally I want to be able to call a view of Person's and have each ones specific details listed in a custom way for each class type. 理想情况下,我希望能够调用Person的视图,并以每种类类型的自定义方式列出每个特定的详细信息。 I'd like to use a custom inclusion_tag to do this. 我想使用自定义的inclusion_tag来执行此操作。

people.html people.html

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

people_extras.py - templatetags 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.

I have no idea how to get it to call the correct template based on the person type. 我不知道如何让它根据人物类型调用正确的模板。

I couldn't figure out how to accomplish this with the template using {% ifequal %} like this: 我无法弄清楚如何使用{%ifequal%}模板完成此操作,如下所示:

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

I went the route I wrote above with the templatetags. 我用模板标签去了上面写的路线。 However, I dont know where to put the logic to determine the person type! 但是,我不知道在哪里放逻辑来确定人的类型!

I think eventually I'd like to be able to use a generic view for this as well on the Person object. 我想最终我希望能够在Person对象上使用通用视图。

If there's a far better way to do this, I'm open to suggestions, I just want to get it working. 如果有更好的方法可以做到这一点,我愿意接受建议,我只是想让它发挥作用。

I've been kinda stuck here for over a day... could really use a push. 我已经被困在这里超过一天......真的可以使用推动。

See this answer for an efficient way to get the right person type sub-object after querying on the Person table. 查看此答案 ,了解在Person表上查询后获取正确人员类型子对象的有效方法。

Once you have that working, you should be able to eliminate most of the complexity in your template tags by using polymorphism. 一旦你有了这个工作,你应该能够通过使用多态来消除模板标签中的大部分复杂性。 If you want to display each person type using a different template, make that template name a class attribute of the model, or even just make the template name based on the model name (using person._meta.module_name). 如果要使用不同的模板显示每个人的类型,请将该模板名称设为模型的类属性,或者甚至根据模型名称创建模板名称(使用person._meta.module_name)。 One simple template tag should then be able to cover all cases without even knowing any details of which subclasses exist. 一个简单的模板标签应该能够覆盖所有情况,甚至不知道存在哪些子类的任何细节。 EDIT This single tag can't be registered using the inclusion_tag decorator, because you'll need to determine the template name dynamically. 编辑无法使用inclusion_tag装饰器注册此单个标记,因为您需要动态确定模板名称。 But it's easy to write using the simple_tag decorator: 但是使用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})

This will render a Worker using worker.html, a Retired using retired.html, etc. If the specific template for the subtype is not found, it falls back to the default person.html. 这将使用worker.html呈现工作者,使用retired.html呈现退休等。如果找不到子类型的特定模板,则它将回退到默认的person.html。

Take advantage of Django's contenttypes framework to identify your model types. 利用Django的contenttypes框架来识别您的模型类型。

See this snippet: Child aware model inheritance and use Carl Meyer's suggestion in the comments (wrap the assignment in " if not self.id: ") 请参阅以下片段: 儿童感知模型继承并在评论中使用Carl Meyer的建议(将作业包装在“ if not self.id: ”中)

I use a method that I hacked together quickly at the moment to do a very similar job. 我使用了一种方法,我现在很快就一起攻击,做了一个非常相似的工作。 I have many models inheriting from a main "base" model - to I can access everything in my database by a unique code (we call it a "go code"). 我有许多模型继承自主“基础”模型 - 我可以通过一个独特的代码访问我数据库中的所有内容(我们称之为“转码”)。 To find out the child of the parent object, I do something like this: 为了找出父对象的子对象,我做了这样的事情:

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

I know it's messy, but it works fine. 我知道它很乱,但它工作正常。 I store the object's "type" in a denormalized field in the parent object model, so I only ever have to "find" it once - which reduces the hits on the database and the CPU work required. 我将对象的“类型”存储在父对象模型的非规范化字段中,因此我只需要“找到”它一次 - 这会减少数据库上的命中数和所需的CPU工作量。 I then just override save() to find the object type on creation, and store it in that field. 然后我只是覆盖save()以在创建时找到对象类型,并将其存储在该字段中。

Hope it helps! 希望能帮助到你!

Use this snippet for your getRealPerson() Person model method: 将此片段用于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

It will return you the first related object (either a Worker or a Retired). 它将返回第一个相关对象(Worker或Retired)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM