Package: django-admin-performance-tools
Django Admin Performance ToolsTable of ContentsDescriptionRequirementsInstallation InstructionsQuick ActionsLanguages DropdownIntermediate Pages and Model Action ToolsTools for admin Querysets/FiltersTools for admin search/filtersWidgetsSettings1- DescriptionThis Package is a collection of extensions/tools for the default django administration interface, it includes:Quick ActionsLanguages Dropdown InterfaceIntermediate Pages and model actions toolsTools for adminQuerysets/Filtersoptemization (helps avoiding N+1 issue)Tools for adminsearch/filtersWidgetsFull documentation is avilable onGithub Repo2- RequirementsBefore you begin, ensure you have met the following requirements:Python 3.8+Django >= 3.23- Installation InstructionsYou don't need this source code unless you want to modify the package. If you just
want to use the package, just run:pipinstalldjango-admin-performance-toolsAdd 'django_admin_performance_tools' to your INSTALLED_APPS settings.INSTALLED_APPS=["django_admin_performance_tools",...]Must be added on the top of the listinsettings.pyupdate TEMPLATESTEMPLATES=[{...'DIRS':["templates"],'OPTIONS':{'context_processors':[..."django_admin_performance_tools.context_processors.settings",],},},]4- Quick ActionsQuick Actions is a new feature that allows you to take actions quickly from the admin home page, it is the same as actions in the model admin page, but the main differences are:It is not attached to any modelActions acts like views but only supports (POST,GET) http methodsSupport permissions, so you can write your own logic to control who can see the actionForm View Action is introduced to enables you to create an action to render any form (It is implemented on top of django FormView and CreateView)Wizard Form View Action is introduced to enables you to create multi-step forms (It is implemented on top of django-formtools)Template View Action is introduced to enables you to render your own templatesBase View Action is introduced to enables you to create customized actions as you wantSetupinsettings.pyreplacedjango.contrib.adminbydjango_admin_performance_tools.sites.MainAdminConfigin your INSTALLED_APPS.INSTALLED_APPS=["django_admin_performance_tools","django_admin_performance_tools.sites.MainAdminConfig",...]🚀🚀What if you already implemented your own Admin site? all you've to do is to inherit fromAbstractAdminSiteMixinExample:fromdjango_admin_performance_tools.sitesimportAbstractAdminSiteMixinclassYourAdmin(AbstractAdminSiteMixin,AdminSite):"""Your Admin Site"""by doing that you don't need to replace your admin site inINSTALLED_APPS4.1- FormViewQuickActionForm View Quick Action is used to create an action to render a form (It is implemented on top of django FormView)Example:fromdjango_admin_performance_tools.quick_actionsimportFormViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_action@register_quick_action()classFormAction(FormViewQuickAction):name="My Form Action"form_class=MyFormdefpost(self,request,*args,**kwargs):# Write your logic herereturnsuper().post(request,*args,**kwargs)-To customize submit button name, you can setsubmit_button_valueattribute in theFormActionclass-To customize success redirection of the form you can setsuccess_urlattribute or overrideget_success_urlfunction (Default is redirect to the action page).4.2- CreateViewQuickActionCreate View Quick Action is used to create an action to render a model form (It is implemented on top of django CreateView)Example:fromdjango_admin_performance_tools.quick_actionsimportCreateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_actionfrom.modelsimportMyModel@register_quick_action()classCreateFormAction(CreateViewQuickAction):name="My Craete Form Action"model=modelfields=["name"]-To customize submit button name, you can setsubmit_button_valueattribute in theCreateFormActionclass-To customize success redirection of the form you can setsuccess_urlattribute or overrideget_success_urlfunction (Default is redirect to the action page).4.3- WizardFormViewQuickActionWizard Form View Quick Action is implemented on top ofdjango-formtoolslibrary, and it is used to create an action to render a wizard form.setupdjango-formtoolslibrary is required. to install it use the following pip command:pipinstalldjango-formtoolsAdd 'formtools' to your INSTALLED_APPS settings.INSTALLED_APPS=[..."formtools",]Example:fromformtools.wizard.viewsimportSessionWizardViewfromdjango_admin_performance_tools.quick_actionsimportWizardFormViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_action@register_quick_action()classWizardFormAction(WizardFormViewQuickAction,SessionWizardView):name="My Wizard Form Action"form_list=[Form1,Form2,Form3]defdone(self,form_list,**kwargs):# form_list[0].cleaned_data# form_list[1].cleaned_data# form_list[2].cleaned_data# Continue writing your logic herereturnsuper().done(form_list,**kwargs)And that's it 🎉-To customize last step button name, you can setsubmit_button_valueattribute in theWizardFormActionclass-To customizedone()function redirection you can setsuccess_urlattribute or overrideget_success_urlfunction (Default is redirect to the action page).4.4- TemplateViewQuickActionTemplate View Quick Action is used to create an action to render a template (It is implemented on top of django TemplateView)Example:fromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_action@register_quick_action()classTemplateAction(TemplateViewQuickAction):name="My Template Action"template_name="my_template.html"Notes-The template file you created (my_template.html) must extends frombase_quick_action.html{%extends'admin/quick_actions/base_quick_action.html'%}{%blockaction_body%}# Write your own HTML{%endblock%}4.5- Abstract QuickActionQuickAction is used to create a custom action, that means you will've to implementget(),post()yourself (It is implemented on top of django View)Example:fromdjango_admin_performance_tools.quick_actionsimportQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_action@register_quick_action()classCustomAction(QuickAction):name="My custom Action"defget(self,request,*args,**kwargs):# Write your own logic herereturnsuper().get(request,*args,**kwargs)defpost(self,request,*args,**kwargs):# Write your own logic herereturnsuper().post(request,*args,**kwargs)defget_context_data(self,**kwargs):super().get_context_data(**kwargs)return{# Pass your extra context here**super().get_context_data(**kwargs),}You can overrideget_context_data()function to pass extra context values4.6- Control who can see the actionsQuick actions acts like views so you can setpermission_requiredattribute or overrideget_permission_required(),has_permission()methods to control who can see the actions.Example:fromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_action@register_quick_action()classTemplateAction(TemplateViewQuickAction):name="My Template Action"template_name="my_template.html"permission_required=("myapp.add_mymodel")defhas_permission(self):# Write your own logic herereturnsuper().has_permission()the previous example will check the following by default:The user has add permission on MyModel ViewThe user is active and is staffNotesOn overridinghas_permission()you must callsuper(). Default check the useris_active=Trueandis_staff=Truepermission_requiredattribute default value isNone4.7- Register Quick Actions to Multiple Admin Sites@register_quick_action()decorator register the action to all admin sites, so if you need to register an action to a specific site you can passsites=[site1, site2, site3]to the decoratorExample:fromdjango.contribimportadminfromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_actionfrom.my_sitesimportsite2,site3@register_quick_action(sites=[admin.site,site2,site3])classTemplateAction(TemplateViewQuickAction):name="My Template Action"template_name="my_template.html"defhas_permission(self):# Write your own logic herereturnsuper().has_permission()4.8- Redirect Success MessagesYou can define messges to be displayed to the user after form submissionpost_success_messageattribute is used forpostrequestsExample:fromdjango.contribimportadminfromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_actionfrom.my_sitesimportsite2,site3@register_quick_action()classTemplateAction(TemplateViewQuickAction):name="My Template Action"template_name="my_template.html"post_success_message="Data Submitted Successfully"# NOTE: Also you can override the messages using the following method# You can access the current request by using self.requestdefget_post_success_message(self):# Write your own logic hereNotes1-All actions must be added/imported in admin.py as to be detected and registered.4.9- URLs and Path Nameurl_pathis the URL path of an action, if not set the package will create a url path dynamically from the action class's namepath_nameis the URL path name of an action, if not set the package will create a url path name dynamically from the action class's nameExample 1:fromdjango.contribimportadminfromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_actionfrom.my_sitesimportsite2,site3@register_quick_action()classCreateUserTemplate(TemplateViewQuickAction):name="My Template Action"template_name="my_template.html"url_pathvalue will bewww.mysite.com/admin/quick-actions/create-user-templatepath_namevalue will bequick-actions-create-user-templateExample 2:fromdjango.contribimportadminfromdjango_admin_performance_tools.quick_actionsimportTemplateViewQuickActionfromdjango_admin_performance_tools.quick_actions.registryimportregister_quick_actionfrom.my_sitesimportsite2,site3@register_quick_action()classCreateUserTemplate(TemplateViewQuickAction):name="My Template Action"url_path="my-template"path_name="my-template"template_name="my_template.html"url_pathvalue will bewww.mysite.com/admin/quick-actions/my-templatepath_namevalue will bequick-actions-my-template5- Languages DropdownThis will show a dropdown menu in the admin pages that allows you change the site language easily, so all you have to do is to add the following URLs in the main rooturls.pyfileSetupin the rooturls.pyadd the following:fromdjango.urlsimportinclude,pathurlpatterns=[path("i18n/",include("django.conf.urls.i18n")),...]Add 'django_admin_performance_tools' to your INSTALLED_APPS setting.
insettings.pyadddjango.middleware.locale.LocaleMiddlewareto the MIDDLEWAREMIDDLEWARE=[..."django.middleware.locale.LocaleMiddleware",]And that is it6- Intermediate Pages and Model Action Tools6.1- Intermediate PagesWe introduceIntermediate Pagesfor admin actions to render a form before proceeding to the action logic. This will help if you need to pass extra params to your actions.Form Example:fromdjangoimportformsfromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.intermediate_pages.decoratorsimportintermediate_pagefromdjango_admin_performance_tools.intermediate_pages.formsimportIntermediatePageFormfrom.modelsimportMyModelclassMyForm(IntermediatePageForm):user=forms.ModelChoiceField(queryset=User.objects.all())@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):actions=["assign_user"]@intermediate_page(form=MyForm)defassign_user(self,request,queryset,submitted_form):# Write your own Logicuser=submitted_form.cleaned_data.get("user")queryset.update(user=user)ModelForm Example:fromdjangoimportformsfromdjango.contribimportadminfromdjango_admin_performance_tools.intermediate_pages.decoratorsimportintermediate_pagefromdjango_admin_performance_tools.intermediate_pages.formsimportIntermediatePageModelFormfrom.modelsimportMyModelclassMyForm(IntermediatePageModelForm):classMeta:model=MyModelfields="__all__"defclean(self)->dict[str,Any]:# Write your own Logicreturnsuper().clean()defsave(self,commit:bool=...)->Any:# Write your own Logicreturnsuper().save(commit)@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):actions=["create_object"]@intermediate_page(form=MyForm)defcreate_object(self,request,queryset,submitted_form):# Write your own Logicsubmitted_form.save()-IntermediatePageFormis implemented on top offorms.Form-IntermediatePageModelFormis implemented on top offorms.ModelFormNoteintermediate_pagedecorator checks for form validity, it means that it will not continue to the action logic only if the form is valid.6.1.1 intermediate_page decorator paramsform(required): A form inheriting fromIntermediatePageFormorIntermediatePageModelFormthat is passed to the intermediate page template to be renderedtemplate: Path of an HTML template to use for rendering the intermediate page. defaults toadmin/intermediate_pages/abstract_form_page.htmlthat normally renders the form and shows selected objects if anytitle: Custom title for the intermediate page, defaults to the action name.success_redirect_url: URL to redirect after successful form submission defaults to the model change list page.6.2- Non-Selection ActionsThe existing Django actions require at least one selected instance to proceed, so
We introduceNon-Selection Actionsfor admin actions to proceed to the action without selecting any instances.also Django admin actions are shown if there is at least one instance, but now all non-selection actions will be shown in actions dropdown even if there is no instances in change list page (andDelete selected modelsaction will be excluded)Example:fromdjango.contribimportadminfromdjango_admin_performance_tools.mixinsimportNonSelectionActionsMixinfrom.modelsimportMyModel@admin.register(MyModel)classMyModelAdmin(NonSelectionActionsMixin,admin.ModelAdmin):actions=["assign_user"]non_selection_actions=["assign_user"]defassign_user(self,request,queryset):# Write your own LogicNo-Selectionactions overrides djangoChangeListclass (to show the actions when no instances in the changelist page) so if you've already override it simply you can inherits fromNoSelectionActionsChangeListMixinExample:fromdjango.contribimportadminfromdjango_admin_performance_tools.mixinsimportNonSelectionActionsMixin,NoSelectionActionsChangeListMixinfrom.modelsimportMyModelfromdjango.contrib.admin.views.mainimportChangeListclassMyChangeList(NoSelectionActionsChangeListMixin,ChangeList):# Your own logic@admin.register(MyModel)classMyModelAdmin(NonSelectionActionsMixin,admin.ModelAdmin):actions=["assign_user"]non_selection_actions=["assign_user"]defassign_user(self,request,queryset):# Write your own Logicdefget_changelist(self,request,**kwargs):"""Return the ChangeList class for use on the changelist page."""ifself.non_selection_actions:returnMyChangeListreturnChangeList6.3- Max Selection CountThe existing Django actions allows all staff users to select all the queryset and apply the action on it, imagine you have a 1 Million records and a staff user selected all the queryset and applied the action on it!So ,We introducedMax Selection Countto set max instances to be selected to an action.Example:fromdjango.contribimportadminfromdjango_admin_performance_tools.decoratorsimportcheck_queryset_max_selectionfrom.modelsimportMyModel@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):actions=["assign_user"]@check_queryset_max_selection(max_selection=100)defassign_user(self,request,queryset):# Write your own Logicin case you want to customizemax_selectionbased on the request you can pass afunction/lambdathat takesrequestas an argument instead of anintnumber.if you setmax_selectionto-1means unlimited.Example:fromdjango.contribimportadminfromdjango_admin_performance_tools.decoratorsimportcheck_queryset_max_selectionfrom.modelsimportMyModeldefget_max_selection(request):ifrequest.user.is_superuser:return1000else:return10@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):actions=["assign_user"]@check_queryset_max_selection(max_selection=lambdarequest:get_max_selection(request))defassign_user(self,request,queryset):# Write your own Logic7- Tools for admin Querysets and Filters optemization7.1- Readonly Select RelatedAllModelAdmin/StackedInline/TabularInlinehits the db to fetch all related fields inreadonly_fieldslistExample:fromdjango.contribimportadminfrom.modelsimportMyModel,AnotherModelclassMyModel(models.Model):related_field_1=models.ForeignKey(...)related_field_2=models.ForeignKey(...)related_field_3=models.ForeignKey(...)related_field_4=models.ForeignKey(...)classAnotherModel(models.Model):my_model=models.ForeignKey(MyModel)related_field_5=models.ForeignKey(...)related_field_6=models.ForeignKey(...)related_field_7=models.ForeignKey(...)classAnotherModelInline(admin.StackedInline):model=AnotherModelreadonly_fields=["related_field_5","related_field_6","related_field_7"]@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):inlines=[AnotherModelInline]redaonly_fields=["related_field_1","related_field_2","related_field_3","related_field_4"]Consider the above example Django will hit the DB 7 times to get the related fields and this number will increase if more inlines are added.So, We introducereadonly_select_relatedto select all read-only fields while rendering the models and its inlinesExample:fromdjango.contribimportadminfromdjango_admin_performance_tools.mixinsimportReadonlySelectRelatedMixinfrom.modelsimportMyModel,AnotherModelclassMyModel(models.Model):related_field_1=models.ForeignKey(...)related_field_2=models.ForeignKey(...)related_field_3=models.ForeignKey(...)related_field_4=models.ForeignKey(...)classAnotherModel(models.Model):my_model=models.ForeignKey(MyModel)related_field_5=models.ForeignKey(...)related_field_6=models.ForeignKey(...)related_field_7=models.ForeignKey(...)classAnotherModelInline(ReadonlySelectRelatedMixin,admin.StackedInline):model=AnotherModelreadonly_fields=["related_field_5","related_field_6","related_field_7"]readonly_select_related=["related_field_5","related_field_6","related_field_7"]@admin.register(MyModel)classMyModelAdmin(ReadonlySelectRelatedMixin,admin.ModelAdmin):inlines=[AnotherModelInline]redaonly_fields=["related_field_1","related_field_2","related_field_3","related_field_4"]readonly_select_related=["related_field_1","related_field_2","related_field_3","related_field_4"]7.2- List Prefetch RelatedDjangolist_displayallows functions that are decorated by@admin.display, in these functions you may access a reverse relation or many-to-many fields of the instance, this means that the admin will hit the DB in every row to get the data and this will lead to a huge number of queries and may cause N+1 issueExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUser@admin.register(User)classUserAdmin(admin.ModelAdmin):list_display=["name","email,"groups]@admin.displaydefgroups(self,obj):groups=[]forgroupinobj.groups.all():groups.append(group.name)return" ".join(groups)Consider that the page loaded 100 users the above example will hit the DB 100 times to get the related groups of each user.So, We introducelist_prefetch_relatedto prefetch all reverse relations while rendering the changelist pageExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.mixinsimportListPrefetchRelatedMixin@admin.register(User)classUserAdmin(ListPrefetchRelatedMixin,admin.ModelAdmin):list_display=["name","email,"groups]list_prefetch_related=["groups"]@admin.displaydefgroups(self,obj):groups=[]forgroupinobj.groups.all():groups.append(group.name)return" ".join(groups)7.3- Change Prefetch RelatedDefault behavior of Django admin is to render all the related fields of an instance in dropdowns and call model's__str__function for each row in this dropdownsExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfrom.modelsimportMyModel,AnotherModelclassAnotherModel(models.Model):name=models.CharField()user=models.ForeignKey(User)def__str__(self):returnf"{self.name}User:{self.user.username}"classMyModel(models.Model):name=models.CharField()another_model=models.ForeignKey(AnotherModel)@admin.register(MyModel)classMyModelAdmin(admin.ModelAdmin):fields=["name","another_model"]Consider the above example, a form will be rendered with two fieldsnameandanother_modelimagine thatanother_modeldropdown has 100 row, and__str__function ofAnotherModelaccess the user to get its username, this means that in every row Django will hit the DB to fetch the username of the user.So, We introducechange_select_relatedto select all related fields while rendering the change pageExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.mixinsimportAdminChangeSelectRelatedMixinfrom.modelsimportMyModel,AnotherModelclassAnotherModel(models.Model):name=models.CharField()user=models.ForeignKey(User)def__str__(self):returnf"{self.name}User:{self.user.username}"classMyModel(models.Model):name=models.CharField()another_model=models.ForeignKey(AnotherModel)@admin.register(MyModel)classMyModelAdmin(AdminChangeSelectRelatedMixin,admin.ModelAdmin):fields=["name","another_model"]change_select_related=["another_model__user"]It is supported in inlines tooExample:fromdjango_admin_performance_tools.mixinsimportInlineChangeSelectRelatedMixinfrom.modelsimportAnotherModelclassAnotherModelInline(InlineChangeSelectRelatedMixin,admin.StackedInline):model=AnotherModelchange_select_related=[...]8- Tools for admin search and filters8.1 Select Related with Filter Related FieldsSame as forms dropdowns, related filters get a list of instances and display its__str__function so if you access a related field  in the__str__it will hit the DB for each row in the related filter choices list.So, We introduceFilterWithSelectRelatedto select all related fields while rendering the filter choicesExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfrom.modelsimportMyModel,AnotherModelclassAnotherModel(models.Model):name=models.CharField()user=models.ForeignKey(User)def__str__(self):returnf"{self.name}User:{self.user.username}"classMyModel(models.Model):name=models.CharField()another_model=models.ForeignKey(AnotherModel)@admin.register(MyModel)classMyModelAdmin(AdminChangeSelectRelatedMixin,admin.ModelAdmin):list_filter=["another_model"]in the previous example, if we've 100 choice in theanother_modelfilter list, it means that we've hit the DB 100 times, but by usingFilterWithSelectRelatedwe can selectuserwhile rendering the choices.Example:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.filtersimportFilterWithSelectRelatedfrom.modelsimportMyModel,AnotherModelclassAnotherModel(models.Model):name=models.CharField()user=models.ForeignKey(User)def__str__(self):returnf"{self.name}User:{self.user.username}"classMyModel(models.Model):name=models.CharField()another_model=models.ForeignKey(AnotherModel)classAnotherModelFilter(FilterWithSelectRelated):list_select_related=["user"]@admin.register(MyModel)classMyModelAdmin(AdminChangeSelectRelatedMixin,admin.ModelAdmin):list_filter=[AnotherModelFilter]8.2 Search Help TextRecently Django featured a new admin attributesearch_help_textand it adds a help text below the search bar, So we extended this feature to be more useful and readable by showing all the fields that the admin will search in.Example:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.mixinsimportSearchHelpTextMixin@admin.register(User)classUserAdmin(SearchHelpTextMixin,admin.ModelAdmin):search_fields=["email","name","username","phone_number"]Not just field names, you can customize any field to represent another textExample:fromdjango.contribimportadminfromdjango.contrin.auth.modelsimportUserfromdjango_admin_performance_tools.mixinsimportSearchHelpTextMixin@admin.register(User)classUserAdmin(SearchHelpTextMixin,admin.ModelAdmin):search_fields=["email","name","username","phone_number"]search_help_text_map={"email":"Email Address"}There is an abstract class to use if you intend to use all the following features in Model Admin:ListPrefetchRelatedMixinReadonlySelectRelatedMixinAdminChangeSelectRelatedMixinSearchHelpTextMixinNonSelectionActionsMixincan be imported from the following path:fromdjango_admin_performance_tools.adminimportAbstractModelAdminThere is an abstract classes to use if you intend to use all the following features in Inline Admin:ReadonlySelectRelatedMixinAdminChangeSelectRelatedMixincan be imported from the following path:fromdjango_admin_performance_tools.adminimport(AbstractStackedInline,AbstractTabularInline)UpcommingAuto Complete filters with custome titleFilters with custom title9- WidgetsSometimes we may need to disable some choices of choice list fields based on who interacting with the field, for example: a super user can change status field to any choice but the staff user may have a limited options to change the status.SetupaddFORM_RENDERERinsettings.py.FORM_RENDERER="django.forms.renderers.TemplatesSetting"Add 'django.forms' to your INSTALLED_APPS settings.INSTALLED_APPS=[..."django.forms",]Example:fromdjangoimportformsfromdjango_admin_performance_tools.widgetsimportDisabledSelectfromdjango.dbimportmodelsclassStatusEnum(models.IntegerChoices):INITIAL=0,"Initial"DONE=1,"Done"CLOSED=2,"Closed"classContactForm1(forms.Form):status=forms.ChoiceField(required=False,choices=StatusEnum.choices,widget=DisabledSelect(disabled_options=[StatusEnum.DONE,StatusEnum.CLOSED]))10- SettingsYou can controll some behaves by adding the following insettings.py- HIDE_QUICK_ACTIONS_DROPDOWNThis will hide the Quick Actions dropdown from admin sitesDefault value isFalse- QUICK_ACTIONS_URL_PATH_PREFIXThis is the prefix before all Quick-Actions URL paths/namesDefault value isquick-actions- HIDE_LANGUAGE_DROPDOWNThis will hide the Languages dropdown from admin sitesDefault value isFalseContributingIf you are interested to fix an issue or to add new feature, you can just open a pull request.Contributors