mezzanine的page_menu tag

Posted on 2018-03-14 16:41  王将军之武库  阅读(257)  评论(0)    收藏  举报

    mezzanine的head 导航条、左侧tree、footer是由page_menu产生的。page_menu的算法,先计算出每一页的孩子,然后再逐页去page_menu。

@register.render_tag
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:]#对page_menu菜单分离,取得参数
    for part in parts:
        part = Variable(part).resolve(context)
        if isinstance(part, str):
            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
        rel = [m.__name__.lower()#取得Page的子类,但不包括Page自身
               for m in Page.get_content_models()
               if not m._meta.proxy]
        published = Page.objects.published(for_user=user).select_related(*rel)#把相关联的model也进行查询
        # Store the current page being viewed in the context. Used
        # for comparisons in page.set_menu_helpers.
        if "page" not in context:
            try:
                context.dicts[0]["_current_page"] = published.exclude(
                    content_model="link").get(slug=slug)
            except Page.DoesNotExist:
                context.dicts[0]["_current_page"] = None
        elif slug:
            context.dicts[0]["_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.dicts[0]["on_home"] = slug == home
        context.dicts[0]["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.dicts[0]["_parent_page_ids"] = {}#保存父页id的词典
        pages = defaultdict(list)#pages[]不存在时,不会出错,返回[]
        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)#取得各页的子页list
            if page.slug == home:
                context.dicts[0]["has_home"] = True
        # Include menu_pages in all contexts, not only in the
        # block being rendered.
        context.dicts[0]["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#默认层次为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
        context["parent_page"] = page.parent

        # 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(context))

 

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3