Is there a way to augment django QuerySets with extra attributes?

前端 未结 5 1202
陌清茗
陌清茗 2021-01-14 19:06

I\'m trying to add some extra attributes to the elements of a QuerySet so I can use the extra information in templates, instead of hitting the database multiple times. Let m

5条回答
  •  野的像风
    2021-01-14 19:55

    Here is my version of alter_items proposed by Will Hardy.

    Instead of a single value it allows different values of a custom attribute for each object: you can pass a mapping of values by object id.

    It also automatically wraps the results of all methods that return QuerySet.

    import types
    from itertools import islice
    
    from django.db.models import Model, QuerySet
    
    
    class QuerySetWithCustomAttributes(object):
        def __init__(self, queryset, **custom_attrs):
            self.queryset = queryset
            self.custom_attrs = custom_attrs
    
        def __set_custom_attrs(self, obj):
            if isinstance(obj, Model):
                for key, val in self.custom_attrs.items():
                    setattr(obj, key, val[obj.id])
            return obj
    
        def __iter__(self):
            for obj in self.queryset:
                yield self.__set_custom_attrs(obj)
    
        def __getitem__(self, ndx):
            if type(ndx) is slice:
                return self.__class__(self.queryset.__getitem__(ndx), **self.custom_attrs)
            else:
                return self.__set_custom_attrs(next(islice(self.queryset, ndx, ndx + 1)))
    
        def __len__(self):
            return len(self.queryset)
    
        def __apply(self, method):
            def apply(*args, **kwargs):
                result = method(*args, **kwargs)
                if isinstance(result, QuerySet):
                    result = self.__class__(result, **self.custom_attrs)
                elif isinstance(result, Model):
                    self.__set_custom_attrs(result)
                return result
            return apply
    
        def __getattr__(self, name):
            attr = getattr(self.queryset, name)
            if isinstance(attr, types.MethodType):
                return self.__apply(attr)
            else:
                return attr
    

提交回复
热议问题