Movatterモバイル変換


[0]ホーム

URL:


Login

djangosnippets

Custom model manager chaining (Python 3 re-write)

Author:
Spotted1270
Posted:
May 6, 2022
Language:
Python
Version:
3.2
Score:
0 (after 0 ratings)

This is a Python 3 re-write for https://djangosnippets.org/snippets/2117/

 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
fromdjango.db.models.managerimportManagerfromdjango.db.models.queryimportQuerySetdefmanager_from(*mixins_and_funcs,**kwargs):"""    Returns a Manager instance with extra methods, also available and chainable on generated querysets.    (param) mixins_and_funcs: Each mixin can be either a class or a function. The generated manager and associated queryset subclasses extend the mixin classes and include the mixin functions (as methods).    (kwarg) queryset_cls: The base queryset class to extend from (`django.db.models.query.QuerySet` by default).    (kwarg) manager_cls: The base manager class to extend from (`django.db.models.manager.Manager` by default).    """base_queryset=kwargs.get("queryset_cls",QuerySet)manager_class=kwargs.get("manager_cls",Manager)# Collect the mixin classes and methods into separate variables.bases=[base_queryset]methods={}formixin_or_funcinmixins_and_funcs:# If the mixin is a class (all classes in Python 3+ inherit from the base `type` class).ifisinstance(mixin_or_func,type):# Add it to our bases list.bases.append(mixin_or_func)# If it is not a class, is it a function?else:try:methods.update({mixin_or_func.__name__,mixin_or_func})exceptAttributeError:# If you pass in a variable of a bool data type, for example, it will raise an attribute error! The __name__ property is only available on classes and methods (?).raiseTypeError(f"Mixin must be class or function, not{mixin_or_func.__class__}")kwargs_as_tuple=tuple(iter(kwargs.items()))args_id=hash(mixins_and_funcs+kwargs_as_tuple)# Create the QuerySet subclass: name it deterministically (same set of arguments returns the same queryset class name), add base classes and class methods.new_queryset_class=type(f"Queryset_{args_id}",tuple(bases),methods)# Create the Manager subclass.bases[0]=manager_classnew_manager_class=type(f"Manager_{args_id}",tuple(bases),methods)# And finally, override new manager's get_query_set.super_get_queryset=manager_class.get_querysetdefget_queryset(self):# First honor the super manager's get_query_setqs=super_get_queryset(self)# And then try to bless the returned queryset by reassigning it to the newly created Queryset class, though this may not be feasible.ifnotissubclass(new_queryset_class,qs.__class__):raiseTypeError("QuerySet subclass conflict: cannot determine a unique class for queryset instance")qs.__class__=new_queryset_classreturnqsnew_manager_class.get_queryset=get_querysetreturnnew_manager_class()

More like this

  1. Mask sensitive data from logger byagusmakmun 1 week, 4 days ago
  2. Template tag - list punctuation for a list of items byshapiromatron 1 year, 2 months ago
  3. JSONRequestMiddleware adds a .json() method to your HttpRequests bycdcarter 1 year, 2 months ago
  4. Serializer factory with Django Rest Framework byjulio 1 year, 9 months ago
  5. Image compression before saving the new model / work with JPG, PNG bySchleidens 1 year, 10 months ago

Comments

Pleaselogin first before commenting.


[8]ページ先頭

©2009-2025 Movatter.jp