Project

General

Profile

Download (12.5 KB) Statistics
| Branch: | Tag: | Revision:
a042c408 Benjamin Dauvergne
from datetime import datetime, date
e04509f6 Benjamin Dauvergne
from dateutil.relativedelta import relativedelta

92163ca0 Benjamin Dauvergne
from django import forms
from django.views.generic import list as list_cbv, edit, base, detail
1097fd0a Benjamin Dauvergne
from django.shortcuts import get_object_or_404
92163ca0 Benjamin Dauvergne
from django.http import Http404, HttpResponseRedirect
a5a20700 Benjamin Dauvergne
from django.core.urlresolvers import resolve
92163ca0 Benjamin Dauvergne
from django.core.exceptions import ImproperlyConfigured
5e0f0c15 Benjamin Dauvergne
1097fd0a Benjamin Dauvergne
from calebasse.ressources.models import Service
726cc46a Mikaël Ates
from calebasse.middleware.request import get_request
from calebasse.utils import is_super_user, is_validator
5e0f0c15 Benjamin Dauvergne
2e9ee32b Benjamin Dauvergne
HOME_SERVICE_COOKIE = 'home-service'

92dc8d95 Benjamin Dauvergne
class ReturnToObjectMixin(object):
def get_success_url(self):
efbccbec Benjamin Dauvergne
return '../#object-' + str(self.object.pk)
92dc8d95 Benjamin Dauvergne
6c174200 Benjamin Dauvergne
92dc8d95 Benjamin Dauvergne
class ServiceFormMixin(object):
def get_form_kwargs(self):
kwargs = super(ServiceFormMixin, self).get_form_kwargs()
kwargs['service'] = self.service
return kwargs

6c174200 Benjamin Dauvergne
5e0f0c15 Benjamin Dauvergne
class ServiceViewMixin(object):
1097fd0a Benjamin Dauvergne
service = None
date = None
popup = False
efe3f40d Serghei MIHAI
cookies_to_clear = [('agenda-worker-tabs', ), ('active-resource-agenda', )]
206fe640 Benjamin Dauvergne
1df3d699 Serghei MIHAI
def clear_cookies(self, response, path):
206fe640 Benjamin Dauvergne
for cookie in self.cookies_to_clear:
efe3f40d Serghei MIHAI
cookie_name = cookie[0]
try:
# delete the cookie for provided path
response.delete_cookie(cookie[0], path = cookie[1])
except IndexError:
# if not use the current page path
response.delete_cookie(cookie[0],
path = '/'.join(path.split('/')[:3])
)
1097fd0a Benjamin Dauvergne
def dispatch(self, request, **kwargs):
self.popup = request.GET.get('popup')
f73e93e0 Benjamin Dauvergne
if 'service' in kwargs:
self.service = get_object_or_404(Service, slug=kwargs['service'])
if 'date' in kwargs:
1097fd0a Benjamin Dauvergne
try:
f73e93e0 Benjamin Dauvergne
self.date = datetime.strptime(kwargs.get('date'),
1097fd0a Benjamin Dauvergne
'%Y-%m-%d').date()
except (TypeError, ValueError):
raise Http404
2e9ee32b Benjamin Dauvergne
result = super(ServiceViewMixin, self).dispatch(request, **kwargs)
if self.service:
result.set_cookie(HOME_SERVICE_COOKIE, self.service.slug,
max_age=3600*24*365, httponly=True)
1df3d699 Serghei MIHAI
self.clear_cookies(result, request.path)
2e9ee32b Benjamin Dauvergne
return result
1097fd0a Benjamin Dauvergne
5e0f0c15 Benjamin Dauvergne
def get_context_data(self, **kwargs):
context = super(ServiceViewMixin, self).get_context_data(**kwargs)
a5a20700 Benjamin Dauvergne
context['url_name'] = resolve(self.request.path).url_name
1097fd0a Benjamin Dauvergne
context['popup'] = self.popup
if self.service is not None:
context['service'] = self.service.slug
context['service_name'] = self.service.name

if self.date is not None:
context['date'] = self.date
context['previous_day'] = self.date + relativedelta(days=-1)
context['next_day'] = self.date + relativedelta(days=1)
context['previous_month'] = self.date + relativedelta(months=-1)
context['next_month'] = self.date + relativedelta(months=1)
726cc46a Mikaël Ates
context['role'] = None
user = get_request().user
if is_super_user(user):
context['role'] = ['super', 'validator']
elif is_validator(user):
context['role'] = ['validator']
a042c408 Benjamin Dauvergne
context['today'] = date.today()
5e0f0c15 Benjamin Dauvergne
return context

6c174200 Benjamin Dauvergne
5e0f0c15 Benjamin Dauvergne
class TemplateView(ServiceViewMixin, base.TemplateView):
pass

