#Background
Over the years, as Django has evolved, the idea of what constitutes "best practice" has also evolved. However, some parts of Django haven't kept up with those best practices. For example, contrib apps do not use class based views.
In short, Django has been bad at eating it's own dogfood. The contents of contrib should be audited and updated to make sure it meets current best practices.
And another part is django FormSet infrastructure which have limitations which needs to overcome to remove some legacy codes and implement best practices easily to some apps like django admin
Django needs some improvement in implementing class based views in some of its apps/modules so that they can be more extensible by the users and remove legacy code base from django itself. Besides introducing some good features from well known 3rd party projects will help django to implement some of the recent best practices more easily.
The main challenges of the project could be maintaining the backward compatibility and logically factor out all the complex codes to be converted in current best practices. Another thing could be the introduction of new API which could break others parts or incompatible with others which need to be addressed carefully.
The broader plans for this project is analyzing django contrib apps and findout which parts of them need to be updated so that they can overcome their present drawbacks.
Class Based views can be used to remove some legacy codes from some popular contrib apps which will make them more extensible.
So the value in converting some of the function based views to CBVs the key thing is to identify what features need to be factored out. class-based structure allows us to factor out key functionality in a way that subclasses can override or modify that functionality.
In this case contrib.auth and contrib.admin are the main candidates for this CBV converting.
For updating best practices first thing to consider is to convert the functional views of django contrib apps to class based views where possible and necessary. To do so first app to consider is django contrib auth. Then use them to modify the views in admin app related to authentication. Many features of contrib admin app also need to be converted as class based view for extensibility. Additionally convertion of auth will need some changes in admin app to.
Another thing of my plan is introducing some generic FormSet and ModelformSet views in django proper tat will help to make admin app more extensible with the help of class based views conversion easier.
My Projects aim in GOSC 2015 is to achieve this goal.
contrib.auth views.py now have function based views and they are
login logout logout_then_login redirect_to_login password_reset password_reset_done password_reset_confirm password_reset_complete password_change password_change_done
and in urls.py url mapping for function based views as follows
urlpatterns = [ url(r'^login/$', views.login, name='login'), url(r'^logout/$', views.logout, name='logout'), url(r'^password_change/$', views.password_change, name='password_change'), url(r'^password_change/done/$', views.password_change_done, name='password_change_done'), url(r'^password_reset/$', views.password_reset, name='password_reset'), url(r'^password_reset/done/$', views.password_reset_done, name='password_reset_done'), url(r'^reset/(?P[0-9A-Za-z_-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', views.password_reset_confirm, name='password_reset_confirm'), url(r'^reset/done/$', views.password_reset_complete, name='password_reset_complete'), ]
and tests for this in tests/auth_tests/test_views.py
the views have to be converted into CBV and also the urls. and this should be done in a backward compatible manner.
as an example password_change_done view is now implemented as below.
@login_required def password_change_done(request, template_name='registration/password_change_done.html', current_app=None, extra_context=None): context = { 'title': _('Password change successful'), } if extra_context is not None: context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
this could be changed to cbv like below
class PasswordChangeDoneView(TemplateView): template_name='registration/password_change_done.html' current_app=None extra_context=None
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(Password_Change_Done, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(Password_Change_Done, self).get_context_data(**kwargs)
context.update({
'title': _('Password change successful'),
'current_app': self.current_app,
})
if self.extra_context is not None:
context.update(self.extra_context)
return context
def password_change_done(request, *args, **kwargs): return PasswordChangeDoneView.as_view(**kwargs)(request, *args, **kwargs)
converting auth views to cbv will help to make this auth view more extensible. and using them in other apps will reduce a lot of code.
Admin site need to be audited updated with the contrib auth class based views. Changes applied in contrib auth will need to be implemented in some parts of contrib admin and other apps where needed.
#For admin
It would be good to do a) on principle, b) to make the admin views easier to extend, and c) to potentially find and correct issues in the generic class-based views. Naturally, any solution would need to be backwards-compatible.
dog fooding admin app will be most difficult task. For doing so Spliting admin app main views to base, list, edit etc smaller parts could be a feasible option. And editing the relevent files to work with.
for listing the available models the built in generic views should be enough ListView and DetailView
A base view file where AdminViewMixin and AdminHistoryView could be placed and AdminViewMixin will be inherited by many views in other views.
class AdminViewMixin(object):
def __init__(self, **kwargs):
super(AdminViewMixin, self).__init__(**kwargs)
self.model = self.admin_opts.model
self.model_opts = self.model._meta
def get_queryset(self):
return self.admin_opts.queryset(self.request)
There will be a edit view where all admin edit actions will be placed
Like
AdminAddView AdminDeleteView AdminUpdateView
AdminDeleteView could be like
class AdminDeleteView(AdminViewMixin, DeleteView):
def dispatch(self, request, *args, **kwargs):
return super(AdminDeleteView, self).dispatch(request, *args, **kwargs)
def get_object(self, queryset=None):
object = self.admin_opts.get_object(
self.request, unquote(self.object_id), queryset=queryset)
if not self.admin_opts.has_delete_permission(self.request, object):
raise PermissionDenied
if object is None:
raise Http404(
_('%(name)s object with primary key %(key)r does not exist.') % {
'name': force_unicode(self.model_opts.verbose_name),
'key': escape(self.object_id)})
using = router.db_for_write(self.model)
# Populate deleted_objects, a data structure of all related objects that
# will also be deleted.
(self.deleted_objects, self.perms_needed, self.protected) = get_deleted_objects(
[object], self.model_opts, self.request.user, self.admin_opts.admin_site, using)
return object
def post(self, *args, **kwargs):
self.object = self.get_object()
# The user has already confirmed the deletion.
if self.perms_needed:
raise PermissionDenied
obj_display = force_unicode(self.object)
self.admin_opts.log_deletion(self.request, self.object, obj_display)
self.admin_opts.delete_model(self.request, self.object)
self.admin_opts.message_user(
self.request, _('The %(name)s "%(obj)s" was deleted successfully.') % {
'name': force_unicode(self.model_opts.verbose_name),
'obj': force_unicode(obj_display)})
if not self.admin_opts.has_change_permission(self.request, None):
return HttpResponseRedirect(
reverse('admin:index', current_app=self.admin_opts.admin_site.name))
return HttpResponseRedirect(
reverse('admin:%s_%s_changelist' % (
self.model_opts.app_label, self.model_opts.module_name),
current_app=self.admin_opts.admin_site.name))
def get_context_data(self, **kwargs):
context = super(AdminDeleteView, self).get_context_data(**kwargs)
object_name = force_unicode(self.model_opts.verbose_name)
if self.perms_needed or self.protected:
title = _("Cannot delete %(name)s") % {"name": object_name}
else:
title = _("Are you sure?")
context.update({
"title": title,
"object_name": object_name,
"object": self.object,
"deleted_objects": self.deleted_objects,
"perms_lacking": self.perms_needed,
"protected": self.protected,
"opts": self.model_opts,
"app_label": self.model_opts.app_label,
})
context.update(self.extra_context or {})
return context
def get_template_names(self):
form_template = self.admin_opts.delete_confirmation_template
if form_template:
return [form_template]
else:
return [
"admin/%s/%s/delete_confirmation.html" % (self.model_opts.app_label, self.model_opts.object_name.lower()),
"admin/%s/delete_confirmation.html" % self.model_opts.app_label,
"admin/delete_confirmation.html"
]
In list view the changeList related views could be placed Where AdminChangeListView and changeList class will be placed.
The views of admin/options will be returning the converted the Class Based views.
which are now add_view, delete_view, history_view and changelist_view
options.py have huge amount of codes which could be split out with the cbv and generic formsets. ModelAdmin could be modifeid too.
I am considering philosophy to brought in django proper and django-extra-views for FormSet improvement.
From django-extra-views:
Django's class-based generic views are great, they let you accomplish a large number of web application design patterns in relatively few lines of code. They do have their limits though, and that's what this library of views aims to overcome.
I plan is to introduce some small subset from django-extra-views features to django proper to improve its formset infrastructure. which later can be used in django admin and others apps.
FormSet and ModelFormSet views - The formset equivalents of FormView and ModelFormView. InlineFormSetView - Lets you edit formsets related to a model CreateWithInlinesView and UpdateWithInlinesView - Lets users edit a model and its relations Some generic InlineFormSetViews could be introduced for generic foreign keys
Improvment of formset in a generic manner like extra views will help improvement the django formset infrastructure and use that in admin app.
Django admin 2 shows some good ideas about using class based views, features from extra views and themming support etc which makes it more extensible. I am planning to bring some of those goodies in django admin. The feature I'm willing to add to django is the theme changing capability for admin app. User can change the theme of the admin app if they wish. Following the admin two way or any other better easier solutions for this part.
My semister finals will be completed by 26th of April. So I am planning to work from may 1/2 and allocate 16 weeks for this project
- Community bonding period:
At this period I will discuss with the community more detail about the project if there is any tweak needed or better way of implementing my ideas hope fully this might take 1/2 weeks
Implementing the auth views to cbv with bc and later converting the tests in class based views tests
Converting some of admin auth fatures converted to cbv in django admin app
Introducing some small subset of features from django extra views like FormSet as a form of generic views
implementing more class based views for formset
analyzing admin app to decide which views need to be converted to cbv and why should they implemented
working on converting some views to edit view like AdminAddViews
work on admin listViews and historyView
working more on different parts of admin app to convert them logically to cbv
completing analyzing
adding theme changing ability to django admin following suitable
I'm Asif Saif Uddin (auvi) Postgraduate Student of Institute of Information Technology, Jahangirnagar University, Savar, Dhaka, Bangladesh. Have been working with python for more then 3 years and with django for two years.
Participated in co developement of a local e-commerce project with django after my graduation and then worked full time django developer for a start up. Have worked with django, django rest framework, mezzanine cms and many python/django tools. I like django's batteries included nature and its huge 3rd party app/tools eco system.
After that I enrolled to masters program in IIT, Jahangirnagar University and I'm Firefox student ambassador and club lead of My campus. I'm a opensource fan and trying to utilize the power of open source software as learning tool.
Now I'm looking to participate on gsoc program under DSF to increase my technical ability and learning better internals about django which will eventually make a better developer.
My long term goal is a to become good contributor and learn through contributing to django core.
Email: auvipy@gmail.com
Github: auvipy
IRC nick: auvipy
TimeZone: UTC+6
https://code.djangoproject.com/ticket/17209 https://code.djangoproject.com/ticket/17208 https://code.djangoproject.com/ticket/16256 https://code.djangoproject.com/ticket/10403