Last active
October 25, 2020 00:00
-
-
Save egasimus/5248517 to your computer and use it in GitHub Desktop.
Django CBV factory function, with example usage.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from inspect import isfunction | |
from django.views.generic import View, CreateView, UpdateView, DeleteView, DetailView, ListView | |
from django.views.generic.edit import ModelFormMixin | |
from django.views.generic.detail import SingleObjectMixin | |
def parse_func_dict(selfobj, d): | |
""" | |
Recursively goes through a dict, calling functions that refer to a view's | |
self and therefore need to be called from within -- such as getting extra | |
kwargs for a form constructor based on request data. | |
""" | |
for i in d.keys(): | |
if isfunction(d[i]): | |
d[i] = d[i](selfobj) | |
elif isinstance(d[i],dict): | |
d[i] = parse_func_dict(selfobj,d[i]) | |
return d | |
def cbv_factory(modelclass, **kwargs): | |
""" | |
For a given model, returns generic class-based ListView, DetailView, | |
CreateView, UpdateView, DeleteView. | |
""" | |
_queryset = kwargs.get('queryset',None) | |
_form_class = kwargs.get('form_class',None) | |
_extra_context = kwargs.get('extra_context',{}) | |
_extra_form_kwargs = kwargs.get('extra_form_kwargs',{}) | |
_list_template = kwargs.get('list_template',{}) | |
_form_template = kwargs.get('form_template',{}) | |
_detail_template = kwargs.get('detail_template',{}) | |
class FactoryObjectMixin(SingleObjectMixin): | |
""" | |
Common properties of all views. | |
""" | |
model = modelclass | |
if _queryset: | |
queryset = _queryset | |
def get_context_data(self, **kwargs): | |
d = super(FactoryObjectMixin, self).get_context_data(**kwargs) | |
d.update(parse_func_dict(self, _extra_context)) | |
return d | |
class FactoryFormMixin(ModelFormMixin): | |
""" | |
Common properties of form-based views (Create, Update). | |
""" | |
if _form_template: | |
template_name = _form_template | |
if _form_class: | |
form_class = _form_class | |
def get_form_kwargs(self, **kwargs): | |
d = super(FactoryFormMixin,self).get_form_kwargs(**kwargs) | |
d.update(parse_func_dict(self, _extra_form_kwargs)) | |
return d | |
class Detail(FactoryObjectMixin, DetailView): | |
if _detail_template: | |
template_name = _detail_template | |
class List(ListView): | |
model = modelclass | |
if _list_template: | |
template_name = _list_template | |
if _field_list: | |
field_list = _field_list | |
if _queryset: | |
queryset = _queryset | |
class Create(FactoryFormMixin, FactoryObjectMixin, CreateView): | |
pass | |
class Update(FactoryFormMixin, FactoryObjectMixin, UpdateView): | |
pass | |
class Delete(FactoryObjectMixin, DeleteView): | |
pass | |
return { | |
'list':List, | |
'detail':Detail, | |
'create':Create, | |
'update':Update, | |
'delete':Delete | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from django.db.models import Model | |
from django.conf.urls import patterns, url | |
from django.views.generic import CreateView | |
from cbv_factory import cbv_factory | |
def get_request_company(obj): | |
return obj.request.user.employee.company | |
def get_request_user(obj): | |
return obj.request.user | |
def get_createview(obj): | |
if issubclass(obj.__class__,CreateView): | |
return True | |
return False | |
def manufacture_views(): | |
""" | |
Automatically creates a lot of views using objectviews_factory to handle the | |
shared boilerplate code. | |
""" | |
# Import models and form classes from corresponding modules. | |
MODELS = __import__('models',level=2,globals=globals(),locals=locals()) | |
FORMS = __import__('forms',level=2,globals=globals(),locals=locals()) | |
# Any model that should explicitly not get this treatment goes here | |
EXCLUDE_MODELS = ['ActionLog','StatusMixin'] | |
# Extra context variables to be added to each view | |
EXTRA_CONTEXT = {} | |
for k in MODELS.__all__: | |
if k in EXCLUDE_MODELS: | |
continue | |
EXTRA_CONTEXT[k] = {} | |
EXTRA_CONTEXT[k].update({ 'modelclass':getattr(MODELS,k) }) | |
for k in ['Model1','Model2','Model3']: | |
EXTRA_CONTEXT[k].update({ 'mode':'manager' }) | |
for k in ['Model4','Model5','Model6']: | |
EXTRA_CONTEXT[k].update({ 'mode':'admin' }) | |
# Extra kwargs to be passed as kwargs to CreateView/UpdateView constructors. | |
EXTRA_FORM_KWARGS = {} | |
for k in MODELS.__all__: | |
if k in EXCLUDE_MODELS: | |
continue | |
EXTRA_FORM_KWARGS[k] = {} | |
formclass = getattr(FORMS,k+'Form') | |
if issubclass(formclass,FORMS.LogActionMixin): | |
EXTRA_FORM_KWARGS[k].update({ 'user' : get_request_user }) | |
if issubclass(formclass,FORMS.CreateOrUpdateMixin): | |
EXTRA_FORM_KWARGS[k].update({ 'is_createview' : get_createview }) | |
for k in ['Model1', 'Model2']: | |
EXTRA_FORM_KWARGS[k].update({ 'extra_values' : { 'company' : get_request_company } }) | |
# Create views from imported modules | |
VIEWS = {} | |
for classname in MODELS.__all__: | |
if classname in EXCLUDE_MODELS: | |
continue | |
cls = getattr(MODELS,classname) | |
if issubclass(cls, Model): | |
VIEWS[classname] = cbv_factory( | |
cls, | |
extra_context=EXTRA_CONTEXT.get(classname,{}), | |
form_class=getattr(FORMS,classname+'Form'), | |
extra_form_kwargs=EXTRA_FORM_KWARGS.get(classname,{}) | |
) | |
return VIEWS | |
def generate_urls(): | |
""" | |
Generates URLs from manufactured views | |
""" | |
urlpatterns = [] | |
# URL pattern templates for each type of view | |
VIEW_PATTERNS = { | |
'list':'^%s/$', | |
'detail':'^%s/(?P<pk>\d+)/$', | |
'create':'^%s/add/$', | |
'update':'^%s/(?P<pk>\d+)/edit/$', | |
'delete':'^%s/(?P<pk>\d+)/delete/$', | |
} | |
VIEWS = manufacture_views() | |
for m, mod in VIEWS.items(): | |
for t, cls in mod.items(): | |
urlpatterns += patterns('',url( | |
VIEW_PATTERNS[t] % m.lower(), | |
cls.as_view(), | |
name=('%s_%s') % (m.lower(), t.lower()) | |
)) | |
return urlpatterns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What about permission mixin ?