6c174200 Benjamin Dauvergne
235cb1d4 Benjamin Dauvergne
class AppTemplateFirstMixin(object):
def get_template_names(self):
names = []
model = getattr(self, 'model', None)
if not model:
model = self.queryset.model
if model is not None:
opts = model._meta
names.append("%s/%s%s.html" % (opts.app_label, opts.object_name.lower(), self.template_name_suffix))
names.append("%s/%s.html" % (opts.app_label, self.template_name_suffix.strip('_')))
if getattr(self, 'template_name', None):
names.append(self.template_name)
return names

6c174200 Benjamin Dauvergne
3fb70ba0 Benjamin Dauvergne
class ModelNameMixin(object):
def get_context_data(self, **kwargs):
ctx = super(ModelNameMixin, self).get_context_data(**kwargs)
ctx['model_verbose_name_plural'] = self.model._meta.verbose_name_plural
ctx['model_verbose_name'] = self.model._meta.verbose_name
return ctx

6c174200 Benjamin Dauvergne
235cb1d4 Benjamin Dauvergne
class ListView(AppTemplateFirstMixin, ModelNameMixin, ServiceViewMixin,
list_cbv.ListView):
b3317974 Frédéric Péters
def get_context_data(self, **kwargs):
bb3c11f8 Frédéric Péters
ctx = super(AppTemplateFirstMixin, self).get_context_data(**kwargs)
ctx.update(super(ModelNameMixin, self).get_context_data(**kwargs))
b3317974 Frédéric Péters
ctx.update(super(ServiceViewMixin, self).get_context_data(**kwargs))
bb3c11f8 Frédéric Péters
ctx.update(super(list_cbv.ListView, self).get_context_data(**kwargs))
ec7fa0f8 Frédéric Péters
if self.request.GET.get('new_id'):
ctx['new_id'] = int(self.request.GET.get('new_id'))
b3317974 Frédéric Péters
return ctx
3fb70ba0 Benjamin Dauvergne
b8f587fc Benjamin Dauvergne
class M2MFormMixin(object):
'''Alos save Many2Many relations for model forms if needed.'''
def form_valid(self, form):
res = super(M2MFormMixin, self).form_valid(form)
if hasattr(form, 'save_m2m'):
form.save_m2m()
return res

763013dd Benjamin Dauvergne
class DetailView(M2MFormMixin, AppTemplateFirstMixin, ModelNameMixin, ServiceViewMixin,
detail.DetailView):
pass
b8f587fc Benjamin Dauvergne
class CreateView(M2MFormMixin, AppTemplateFirstMixin, ModelNameMixin, ServiceViewMixin,
235cb1d4 Benjamin Dauvergne
edit.CreateView):
5e0f0c15 Benjamin Dauvergne
pass

3fb70ba0 Benjamin Dauvergne
235cb1d4 Benjamin Dauvergne
class DeleteView(AppTemplateFirstMixin,
ModelNameMixin, ServiceViewMixin, edit.DeleteView):
5e0f0c15 Benjamin Dauvergne
pass

3fb70ba0 Benjamin Dauvergne
b8f587fc Benjamin Dauvergne
class UpdateView(M2MFormMixin, AppTemplateFirstMixin,
235cb1d4 Benjamin Dauvergne
ModelNameMixin, ServiceViewMixin, edit.UpdateView):
5e0f0c15 Benjamin Dauvergne
pass
92163ca0 Benjamin Dauvergne
6c174200 Benjamin Dauvergne
2e94f19b Benjamin Dauvergne
class FormView(ServiceViewMixin, edit.FormView):
pass

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class ContextMixin(object):
"""
A default context mixin that passes the keyword arguments received by
get_context_data as the template context.
"""

def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class MultiFormMixin(ContextMixin):
"""
A mixin that provides a way to show and handle multiple forms in a request.
"""

initial = {}
initials = {}
forms_classes = None
success_url = None

def get_prefixes(self):
return self.forms_classes.keys()

def get_initial(self, prefix):
"""
Returns the initial data to use for forms on this view.
"""
return self.initials.get(prefix, self.initial).copy()

def get_form_class(self, prefix):
"""
Returns the form class to use in this view
"""
return self.forms_classes[prefix]

def get_form(self, form_class, prefix):
"""
Returns an instance of the form to be used in this view.
"""
return form_class(**self.get_form_kwargs(prefix))

def get_current_prefix(self):
"""
Returns the current prefix by parsing first keys in POST
"""
keys = self.request.POST.keys() or self.request.FILES.keys()
42838d50 Benjamin Dauvergne
for key in keys:
if '-' in key:
return key.split('-', 1)[0]
return None
92163ca0 Benjamin Dauvergne
def get_forms(self):
"""
Returns the dictionnary of forms instances
"""
form_instances = {}
for prefix in self.get_prefixes():
form_instances[prefix] = self.get_form(self.get_form_class(prefix), prefix)
return form_instances

