def get_content_models(cls): """ Return all Page subclasses that are admin registered, ordered based on the ``ADD_PAGE_ORDER`` setting. """ models = [] for model in Page.get_content_models(): try: admin_url(model, "add") except NoReverseMatch: continue else: setattr(model, "meta_verbose_name", model._meta.verbose_name) setattr(model, "add_url", admin_url(model, "add")) models.append(model) order = [name.lower() for name in settings.ADD_PAGE_ORDER] def sort_key(page): name = "%s.%s" % (page._meta.app_label, page._meta.object_name) unordered = len(order) try: return (order.index(name.lower()), "") except ValueError: return (unordered, page.meta_verbose_name) return sorted(models, key=sort_key)
def changelist_view(self, *args, **kwargs): """ Redirect to the add view if no records exist or the change view if the singleton instance exists. """ try: singleton = self.model.objects.get() except self.model.MultipleObjectsReturned: return super(SingletonAdmin, self).changelist_view(*args, **kwargs) except self.model.DoesNotExist: return redirect(admin_url(self.model, "add")) return redirect(admin_url(self.model, "change", singleton.id))
def test_contenttyped_admin_redirects(self): self.client.login(username=self._username, password=self._password) # Unsubclassed objects should not redirect page = Page.objects.create(title="Test page") response = self.client.get(admin_url(Page, "change", page.pk)) self.assertEqual(response.status_code, 200) # Subclassed objects should redirect to the admin for child class richtext = RichTextPage.objects.create(title="Test rich text") response = self.client.get(admin_url(Page, "change", richtext.pk)) richtext_change_url = admin_url(RichTextPage, "change", richtext.pk) self.assertRedirects(response, richtext_change_url)
def get_content_models(self): """ Return all subclasses that are admin registered. """ models = [] for model in self.concrete_model.get_content_models(): try: admin_url(model, "add") except NoReverseMatch: continue else: setattr(model, "meta_verbose_name", model._meta.verbose_name) setattr(model, "add_url", admin_url(model, "add")) models.append(model) return models
def models_for_pages(*args): """ Create a select list containing each of the models that subclass the ``Page`` model. """ page_models = [] for model in Page.get_content_models(): try: admin_url(model, "add") except NoReverseMatch: continue else: setattr(model, "name", model._meta.verbose_name) setattr(model, "add_url", admin_url(model, "add")) page_models.append(model) return page_models
def export_view(self, request, form_id): """ Exports the form entries in either a HTML table or CSV file. """ if request.POST.get("back"): change_url = admin_url(Form, "change", form_id) return HttpResponseRedirect(change_url) form = get_object_or_404(Form, id=form_id) export_form = ExportForm(form, request, request.POST or None) submitted = export_form.is_valid() if submitted: if request.POST.get("export"): response = HttpResponse(mimetype="text/csv") timestamp = slugify(datetime.now().ctime()) fname = "%s-%s.csv" % (form.slug, timestamp) header = "attachment; filename=%s" % fname response["Content-Disposition"] = header csv = writer(response, delimiter=settings.FORMS_CSV_DELIMITER) csv.writerow(export_form.columns()) for rows in export_form.rows(): csv.writerow(rows) return response template = "admin/forms/export.html" context = {"title": _("Export Entries"), "export_form": export_form, "submitted": submitted} return render_to_response(template, context, RequestContext(request))
def changelist_view(self, request, extra_context=None): """ Redirect to the ``Page`` changelist view for ``Page`` subclasses. """ if self.model is not Page: return HttpResponseRedirect(admin_url(Page, "changelist")) return super(PageAdmin, self).changelist_view(request, extra_context)
def get_block_type_queryset(self,db): qry = None for m in self.get_block_models(): try: admin_url(m, 'add') except NoReverseMatch: continue q = models.Q(app_label=m._meta.app_label) & \ models.Q(model=m._meta.object_name.lower()) qry = qry | q if qry else q # If qry has not been set, i.e. no blocks extend the block_type, or # Blocks do not have an admin, then exclude all content types.. return ContentType.objects.filter(qry).using(db) if qry else \ ContentType.objects.exclude(pk__gte=0)
def add_view(self, request, **kwargs): """ For the ``Page`` model, redirect to the add view for the ``ContentPage`` model. """ if self.model is Page: add_url = admin_url(ContentPage, "add") return HttpResponseRedirect(add_url) return super(PageAdmin, self).add_view(request, **kwargs)
def changelist_view(self, request, **kwargs): """ Redirect to the ``Page`` changelist view for ``Page`` subclasses. """ if self.model is not Page: return HttpResponseRedirect(admin_url(Page, "changelist")) kwargs.setdefault("extra_context", {}) kwargs["extra_context"]["page_models"] = self.get_content_models() return super(PageAdmin, self).changelist_view(request, **kwargs)
def add_view(self, *args, **kwargs): """ Redirect to the change view if the singleton instance exists. """ try: singleton = self.model.objects.get() except (self.model.DoesNotExist, self.model.MultipleObjectsReturned): return super(SingletonAdmin, self).add_view(*args, **kwargs) else: change_url = admin_url(self.model, "change", singleton.id) return HttpResponseRedirect(change_url)
def changelist_view(self, request, extra_context=None): """ Redirect to the changelist view for subclasses. """ if self.model is not self.concrete_model: return HttpResponseRedirect( admin_url(self.concrete_model, "changelist")) extra_context = extra_context or {} extra_context["content_models"] = self.get_content_models() return super(ContentTypedAdmin, self).changelist_view( request, extra_context)
def entries_view(self, request, form_id): """ Displays the form entries in a HTML table with option to export as CSV file. """ if request.POST.get("back"): change_url = admin_url(Form, "change", form_id) return HttpResponseRedirect(change_url) form = get_object_or_404(Form, id=form_id) entries_form = EntriesForm(form, request, request.POST or None) delete_entries_perm = "%s.delete_formentry" % FormEntry._meta.app_label can_delete_entries = request.user.has_perm(delete_entries_perm) submitted = entries_form.is_valid() if submitted: if request.POST.get("export"): response = HttpResponse(content_type="text/csv") timestamp = slugify(datetime.now().ctime()) fname = "%s-%s.csv" % (form.slug, timestamp) header = "attachment; filename=%s" % fname response["Content-Disposition"] = header queue = StringIO() delimiter = settings.FORMS_CSV_DELIMITER try: csv = writer(queue, delimiter=delimiter) writerow = csv.writerow except TypeError: queue = BytesIO() delimiter = bytes(delimiter, encoding="utf-8") csv = writer(queue, delimiter=delimiter) writerow = lambda row: csv.writerow([c.encode("utf-8") if hasattr(c, "encode") else c for c in row]) writerow(entries_form.columns()) for row in entries_form.rows(csv=True): writerow(row) data = queue.getvalue() response.write(data) return response elif request.POST.get("delete") and can_delete_entries: selected = request.POST.getlist("selected") if selected: entries = FormEntry.objects.filter(id__in=selected) count = entries.count() if count > 0: entries.delete() message = ungettext("1 entry deleted", "%(count)s entries deleted", count) info(request, message % {"count": count}) template = "admin/forms/entries.html" context = {"title": _("View Entries"), "entries_form": entries_form, "opts": self.model._meta, "original": form, "can_delete_entries": can_delete_entries, "submitted": submitted} return render_to_response(template, context, RequestContext(request))
def add_view(self, request, extra_context=None, **kwargs): """ For the ``Page`` model, redirect to the add view for the ``RichText`` model. """ if self.model is Page: try: add_url = admin_url(RichTextPage, "add") return HttpResponseRedirect(add_url) except NoReverseMatch: pass return super(PageAdmin, self).add_view(request, **kwargs)
def add_view(self, *args, **kwargs): """ Redirect to the change view if the singleton instance exists. """ try: singleton = self.model.objects.get() except (self.model.DoesNotExist, self.model.MultipleObjectsReturned): kwargs.setdefault("extra_context", {}) kwargs["extra_context"]["singleton"] = True response = super(SingletonAdmin, self).add_view(*args, **kwargs) return self.handle_save(args[0], response) return redirect(admin_url(self.model, "change", singleton.id))
def models_for_pages(*args): """ Create a select list containing each of the models that subclass the ``Page`` model. """ page_models = [] for model in get_models(): if model is not Page and issubclass(model, Page): setattr(model, "name", model._meta.verbose_name) setattr(model, "add_url", admin_url(model, "add")) page_models.append(model) return page_models
def change_view(self, request, object_id, extra_context=None): """ As in Mezzanine's ``Page`` model, check ``product.get_content_model()`` for a subclass and redirect to its admin change view. """ if self.model is Product: product = get_object_or_404(Product, pk=object_id) content_model = product.get_content_model() if content_model is not None: change_url = admin_url(content_model.__class__, "change", content_model.id) return HttpResponseRedirect(change_url) return super(ProductAdmin, self).change_view(request, object_id, extra_context=extra_context)
def send_approve_mail(request, user): """ Sends an email to staff in listed in the setting ``ACCOUNTS_APPROVAL_EMAILS``, when a new user signs up and the ``ACCOUNTS_APPROVAL_REQUIRED`` setting is ``True``. """ settings.use_editable() approval_emails = split_addresses(settings.ACCOUNTS_APPROVAL_EMAILS) if not approval_emails: return context = {"request": request, "user": user, "change_url": admin_url(user.__class__, "change", user.id)} subject = subject_template("email/account_approve_subject.txt", context) send_mail_template(subject, "email/account_approve", settings.DEFAULT_FROM_EMAIL, approval_emails, context=context)
def create_page(request): models = request.GET['module'] pageclass = request.GET['classname'] parent = request.GET['parent'] parent = Page.objects.get(slug=parent).get_content_model() models = importlib.import_module(models) pageclass = getattr(models, pageclass) title = request.GET.get('title', "new " + pageclass._meta.object_name) # page = pageclass.objects.create(title=title, parent=parent) return HttpResponseRedirect( admin_url(pageclass, 'add') + "?parent={pk}&next={next}".format(pk=parent.pk, next=parent.get_absolute_url()))
def change_view(self, request, object_id, extra_context=None): """ For the ``Page`` model, check ``page.get_content_model()`` for a subclass and redirect to its admin change view. """ if self.model is Page: page = get_object_or_404(Page, pk=object_id) content_model = page.get_content_model() if content_model is not None: change_url = admin_url(content_model.__class__, "change", content_model.id) return HttpResponseRedirect(change_url) return super(PageAdmin, self).change_view(request, object_id, extra_context=None)
def models_for_products(*args): """ Create a select list containing each of the models that subclass the ``Product`` model, plus the ``Product`` model itself. """ product_models = [] for model in Product.get_content_models(): try: admin_add_url = admin_url(model, "add") except NoReverseMatch: continue else: setattr(model, "name", model._meta.verbose_name) setattr(model, "add_url", admin_add_url) product_models.append(model) return product_models
def change_view(self, request, object_id, **kwargs): """ For the concrete model, check ``get_content_model()`` for a subclass and redirect to its admin change view. """ instance = get_object_or_404(self.concrete_model, pk=object_id) content_model = instance.get_content_model() self.check_permission(request, content_model, "change") if content_model.__class__ != self.model: change_url = admin_url(content_model.__class__, "change", content_model.id) return HttpResponseRedirect(change_url) return super(ContentTypedAdmin, self).change_view( request, object_id, **kwargs)
def change_view(self, request, object_id, **kwargs): """ For the ``Page`` model, check ``page.get_content_model()`` for a subclass and redirect to its admin change view. Also enforce custom change permissions for the page instance. """ page = get_object_or_404(Page, pk=object_id) content_model = page.get_content_model() self._check_permission(request, content_model, "change") if self.model is Page: if content_model is not None: change_url = admin_url(content_model.__class__, "change", content_model.id) return HttpResponseRedirect(change_url) kwargs.setdefault("extra_context", {}) kwargs["extra_context"].update( {"hide_delete_link": not content_model.can_delete(request), "hide_slug_field": content_model.overridden()} ) return super(PageAdmin, self).change_view(request, object_id, **kwargs)
def change_view(self, request, object_id, extra_context=None): """ For the ``Page`` model, check ``page.get_content_model()`` for a subclass and redirect to its admin change view. Also enforce custom change permissions for the page instance. """ page = get_object_or_404(Page, pk=object_id) content_model = page.get_content_model() self._check_permission(request, content_model, "change") if self.model is Page: if content_model is not None: change_url = admin_url(content_model.__class__, "change", content_model.id) return HttpResponseRedirect(change_url) extra_context = extra_context or {} extra_context["hide_delete_link"] = not page.can_delete(request) extra_context["hide_slug_field"] = not page.overridden() return super(PageAdmin, self).change_view(request, object_id, extra_context)
def export_view(self, request, form_id): """ Output a CSV file to the browser containing the entries for the form. """ if request.POST.get("back"): change_url = admin_url(Form, "change", form_id) return HttpResponseRedirect(change_url) form = get_object_or_404(Form, id=form_id) export_form = ExportForm(form, request, request.POST or None) if export_form.is_valid(): response = HttpResponse(mimetype="text/csv") fname = "%s-%s.csv" % (form.slug, slugify(datetime.now().ctime())) response["Content-Disposition"] = "attachment; filename=%s" % fname csv = writer(response) csv.writerow(export_form.columns()) for rows in export_form.rows(): csv.writerow(rows) return response template = "admin/forms/export.html" context = {"title": _("Export Entries"), "export_form": export_form} return render_to_response(template, context, RequestContext(request))
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} # Model or view --> (group index, group title, item index, item title). menu_order = {} for (group_index, group) in enumerate(settings.ADMIN_MENU_ORDER): group_title, items = group group_title = group_title.title() for (item_index, item) in enumerate(items): if isinstance(item, (tuple, list)): item_title, item = item else: item_title = None menu_order[item] = (group_index, group_title, item_index, item_title) # Add all registered models, using group and title from menu order. for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if in_menu and request.user.has_module_perms(opts.app_label): perms = model_admin.get_model_perms(request) admin_url_name = "" if perms["change"]: admin_url_name = "changelist" change_url = admin_url(model, admin_url_name) else: change_url = None if perms["add"]: admin_url_name = "add" add_url = admin_url(model, admin_url_name) else: add_url = None if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) try: app_index, app_title, model_index, model_title = \ menu_order[model_label] except KeyError: app_index = None app_title = opts.app_label.title() model_index = None model_title = None else: del menu_order[model_label] if not model_title: model_title = capfirst(model._meta.verbose_name_plural) if app_title not in app_dict: app_dict[app_title] = { "index": app_index, "name": app_title, "models": [], } app_dict[app_title]["models"].append({ "index": model_index, "perms": model_admin.get_model_perms(request), "name": model_title, "admin_url": change_url, "add_url": add_url }) # Menu may also contain view or url pattern names given as (title, name). for (item_url, item) in menu_order.iteritems(): app_index, app_title, item_index, item_title = item try: item_url = reverse(item_url) except NoReverseMatch: continue if app_title not in app_dict: app_dict[app_title] = { "index": app_index, "name": app_title, "models": [], } app_dict[app_title]["models"].append({ "index": item_index, "perms": {"custom": True}, "name": item_title, "admin_url": item_url, }) app_list = app_dict.values() sort = lambda x: x["name"] if x["index"] is None else x["index"] for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list
def changelist_redirect(self): changelist_url = admin_url(Setting, "changelist") return HttpResponseRedirect(changelist_url)
def get_admin_url(self): return admin_url(self, "change", self.id)
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} menu_order = [(x[0], list(x[1])) for x in settings.ADMIN_MENU_ORDER] found_items = set() for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if in_menu and request.user.has_module_perms(opts.app_label): perms = model_admin.get_model_perms(request) admin_url_name = "" if perms["change"]: admin_url_name = "changelist" elif perms["add"]: admin_url_name = "add" if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) for (name, items) in menu_order: try: index = list(items).index(model_label) except ValueError: pass else: found_items.add(model_label) app_title = name break else: index = None app_title = opts.app_label model_dict = { "index": index, "perms": model_admin.get_model_perms(request), "name": capfirst(model._meta.verbose_name_plural), "admin_url": admin_url(model, admin_url_name), } app_title = app_title.title() if app_title in app_dict: app_dict[app_title]["models"].append(model_dict) else: try: titles = [x[0] for x in settings.ADMIN_MENU_ORDER] index = titles.index(app_title) except ValueError: index = None app_dict[app_title] = { "index": index, "name": app_title, "models": [model_dict], } for (i, (name, items)) in enumerate(menu_order): name = unicode(name) for unfound_item in set(items) - found_items: if isinstance(unfound_item, (list, tuple)): item_name, item_url = unfound_item[0], try_url(unfound_item[1]) if item_url: if name not in app_dict: app_dict[name] = { "index": i, "name": name, "models": [], } app_dict[name]["models"].append({ "index": items.index(unfound_item), "perms": {"custom": True}, "name": item_name, "admin_url": item_url, }) app_list = app_dict.values() sort = lambda x: x["name"] if x["index"] is None else x["index"] for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} # Model or view --> (group index, group title, item index, item title). menu_order = {} for (group_index, group) in enumerate(settings.ADMIN_MENU_ORDER): group_title, items = group group_title = group_title.title() for (item_index, item) in enumerate(items): if isinstance(item, (tuple, list)): item_title, item = item else: item_title = None menu_order[item] = (group_index, group_title, item_index, item_title) # Add all registered models, using group and title from menu order. for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if in_menu and request.user.has_module_perms(opts.app_label): perms = model_admin.get_model_perms(request) admin_url_name = "" if perms["change"]: admin_url_name = "changelist" change_url = admin_url(model, admin_url_name) else: change_url = None if perms["add"]: admin_url_name = "add" add_url = admin_url(model, admin_url_name) else: add_url = None if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) try: app_index, app_title, model_index, model_title = menu_order[model_label] except KeyError: app_index = None app_title = opts.app_label.title() model_index = None model_title = None else: del menu_order[model_label] if not model_title: model_title = capfirst(model._meta.verbose_name_plural) if app_title not in app_dict: app_dict[app_title] = {"index": app_index, "name": app_title, "models": []} app_dict[app_title]["models"].append( { "index": model_index, "perms": model_admin.get_model_perms(request), "name": model_title, "admin_url": change_url, "add_url": add_url, } ) # Menu may also contain view or url pattern names given as (title, name). for (item_url, item) in menu_order.iteritems(): app_index, app_title, item_index, item_title = item try: item_url = reverse(item_url) except NoReverseMatch: continue if app_title not in app_dict: app_dict[app_title] = {"index": app_index, "name": app_title, "models": []} app_dict[app_title]["models"].append( {"index": item_index, "perms": {"custom": True}, "name": item_title, "admin_url": item_url} ) app_list = app_dict.values() sort = lambda x: x["name"] if x["index"] is None else x["index"] for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} # Model or view --> (group index, group title, item index, item title). menu_order = {} for (group_index, group) in enumerate(settings.ADMIN_MENU_ORDER): group_title, items = group for (item_index, item) in enumerate(items): if isinstance(item, (tuple, list)): item_title, item = item else: item_title = None menu_order[item] = (group_index, group_title, item_index, item_title) # Add all registered models, using group and title from menu order. for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if hasattr(model_admin, "in_menu"): import warnings warnings.warn( "ModelAdmin.in_menu() has been replaced with " "ModelAdmin.has_module_permission(request). See " "https://docs.djangoproject.com/en/stable/ref/contrib/admin/" "#django.contrib.admin.ModelAdmin.has_module_permission.", DeprecationWarning, ) in_menu = in_menu and model_admin.has_module_permission(request) if in_menu and request.user.has_module_perms(opts.app_label): admin_url_name = "" if model_admin.has_change_permission(request): admin_url_name = "changelist" change_url = admin_url(model, admin_url_name) else: change_url = None if model_admin.has_add_permission(request): admin_url_name = "add" add_url = admin_url(model, admin_url_name) else: add_url = None if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) try: app_index, app_title, model_index, model_title = menu_order[model_label] except KeyError: app_index = None try: app_title = opts.app_config.verbose_name.title() except AttributeError: # Third party admin classes doing weird things. # See GH #1628 app_title = "" model_index = None model_title = None else: del menu_order[model_label] if not model_title: model_title = capfirst(model._meta.verbose_name_plural) if app_title not in app_dict: app_dict[app_title] = {"index": app_index, "name": app_title, "models": []} app_dict[app_title]["models"].append( { "index": model_index, "perms": model_admin.get_model_perms(request), "name": model_title, "object_name": opts.object_name, "admin_url": change_url, "add_url": add_url, } ) # Menu may also contain view or url pattern names given as (title, name). for (item_url, item) in menu_order.items(): app_index, app_title, item_index, item_title = item try: item_url = reverse(item_url) except NoReverseMatch: continue if app_title not in app_dict: app_dict[app_title] = {"index": app_index, "name": app_title, "models": []} app_dict[app_title]["models"].append( {"index": item_index, "perms": {"custom": True}, "name": item_title, "admin_url": item_url} ) app_list = list(app_dict.values()) sort = lambda x: (x["index"] if x["index"] is not None else 999, x["name"]) for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list
def page_menu(context, token): """ Return a list of child pages for the given parent, storing all pages in a dict in the context when first called using parents as keys for retrieval on subsequent recursive calls from the menu template. """ # First arg could be the menu template file name, or the parent page. # Also allow for both to be used. template_name = None parent_page = None parts = token.split_contents()[1:] for part in parts: part = Variable(part).resolve(context) if isinstance(part, unicode): template_name = part elif isinstance(part, Page): parent_page = part if template_name is None: try: template_name = context["menu_template_name"] except KeyError: error = "No template found for page_menu in: %s" % parts raise TemplateSyntaxError(error) context["menu_template_name"] = template_name if "menu_pages" not in context: try: user = context["request"].user slug = context["request"].path except KeyError: user = None slug = "" num_children = lambda id: lambda: len(context["menu_pages"][id]) has_children = lambda id: lambda: num_children(id)() > 0 published = Page.objects.published(for_user=user) if slug == admin_url(Page, "changelist"): related = [m.__name__.lower() for m in Page.get_content_models()] published = published.select_related(*related) else: published = published.select_related(depth=2) # Store the current page being viewed in the context. Used # for comparisons in page.set_menu_helpers. if "page" not in context: try: context["_current_page"] = published.get(slug=slug) except Page.DoesNotExist: context["_current_page"] = None elif slug: context["_current_page"] = context["page"] # Some homepage related context flags. on_home is just a helper # indicated we're on the homepage. has_home indicates an actual # page object exists for the homepage, which can be used to # determine whether or not to show a hard-coded homepage link # in the page menu. home = home_slug() context["on_home"] = slug == home context["has_home"] = False # Maintain a dict of page IDs -> parent IDs for fast # lookup in setting page.is_current_or_ascendant in # page.set_menu_helpers. context["_parent_page_ids"] = {} pages = defaultdict(list) for page in published.order_by("_order"): page.set_helpers(context) context["_parent_page_ids"][page.id] = page.parent_id setattr(page, "num_children", num_children(page.id)) setattr(page, "has_children", has_children(page.id)) pages[page.parent_id].append(page) if page.slug == home: context["has_home"] = True context["menu_pages"] = pages # ``branch_level`` must be stored against each page so that the # calculation of it is correctly applied. This looks weird but if we do # the ``branch_level`` as a separate arg to the template tag with the # addition performed on it, the addition occurs each time the template # tag is called rather than once per level. context["branch_level"] = 0 parent_page_id = None if parent_page is not None: context["branch_level"] = getattr(parent_page, "branch_level", 0) + 1 parent_page_id = parent_page.id # Build the ``page_branch`` template variable, which is the list of # pages for the current parent. Here we also assign the attributes # to the page object that determines whether it belongs in the # current menu template being rendered. context["page_branch"] = context["menu_pages"].get(parent_page_id, []) context["page_branch_in_menu"] = False for page in context["page_branch"]: page.in_menu = page.in_menu_template(template_name) page.num_children_in_menu = 0 if page.in_menu: context["page_branch_in_menu"] = True for child in context["menu_pages"].get(page.id, []): if child.in_menu_template(template_name): page.num_children_in_menu += 1 page.has_children_in_menu = page.num_children_in_menu > 0 page.branch_level = context["branch_level"] page.parent = parent_page # Prior to pages having the ``in_menus`` field, pages had two # boolean fields ``in_navigation`` and ``in_footer`` for # controlling menu inclusion. Attributes and variables # simulating these are maintained here for backwards # compatibility in templates, but will be removed eventually. page.in_navigation = page.in_menu page.in_footer = not (not page.in_menu and "footer" in template_name) if page.in_navigation: context["page_branch_in_navigation"] = True if page.in_footer: context["page_branch_in_footer"] = True t = get_template(template_name) return t.render(context)
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} # Model or view --> (group index, group title, item index, item title). menu_order = {} for (group_index, group) in enumerate(settings.ADMIN_MENU_ORDER): group_title, items = group for (item_index, item) in enumerate(items): if isinstance(item, (tuple, list)): item_title, item = item else: item_title = None menu_order[item] = (group_index, group_title, item_index, item_title) # Add all registered models, using group and title from menu order. for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if hasattr(model_admin, "in_menu"): import warnings warnings.warn( 'ModelAdmin.in_menu() has been replaced with ' 'ModelAdmin.has_module_permission(request). See ' 'https://docs.djangoproject.com/en/stable/ref/contrib/admin/' '#django.contrib.admin.ModelAdmin.has_module_permission.', DeprecationWarning) in_menu = in_menu and model_admin.has_module_permission(request) if in_menu and request.user.has_module_perms(opts.app_label): admin_url_name = "" if model_admin.has_change_permission(request): admin_url_name = "changelist" change_url = admin_url(model, admin_url_name) else: change_url = None if model_admin.has_add_permission(request): admin_url_name = "add" add_url = admin_url(model, admin_url_name) else: add_url = None if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) try: app_index, app_title, model_index, model_title = \ menu_order[model_label] except KeyError: app_index = None try: app_title = opts.app_config.verbose_name.title() except AttributeError: # Third party admin classes doing weird things. # See GH #1628 app_title = "" model_index = None model_title = None else: del menu_order[model_label] if not model_title: model_title = capfirst(model._meta.verbose_name_plural) if app_title not in app_dict: app_dict[app_title] = { "index": app_index, "name": app_title, "models": [], } app_dict[app_title]["models"].append({ "index": model_index, "perms": model_admin.get_model_perms(request), "name": model_title, "object_name": opts.object_name, "admin_url": change_url, "add_url": add_url }) # Menu may also contain view or url pattern names given as (title, name). for (item_url, item) in menu_order.items(): app_index, app_title, item_index, item_title = item try: item_url = reverse(item_url) except NoReverseMatch: continue if app_title not in app_dict: app_dict[app_title] = { "index": app_index, "name": app_title, "models": [], } app_dict[app_title]["models"].append({ "index": item_index, "perms": { "custom": True }, "name": item_title, "admin_url": item_url, }) app_list = list(app_dict.values()) sort = lambda x: (x["index"] if x["index"] is not None else 999, x["name"]) for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list
def page_menu(context, token): """ Return a list of child pages for the given parent, storing all pages in a dict in the context when first called using parents as keys for retrieval on subsequent recursive calls from the menu template. """ # First arg could be the menu template file name, or the parent page. # Also allow for both to be used. template_name = None parent_page = None parts = token.split_contents()[1:] for part in parts: part = Variable(part).resolve(context) if isinstance(part, unicode): template_name = part elif isinstance(part, Page): parent_page = part if template_name is None: try: template_name = context["menu_template_name"] except KeyError: error = "No template found for page_menu in: %s" % parts raise TemplateSyntaxError(error) context["menu_template_name"] = template_name if "menu_pages" not in context: try: user = context["request"].user slug = context["request"].path except KeyError: user = None slug = "" num_children = lambda id: lambda: len(context["menu_pages"][id]) has_children = lambda id: lambda: num_children(id)() > 0 published = Page.objects.published(for_user=user) if slug == admin_url(Page, "changelist"): related = [m.__name__.lower() for m in Page.get_content_models()] published = published.select_related(*related) else: published = published.select_related(depth=2) # Store the current page being viewed in the context. Used # for comparisons in page.set_menu_helpers. if "page" not in context: try: context["_current_page"] = published.get(slug=slug) except Page.DoesNotExist: context["_current_page"] = None elif slug: context["_current_page"] = context["page"] # Maintain a dict of page IDs -> parent IDs for fast # lookup in setting page.is_current_or_ascendant in # page.set_menu_helpers. context["_parent_page_ids"] = {} pages = defaultdict(list) for page in published.order_by("_order"): page.set_helpers(context) context["_parent_page_ids"][page.id] = page.parent_id setattr(page, "num_children", num_children(page.id)) setattr(page, "has_children", has_children(page.id)) pages[page.parent_id].append(page) context["menu_pages"] = pages context["on_home"] = slug == reverse("home") # ``branch_level`` must be stored against each page so that the # calculation of it is correctly applied. This looks weird but if we do # the ``branch_level`` as a separate arg to the template tag with the # addition performed on it, the addition occurs each time the template # tag is called rather than once per level. context["branch_level"] = 0 parent_page_id = None if parent_page is not None: context["branch_level"] = getattr(parent_page, "branch_level", 0) + 1 parent_page_id = parent_page.id context["page_branch"] = context["menu_pages"].get(parent_page_id, []) context["page_branch_in_menu"] = False for page in context["page_branch"]: # footer/nav for backward compatibility. Also check that in_menus # has a value, as it may not have been populated correctly # if migrations weren't run when it was added. page.in_footer = page.in_navigation = page.in_menu = True if page.in_menus is not None: for i, l, t in settings.PAGE_MENU_TEMPLATES: if not unicode(i) in page.in_menus and t == template_name: page.in_navigation = page.in_menu = False if "footer" in template_name: page.in_footer = False break if page.in_menu: context["page_branch_in_menu"] = True # Backwards compatibility context['page_branch_in_navigation'] = context["page_branch_in_menu"] context['page_branch_in_footer'] = (context["page_branch_in_menu"] and template_name == "pages/menu/footer.html") for i, page in enumerate(context["page_branch"]): context["page_branch"][i].branch_level = context["branch_level"] context["page_branch"][i].parent = parent_page t = get_template(template_name) return t.render(context)
def admin_app_list(request): """ Adopted from ``django.contrib.admin.sites.AdminSite.index``. Returns a list of lists of models grouped and ordered according to ``mezzanine.conf.ADMIN_MENU_ORDER``. Called from the ``admin_dropdown_menu`` template tag as well as the ``app_list`` dashboard widget. """ app_dict = {} menu_order = [(x[0], list(x[1])) for x in settings.ADMIN_MENU_ORDER] found_items = set() for (model, model_admin) in admin.site._registry.items(): opts = model._meta in_menu = not hasattr(model_admin, "in_menu") or model_admin.in_menu() if in_menu and request.user.has_module_perms(opts.app_label): perms = model_admin.get_model_perms(request) admin_url_name = "" if perms["change"]: admin_url_name = "changelist" elif perms["add"]: admin_url_name = "add" if admin_url_name: model_label = "%s.%s" % (opts.app_label, opts.object_name) for (name, items) in menu_order: try: index = list(items).index(model_label) except ValueError: pass else: found_items.add(model_label) app_title = name break else: index = None app_title = opts.app_label model_dict = { "index": index, "perms": model_admin.get_model_perms(request), "name": capfirst(model._meta.verbose_name_plural), "admin_url": admin_url(model, admin_url_name), } app_title = app_title.title() if app_title in app_dict: app_dict[app_title]["models"].append(model_dict) else: try: titles = [x[0] for x in settings.ADMIN_MENU_ORDER] index = titles.index(app_title) except ValueError: index = None app_dict[app_title] = { "index": index, "name": app_title, "models": [model_dict], } for (i, (name, items)) in enumerate(menu_order): name = unicode(name) for unfound_item in set(items) - found_items: if isinstance(unfound_item, (list, tuple)): item_name, item_url = unfound_item[0], try_url(unfound_item[1]) if item_url: if name not in app_dict: app_dict[name] = { "index": i, "name": name, "models": [], } app_dict[name]["models"].append({ "index": items.index(unfound_item), "perms": { "custom": True }, "name": item_name, "admin_url": item_url, }) app_list = app_dict.values() sort = lambda x: x["name"] if x["index"] is None else x["index"] for app in app_list: app["models"].sort(key=sort) app_list.sort(key=sort) return app_list