def test_table_render(self): data = [ { "first_name": "Paul", "last_name": "Simon" }, { "first_name": "Art", "last_name": "Garfunkel" }, ] table = Table( [ Column("first_name"), Column("last_name"), ], data, ) html = self.render_component(table) self.assertHTMLEqual( html, """ <table class="listing"> <thead> <tr><th>First name</th><th>Last name</th></tr> </thead> <tbody> <tr><td>Paul</td><td>Simon</td></tr> <tr><td>Art</td><td>Garfunkel</td></tr> </tbody> </table> """, )
def test_table_render_with_width(self): data = [ {'first_name': 'Paul', 'last_name': 'Simon'}, {'first_name': 'Art', 'last_name': 'Garfunkel'}, ] table = Table([ Column('first_name'), Column('last_name', width='75%'), ], data) html = self.render_component(table) self.assertHTMLEqual(html, ''' <table class="listing"> <col /> <col width="75%" /> <thead> <tr><th>First name</th><th>Last name</th></tr> </thead> <tbody> <tr><td>Paul</td><td>Simon</td></tr> <tr><td>Art</td><td>Garfunkel</td></tr> </tbody> </table> ''')
class HistoryView(IndexView): template_name = "wagtailadmin/generic/index.html" page_title = gettext_lazy("Snippet history") header_icon = "history" paginate_by = 50 columns = [ Column("message", label=gettext_lazy("Action")), UserColumn("user", blank_display_name="system"), DateColumn("timestamp", label=gettext_lazy("Date")), ] def dispatch(self, request, app_label, model_name, pk): self.app_label = app_label self.model_name = model_name self.model = get_snippet_model_from_url_params(app_label, model_name) self.object = get_object_or_404(self.model, pk=unquote(pk)) return super().dispatch(request) def get_page_subtitle(self): return str(self.object) def get_index_url(self): return reverse( "wagtailsnippets:history", args=(self.app_label, self.model_name, quote(self.object.pk)), ) def get_queryset(self): return log_registry.get_logs_for_instance( self.object).prefetch_related("user__wagtail_userprofile")
class HistoryView(MultipleObjectMixin, WagtailAdminTemplateMixin, InstanceSpecificView): page_title = gettext_lazy('History') paginate_by = 50 columns = [ Column('message', label=gettext_lazy("Action")), UserColumn('user', blank_display_name='system'), DateColumn('timestamp', label=gettext_lazy("Date")), ] def get_page_subtitle(self): return str(self.instance) def get_template_names(self): return self.model_admin.get_history_template() def get_queryset(self): return log_registry.get_logs_for_instance( self.instance).prefetch_related('user__wagtail_userprofile') def get_context_data(self, **kwargs): self.object_list = self.get_queryset() context = super().get_context_data(**kwargs) index_url = self.url_helper.get_action_url('history', quote(self.instance.pk)) table = Table(self.columns, context['object_list'], base_url=index_url, ordering=self.get_ordering()) context['table'] = table context['media'] = table.media context['index_url'] = index_url context['is_paginated'] = True return context
def test_column_media(self): class FancyColumn(Column): class Media: js = ["js/gradient-fill.js"] data = [ { "first_name": "Paul", "last_name": "Simon" }, { "first_name": "Art", "last_name": "Garfunkel" }, ] table = Table( [ FancyColumn("first_name"), Column("last_name"), ], data, ) self.assertIn('src="/static/js/gradient-fill.js"', str(table.media["js"]))
def test_row_classname(self): class SiteTable(Table): def get_row_classname(self, instance): return "default-site" if instance.is_default_site else "" root_page = Page.objects.filter(depth=2).first() blog = Site.objects.create( hostname="blog.example.com", site_name="My blog", root_page=root_page, is_default_site=True, ) gallery = Site.objects.create(hostname="gallery.example.com", site_name="My gallery", root_page=root_page) data = [blog, gallery] table = SiteTable( [ Column("hostname"), Column("site_name", label="Site name"), ], data, ) html = self.render_component(table) self.assertHTMLEqual( html, """ <table class="listing"> <thead> <tr><th>Hostname</th><th>Site name</th></tr> </thead> <tbody> <tr class="default-site"> <td>blog.example.com</td> <td>My blog</td> </tr> <tr> <td>gallery.example.com</td> <td>My gallery</td> </tr> </tbody> </table> """, )
class IndexView(generic.IndexView): page_title = _("Sites") add_item_label = _("Add a site") context_object_name = 'sites' default_ordering = 'hostname' columns = [ TitleColumn('hostname', label=_("Site"), sort_key='hostname', url_name='wagtailsites:edit'), Column('port', sort_key='port'), Column('site_name'), Column('root_page'), StatusFlagColumn('is_default_site', label=_("Default?"), true_label=_("Default")), ]
def columns(self): columns = super().columns + [ DownloadColumn("filename", label=_("File")), DateColumn("created_at", label=_("Created"), width="16%"), ] if self.collections: columns.insert(2, Column("collection", label=_("Collection"))) return columns
class IndexView(generic.IndexView): page_title = _("Sites") add_item_label = _("Add a site") context_object_name = "sites" default_ordering = "hostname" columns = [ TitleColumn( "hostname", label=_("Site"), sort_key="hostname", url_name="wagtailsites:edit", ), Column("port", sort_key="port"), Column("site_name"), Column("root_page"), StatusFlagColumn( "is_default_site", label=_("Default?"), true_label=_("Default") ), ]
def test_title_column(self): root_page = Page.objects.filter(depth=2).first() blog = Site.objects.create( hostname="blog.example.com", site_name="My blog", root_page=root_page ) gallery = Site.objects.create( hostname="gallery.example.com", site_name="My gallery", root_page=root_page ) data = [blog, gallery] table = Table( [ TitleColumn( "hostname", url_name="wagtailsites:edit", link_classname="choose-site", ), Column("site_name", label="Site name"), ], data, ) html = self.render_component(table) self.assertHTMLEqual( html, """ <table class="listing"> <thead> <tr><th>Hostname</th><th>Site name</th></tr> </thead> <tbody> <tr> <td class="title"> <div class="title-wrapper"> <a href="/admin/sites/%d/" class="choose-site">blog.example.com</a> </div> </td> <td>My blog</td> </tr> <tr> <td class="title"> <div class="title-wrapper"> <a href="/admin/sites/%d/" class="choose-site">gallery.example.com</a> </div> </td> <td>My gallery</td> </tr> </tbody> </table> """ % (blog.pk, gallery.pk), )
def test_column_media(self): class FancyColumn(Column): class Media: js = ['js/gradient-fill.js'] data = [ {'first_name': 'Paul', 'last_name': 'Simon'}, {'first_name': 'Art', 'last_name': 'Garfunkel'}, ] table = Table([ FancyColumn('first_name'), Column('last_name'), ], data) self.assertIn('src="/static/js/gradient-fill.js"', str(table.media['js']))
def columns(self): return [ PageTitleColumn("title", label=_("Title"), show_locale_labels=self.i18n_enabled), DateColumn( "updated", label=_("Updated"), width="12%", accessor="latest_revision_created_at", ), Column( "type", label=_("Type"), width="12%", accessor="page_type_display_name", ), PageStatusColumn("status", label=_("Status"), width="12%"), PageNavigateToChildrenColumn("children", label="", width="10%"), ]
class HistoryView(MultipleObjectMixin, WagtailAdminTemplateMixin, InstanceSpecificView): page_title = gettext_lazy("History") paginate_by = 50 columns = [ Column("message", label=gettext_lazy("Action")), UserColumn("user", blank_display_name="system"), DateColumn("timestamp", label=gettext_lazy("Date")), ] def get_page_subtitle(self): return str(self.instance) def get_template_names(self): return self.model_admin.get_history_template() def get_queryset(self): return log_registry.get_logs_for_instance( self.instance).prefetch_related("user__wagtail_userprofile") def get_context_data(self, **kwargs): self.object_list = self.get_queryset() context = super().get_context_data(**kwargs) index_url = self.url_helper.get_action_url("history", quote(self.instance.pk)) table = Table( self.columns, context["object_list"], base_url=index_url, ordering=self.get_ordering(), ) context["table"] = table context["media"] = table.media context["index_url"] = index_url context["is_paginated"] = True return context
def test_title_column(self): root_page = Page.objects.filter(depth=2).first() blog = Site.objects.create(hostname='blog.example.com', site_name='My blog', root_page=root_page) gallery = Site.objects.create(hostname='gallery.example.com', site_name='My gallery', root_page=root_page) data = [blog, gallery] table = Table([ TitleColumn('hostname', url_name='wagtailsites:edit'), Column('site_name', label="Site name"), ], data) html = self.render_component(table) self.assertHTMLEqual(html, ''' <table class="listing"> <thead> <tr><th>Hostname</th><th>Site name</th></tr> </thead> <tbody> <tr> <td class="title"> <div class="title-wrapper"> <a href="/admin/sites/%d/">blog.example.com</a> </div> </td> <td>My blog</td> </tr> <tr> <td class="title"> <div class="title-wrapper"> <a href="/admin/sites/%d/">gallery.example.com</a> </div> </td> <td>My gallery</td> </tr> </tbody> </table> ''' % (blog.pk, gallery.pk))
def browse(request, parent_page_id=None): # A missing or empty page_type parameter indicates 'all page types' # (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get("page_type") or "wagtailcore.page" user_perm = request.GET.get("user_perms", False) try: desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): raise Http404 # Find parent page if parent_page_id: parent_page = get_object_or_404(Page, id=parent_page_id) elif desired_classes == (Page, ): # Just use the root page parent_page = Page.get_first_root_node() else: # Find the highest common ancestor for the specific classes passed in # In many cases, such as selecting an EventPage under an EventIndex, # this will help the administrator find their page quicker. all_desired_pages = Page.objects.all().type(*desired_classes) parent_page = all_desired_pages.first_common_ancestor() parent_page = parent_page.specific # Get children of parent page (without streamfields) pages = parent_page.get_children().defer_streamfields().specific() # allow hooks to modify the queryset for hook in hooks.get_hooks("construct_page_chooser_queryset"): pages = hook(pages, request) # Filter them by page type if desired_classes != (Page, ): # restrict the page listing to just those pages that: # - are of the given content type (taking into account class inheritance) # - or can be navigated into (i.e. have children) choosable_pages = pages.type(*desired_classes) descendable_pages = pages.filter(numchild__gt=0) pages = choosable_pages | descendable_pages can_choose_root = request.GET.get("can_choose_root", False) target_pages = Page.objects.filter(pk__in=[ int(pk) for pk in request.GET.getlist("target_pages[]", []) if pk ]) match_subclass = request.GET.get("match_subclass", True) # Do permission lookups for this user now, instead of for every page. permission_proxy = UserPagePermissionsProxy(request.user) # Parent page can be chosen if it is a instance of desired_classes parent_page.can_choose = can_choose_page( parent_page, permission_proxy, desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) parent_page.is_parent_page = True parent_page.can_descend = False selected_locale = None locale_options = [] show_locale_labels = getattr(settings, "WAGTAIL_I18N_ENABLED", False) if show_locale_labels: pages = pages.select_related("locale") if parent_page.is_root(): # 'locale' is the current value of the "Locale" selector in the UI if request.GET.get("locale"): selected_locale = get_object_or_404( Locale, language_code=request.GET["locale"]) active_locale_id = selected_locale.pk else: active_locale_id = Locale.get_active().pk # we are at the Root level, so get the locales from the current pages choose_url = reverse("wagtailadmin_choose_page") locale_options = [{ "locale": locale, "url": choose_url + "?" + urlencode({ "page_type": page_type_string, "locale": locale.language_code }), } for locale in Locale.objects.filter( pk__in=pages.values_list("locale_id")).exclude( pk=active_locale_id)] else: # We have a parent page (that is not the root page). Use its locale as the selected localer selected_locale = parent_page.locale # and get the locales based on its available translations locales_and_parent_pages = { item["locale"]: item["pk"] for item in Page.objects.translation_of(parent_page).values( "locale", "pk") } locales_and_parent_pages[selected_locale.pk] = parent_page.pk for locale in Locale.objects.filter( pk__in=list(locales_and_parent_pages.keys())).exclude( pk=selected_locale.pk): choose_child_url = reverse( "wagtailadmin_choose_page_child", args=[locales_and_parent_pages[locale.pk]], ) locale_options.append({ "locale": locale, "url": choose_child_url + "?" + urlencode({"page_type": page_type_string}), }) # finally, filter the browseable pages on the selected locale if selected_locale: pages = pages.filter(locale=selected_locale) # Pagination # We apply pagination first so we don't need to walk the entire list # in the block below paginator = Paginator(pages, per_page=25) pages = paginator.get_page(request.GET.get("p")) # Annotate each page with can_choose/can_decend flags for page in pages: page.can_choose = can_choose_page( page, permission_proxy, desired_classes, can_choose_root, user_perm, target_pages=target_pages, match_subclass=match_subclass, ) page.can_descend = page.get_children_count() page.is_parent_page = False table = PageChooserTable( [ PageTitleColumn("title", label=_("Title")), DateColumn( "updated", label=_("Updated"), width="12%", accessor="latest_revision_created_at", ), Column("type", label=_("Type"), width="12%", accessor="page_type_display_name"), PageStatusColumn("status", label=_("Status"), width="12%"), PageNavigateToChildrenColumn("children", label="", width="10%"), ], [parent_page] + list(pages), ) # Render context = shared_context( request, { "parent_page": parent_page, "parent_page_id": parent_page.pk, "table": table, "pagination_page": pages, "search_form": SearchForm(), "page_type_string": page_type_string, "page_type_names": [ desired_class.get_verbose_name() for desired_class in desired_classes ], "page_types_restricted": (page_type_string != "wagtailcore.page"), "show_locale_labels": show_locale_labels, "locale_options": locale_options, "selected_locale": selected_locale, }, ) return render_modal_workflow( request, "wagtailadmin/chooser/browse.html", None, context, json_data={ "step": "browse", "parent_page_id": context["parent_page_id"] }, )
def search(request, parent_page_id=None): # A missing or empty page_type parameter indicates 'all page types' (i.e. descendants of wagtailcore.page) page_type_string = request.GET.get("page_type") or "wagtailcore.page" try: desired_classes = page_models_from_string(page_type_string) except (ValueError, LookupError): raise Http404 pages = Page.objects.all() show_locale_labels = getattr(settings, "WAGTAIL_I18N_ENABLED", False) if show_locale_labels: pages = pages.select_related("locale") # allow hooks to modify the queryset for hook in hooks.get_hooks("construct_page_chooser_queryset"): pages = hook(pages, request) search_form = SearchForm(request.GET) if search_form.is_valid() and search_form.cleaned_data["q"]: pages = pages.exclude(depth=1) # never include root pages = pages.type(*desired_classes) pages = pages.specific() pages = pages.search(search_form.cleaned_data["q"]) else: pages = pages.none() paginator = Paginator(pages, per_page=25) pages = paginator.get_page(request.GET.get("p")) for page in pages: page.can_choose = True page.is_parent_page = False table = PageChooserTable( [ PageTitleColumn("title", label=_("Title")), ParentPageColumn("parent", label=_("Parent")), DateColumn( "updated", label=_("Updated"), width="12%", accessor="latest_revision_created_at", ), Column("type", label=_("Type"), width="12%", accessor="page_type_display_name"), PageStatusColumn("status", label=_("Status"), width="12%"), ], pages, ) return TemplateResponse( request, "wagtailadmin/chooser/_search_results.html", shared_context( request, { "searchform": search_form, "table": table, "pages": pages, "page_type_string": page_type_string, "show_locale_labels": show_locale_labels, }, ), )
def get(self, request): Document = get_document_model() if permission_policy.user_has_permission(request.user, "add"): DocumentForm = get_document_form(Document) self.uploadform = DocumentForm( user=request.user, prefix="document-chooser-upload" ) else: self.uploadform = None documents = permission_policy.instances_user_has_any_permission_for( request.user, ["choose"] ) # allow hooks to modify the queryset for hook in hooks.get_hooks("construct_document_chooser_queryset"): documents = hook(documents, request) self.q = None self.is_searching = False self.collection_id = request.GET.get("collection_id") if self.collection_id: documents = documents.filter(collection=self.collection_id) self.documents_exist = documents.exists() if "q" in request.GET: self.searchform = SearchForm(request.GET) if self.searchform.is_valid(): self.q = self.searchform.cleaned_data["q"] documents = documents.search(self.q) self.is_searching = True else: self.searchform = SearchForm() if not self.is_searching: documents = documents.order_by("-created_at") paginator = Paginator(documents, per_page=10) self.documents = paginator.get_page(request.GET.get("p")) self.collections = permission_policy.collections_user_has_permission_for( request.user, "choose" ) if len(self.collections) < 2: self.collections = None columns = [ TitleColumn( "title", label=_("Title"), url_name="wagtaildocs:document_chosen", link_classname="document-choice", ), DownloadColumn("filename", label=_("File")), DateColumn("created_at", label=_("Created"), width="16%"), ] if self.collections: columns.insert(2, Column("collection", label=_("Collection"))) self.table = Table(columns, self.documents) return self.render_to_response()