开发者

Accessing a proxy model from the parent within a template

开发者 https://www.devze.com 2023-02-13 12:38 出处:网络
I have the following Django model that extends the Post model from django basic blog: from django.basic.blog.models import Post

I have the following Django model that extends the Post model from django basic blog:

from django.basic.blog.models import Post
from l10n.utils import lookup_translation

class ExtendedPost(Post):
    class Meta:
        proxy = True
    def translated_title(self, language_code=None):
        return lookup_translation(self, 'title', language_code)

I'm trying to use django basic blog's view by just overriding their template and making use of the new ExtendedPost behaviour in there:

{{ post.extendedpost.translated_title }}

But obviously this doesn't work because you can't just access a开发者_Python百科 subclass like that. How DO you do this type of thing?


Well, the view would still be referencing the original model, so you'd have to modify the view to pass in the ExtendedPost class.

You can't just define a proxy model and have it magically override the parent class.

  1. Untested idea based on: Can django's auth_user.username be varchar(75)? How could that be done?

    from django.db.models.signals import class_prepared
    
    def add_func(sender, *args, **kwargs):
        if sender.__name__ == "Post" and sender.__module__ == "django-basic-blog-module":
            sender.translated_title = lambda self, language_code=None: lookup_translations(self, 'title', language_code)
    
    class_prepared.connect(add_func)
    
  2. Override sys.modules

    import sys
    from django.basic.blog import models
    
    models.Post.translated_title = lambda self, language_code=None: lookup_translations(self, 'title', language_code)
    


You can make

{{ post.extendedpost.translated_title }}

work if you use multi-table inheritance rather than a proxy model.

However, introducing a whole new table just to add a function doesn't make a whole lot of sense.


This issue is too old but I found a solution that works for me and I will share it

you can just create a decorator like this:

def connect_proxy_to_model(property_name=None, return_copy=False):
    def get_proxy_func(proxy_class, self):
        if return_copy:
            proxy_obj = copy.deepcopy(self)
        else:
            proxy_obj = self
        proxy_obj.__class__ = proxy_class
        return proxy_obj

    def connect(proxy_class):
        name = property_name if property_name else proxy_class.__name__.lower()
        setattr(proxy_class.__base__, name, property(lambda self: get_proxy_func(proxy_class, self)))

    def wrapper(proxy_class):
        connect(proxy_class)
        return proxy_class

    return wrapper

And then you can decorate your proxy model with this:

from django.basic.blog.models import Post
from l10n.utils import lookup_translation


@connect_proxy_to_model(property_name='extendedpost', return_copy=True)
class ExtendedPost(Post):
    class Meta:
        proxy = True

    def translated_title(self, language_code=None):
        return lookup_translation(self, 'title', language_code)

Now you can use it just doing

{{ post.extendedpost.translated_title }}

The return_copy option that helps you if you want overwrite the current object ty

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号