mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-03-17 06:30:25 +00:00
251 lines
8.4 KiB
Python
251 lines
8.4 KiB
Python
from django.contrib.auth.forms import (PasswordChangeForm,
|
|
AdminPasswordChangeForm)
|
|
from django.contrib.auth.views import (logout as auth_logout,
|
|
login as auth_login)
|
|
from django.contrib.auth import get_user_model
|
|
from django.core.urlresolvers import reverse, reverse_lazy
|
|
from django.db import models
|
|
from django.http import HttpResponseRedirect
|
|
from django.utils.encoding import force_text
|
|
from django.utils.text import capfirst
|
|
from django.views import generic
|
|
|
|
import extra_views
|
|
|
|
import operator
|
|
|
|
from . import permissions, utils
|
|
from .forms import AdminAuthenticationForm
|
|
from .viewmixins import Admin2Mixin, AdminModel2Mixin, Admin2ModelFormMixin
|
|
|
|
|
|
class AdminView(object):
|
|
|
|
def __init__(self, url, view):
|
|
self.url = url
|
|
self.view = view
|
|
|
|
|
|
class IndexView(Admin2Mixin, generic.TemplateView):
|
|
default_template_name = "index.html"
|
|
registry = None
|
|
apps = None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
data = super(IndexView, self).get_context_data(**kwargs)
|
|
data.update({
|
|
'apps': self.apps,
|
|
})
|
|
return data
|
|
|
|
|
|
class AppIndexView(Admin2Mixin, generic.TemplateView):
|
|
default_template_name = "app_index.html"
|
|
registry = None
|
|
apps = None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
data = super(AppIndexView, self).get_context_data(**kwargs)
|
|
app_label = self.kwargs['app_label']
|
|
registry = self.apps[app_label]
|
|
|
|
data.update({
|
|
'app_label': app_label,
|
|
'registry': registry,
|
|
})
|
|
return data
|
|
|
|
|
|
class ModelListView(AdminModel2Mixin, generic.ListView):
|
|
default_template_name = "model_list.html"
|
|
permission_classes = (
|
|
permissions.IsStaffPermission,
|
|
permissions.ModelViewPermission)
|
|
|
|
def post(self, request):
|
|
action_name = request.POST['action']
|
|
action_callable = self.get_actions()[action_name]['action_callable']
|
|
selected_model_pks = request.POST.getlist('selected_model_pk')
|
|
queryset = self.model.objects.filter(pk__in=selected_model_pks)
|
|
|
|
# If action_callable is a class subclassing from actions.BaseListAction
|
|
# then we generate the callable object.
|
|
if hasattr(action_callable, "process_queryset"):
|
|
response = action_callable.as_view(queryset=queryset)(request)
|
|
else:
|
|
# generate the reponse if a function.
|
|
response = action_callable(request, queryset)
|
|
|
|
if response is None:
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
else:
|
|
return response
|
|
|
|
def get_search_results(self, queryset, search_term):
|
|
# Lifted from django.contrib.admin
|
|
def construct_search(field_name):
|
|
if field_name.startswith('^'):
|
|
return "%s__istartswith" % field_name[1:]
|
|
elif field_name.startswith('='):
|
|
return "%s__iexact" % field_name[1:]
|
|
elif field_name.startswith('@'):
|
|
return "%s__search" % field_name[1:]
|
|
else:
|
|
return "%s__icontains" % field_name
|
|
|
|
use_distinct = False
|
|
|
|
orm_lookups = [construct_search(str(search_field))
|
|
for search_field in self.model_admin.search_fields]
|
|
|
|
for bit in search_term.split():
|
|
or_queries = [models.Q(**{orm_lookup: bit})
|
|
for orm_lookup in orm_lookups]
|
|
queryset = queryset.filter(reduce(operator.or_, or_queries))
|
|
|
|
if not use_distinct:
|
|
for search_spec in orm_lookups:
|
|
opts = utils.model_options(self.get_model())
|
|
if utils.lookup_needs_distinct(opts, search_spec):
|
|
use_distinct = True
|
|
break
|
|
|
|
return queryset, use_distinct
|
|
|
|
def get_queryset(self):
|
|
queryset = super(ModelListView, self).get_queryset()
|
|
search_term = self.request.GET.get('q', None)
|
|
search_use_distinct = False
|
|
if self.model_admin.search_fields and search_term:
|
|
queryset, search_use_distinct = self.get_search_results(queryset, search_term)
|
|
|
|
if search_use_distinct:
|
|
return queryset.distinct()
|
|
else:
|
|
return queryset
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ModelListView, self).get_context_data(**kwargs)
|
|
context['model'] = self.get_model()
|
|
context['actions'] = self.get_actions().values()
|
|
context['search_fields'] = self.get_search_fields()
|
|
context['search_term'] = self.request.GET.get('q', '')
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
view_name = 'admin2:{}_{}_index'.format(self.app_label, self.model_name)
|
|
return reverse(view_name)
|
|
|
|
def get_actions(self):
|
|
return self.model_admin.get_list_actions()
|
|
|
|
def get_search_fields(self):
|
|
return self.model_admin.search_fields
|
|
|
|
|
|
class ModelDetailView(AdminModel2Mixin, generic.DetailView):
|
|
default_template_name = "model_detail.html"
|
|
permission_classes = (
|
|
permissions.IsStaffPermission,
|
|
permissions.ModelViewPermission)
|
|
|
|
|
|
class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.UpdateWithInlinesView):
|
|
form_class = None
|
|
default_template_name = "model_update_form.html"
|
|
permission_classes = (
|
|
permissions.IsStaffPermission,
|
|
permissions.ModelChangePermission)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ModelEditFormView, self).get_context_data(**kwargs)
|
|
context['model'] = self.get_model()
|
|
context['action'] = "Change"
|
|
return context
|
|
|
|
|
|
class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.CreateWithInlinesView):
|
|
form_class = None
|
|
default_template_name = "model_update_form.html"
|
|
permission_classes = (
|
|
permissions.IsStaffPermission,
|
|
permissions.ModelAddPermission)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ModelAddFormView, self).get_context_data(**kwargs)
|
|
context['model'] = self.get_model()
|
|
context['action'] = "Add"
|
|
return context
|
|
|
|
|
|
class ModelDeleteView(AdminModel2Mixin, generic.DeleteView):
|
|
success_url = "../../" # TODO - fix this!
|
|
default_template_name = "model_confirm_delete.html"
|
|
permission_classes = (
|
|
permissions.IsStaffPermission,
|
|
permissions.ModelDeletePermission)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ModelDeleteView, self).get_context_data(**kwargs)
|
|
|
|
def _format_callback(obj):
|
|
opts = utils.model_options(obj)
|
|
return '%s: %s' % (force_text(capfirst(opts.verbose_name)),
|
|
force_text(obj))
|
|
|
|
collector = utils.NestedObjects(using=None)
|
|
collector.collect([self.get_object()])
|
|
context.update({
|
|
'deletable_objects': collector.nested(_format_callback)
|
|
})
|
|
return context
|
|
|
|
|
|
class PasswordChangeView(Admin2Mixin, generic.UpdateView):
|
|
|
|
default_template_name = 'auth/password_change_form.html'
|
|
form_class = AdminPasswordChangeForm
|
|
admin_form_class = PasswordChangeForm
|
|
model = get_user_model()
|
|
success_url = reverse_lazy('admin2:password_change_done')
|
|
|
|
def get_form_kwargs(self, **kwargs):
|
|
data = {'user': self.get_object()}
|
|
|
|
if self.request.method in ('POST', 'PUT'):
|
|
data.update({
|
|
'data': self.request.POST
|
|
})
|
|
|
|
return data
|
|
|
|
def get_form_class(self):
|
|
if self.request.user == self.get_object():
|
|
return self.admin_form_class
|
|
return super(PasswordChangeView, self).get_form_class()
|
|
|
|
|
|
class PasswordChangeDoneView(Admin2Mixin, generic.TemplateView):
|
|
|
|
default_template_name = 'auth/password_change_done.html'
|
|
|
|
|
|
class LoginView(Admin2Mixin, generic.TemplateView):
|
|
|
|
default_template_name = 'auth/login.html'
|
|
authentication_form = AdminAuthenticationForm
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
return auth_login(request,
|
|
authentication_form=self.authentication_form,
|
|
template_name=self.get_template_names(),
|
|
*args, **kwargs)
|
|
|
|
|
|
class LogoutView(Admin2Mixin, generic.TemplateView):
|
|
|
|
default_template_name = 'auth/logout.html'
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return auth_logout(request, template_name=self.get_template_names(),
|
|
*args, **kwargs)
|