Skip to content

@egasimus /cbv_factory.py
Last active

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Django CBV factory function, with example usage.
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
}
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
Something went wrong with that request. Please try again.