From 376b36bd9b1c1a555176251b28bb2b8d5e56923d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jun 2014 21:02:25 -0400 Subject: [PATCH] Remove last usage of the backported generic function views --- mayan/apps/common/backport/__init__.py | 0 .../apps/common/backport/generic/__init__.py | 12 - mayan/apps/common/backport/generic/base.py | 178 ----- .../common/backport/generic/create_update.py | 221 ------- .../common/backport/generic/date_based.py | 376 ----------- mayan/apps/common/backport/generic/dates.py | 607 ------------------ mayan/apps/common/backport/generic/detail.py | 150 ----- mayan/apps/common/backport/generic/edit.py | 242 ------- mayan/apps/common/backport/generic/list.py | 153 ----- .../common/backport/generic/list_detail.py | 152 ----- mayan/apps/common/backport/generic/simple.py | 68 -- mayan/apps/common/urls.py | 12 +- 12 files changed, 6 insertions(+), 2165 deletions(-) delete mode 100644 mayan/apps/common/backport/__init__.py delete mode 100644 mayan/apps/common/backport/generic/__init__.py delete mode 100644 mayan/apps/common/backport/generic/base.py delete mode 100644 mayan/apps/common/backport/generic/create_update.py delete mode 100644 mayan/apps/common/backport/generic/date_based.py delete mode 100644 mayan/apps/common/backport/generic/dates.py delete mode 100644 mayan/apps/common/backport/generic/detail.py delete mode 100644 mayan/apps/common/backport/generic/edit.py delete mode 100644 mayan/apps/common/backport/generic/list.py delete mode 100644 mayan/apps/common/backport/generic/list_detail.py delete mode 100644 mayan/apps/common/backport/generic/simple.py diff --git a/mayan/apps/common/backport/__init__.py b/mayan/apps/common/backport/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mayan/apps/common/backport/generic/__init__.py b/mayan/apps/common/backport/generic/__init__.py deleted file mode 100644 index 799ea2b36b..0000000000 --- a/mayan/apps/common/backport/generic/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from .base import View, TemplateView, RedirectView -from .dates import (ArchiveIndexView, YearArchiveView, MonthArchiveView, - WeekArchiveView, DayArchiveView, TodayArchiveView, - DateDetailView) -from .detail import DetailView -from .edit import FormView, CreateView, UpdateView, DeleteView -from .list import ListView - - -class GenericViewError(Exception): - """A problem in a generic view.""" - pass diff --git a/mayan/apps/common/backport/generic/base.py b/mayan/apps/common/backport/generic/base.py deleted file mode 100644 index fcdc7c785b..0000000000 --- a/mayan/apps/common/backport/generic/base.py +++ /dev/null @@ -1,178 +0,0 @@ -from functools import update_wrapper -from django import http -from django.core.exceptions import ImproperlyConfigured -from django.template.response import TemplateResponse -from django.utils.log import getLogger -from django.utils.decorators import classonlymethod - -logger = getLogger('django.request') - - -class View(object): - """ - Intentionally simple parent class for all views. Only implements - dispatch-by-method and simple sanity checking. - """ - - http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace'] - - def __init__(self, **kwargs): - """ - Constructor. Called in the URLconf; can contain helpful extra - keyword arguments, and other things. - """ - # Go through keyword arguments, and either save their values to our - # instance, or raise an error. - for key, value in kwargs.iteritems(): - setattr(self, key, value) - - @classonlymethod - def as_view(cls, **initkwargs): - """ - Main entry point for a request-response process. - """ - # sanitize keyword arguments - for key in initkwargs: - if key in cls.http_method_names: - raise TypeError(u"You tried to pass in the %s method name as a " - u"keyword argument to %s(). Don't do that." - % (key, cls.__name__)) - if not hasattr(cls, key): - raise TypeError(u"%s() received an invalid keyword %r" % ( - cls.__name__, key)) - - def view(request, *args, **kwargs): - self = cls(**initkwargs) - if hasattr(self, 'get') and not hasattr(self, 'head'): - self.head = self.get - return self.dispatch(request, *args, **kwargs) - - # take name and docstring from class - update_wrapper(view, cls, updated=()) - - # and possible attributes set by decorators - # like csrf_exempt from dispatch - update_wrapper(view, cls.dispatch, assigned=()) - return view - - def dispatch(self, request, *args, **kwargs): - # Try to dispatch to the right method; if a method doesn't exist, - # defer to the error handler. Also defer to the error handler if the - # request method isn't on the approved list. - if request.method.lower() in self.http_method_names: - handler = getattr(self, request.method.lower(), self.http_method_not_allowed) - else: - handler = self.http_method_not_allowed - self.request = request - self.args = args - self.kwargs = kwargs - return handler(request, *args, **kwargs) - - def http_method_not_allowed(self, request, *args, **kwargs): - allowed_methods = [m for m in self.http_method_names if hasattr(self, m)] - logger.warning('Method Not Allowed (%s): %s', request.method, request.path, - extra={ - 'status_code': 405, - 'request': self.request - } - ) - return http.HttpResponseNotAllowed(allowed_methods) - - -class TemplateResponseMixin(object): - """ - A mixin that can be used to render a template. - """ - template_name = None - response_class = TemplateResponse - - def render_to_response(self, context, **response_kwargs): - """ - Returns a response with a template rendered with the given context. - """ - return self.response_class( - request = self.request, - template = self.get_template_names(), - context = context, - **response_kwargs - ) - - def get_template_names(self): - """ - Returns a list of template names to be used for the request. Must return - a list. May not be called if render_to_response is overridden. - """ - if self.template_name is None: - raise ImproperlyConfigured( - "TemplateResponseMixin requires either a definition of " - "'template_name' or an implementation of 'get_template_names()'") - else: - return [self.template_name] - - -class TemplateView(TemplateResponseMixin, View): - """ - A view that renders a template. - """ - def get_context_data(self, **kwargs): - return { - 'params': kwargs - } - - def get(self, request, *args, **kwargs): - context = self.get_context_data(**kwargs) - return self.render_to_response(context) - - -class RedirectView(View): - """ - A view that provides a redirect on any GET request. - """ - permanent = True - url = None - query_string = False - - def get_redirect_url(self, **kwargs): - """ - Return the URL redirect to. Keyword arguments from the - URL pattern match generating the redirect request - are provided as kwargs to this method. - """ - if self.url: - url = self.url % kwargs - args = self.request.META.get('QUERY_STRING', '') - if args and self.query_string: - url = "%s?%s" % (url, args) - return url - else: - return None - - def get(self, request, *args, **kwargs): - url = self.get_redirect_url(**kwargs) - if url: - if self.permanent: - return http.HttpResponsePermanentRedirect(url) - else: - return http.HttpResponseRedirect(url) - else: - logger.warning('Gone: %s', self.request.path, - extra={ - 'status_code': 410, - 'request': self.request - }) - return http.HttpResponseGone() - - def head(self, request, *args, **kwargs): - return self.get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - return self.get(request, *args, **kwargs) - - def options(self, request, *args, **kwargs): - return self.get(request, *args, **kwargs) - - def delete(self, request, *args, **kwargs): - return self.get(request, *args, **kwargs) - - def put(self, request, *args, **kwargs): - return self.get(request, *args, **kwargs) diff --git a/mayan/apps/common/backport/generic/create_update.py b/mayan/apps/common/backport/generic/create_update.py deleted file mode 100644 index 7ea171f42b..0000000000 --- a/mayan/apps/common/backport/generic/create_update.py +++ /dev/null @@ -1,221 +0,0 @@ -from django.forms.models import ModelFormMetaclass, ModelForm -from django.template import RequestContext, loader -from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.core.xheaders import populate_xheaders -from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured -from django.utils.translation import ugettext -from django.contrib.auth.views import redirect_to_login -from . import GenericViewError -from django.contrib import messages - -import warnings -warnings.warn( - 'Function-based generic views have been deprecated; use class-based views instead.', - DeprecationWarning -) - - -def apply_extra_context(extra_context, context): - """ - Adds items from extra_context dict to context. If a value in extra_context - is callable, then it is called and the result is added to context. - """ - for key, value in extra_context.iteritems(): - if callable(value): - context[key] = value() - else: - context[key] = value - -def get_model_and_form_class(model, form_class): - """ - Returns a model and form class based on the model and form_class - parameters that were passed to the generic view. - - If ``form_class`` is given then its associated model will be returned along - with ``form_class`` itself. Otherwise, if ``model`` is given, ``model`` - itself will be returned along with a ``ModelForm`` class created from - ``model``. - """ - if form_class: - return form_class._meta.model, form_class - if model: - # The inner Meta class fails if model = model is used for some reason. - tmp_model = model - # TODO: we should be able to construct a ModelForm without creating - # and passing in a temporary inner class. - class Meta: - model = tmp_model - class_name = model.__name__ + 'Form' - form_class = ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta}) - return model, form_class - raise GenericViewError("Generic view must be called with either a model or" - " form_class argument.") - -def redirect(post_save_redirect, obj): - """ - Returns a HttpResponseRedirect to ``post_save_redirect``. - - ``post_save_redirect`` should be a string, and can contain named string- - substitution place holders of ``obj`` field names. - - If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned - by ``get_absolute_url()``. If ``obj`` has no ``get_absolute_url`` method, - then raise ImproperlyConfigured. - - This function is meant to handle the post_save_redirect parameter to the - ``create_object`` and ``update_object`` views. - """ - if post_save_redirect: - return HttpResponseRedirect(post_save_redirect % obj.__dict__) - elif hasattr(obj, 'get_absolute_url'): - return HttpResponseRedirect(obj.get_absolute_url()) - else: - raise ImproperlyConfigured( - "No URL to redirect to. Either pass a post_save_redirect" - " parameter to the generic view or define a get_absolute_url" - " method on the Model.") - -def lookup_object(model, object_id, slug, slug_field): - """ - Return the ``model`` object with the passed ``object_id``. If - ``object_id`` is None, then return the object whose ``slug_field`` - equals the passed ``slug``. If ``slug`` and ``slug_field`` are not passed, - then raise Http404 exception. - """ - lookup_kwargs = {} - if object_id: - lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id - elif slug and slug_field: - lookup_kwargs['%s__exact' % slug_field] = slug - else: - raise GenericViewError( - "Generic view must be called with either an object_id or a" - " slug/slug_field.") - try: - return model.objects.get(**lookup_kwargs) - except ObjectDoesNotExist: - raise Http404("No %s found for %s" - % (model._meta.verbose_name, lookup_kwargs)) - -def create_object(request, model=None, template_name=None, - template_loader=loader, extra_context=None, post_save_redirect=None, - login_required=False, context_processors=None, form_class=None): - """ - Generic object-creation function. - - Templates: ``/_form.html`` - Context: - form - the form for the object - """ - if extra_context is None: extra_context = {} - if login_required and not request.user.is_authenticated(): - return redirect_to_login(request.path) - - model, form_class = get_model_and_form_class(model, form_class) - if request.method == 'POST': - form = form_class(request.POST, request.FILES) - if form.is_valid(): - new_object = form.save() - - msg = ugettext("The %(verbose_name)s was created successfully.") %\ - {"verbose_name": model._meta.verbose_name} - messages.success(request, msg, fail_silently=True) - return redirect(post_save_redirect, new_object) - else: - form = form_class() - - # Create the template, context, response - if not template_name: - template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - 'form': form, - }, context_processors) - apply_extra_context(extra_context, c) - return HttpResponse(t.render(c)) - -def update_object(request, model=None, object_id=None, slug=None, - slug_field='slug', template_name=None, template_loader=loader, - extra_context=None, post_save_redirect=None, login_required=False, - context_processors=None, template_object_name='object', - form_class=None): - """ - Generic object-update function. - - Templates: ``/_form.html`` - Context: - form - the form for the object - object - the original object being edited - """ - if extra_context is None: extra_context = {} - if login_required and not request.user.is_authenticated(): - return redirect_to_login(request.path) - - model, form_class = get_model_and_form_class(model, form_class) - obj = lookup_object(model, object_id, slug, slug_field) - - if request.method == 'POST': - form = form_class(request.POST, request.FILES, instance=obj) - if form.is_valid(): - obj = form.save() - msg = ugettext("The %(verbose_name)s was updated successfully.") %\ - {"verbose_name": model._meta.verbose_name} - messages.success(request, msg, fail_silently=True) - return redirect(post_save_redirect, obj) - else: - form = form_class(instance=obj) - - if not template_name: - template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - 'form': form, - template_object_name: obj, - }, context_processors) - apply_extra_context(extra_context, c) - response = HttpResponse(t.render(c)) - populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) - return response - -def delete_object(request, model, post_delete_redirect, object_id=None, - slug=None, slug_field='slug', template_name=None, - template_loader=loader, extra_context=None, login_required=False, - context_processors=None, template_object_name='object'): - """ - Generic object-delete function. - - The given template will be used to confirm deletetion if this view is - fetched using GET; for safty, deletion will only be performed if this - view is POSTed. - - Templates: ``/_confirm_delete.html`` - Context: - object - the original object being deleted - """ - if extra_context is None: extra_context = {} - if login_required and not request.user.is_authenticated(): - return redirect_to_login(request.path) - - obj = lookup_object(model, object_id, slug, slug_field) - - if request.method == 'POST': - obj.delete() - msg = ugettext("The %(verbose_name)s was deleted.") %\ - {"verbose_name": model._meta.verbose_name} - messages.success(request, msg, fail_silently=True) - return HttpResponseRedirect(post_delete_redirect) - else: - if not template_name: - template_name = "%s/%s_confirm_delete.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - template_object_name: obj, - }, context_processors) - apply_extra_context(extra_context, c) - response = HttpResponse(t.render(c)) - populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) - return response diff --git a/mayan/apps/common/backport/generic/date_based.py b/mayan/apps/common/backport/generic/date_based.py deleted file mode 100644 index 75094aa775..0000000000 --- a/mayan/apps/common/backport/generic/date_based.py +++ /dev/null @@ -1,376 +0,0 @@ -import datetime -import time - -from django.template import loader, RequestContext -from django.core.exceptions import ObjectDoesNotExist -from django.core.xheaders import populate_xheaders -from django.db.models.fields import DateTimeField -from django.http import Http404, HttpResponse -from django.utils import timezone - -import warnings -warnings.warn( - 'Function-based generic views have been deprecated; use class-based views instead.', - DeprecationWarning -) - - -def archive_index(request, queryset, date_field, num_latest=15, - template_name=None, template_loader=loader, - extra_context=None, allow_empty=True, context_processors=None, - mimetype=None, allow_future=False, template_object_name='latest'): - """ - Generic top-level archive of date-based objects. - - Templates: ``/_archive.html`` - Context: - date_list - List of years - latest - Latest N (defaults to 15) objects by date - """ - if extra_context is None: extra_context = {} - model = queryset.model - if not allow_future: - queryset = queryset.filter(**{'%s__lte' % date_field: timezone.now()}) - date_list = queryset.dates(date_field, 'year')[::-1] - if not date_list and not allow_empty: - raise Http404("No %s available" % model._meta.verbose_name) - - if date_list and num_latest: - latest = queryset.order_by('-'+date_field)[:num_latest] - else: - latest = None - - if not template_name: - template_name = "%s/%s_archive.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - 'date_list' : date_list, - template_object_name : latest, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - return HttpResponse(t.render(c), mimetype=mimetype) - -def archive_year(request, year, queryset, date_field, template_name=None, - template_loader=loader, extra_context=None, allow_empty=False, - context_processors=None, template_object_name='object', mimetype=None, - make_object_list=False, allow_future=False): - """ - Generic yearly archive view. - - Templates: ``/_archive_year.html`` - Context: - date_list - List of months in this year with objects - year - This year - object_list - List of objects published in the given month - (Only available if make_object_list argument is True) - """ - if extra_context is None: extra_context = {} - model = queryset.model - now = timezone.now() - - lookup_kwargs = {'%s__year' % date_field: year} - - # Only bother to check current date if the year isn't in the past and future objects aren't requested. - if int(year) >= now.year and not allow_future: - lookup_kwargs['%s__lte' % date_field] = now - date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month') - if not date_list and not allow_empty: - raise Http404 - if make_object_list: - object_list = queryset.filter(**lookup_kwargs) - else: - object_list = [] - if not template_name: - template_name = "%s/%s_archive_year.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - 'date_list': date_list, - 'year': year, - '%s_list' % template_object_name: object_list, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - return HttpResponse(t.render(c), mimetype=mimetype) - -def archive_month(request, year, month, queryset, date_field, - month_format='%b', template_name=None, template_loader=loader, - extra_context=None, allow_empty=False, context_processors=None, - template_object_name='object', mimetype=None, allow_future=False): - """ - Generic monthly archive view. - - Templates: ``/_archive_month.html`` - Context: - date_list: - List of days in this month with objects - month: - (date) this month - next_month: - (date) the first day of the next month, or None if the next month is in the future - previous_month: - (date) the first day of the previous month - object_list: - list of objects published in the given month - """ - if extra_context is None: extra_context = {} - try: - tt = time.strptime("%s-%s" % (year, month), '%s-%s' % ('%Y', month_format)) - date = datetime.date(*tt[:3]) - except ValueError: - raise Http404 - - model = queryset.model - now = timezone.now() - - # Calculate first and last day of month, for use in a date-range lookup. - first_day = date.replace(day=1) - if first_day.month == 12: - last_day = first_day.replace(year=first_day.year + 1, month=1) - else: - last_day = first_day.replace(month=first_day.month + 1) - lookup_kwargs = { - '%s__gte' % date_field: first_day, - '%s__lt' % date_field: last_day, - } - - # Only bother to check current date if the month isn't in the past and future objects are requested. - if last_day >= now.date() and not allow_future: - lookup_kwargs['%s__lte' % date_field] = now - object_list = queryset.filter(**lookup_kwargs) - date_list = object_list.dates(date_field, 'day') - if not object_list and not allow_empty: - raise Http404 - - # Calculate the next month, if applicable. - if allow_future: - next_month = last_day - elif last_day <= datetime.date.today(): - next_month = last_day - else: - next_month = None - - # Calculate the previous month - if first_day.month == 1: - previous_month = first_day.replace(year=first_day.year-1,month=12) - else: - previous_month = first_day.replace(month=first_day.month-1) - - if not template_name: - template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - 'date_list': date_list, - '%s_list' % template_object_name: object_list, - 'month': date, - 'next_month': next_month, - 'previous_month': previous_month, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - return HttpResponse(t.render(c), mimetype=mimetype) - -def archive_week(request, year, week, queryset, date_field, - template_name=None, template_loader=loader, - extra_context=None, allow_empty=True, context_processors=None, - template_object_name='object', mimetype=None, allow_future=False): - """ - Generic weekly archive view. - - Templates: ``/_archive_week.html`` - Context: - week: - (date) this week - object_list: - list of objects published in the given week - """ - if extra_context is None: extra_context = {} - try: - tt = time.strptime(year+'-0-'+week, '%Y-%w-%U') - date = datetime.date(*tt[:3]) - except ValueError: - raise Http404 - - model = queryset.model - now = timezone.now() - - # Calculate first and last day of week, for use in a date-range lookup. - first_day = date - last_day = date + datetime.timedelta(days=7) - lookup_kwargs = { - '%s__gte' % date_field: first_day, - '%s__lt' % date_field: last_day, - } - - # Only bother to check current date if the week isn't in the past and future objects aren't requested. - if last_day >= now.date() and not allow_future: - lookup_kwargs['%s__lte' % date_field] = now - object_list = queryset.filter(**lookup_kwargs) - if not object_list and not allow_empty: - raise Http404 - if not template_name: - template_name = "%s/%s_archive_week.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - '%s_list' % template_object_name: object_list, - 'week': date, - }) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - return HttpResponse(t.render(c), mimetype=mimetype) - -def archive_day(request, year, month, day, queryset, date_field, - month_format='%b', day_format='%d', template_name=None, - template_loader=loader, extra_context=None, allow_empty=False, - context_processors=None, template_object_name='object', - mimetype=None, allow_future=False): - """ - Generic daily archive view. - - Templates: ``/_archive_day.html`` - Context: - object_list: - list of objects published that day - day: - (datetime) the day - previous_day - (datetime) the previous day - next_day - (datetime) the next day, or None if the current day is today - """ - if extra_context is None: extra_context = {} - try: - tt = time.strptime('%s-%s-%s' % (year, month, day), - '%s-%s-%s' % ('%Y', month_format, day_format)) - date = datetime.date(*tt[:3]) - except ValueError: - raise Http404 - - model = queryset.model - now = timezone.now() - - if isinstance(model._meta.get_field(date_field), DateTimeField): - lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))} - else: - lookup_kwargs = {date_field: date} - - # Only bother to check current date if the date isn't in the past and future objects aren't requested. - if date >= now.date() and not allow_future: - lookup_kwargs['%s__lte' % date_field] = now - object_list = queryset.filter(**lookup_kwargs) - if not allow_empty and not object_list: - raise Http404 - - # Calculate the next day, if applicable. - if allow_future: - next_day = date + datetime.timedelta(days=1) - elif date < datetime.date.today(): - next_day = date + datetime.timedelta(days=1) - else: - next_day = None - - if not template_name: - template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - c = RequestContext(request, { - '%s_list' % template_object_name: object_list, - 'day': date, - 'previous_day': date - datetime.timedelta(days=1), - 'next_day': next_day, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - return HttpResponse(t.render(c), mimetype=mimetype) - -def archive_today(request, **kwargs): - """ - Generic daily archive view for today. Same as archive_day view. - """ - today = datetime.date.today() - kwargs.update({ - 'year': str(today.year), - 'month': today.strftime('%b').lower(), - 'day': str(today.day), - }) - return archive_day(request, **kwargs) - -def object_detail(request, year, month, day, queryset, date_field, - month_format='%b', day_format='%d', object_id=None, slug=None, - slug_field='slug', template_name=None, template_name_field=None, - template_loader=loader, extra_context=None, context_processors=None, - template_object_name='object', mimetype=None, allow_future=False): - """ - Generic detail view from year/month/day/slug or year/month/day/id structure. - - Templates: ``/_detail.html`` - Context: - object: - the object to be detailed - """ - if extra_context is None: extra_context = {} - try: - tt = time.strptime('%s-%s-%s' % (year, month, day), - '%s-%s-%s' % ('%Y', month_format, day_format)) - date = datetime.date(*tt[:3]) - except ValueError: - raise Http404 - - model = queryset.model - now = timezone.now() - - if isinstance(model._meta.get_field(date_field), DateTimeField): - lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))} - else: - lookup_kwargs = {date_field: date} - - # Only bother to check current date if the date isn't in the past and future objects aren't requested. - if date >= now.date() and not allow_future: - lookup_kwargs['%s__lte' % date_field] = now - if object_id: - lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id - elif slug and slug_field: - lookup_kwargs['%s__exact' % slug_field] = slug - else: - raise AttributeError("Generic detail view must be called with either an object_id or a slug/slugfield") - try: - obj = queryset.get(**lookup_kwargs) - except ObjectDoesNotExist: - raise Http404("No %s found for" % model._meta.verbose_name) - if not template_name: - template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower()) - if template_name_field: - template_name_list = [getattr(obj, template_name_field), template_name] - t = template_loader.select_template(template_name_list) - else: - t = template_loader.get_template(template_name) - c = RequestContext(request, { - template_object_name: obj, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - response = HttpResponse(t.render(c), mimetype=mimetype) - populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name)) - return response diff --git a/mayan/apps/common/backport/generic/dates.py b/mayan/apps/common/backport/generic/dates.py deleted file mode 100644 index 42036c427f..0000000000 --- a/mayan/apps/common/backport/generic/dates.py +++ /dev/null @@ -1,607 +0,0 @@ -import datetime -from django.db import models -from django.core.exceptions import ImproperlyConfigured -from django.http import Http404 -from django.utils.encoding import force_unicode -from django.utils.translation import ugettext as _ -from django.utils import timezone -from .base import View -from .detail import BaseDetailView, SingleObjectTemplateResponseMixin -from .list import MultipleObjectMixin, MultipleObjectTemplateResponseMixin - -class YearMixin(object): - year_format = '%Y' - year = None - - def get_year_format(self): - """ - Get a year format string in strptime syntax to be used to parse the - year from url variables. - """ - return self.year_format - - def get_year(self): - "Return the year for which this view should display data" - year = self.year - if year is None: - try: - year = self.kwargs['year'] - except KeyError: - try: - year = self.request.GET['year'] - except KeyError: - raise Http404(_(u"No year specified")) - return year - - -class MonthMixin(object): - month_format = '%b' - month = None - - def get_month_format(self): - """ - Get a month format string in strptime syntax to be used to parse the - month from url variables. - """ - return self.month_format - - def get_month(self): - "Return the month for which this view should display data" - month = self.month - if month is None: - try: - month = self.kwargs['month'] - except KeyError: - try: - month = self.request.GET['month'] - except KeyError: - raise Http404(_(u"No month specified")) - return month - - def get_next_month(self, date): - """ - Get the next valid month. - """ - first_day, last_day = _month_bounds(date) - next = (last_day + datetime.timedelta(days=1)).replace(day=1) - return _get_next_prev_month(self, next, is_previous=False, use_first_day=True) - - def get_previous_month(self, date): - """ - Get the previous valid month. - """ - first_day, last_day = _month_bounds(date) - prev = (first_day - datetime.timedelta(days=1)) - return _get_next_prev_month(self, prev, is_previous=True, use_first_day=True) - - -class DayMixin(object): - day_format = '%d' - day = None - - def get_day_format(self): - """ - Get a day format string in strptime syntax to be used to parse the day - from url variables. - """ - return self.day_format - - def get_day(self): - "Return the day for which this view should display data" - day = self.day - if day is None: - try: - day = self.kwargs['day'] - except KeyError: - try: - day = self.request.GET['day'] - except KeyError: - raise Http404(_(u"No day specified")) - return day - - def get_next_day(self, date): - """ - Get the next valid day. - """ - next = date + datetime.timedelta(days=1) - return _get_next_prev_month(self, next, is_previous=False, use_first_day=False) - - def get_previous_day(self, date): - """ - Get the previous valid day. - """ - prev = date - datetime.timedelta(days=1) - return _get_next_prev_month(self, prev, is_previous=True, use_first_day=False) - - -class WeekMixin(object): - week_format = '%U' - week = None - - def get_week_format(self): - """ - Get a week format string in strptime syntax to be used to parse the - week from url variables. - """ - return self.week_format - - def get_week(self): - "Return the week for which this view should display data" - week = self.week - if week is None: - try: - week = self.kwargs['week'] - except KeyError: - try: - week = self.request.GET['week'] - except KeyError: - raise Http404(_(u"No week specified")) - return week - - -class DateMixin(object): - """ - Mixin class for views manipulating date-based data. - """ - date_field = None - allow_future = False - - def get_date_field(self): - """ - Get the name of the date field to be used to filter by. - """ - if self.date_field is None: - raise ImproperlyConfigured(u"%s.date_field is required." % self.__class__.__name__) - return self.date_field - - def get_allow_future(self): - """ - Returns `True` if the view should be allowed to display objects from - the future. - """ - return self.allow_future - - -class BaseDateListView(MultipleObjectMixin, DateMixin, View): - """ - Abstract base class for date-based views display a list of objects. - """ - allow_empty = False - - def get(self, request, *args, **kwargs): - self.date_list, self.object_list, extra_context = self.get_dated_items() - context = self.get_context_data(object_list=self.object_list, - date_list=self.date_list) - context.update(extra_context) - return self.render_to_response(context) - - def get_dated_items(self): - """ - Obtain the list of dates and itesm - """ - raise NotImplementedError('A DateView must provide an implementation of get_dated_items()') - - def get_dated_queryset(self, **lookup): - """ - Get a queryset properly filtered according to `allow_future` and any - extra lookup kwargs. - """ - qs = self.get_queryset().filter(**lookup) - date_field = self.get_date_field() - allow_future = self.get_allow_future() - allow_empty = self.get_allow_empty() - - if not allow_future: - qs = qs.filter(**{'%s__lte' % date_field: timezone.now()}) - - if not allow_empty and not qs: - raise Http404(_(u"No %(verbose_name_plural)s available") % { - 'verbose_name_plural': force_unicode(qs.model._meta.verbose_name_plural) - }) - - return qs - - def get_date_list(self, queryset, date_type): - """ - Get a date list by calling `queryset.dates()`, checking along the way - for empty lists that aren't allowed. - """ - date_field = self.get_date_field() - allow_empty = self.get_allow_empty() - - date_list = queryset.dates(date_field, date_type)[::-1] - if date_list is not None and not date_list and not allow_empty: - name = force_unicode(queryset.model._meta.verbose_name_plural) - raise Http404(_(u"No %(verbose_name_plural)s available") % - {'verbose_name_plural': name}) - - return date_list - - def get_context_data(self, **kwargs): - """ - Get the context. Must return a Context (or subclass) instance. - """ - items = kwargs.pop('object_list') - context = super(BaseDateListView, self).get_context_data(object_list=items) - context.update(kwargs) - return context - - -class BaseArchiveIndexView(BaseDateListView): - """ - Base class for archives of date-based items. - - Requires a response mixin. - """ - context_object_name = 'latest' - - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - qs = self.get_dated_queryset() - date_list = self.get_date_list(qs, 'year') - - if date_list: - object_list = qs.order_by('-' + self.get_date_field()) - else: - object_list = qs.none() - - return (date_list, object_list, {}) - - -class ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView): - """ - Top-level archive of date-based items. - """ - template_name_suffix = '_archive' - - -class BaseYearArchiveView(YearMixin, BaseDateListView): - """ - List of objects published in a given year. - """ - make_object_list = False - - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - # Yes, no error checking: the URLpattern ought to validate this; it's - # an error if it doesn't. - year = self.get_year() - date_field = self.get_date_field() - qs = self.get_dated_queryset(**{date_field+'__year': year}) - date_list = self.get_date_list(qs, 'month') - - if self.get_make_object_list(): - object_list = qs.order_by('-'+date_field) - else: - # We need this to be a queryset since parent classes introspect it - # to find information about the model. - object_list = qs.none() - - return (date_list, object_list, {'year': year}) - - def get_make_object_list(self): - """ - Return `True` if this view should contain the full list of objects in - the given year. - """ - return self.make_object_list - - -class YearArchiveView(MultipleObjectTemplateResponseMixin, BaseYearArchiveView): - """ - List of objects published in a given year. - """ - template_name_suffix = '_archive_year' - - -class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView): - """ - List of objects published in a given year. - """ - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - year = self.get_year() - month = self.get_month() - - date_field = self.get_date_field() - date = _date_from_string(year, self.get_year_format(), - month, self.get_month_format()) - - # Construct a date-range lookup. - first_day, last_day = _month_bounds(date) - lookup_kwargs = { - '%s__gte' % date_field: first_day, - '%s__lt' % date_field: last_day, - } - - qs = self.get_dated_queryset(**lookup_kwargs) - date_list = self.get_date_list(qs, 'day') - - return (date_list, qs, { - 'month': date, - 'next_month': self.get_next_month(date), - 'previous_month': self.get_previous_month(date), - }) - - -class MonthArchiveView(MultipleObjectTemplateResponseMixin, BaseMonthArchiveView): - """ - List of objects published in a given year. - """ - template_name_suffix = '_archive_month' - - -class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView): - """ - List of objects published in a given week. - """ - - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - year = self.get_year() - week = self.get_week() - - date_field = self.get_date_field() - week_format = self.get_week_format() - week_start = { - '%W': '1', - '%U': '0', - }[week_format] - date = _date_from_string(year, self.get_year_format(), - week_start, '%w', - week, week_format) - - # Construct a date-range lookup. - first_day = date - last_day = date + datetime.timedelta(days=7) - lookup_kwargs = { - '%s__gte' % date_field: first_day, - '%s__lt' % date_field: last_day, - } - - qs = self.get_dated_queryset(**lookup_kwargs) - - return (None, qs, {'week': date}) - - -class WeekArchiveView(MultipleObjectTemplateResponseMixin, BaseWeekArchiveView): - """ - List of objects published in a given week. - """ - template_name_suffix = '_archive_week' - - -class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView): - """ - List of objects published on a given day. - """ - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - year = self.get_year() - month = self.get_month() - day = self.get_day() - - date = _date_from_string(year, self.get_year_format(), - month, self.get_month_format(), - day, self.get_day_format()) - - return self._get_dated_items(date) - - def _get_dated_items(self, date): - """ - Do the actual heavy lifting of getting the dated items; this accepts a - date object so that TodayArchiveView can be trivial. - """ - date_field = self.get_date_field() - - field = self.get_queryset().model._meta.get_field(date_field) - lookup_kwargs = _date_lookup_for_field(field, date) - - qs = self.get_dated_queryset(**lookup_kwargs) - - return (None, qs, { - 'day': date, - 'previous_day': self.get_previous_day(date), - 'next_day': self.get_next_day(date), - 'previous_month': self.get_previous_month(date), - 'next_month': self.get_next_month(date) - }) - - -class DayArchiveView(MultipleObjectTemplateResponseMixin, BaseDayArchiveView): - """ - List of objects published on a given day. - """ - template_name_suffix = "_archive_day" - - -class BaseTodayArchiveView(BaseDayArchiveView): - """ - List of objects published today. - """ - - def get_dated_items(self): - """ - Return (date_list, items, extra_context) for this request. - """ - return self._get_dated_items(datetime.date.today()) - - -class TodayArchiveView(MultipleObjectTemplateResponseMixin, BaseTodayArchiveView): - """ - List of objects published today. - """ - template_name_suffix = "_archive_day" - - -class BaseDateDetailView(YearMixin, MonthMixin, DayMixin, DateMixin, BaseDetailView): - """ - Detail view of a single object on a single date; this differs from the - standard DetailView by accepting a year/month/day in the URL. - """ - def get_object(self, queryset=None): - """ - Get the object this request displays. - """ - year = self.get_year() - month = self.get_month() - day = self.get_day() - date = _date_from_string(year, self.get_year_format(), - month, self.get_month_format(), - day, self.get_day_format()) - - # Use a custom queryset if provided - qs = queryset or self.get_queryset() - - if not self.get_allow_future() and date > datetime.date.today(): - raise Http404(_(u"Future %(verbose_name_plural)s not available because %(class_name)s.allow_future is False.") % { - 'verbose_name_plural': qs.model._meta.verbose_name_plural, - 'class_name': self.__class__.__name__, - }) - - # Filter down a queryset from self.queryset using the date from the - # URL. This'll get passed as the queryset to DetailView.get_object, - # which'll handle the 404 - date_field = self.get_date_field() - field = qs.model._meta.get_field(date_field) - lookup = _date_lookup_for_field(field, date) - qs = qs.filter(**lookup) - - return super(BaseDetailView, self).get_object(queryset=qs) - - -class DateDetailView(SingleObjectTemplateResponseMixin, BaseDateDetailView): - """ - Detail view of a single object on a single date; this differs from the - standard DetailView by accepting a year/month/day in the URL. - """ - template_name_suffix = '_detail' - - -def _date_from_string(year, year_format, month, month_format, day='', day_format='', delim='__'): - """ - Helper: get a datetime.date object given a format string and a year, - month, and possibly day; raise a 404 for an invalid date. - """ - format = delim.join((year_format, month_format, day_format)) - datestr = delim.join((year, month, day)) - try: - return datetime.datetime.strptime(datestr, format).date() - except ValueError: - raise Http404(_(u"Invalid date string '%(datestr)s' given format '%(format)s'") % { - 'datestr': datestr, - 'format': format, - }) - - -def _month_bounds(date): - """ - Helper: return the first and last days of the month for the given date. - """ - first_day = date.replace(day=1) - if first_day.month == 12: - last_day = first_day.replace(year=first_day.year + 1, month=1) - else: - last_day = first_day.replace(month=first_day.month + 1) - - return first_day, last_day - - -def _get_next_prev_month(generic_view, naive_result, is_previous, use_first_day): - """ - Helper: Get the next or the previous valid date. The idea is to allow - links on month/day views to never be 404s by never providing a date - that'll be invalid for the given view. - - This is a bit complicated since it handles both next and previous months - and days (for MonthArchiveView and DayArchiveView); hence the coupling to generic_view. - - However in essence the logic comes down to: - - * If allow_empty and allow_future are both true, this is easy: just - return the naive result (just the next/previous day or month, - reguardless of object existence.) - - * If allow_empty is true, allow_future is false, and the naive month - isn't in the future, then return it; otherwise return None. - - * If allow_empty is false and allow_future is true, return the next - date *that contains a valid object*, even if it's in the future. If - there are no next objects, return None. - - * If allow_empty is false and allow_future is false, return the next - date that contains a valid object. If that date is in the future, or - if there are no next objects, return None. - - """ - date_field = generic_view.get_date_field() - allow_empty = generic_view.get_allow_empty() - allow_future = generic_view.get_allow_future() - - # If allow_empty is True the naive value will be valid - if allow_empty: - result = naive_result - - # Otherwise, we'll need to go to the database to look for an object - # whose date_field is at least (greater than/less than) the given - # naive result - else: - # Construct a lookup and an ordering depending on whether we're doing - # a previous date or a next date lookup. - if is_previous: - lookup = {'%s__lte' % date_field: naive_result} - ordering = '-%s' % date_field - else: - lookup = {'%s__gte' % date_field: naive_result} - ordering = date_field - - qs = generic_view.get_queryset().filter(**lookup).order_by(ordering) - - # Snag the first object from the queryset; if it doesn't exist that - # means there's no next/previous link available. - try: - result = getattr(qs[0], date_field) - except IndexError: - result = None - - # Convert datetimes to a dates - if hasattr(result, 'date'): - result = result.date() - - # For month views, we always want to have a date that's the first of the - # month for consistency's sake. - if result and use_first_day: - result = result.replace(day=1) - - # Check against future dates. - if result and (allow_future or result < datetime.date.today()): - return result - else: - return None - - -def _date_lookup_for_field(field, date): - """ - Get the lookup kwargs for looking up a date against a given Field. If the - date field is a DateTimeField, we can't just do filter(df=date) because - that doesn't take the time into account. So we need to make a range lookup - in those cases. - """ - if isinstance(field, models.DateTimeField): - date_range = ( - datetime.datetime.combine(date, datetime.time.min), - datetime.datetime.combine(date, datetime.time.max) - ) - return {'%s__range' % field.name: date_range} - else: - return {field.name: date} diff --git a/mayan/apps/common/backport/generic/detail.py b/mayan/apps/common/backport/generic/detail.py deleted file mode 100644 index c9aa588fb9..0000000000 --- a/mayan/apps/common/backport/generic/detail.py +++ /dev/null @@ -1,150 +0,0 @@ -from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist -from django.http import Http404 -from django.utils.encoding import smart_str -from django.utils.translation import ugettext as _ -from .base import TemplateResponseMixin, View - - -class SingleObjectMixin(object): - """ - Provides the ability to retrieve a single object for further manipulation. - """ - model = None - queryset = None - slug_field = 'slug' - context_object_name = None - slug_url_kwarg = 'slug' - pk_url_kwarg = 'pk' - - def get_object(self, queryset=None): - """ - Returns the object the view is displaying. - - By default this requires `self.queryset` and a `pk` or `slug` argument - in the URLconf, but subclasses can override this to return any object. - """ - # Use a custom queryset if provided; this is required for subclasses - # like DateDetailView - if queryset is None: - queryset = self.get_queryset() - - # Next, try looking up by primary key. - pk = self.kwargs.get(self.pk_url_kwarg, None) - slug = self.kwargs.get(self.slug_url_kwarg, None) - if pk is not None: - queryset = queryset.filter(pk=pk) - - # Next, try looking up by slug. - elif slug is not None: - slug_field = self.get_slug_field() - queryset = queryset.filter(**{slug_field: slug}) - - # If none of those are defined, it's an error. - else: - raise AttributeError(u"Generic detail view %s must be called with " - u"either an object pk or a slug." - % self.__class__.__name__) - - try: - obj = queryset.get() - except ObjectDoesNotExist: - raise Http404(_(u"No %(verbose_name)s found matching the query") % - {'verbose_name': queryset.model._meta.verbose_name}) - return obj - - def get_queryset(self): - """ - Get the queryset to look an object up against. May not be called if - `get_object` is overridden. - """ - if self.queryset is None: - if self.model: - return self.model._default_manager.all() - else: - raise ImproperlyConfigured(u"%(cls)s is missing a queryset. Define " - u"%(cls)s.model, %(cls)s.queryset, or override " - u"%(cls)s.get_object()." % { - 'cls': self.__class__.__name__ - }) - return self.queryset._clone() - - def get_slug_field(self): - """ - Get the name of a slug field to be used to look up by slug. - """ - return self.slug_field - - def get_context_object_name(self, obj): - """ - Get the name to use for the object. - """ - if self.context_object_name: - return self.context_object_name - elif hasattr(obj, '_meta'): - return smart_str(obj._meta.object_name.lower()) - else: - return None - - def get_context_data(self, **kwargs): - context = kwargs - context_object_name = self.get_context_object_name(self.object) - if context_object_name: - context[context_object_name] = self.object - return context - - -class BaseDetailView(SingleObjectMixin, View): - def get(self, request, *args, **kwargs): - self.object = self.get_object() - context = self.get_context_data(object=self.object) - return self.render_to_response(context) - - -class SingleObjectTemplateResponseMixin(TemplateResponseMixin): - template_name_field = None - template_name_suffix = '_detail' - - def get_template_names(self): - """ - Return a list of template names to be used for the request. Must return - a list. May not be called if get_template is overridden. - """ - try: - names = super(SingleObjectTemplateResponseMixin, self).get_template_names() - except ImproperlyConfigured: - # If template_name isn't specified, it's not a problem -- - # we just start with an empty list. - names = [] - - # If self.template_name_field is set, grab the value of the field - # of that name from the object; this is the most specific template - # name, if given. - if self.object and self.template_name_field: - name = getattr(self.object, self.template_name_field, None) - if name: - names.insert(0, name) - - # The least-specific option is the default /_detail.html; - # only use this if the object in question is a model. - if hasattr(self.object, '_meta'): - names.append("%s/%s%s.html" % ( - self.object._meta.app_label, - self.object._meta.object_name.lower(), - self.template_name_suffix - )) - elif hasattr(self, 'model') and hasattr(self.model, '_meta'): - names.append("%s/%s%s.html" % ( - self.model._meta.app_label, - self.model._meta.object_name.lower(), - self.template_name_suffix - )) - return names - - -class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView): - """ - Render a "detail" view of an object. - - By default this is a model instance looked up from `self.queryset`, but the - view will support display of *any* object by overriding `self.get_object()`. - """ diff --git a/mayan/apps/common/backport/generic/edit.py b/mayan/apps/common/backport/generic/edit.py deleted file mode 100644 index e1be9a88ac..0000000000 --- a/mayan/apps/common/backport/generic/edit.py +++ /dev/null @@ -1,242 +0,0 @@ -from django.forms import models as model_forms -from django.core.exceptions import ImproperlyConfigured -from django.http import HttpResponseRedirect -from .base import TemplateResponseMixin, View -from .detail import (SingleObjectMixin, - SingleObjectTemplateResponseMixin, BaseDetailView) - - -class FormMixin(object): - """ - A mixin that provides a way to show and handle a form in a request. - """ - - initial = {} - form_class = None - success_url = None - - def get_initial(self): - """ - Returns the initial data to use for forms on this view. - """ - return self.initial.copy() - - def get_form_class(self): - """ - Returns the form class to use in this view - """ - return self.form_class - - def get_form(self, form_class): - """ - Returns an instance of the form to be used in this view. - """ - return form_class(**self.get_form_kwargs()) - - def get_form_kwargs(self): - """ - Returns the keyword arguments for instanciating the form. - """ - kwargs = {'initial': self.get_initial()} - if self.request.method in ('POST', 'PUT'): - kwargs.update({ - 'data': self.request.POST, - 'files': self.request.FILES, - }) - return kwargs - - def get_context_data(self, **kwargs): - return kwargs - - def get_success_url(self): - 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, form): - return HttpResponseRedirect(self.get_success_url()) - - def form_invalid(self, form): - return self.render_to_response(self.get_context_data(form=form)) - - -class ModelFormMixin(FormMixin, SingleObjectMixin): - """ - A mixin that provides a way to show and handle a modelform in a request. - """ - - def get_form_class(self): - """ - Returns the form class to use in this view - """ - if self.form_class: - return self.form_class - else: - if self.model is not None: - # If a model has been explicitly provided, use it - model = self.model - elif hasattr(self, 'object') and self.object is not None: - # If this view is operating on a single object, use - # the class of that object - model = self.object.__class__ - else: - # Try to get a queryset and extract the model class - # from that - model = self.get_queryset().model - return model_forms.modelform_factory(model) - - def get_form_kwargs(self): - """ - Returns the keyword arguments for instanciating the form. - """ - kwargs = super(ModelFormMixin, self).get_form_kwargs() - kwargs.update({'instance': self.object}) - return kwargs - - def get_success_url(self): - 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 - - def form_valid(self, form): - self.object = form.save() - return super(ModelFormMixin, self).form_valid(form) - - def get_context_data(self, **kwargs): - context = kwargs - 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 - return context - - -class ProcessFormView(View): - """ - A mixin that processes a form on POST. - """ - def get(self, request, *args, **kwargs): - form_class = self.get_form_class() - form = self.get_form(form_class) - return self.render_to_response(self.get_context_data(form=form)) - - def post(self, request, *args, **kwargs): - form_class = self.get_form_class() - form = self.get_form(form_class) - if form.is_valid(): - return self.form_valid(form) - else: - return self.form_invalid(form) - - # 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) - - -class BaseFormView(FormMixin, ProcessFormView): - """ - A base view for displaying a form - """ - - -class FormView(TemplateResponseMixin, BaseFormView): - """ - A view for displaying a form, and rendering a template response. - """ - - -class BaseCreateView(ModelFormMixin, ProcessFormView): - """ - Base view for creating an new object instance. - - Using this base class requires subclassing to provide a response mixin. - """ - def get(self, request, *args, **kwargs): - self.object = None - return super(BaseCreateView, self).get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - self.object = None - return super(BaseCreateView, self).post(request, *args, **kwargs) - - -class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView): - """ - View for creating an new object instance, - with a response rendered by template. - """ - template_name_suffix = '_form' - - -class BaseUpdateView(ModelFormMixin, ProcessFormView): - """ - 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(BaseUpdateView, self).get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - self.object = self.get_object() - return super(BaseUpdateView, self).post(request, *args, **kwargs) - - -class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView): - """ - View for updating an object, - with a response rendered by template.. - """ - template_name_suffix = '_form' - - -class DeletionMixin(object): - """ - A mixin providing the ability to delete objects - """ - success_url = None - - def delete(self, request, *args, **kwargs): - self.object = self.get_object() - self.object.delete() - return HttpResponseRedirect(self.get_success_url()) - - # Add support for browsers which only accept GET and POST for now. - def post(self, *args, **kwargs): - return self.delete(*args, **kwargs) - - def get_success_url(self): - if self.success_url: - return self.success_url - else: - raise ImproperlyConfigured( - "No URL to redirect to. Provide a success_url.") - - -class BaseDeleteView(DeletionMixin, BaseDetailView): - """ - Base view for deleting an object. - - Using this base class requires subclassing to provide a response mixin. - """ - - -class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView): - """ - View for deleting an object retrieved with `self.get_object()`, - with a response rendered by template. - """ - template_name_suffix = '_confirm_delete' diff --git a/mayan/apps/common/backport/generic/list.py b/mayan/apps/common/backport/generic/list.py deleted file mode 100644 index 9731e6a909..0000000000 --- a/mayan/apps/common/backport/generic/list.py +++ /dev/null @@ -1,153 +0,0 @@ -from django.core.paginator import Paginator, InvalidPage -from django.core.exceptions import ImproperlyConfigured -from django.http import Http404 -from django.utils.encoding import smart_str -from django.utils.translation import ugettext as _ -from .base import TemplateResponseMixin, View - - -class MultipleObjectMixin(object): - allow_empty = True - queryset = None - model = None - paginate_by = None - context_object_name = None - paginator_class = Paginator - - def get_queryset(self): - """ - Get the list of items for this view. This must be an interable, and may - be a queryset (in which qs-specific behavior will be enabled). - """ - if self.queryset is not None: - queryset = self.queryset - if hasattr(queryset, '_clone'): - queryset = queryset._clone() - elif self.model is not None: - queryset = self.model._default_manager.all() - else: - raise ImproperlyConfigured(u"'%s' must define 'queryset' or 'model'" - % self.__class__.__name__) - return queryset - - def paginate_queryset(self, queryset, page_size): - """ - Paginate the queryset, if needed. - """ - paginator = self.get_paginator(queryset, page_size, allow_empty_first_page=self.get_allow_empty()) - page = self.kwargs.get('page') or self.request.GET.get('page') or 1 - try: - page_number = int(page) - except ValueError: - if page == 'last': - page_number = paginator.num_pages - else: - raise Http404(_(u"Page is not 'last', nor can it be converted to an int.")) - try: - page = paginator.page(page_number) - return (paginator, page, page.object_list, page.has_other_pages()) - except InvalidPage: - raise Http404(_(u'Invalid page (%(page_number)s)') % { - 'page_number': page_number - }) - - def get_paginate_by(self, queryset): - """ - Get the number of items to paginate by, or ``None`` for no pagination. - """ - return self.paginate_by - - def get_paginator(self, queryset, per_page, orphans=0, allow_empty_first_page=True): - """ - Return an instance of the paginator for this view. - """ - return self.paginator_class(queryset, per_page, orphans=orphans, allow_empty_first_page=allow_empty_first_page) - - def get_allow_empty(self): - """ - Returns ``True`` if the view should display empty lists, and ``False`` - if a 404 should be raised instead. - """ - return self.allow_empty - - def get_context_object_name(self, object_list): - """ - Get the name of the item to be used in the context. - """ - if self.context_object_name: - return self.context_object_name - elif hasattr(object_list, 'model'): - return smart_str('%s_list' % object_list.model._meta.object_name.lower()) - else: - return None - - def get_context_data(self, **kwargs): - """ - Get the context for this view. - """ - queryset = kwargs.pop('object_list') - page_size = self.get_paginate_by(queryset) - context_object_name = self.get_context_object_name(queryset) - if page_size: - paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size) - context = { - 'paginator': paginator, - 'page_obj': page, - 'is_paginated': is_paginated, - 'object_list': queryset - } - else: - context = { - 'paginator': None, - 'page_obj': None, - 'is_paginated': False, - 'object_list': queryset - } - context.update(kwargs) - if context_object_name is not None: - context[context_object_name] = queryset - return context - - -class BaseListView(MultipleObjectMixin, View): - def get(self, request, *args, **kwargs): - self.object_list = self.get_queryset() - allow_empty = self.get_allow_empty() - if not allow_empty and len(self.object_list) == 0: - raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.") - % {'class_name': self.__class__.__name__}) - context = self.get_context_data(object_list=self.object_list) - return self.render_to_response(context) - - -class MultipleObjectTemplateResponseMixin(TemplateResponseMixin): - template_name_suffix = '_list' - - def get_template_names(self): - """ - Return a list of template names to be used for the request. Must return - a list. May not be called if get_template is overridden. - """ - try: - names = super(MultipleObjectTemplateResponseMixin, self).get_template_names() - except ImproperlyConfigured: - # If template_name isn't specified, it's not a problem -- - # we just start with an empty list. - names = [] - - # If the list is a queryset, we'll invent a template name based on the - # app and model name. This name gets put at the end of the template - # name list so that user-supplied names override the automatically- - # generated ones. - if hasattr(self.object_list, 'model'): - opts = self.object_list.model._meta - names.append("%s/%s%s.html" % (opts.app_label, opts.object_name.lower(), self.template_name_suffix)) - - return names - - -class ListView(MultipleObjectTemplateResponseMixin, BaseListView): - """ - Render some list of objects, set by `self.model` or `self.queryset`. - `self.queryset` can actually be any iterable of items, not just a queryset. - """ diff --git a/mayan/apps/common/backport/generic/list_detail.py b/mayan/apps/common/backport/generic/list_detail.py deleted file mode 100644 index 22414ae216..0000000000 --- a/mayan/apps/common/backport/generic/list_detail.py +++ /dev/null @@ -1,152 +0,0 @@ -from django.template import loader, RequestContext -from django.http import Http404, HttpResponse -from django.core.xheaders import populate_xheaders -from django.core.paginator import Paginator, InvalidPage -from django.core.exceptions import ObjectDoesNotExist - -import warnings -warnings.warn( - 'Function-based generic views have been deprecated; use class-based views instead.', - DeprecationWarning -) - - -def object_list(request, queryset, paginate_by=None, page=None, - allow_empty=True, template_name=None, template_loader=loader, - extra_context=None, context_processors=None, template_object_name='object', - mimetype=None): - """ - Generic list of objects. - - Templates: ``/_list.html`` - Context: - object_list - list of objects - is_paginated - are the results paginated? - results_per_page - number of objects per page (if paginated) - has_next - is there a next page? - has_previous - is there a prev page? - page - the current page - next - the next page - previous - the previous page - pages - number of pages, total - hits - number of objects, total - last_on_page - the result number of the last of object in the - object_list (1-indexed) - first_on_page - the result number of the first object in the - object_list (1-indexed) - page_range: - A list of the page numbers (1-indexed). - """ - if extra_context is None: extra_context = {} - queryset = queryset._clone() - if paginate_by: - paginator = Paginator(queryset, paginate_by, allow_empty_first_page=allow_empty) - if not page: - page = request.GET.get('page', 1) - try: - page_number = int(page) - except ValueError: - if page == 'last': - page_number = paginator.num_pages - else: - # Page is not 'last', nor can it be converted to an int. - raise Http404 - try: - page_obj = paginator.page(page_number) - except InvalidPage: - raise Http404 - c = RequestContext(request, { - '%s_list' % template_object_name: page_obj.object_list, - 'paginator': paginator, - 'page_obj': page_obj, - 'is_paginated': page_obj.has_other_pages(), - - # Legacy template context stuff. New templates should use page_obj - # to access this instead. - 'results_per_page': paginator.per_page, - 'has_next': page_obj.has_next(), - 'has_previous': page_obj.has_previous(), - 'page': page_obj.number, - 'next': page_obj.next_page_number(), - 'previous': page_obj.previous_page_number(), - 'first_on_page': page_obj.start_index(), - 'last_on_page': page_obj.end_index(), - 'pages': paginator.num_pages, - 'hits': paginator.count, - 'page_range': paginator.page_range, - }, context_processors) - else: - c = RequestContext(request, { - '%s_list' % template_object_name: queryset, - 'paginator': None, - 'page_obj': None, - 'is_paginated': False, - }, context_processors) - if not allow_empty and len(queryset) == 0: - raise Http404 - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - if not template_name: - model = queryset.model - template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - return HttpResponse(t.render(c), mimetype=mimetype) - -def object_detail(request, queryset, object_id=None, slug=None, - slug_field='slug', template_name=None, template_name_field=None, - template_loader=loader, extra_context=None, - context_processors=None, template_object_name='object', - mimetype=None): - """ - Generic detail of an object. - - Templates: ``/_detail.html`` - Context: - object - the object - """ - if extra_context is None: extra_context = {} - model = queryset.model - if object_id: - queryset = queryset.filter(pk=object_id) - elif slug and slug_field: - queryset = queryset.filter(**{slug_field: slug}) - else: - raise AttributeError("Generic detail view must be called with either an object_id or a slug/slug_field.") - try: - obj = queryset.get() - except ObjectDoesNotExist: - raise Http404("No %s found matching the query" % (model._meta.verbose_name)) - if not template_name: - template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower()) - if template_name_field: - template_name_list = [getattr(obj, template_name_field), template_name] - t = template_loader.select_template(template_name_list) - else: - t = template_loader.get_template(template_name) - c = RequestContext(request, { - template_object_name: obj, - }, context_processors) - for key, value in extra_context.items(): - if callable(value): - c[key] = value() - else: - c[key] = value - response = HttpResponse(t.render(c), mimetype=mimetype) - populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name)) - return response diff --git a/mayan/apps/common/backport/generic/simple.py b/mayan/apps/common/backport/generic/simple.py deleted file mode 100644 index dd2f5277d5..0000000000 --- a/mayan/apps/common/backport/generic/simple.py +++ /dev/null @@ -1,68 +0,0 @@ -from django.template import loader, RequestContext -from django.http import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, HttpResponseGone -from django.utils.log import getLogger - -import warnings -warnings.warn( - 'Function-based generic views have been deprecated; use class-based views instead.', - DeprecationWarning -) - -logger = getLogger('django.request') - - -def direct_to_template(request, template, extra_context=None, mimetype=None, **kwargs): - """ - Render a given template with any extra URL parameters in the context as - ``{{ params }}``. - """ - if extra_context is None: extra_context = {} - dictionary = {'params': kwargs} - for key, value in extra_context.items(): - if callable(value): - dictionary[key] = value() - else: - dictionary[key] = value - c = RequestContext(request, dictionary) - t = loader.get_template(template) - return HttpResponse(t.render(c), content_type=mimetype) - -def redirect_to(request, url, permanent=True, query_string=False, **kwargs): - """ - Redirect to a given URL. - - The given url may contain dict-style string formatting, which will be - interpolated against the params in the URL. For example, to redirect from - ``/foo//`` to ``/bar//``, you could use the following URLconf:: - - urlpatterns = patterns('', - ('^foo/(?P\d+)/$', 'common.backport.generic.simple.redirect_to', {'url' : '/bar/%(id)s/'}), - ) - - If the given url is ``None``, a HttpResponseGone (410) will be issued. - - If the ``permanent`` argument is False, then the response will have a 302 - HTTP status code. Otherwise, the status code will be 301. - - If the ``query_string`` argument is True, then the GET query string - from the request is appended to the URL. - - """ - args = request.META.get('QUERY_STRING', '') - - if url is not None: - if kwargs: - url = url % kwargs - - if args and query_string: - url = "%s?%s" % (url, args) - - klass = permanent and HttpResponsePermanentRedirect or HttpResponseRedirect - return klass(url) - else: - logger.warning('Gone: %s', request.path, - extra={ - 'status_code': 410, - 'request': request - }) - return HttpResponseGone() diff --git a/mayan/apps/common/urls.py b/mayan/apps/common/urls.py index 0b385a6a30..46c7163d81 100644 --- a/mayan/apps/common/urls.py +++ b/mayan/apps/common/urls.py @@ -1,16 +1,16 @@ from django.conf import settings from django.conf.urls import patterns, url +from django.views.generic import RedirectView, TemplateView -from common.backport.generic.simple import direct_to_template urlpatterns = patterns('common.views', - url(r'^about/$', direct_to_template, {'template': 'about.html'}, 'about_view'), - url(r'^license/$', 'license_view', (), 'license_view'), + url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about_view'), + url(r'^license/$', 'license_view', (), name='license_view'), url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'), url(r'^object/multiple/action/$', 'multi_object_action_view', (), name='multi_object_action_view'), - url(r'^user/$', 'current_user_details', (), 'current_user_details'), - url(r'^user/edit/$', 'current_user_edit', (), 'current_user_edit'), + url(r'^user/$', 'current_user_details', (), name='current_user_details'), + url(r'^user/edit/$', 'current_user_edit', (), name='current_user_edit'), url(r'^login/$', 'login_view', (), name='login_view'), url(r'^password/change/$', 'password_change_view', (), name='password_change_view'), @@ -24,7 +24,7 @@ urlpatterns += patterns('', url(r'^password/reset/complete/$', 'django.contrib.auth.views.password_reset_complete', {'template_name': 'password_reset_complete.html'}, name='password_reset_complete_view'), url(r'^password/reset/done/$', 'django.contrib.auth.views.password_reset_done', {'template_name': 'password_reset_done.html'}, name='password_reset_done_view'), - (r'^favicon\.ico$', 'common.backport.generic.simple.redirect_to', {'url': '%s%s' % (settings.STATIC_URL, 'images/favicon.ico')}), + (r'^favicon\.ico$', RedirectView.as_view(url='%s%s' % (settings.STATIC_URL, 'images/favicon.ico'))), ) urlpatterns += patterns('',