class LightweightMixin(object): """ Manager mixin for lightweight functionality. """ # heavy fields to defer in lightweight querysets heavyweight_fields = () # relations that are always fetched with lightweight queries always_related_models = {} def as_public(self, qs, **kwargs): """ Apply visibility filter and relation prefetch on given QuerySet/Batch. """ return qs def public(self, **kwargs): """ Returns default queryset with `as_public()` applied. """ return self.as_public(self.all(), **kwargs) def lightweight(self, select=None, relations=None, **kwargs): """ Returns public() queryset with `as_lightweight()` applied. """ return self.as_lightweight(self.public(**kwargs), select=select, relations=relations) def as_lightweight(self, qs, prefix='', select=None, relations=None): """ Defer heavy-weight fields in given queryset. By default this method defers heavyweight fields in all relations, which are specified in `always_related_models`. Set `relations` to `False` to disable this behavior. You may override default relations by passing `dict` to `relations` argument. :Arguments: - `qs` (`QuerySet`): queryset to defer - `prefix` (str): object prefix, used in recursive defers - `select` (list of str): heavy fields that will be not defered - `relations` (dict or bool): recursively apply itself to relations. """ defer = [] select = set(select) if select else () for fld in self.heavyweight_fields: pat = "%s%s" % (prefix, fld) if pat not in select: defer.append(pat) qs = qs.defer(*defer) if relations is not False: # by default always applies with default relations qs = self.as_lightweight_relations(qs, prefix=prefix, select=select, relations=relations) return qs def as_lightweight_relations(self, qs, prefix='', select=None, relations=None): """ Propogate defer calls to relations. """ relations = relations or self.always_related_models for fld, model in relations.iteritems(): relpref = "%s%s__" % (prefix, fld) qs = model.objects.as_lightweight(qs, relpref, select=select) return qs