Package: django-orm-plus
django-orm-plusA collection of useful ORM features to make using the Django ORM convenient,
performant and safeInstallationpipinstalldjango-orm-plusThen adddjango_orm_plustoINSTALLED_APPSNow you must do one of the following:SetAUTO_ADD_MODEL_MIXINtoTrueinsettings.py:DJANGO_ORM_PLUS={"AUTO_ADD_MODEL_MIXIN":True,}This will automatically patch your models withORMPlusModelMixinOr, add the following model mixin to your models manually:fromdjango.dbimportmodelsfromdjango_orm_plus.mixinsimportORMPlusModelMixinclassMyModel(models.Model,ORMPlusModelMixin):name=models.CharField(max_length=10)UsageThis library has three important functions for use on Django QuerySets:.strict().fetch_related().bulk_update_or_create()strictStrict mode makes sure your ORM queries are efficient and safe by not allowing
related objects to be loaded lazily, thereforeselect_relatedorprefetch_relatedmust be used if related objects are needed. This avoids
then+1 query problem.Strict mode will also raise an error when a deferred field (.defer()or.only())
is accessed.You only need to add.strict()on your queryset wherever it's being used.
So for example in a DRF view:classUserList(generics.ListCreateAPIView):queryset=User.objects.all().strict()serializer_class=UserSerializerpermission_classes=[IsAdminUser]Now your queryset is strict-mode enabled and your view will error if any relations
are loaded for the user queryset eg.users[0].profilewill error ifprofileis a foreign key.
To fix, change the query to also fetch the relation using eitherselect_relatedorprefetch_related:queryset=User.objects.all().select_related("profile").strict()fetch_relatedCombines bothselect_relatedandprefetch_relatedto reduce the total number of queries for you automatically.So instead of:queryset=(User.objects.all().select_related("profile").prefetch_related("likes",Prefetch("books",queryset=Book.objects.all().select_related("author")),))It's now simply:queryset=User.objects.all().fetch_related("profile","likes","books__author")Of course, the two methods can be used together to get easy and safe queryset evaluation:queryset=User.objects.all().fetch_related("profile","likes","books__author").strict()Sinceselect_relateddoes a join in SQL,fetch_relatedopts to useselect_relatedwhen possible, and in other cases will useprefetch_relatedwhich adds a single additional
query and does the join in Python.bulk_update_or_createupdated,created=User.objects.bulk_update_or_create([User(username="john123",first_name="Jonny"),User(username="jane_doe",first_name="Alexa")],lookup_fields=["username"],update_fields=["first_name"],)This will combinebulk_updateandbulk_createand return the records that were
updated and created.lookup_fieldsis a list of field names that should uniquely
identify a record. This method takesbatch_sizeas an optional parameter which defaults to 1000ConfigurationYou can set the following configuration object insettings.py:DJANGO_ORM_PLUS={"AUTO_ADD_MODEL_MIXIN":False,"STRICT_MODE_GLOBAL_OVERRIDE":None,}AUTO_ADD_MODEL_MIXINis a boolean flag that will auto-patch all the models
on load withORMPlusModelMixinSTRICT_MODE_GLOBAL_OVERRIDEis a boolean flag that will enable or disable strict
mode without considering if.strict()is used. This can be useful if you want to
disable strict mode on production, or have all querysets use strict mode for local development.