def get_form_kwargs(self, prefix):
"""
Returns the keyword arguments for instantiating the form.
"""
kwargs = {'initial': self.get_initial(prefix),
'prefix': prefix }
if self.request.method in ('POST', 'PUT') \
and prefix == self.get_current_prefix():
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs

def get_success_url(self):
"""
Returns the supplied success URL.
"""
if self.success_url:
url = self.success_url
else:
raise ImproperlyConfigured(
"No URL to redirect to. Provide a success_url.")
return url

def form_valid(self, forms):
"""
If the form is valid, redirect to the supplied URL.
"""
return HttpResponseRedirect(self.get_success_url())

def form_invalid(self, forms):
"""
If the form is invalid, re-render the context data with the
data-filled form and errors.
"""
return self.render_to_response(self.get_context_data(forms=forms))

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class MultiModelFormMixin(MultiFormMixin, detail.SingleObjectMixin):
"""
A mixin that provides a way to show and handle multiple forms or modelforms
in a request.
"""

def get_form_kwargs(self, prefix):
"""
Returns the keyword arguments for instantiating the form.
"""
kwargs = super(MultiModelFormMixin, self).get_form_kwargs(prefix)
if issubclass(self.get_form_class(prefix), forms.ModelForm):
kwargs.update({'instance': self.object})
return kwargs

def get_success_url(self):
"""
Returns the supplied URL.
"""
if self.success_url:
url = self.success_url % self.object.__dict__
else:
try:
url = self.object.get_absolute_url()
except AttributeError:
raise ImproperlyConfigured(
"No URL to redirect to. Either provide a url or define"
" a get_absolute_url method on the Model.")
return url

f6b61eaf Benjamin Dauvergne
def form_valid(self, form):
92163ca0 Benjamin Dauvergne
"""
If the form is valid, save the associated model.
"""
5bf79d21 Benjamin Dauvergne
form = form[self.get_current_prefix()]
92163ca0 Benjamin Dauvergne
if hasattr(form, 'save'):
if isinstance(form, forms.ModelForm):
b8f587fc Benjamin Dauvergne
self.object = form.save()
92163ca0 Benjamin Dauvergne
else:
form.save()
b8f587fc Benjamin Dauvergne
if hasattr(form, 'save_m2m'): # save many2many relations
form.save_m2m()
92163ca0 Benjamin Dauvergne
return super(MultiModelFormMixin, self).form_valid(form)

def get_context_data(self, **kwargs):
"""
If an object has been supplied, inject it into the context with the
supplied context_object_name name.
"""
context = {}
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
context.update(kwargs)
return super(MultiModelFormMixin, self).get_context_data(**context)

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class ProcessMultiFormView(base.View):
"""
A mixin that renders a form on GET and processes it on POST.
"""
def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates a blank version of the form.
"""
forms = self.get_forms()
return self.render_to_response(self.get_context_data(forms=forms))

def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance with the passed
POST variables and then checked for validity.
"""
forms = self.get_forms()
prefix = self.get_current_prefix()
02d4a748 Serghei MIHAI
if prefix and forms[prefix].is_valid():
92163ca0 Benjamin Dauvergne
return self.form_valid(forms)
else:
return self.form_invalid(forms)

# PUT is a valid HTTP verb for creating (with a known URL) or editing an
# object, note that browsers only support POST for now.
def put(self, *args, **kwargs):
return self.post(*args, **kwargs)

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class BaseMultiFormView(MultiFormMixin, ProcessMultiFormView):
"""
A base view for displaying multiple forms
"""

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class MultiFormView(base.TemplateResponseMixin, BaseMultiFormView):
"""
A base view for displaying multiple forms, and rendering a template reponse.
"""

6c174200 Benjamin Dauvergne
92163ca0 Benjamin Dauvergne
class BaseMultiUpdateView(MultiModelFormMixin, ProcessMultiFormView):
"""
Base view for updating an existing object.

Using this base class requires subclassing to provide a response mixin.
"""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(BaseMultiUpdateView, self).get(request, *args, **kwargs)

def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super(BaseMultiUpdateView, self).post(request, *args, **kwargs)

6c174200 Benjamin Dauvergne
235cb1d4 Benjamin Dauvergne
class MultiUpdateView(AppTemplateFirstMixin,
detail.SingleObjectTemplateResponseMixin, BaseMultiUpdateView):
92163ca0 Benjamin Dauvergne
"""
View for updating an object,
with a response rendered by template.
"""
template_name_suffix = '_form'