from django.contrib.contenttypes.models import ContentType from django.urls.base import reverse from django.db import transaction from django.db.models import Q from django.forms import ModelChoiceField from django.http import QueryDict from django.template import loader from django.utils.decorators import method_decorator from django.utils.encoding import smart_text from django.utils.translation import ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect from xadmin.filters import FILTER_PREFIX, SEARCH_VAR from xadmin.plugins.relate import RELATE_PREFIX from xadmin.plugins.utils import get_context_dict from xadmin.sites import site from xadmin.views import ModelAdminView, BaseAdminPlugin, ListAdminView from xadmin.views.list import COL_LIST_VAR, ORDER_VAR from xadmin.views.dashboard import widget_manager, BaseWidget, PartialBaseWidget from xadmin.models import Bookmark csrf_protect_m = method_decorator(csrf_protect) class BookmarkPlugin(BaseAdminPlugin): # [{'title': "Female", 'query': {'gender': True}, 'order': ('-age'), 'cols': ('first_name', 'age', 'phones'), 'search': 'Tom'}] list_bookmarks = [] show_bookmarks = True def has_change_permission(self, obj=None): if not obj or self.user.is_superuser: return True else: return obj.user == self.user def get_context(self, context): if not self.show_bookmarks: return context bookmarks = [] current_qs = '&'.join([ '%s=%s' % (k, v) for k, v in sorted(filter( lambda i: bool(i[1] and ( i[0] in (COL_LIST_VAR, ORDER_VAR, SEARCH_VAR) or i[0].startswith(FILTER_PREFIX) or i[0].startswith(RELATE_PREFIX) )), self.request.GET.items() )) ]) model_info = (self.opts.app_label, self.opts.model_name) has_selected = False menu_title = _(u"Bookmark") list_base_url = reverse('xadmin:%s_%s_changelist' % model_info, current_app=self.admin_site.name) # local bookmarks for bk in self.list_bookmarks: title = bk['title'] params = dict([ (FILTER_PREFIX + k, v) for (k, v) in bk['query'].items() ]) if 'order' in bk: params[ORDER_VAR] = '.'.join(bk['order']) if 'cols' in bk: params[COL_LIST_VAR] = '.'.join(bk['cols']) if 'search' in bk: params[SEARCH_VAR] = bk['search'] def check_item(i): return bool(i[1]) or i[1] == False bk_qs = '&'.join([ '%s=%s' % (k, v) for k, v in sorted(filter(check_item, params.items())) ]) url = list_base_url + '?' + bk_qs selected = (current_qs == bk_qs) bookmarks.append( {'title': title, 'selected': selected, 'url': url}) if selected: menu_title = title has_selected = True content_type = ContentType.objects.get_for_model(self.model) bk_model_info = (Bookmark._meta.app_label, Bookmark._meta.model_name) bookmarks_queryset = Bookmark.objects.filter( content_type=content_type, url_name='xadmin:%s_%s_changelist' % model_info ).filter(Q(user=self.user) | Q(is_share=True)) for bk in bookmarks_queryset: selected = (current_qs == bk.query) if self.has_change_permission(bk): change_or_detail = 'change' else: change_or_detail = 'detail' bookmarks.append({'title': bk.title, 'selected': selected, 'url': bk.url, 'edit_url': reverse('xadmin:%s_%s_%s' % (bk_model_info[0], bk_model_info[1], change_or_detail), args=(bk.id,))}) if selected: menu_title = bk.title has_selected = True post_url = reverse('xadmin:%s_%s_bookmark' % model_info, current_app=self.admin_site.name) new_context = { 'bk_menu_title': menu_title, 'bk_bookmarks': bookmarks, 'bk_current_qs': current_qs, 'bk_has_selected': has_selected, 'bk_list_base_url': list_base_url, 'bk_post_url': post_url, 'has_add_permission_bookmark': self.admin_view.request.user.has_perm('xadmin.add_bookmark'), 'has_change_permission_bookmark': self.admin_view.request.user.has_perm('xadmin.change_bookmark') } context.update(new_context) return context # Media def get_media(self, media): return media + self.vendor('xadmin.plugin.bookmark.js') # Block Views def block_nav_menu(self, context, nodes): if self.show_bookmarks: nodes.insert(0, loader.render_to_string('xadmin/blocks/model_list.nav_menu.bookmarks.html', context=get_context_dict(context))) class BookmarkView(ModelAdminView): @csrf_protect_m @transaction.atomic def post(self, request): model_info = (self.opts.app_label, self.opts.model_name) url_name = 'xadmin:%s_%s_changelist' % model_info bookmark = Bookmark( content_type=ContentType.objects.get_for_model(self.model), title=request.POST[ 'title'], user=self.user, query=request.POST.get('query', ''), is_share=request.POST.get('is_share', 0), url_name=url_name) bookmark.save() content = {'title': bookmark.title, 'url': bookmark.url} return self.render_response(content) class BookmarkAdmin(object): model_icon = 'fa fa-book' list_display = ('title', 'user', 'url_name', 'query') list_display_links = ('title',) user_fields = ['user'] hidden_menu = True def queryset(self): if self.user.is_superuser: return Bookmark.objects.all() return Bookmark.objects.filter(Q(user=self.user) | Q(is_share=True)) def get_list_display(self): list_display = super(BookmarkAdmin, self).get_list_display() if not self.user.is_superuser: list_display.remove('user') return list_display def has_change_permission(self, obj=None): if not obj or self.user.is_superuser: return True else: return obj.user == self.user @widget_manager.register class BookmarkWidget(PartialBaseWidget): widget_type = _('bookmark') widget_icon = 'fa fa-bookmark' description = _( 'Bookmark Widget, can show user\'s bookmark list data in widget.') template = "xadmin/widgets/list.html" bookmark = ModelChoiceField( label=_('Bookmark'), queryset=Bookmark.objects.all(), required=False) def setup(self): BaseWidget.setup(self) bookmark = self.cleaned_data['bookmark'] model = bookmark.content_type.model_class() data = QueryDict(bookmark.query) self.bookmark = bookmark if not self.title: self.title = smart_text(bookmark) req = self.make_get_request("", data.items()) self.list_view = self.get_view_class( ListAdminView, model, list_per_page=10, list_editable=[])(req) def has_perm(self): return True def context(self, context): list_view = self.list_view list_view.make_result_list() base_fields = list_view.base_list_display if len(base_fields) > 5: base_fields = base_fields[0:5] context['result_headers'] = [c for c in list_view.result_headers( ).cells if c.field_name in base_fields] context['results'] = [ [o for i, o in enumerate(filter( lambda c: c.field_name in base_fields, r.cells ))] for r in list_view.results() ] context['result_count'] = list_view.result_count context['page_url'] = self.bookmark.url site.register(Bookmark, BookmarkAdmin) site.register_plugin(BookmarkPlugin, ListAdminView) site.register_modelview(r'^bookmark/$', BookmarkView, name='%s_%s_bookmark')