prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Render only first-leveled children at the header menu
  Now we have too many categories at the header menu
  ![image](https://user-images.githubusercontent.com/3526796/65932829-d6c31280-e417-11e9-8b01-3ec7f32c76b5.png)
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `shopelectro/logic/header.py`
  Content:
  ```
  1 from django.conf import settings
  2 from django.db.models import Q
  3 
  4 from pages import models as pages_models
  5 from shopelectro import models
  6 
  7 
  8 def menu_qs() -> pages_models.PageQuerySet:
  9     """
  10     QuerySet with header menu items.
  11 
  12     Contains root categories.
  13     Result can be tuned HEADER_LINKS settings option.
  14     """
  15     return (
  16         pages_models.Page.objects.active()
  17         .filter(
  18             Q(slug__in=settings.HEADER_LINKS['add'])
  19             | (
  20                 # @todo #974:30m  Optimize the header menu query.
  21                 #  Fetch catalog page for the header menu at the same query.
  22                 #  root category pages.
  23                 Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))
  24                 & Q(type='model')
  25                 & Q(related_model_name=models.Category._meta.db_table)
  26                 & ~Q(slug__in=settings.HEADER_LINKS['exclude'])
  27             )
  28         )
  29         .order_by('position')
  30     )
  31
  ```
  
  Path: `shopelectro/templatetags/se_extras.py`
  Content:
  ```
  1 import datetime
  2 import math
  3 
  4 from django import template
  5 from django.conf import settings
  6 from django.contrib.humanize.templatetags.humanize import intcomma
  7 from django.template.defaultfilters import floatformat
  8 from django.urls import reverse
  9 
  10 from images.models import ImageMixin
  11 from pages.models import Page
  12 from shopelectro import logic
  13 
  14 register = template.Library()
  15 
  16 
  17 @register.simple_tag
  18 def roots():
  19     return logic.header.menu_qs()
  20 
  21 
  22 @register.simple_tag
  23 def footer_links():
  24     return settings.FOOTER_LINKS
  25 
  26 
  27 @register.filter
  28 def class_name(model):
  29     """Return Model name."""
  30     return type(model).__name__
  31 
  32 
  33 @register.simple_tag
  34 def time_to_call():
  35     def is_weekend(t):
  36         return t.weekday() > 4
  37 
  38     def is_friday(t):
  39         return t.weekday() == 4
  40 
  41     def not_yet_opened(t):
  42         current_time = (t.hour, t.minute)
  43         open_time = (10, 00)
  44         return current_time < open_time and not is_weekend(t)
  45 
  46     def is_closed(t):
  47         current_time = (t.hour, t.minute)
  48         closing_time = (16, 30) if is_friday(t) else (17, 30)
  49         return current_time > closing_time
  50 
  51     when_we_call = {
  52         lambda now: is_weekend(now) or (is_friday(now) and is_closed(now)): 'В понедельник в 10:30',
  53         lambda now: not_yet_opened(now): 'Сегодня в 10:30',
  54         lambda now: is_closed(now) and not (is_friday(now) or is_weekend(now)): 'Завтра в 10:30',
  55         lambda _: True: 'В течение 30 минут'
  56     }
  57 
  58     time_ = datetime.datetime.now()
  59     call = ' позвонит менеджер и обсудит детали доставки.'
  60     for condition, time in when_we_call.items():
  61         if condition(time_):
  62             return time + call
  63 
  64 
  65 @register.simple_tag
  66 def full_url(url_name, *args):
  67     return settings.BASE_URL + reverse(url_name, args=args)
  68 
  69 
  70 @register.filter
  71 def humanize_price(price):
  72     return intcomma(floatformat(price, 0))
  73 
  74 
  75 @register.filter
  76 def show_price_in_units(item):
  77     if (getattr(item, 'in_pack', 1) > 1):
  78         return 'руб / упаковка'
  79     return 'руб / шт'
  80 
  81 
  82 # Not good code, but duker at 06/10/2016 don't know how to fix it.
  83 # It makes Image model very complex.
  84 @register.simple_tag
  85 def get_img_alt(entity: ImageMixin):
  86     product_alt = 'Фотография {}'
  87     logo_alt = 'Логотип компании Shopelectro'
  88 
  89     if not isinstance(entity, Page):
  90         return logo_alt
  91 
  92     # try one of this attributes to get pages name
  93     name_attrs = ['h1', 'title', 'name']
  94     entity_name = next(
  95         getattr(entity, attr)
  96         for attr in name_attrs
  97         if getattr(entity, attr)
  98     )
  99     return product_alt.format(entity_name)
  100 
  101 
  102 @register.simple_tag
  103 def main_image_or_logo(page: Page):
  104     """Used for microdata."""
  105     if hasattr(page, 'main_image') and page.main_image:
  106         return page.main_image.url
  107     else:
  108         return settings.STATIC_URL + 'images/logo.png'
  109 
  110 
  111 @register.inclusion_tag('catalog/product_feedbacks_icons.html')
  112 def icon_stars(rating=0):
  113     """Render set of rating icons based on 1 through 5 rating values."""
  114     full_icons = int(math.floor(rating))
  115     half_icons = 0 if rating == int(rating) else 1
  116     empty_icons = 5 - full_icons - half_icons
  117 
  118     return {
  119         'full_icons': range(full_icons),
  120         'half_icons': range(half_icons),
  121         'empty_icons': range(empty_icons),
  122     }
  123
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/shopelectro/logic/header.py b/shopelectro/logic/header.py
  --- a/shopelectro/logic/header.py
  +++ b/shopelectro/logic/header.py
  @@ -1,3 +1,6 @@
  +import typing
  +from functools import lru_cache
  +
   from django.conf import settings
   from django.db.models import Q
   
  @@ -5,26 +8,41 @@
   from shopelectro import models
   
   
  -def menu_qs() -> pages_models.PageQuerySet:
  -    """
  -    QuerySet with header menu items.
  +class Menu:
  +    DICT_TYPE = typing.Dict[models.CategoryPage, typing.List[models.CategoryPage]]
  +
  +    @staticmethod
  +    def roots() -> pages_models.PageQuerySet:
  +        """
  +        QuerySet with header menu items.
   
  -    Contains root categories.
  -    Result can be tuned HEADER_LINKS settings option.
  -    """
  -    return (
  -        pages_models.Page.objects.active()
  -        .filter(
  -            Q(slug__in=settings.HEADER_LINKS['add'])
  -            | (
  -                # @todo #974:30m  Optimize the header menu query.
  -                #  Fetch catalog page for the header menu at the same query.
  -                #  root category pages.
  -                Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))
  -                & Q(type='model')
  -                & Q(related_model_name=models.Category._meta.db_table)
  -                & ~Q(slug__in=settings.HEADER_LINKS['exclude'])
  +        Contains root categories.
  +        Result can be tuned HEADER_LINKS settings option.
  +        """
  +        return (
  +            pages_models.Page.objects.active()
  +            .filter(
  +                Q(slug__in=settings.HEADER_LINKS['add'])
  +                | (
  +                    # @todo #974:30m  Optimize the header menu query.
  +                    #  Fetch catalog page for the header menu at the same query.
  +                    #  root category pages.
  +                    Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))
  +                    & Q(type='model')
  +                    & Q(related_model_name=models.Category._meta.db_table)
  +                    & ~Q(slug__in=settings.HEADER_LINKS['exclude'])
  +                )
               )
  +            .order_by('position')
           )
  -        .order_by('position')
  -    )
  +
  +    @lru_cache(maxsize=1)
  +    def as_dict(self) -> DICT_TYPE:
  +        return {
  +            root: list(
  +                root.get_children()
  +                .filter(type='model')
  +                .filter(related_model_name=models.Category._meta.db_table)
  +            )
  +            for root in self.roots().iterator()
  +        }
  diff --git a/shopelectro/templatetags/se_extras.py b/shopelectro/templatetags/se_extras.py
  --- a/shopelectro/templatetags/se_extras.py
  +++ b/shopelectro/templatetags/se_extras.py
  @@ -15,8 +15,8 @@
   
   
   @register.simple_tag
  -def roots():
  -    return logic.header.menu_qs()
  +def header_menu() -> logic.header.Menu:
  +    return logic.header.Menu()
   
   
   @register.simple_tag
  
verification_info: {"golden_diff": "diff --git a/shopelectro/logic/header.py b/shopelectro/logic/header.py\n--- a/shopelectro/logic/header.py\n+++ b/shopelectro/logic/header.py\n@@ -1,3 +1,6 @@\n+import typing\n+from functools import lru_cache\n+\n from django.conf import settings\n from django.db.models import Q\n \n@@ -5,26 +8,41 @@\n from shopelectro import models\n \n \n-def menu_qs() -> pages_models.PageQuerySet:\n-    \"\"\"\n-    QuerySet with header menu items.\n+class Menu:\n+    DICT_TYPE = typing.Dict[models.CategoryPage, typing.List[models.CategoryPage]]\n+\n+    @staticmethod\n+    def roots() -> pages_models.PageQuerySet:\n+        \"\"\"\n+        QuerySet with header menu items.\n \n-    Contains root categories.\n-    Result can be tuned HEADER_LINKS settings option.\n-    \"\"\"\n-    return (\n-        pages_models.Page.objects.active()\n-        .filter(\n-            Q(slug__in=settings.HEADER_LINKS['add'])\n-            | (\n-                # @todo #974:30m  Optimize the header menu query.\n-                #  Fetch catalog page for the header menu at the same query.\n-                #  root category pages.\n-                Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))\n-                & Q(type='model')\n-                & Q(related_model_name=models.Category._meta.db_table)\n-                & ~Q(slug__in=settings.HEADER_LINKS['exclude'])\n+        Contains root categories.\n+        Result can be tuned HEADER_LINKS settings option.\n+        \"\"\"\n+        return (\n+            pages_models.Page.objects.active()\n+            .filter(\n+                Q(slug__in=settings.HEADER_LINKS['add'])\n+                | (\n+                    # @todo #974:30m  Optimize the header menu query.\n+                    #  Fetch catalog page for the header menu at the same query.\n+                    #  root category pages.\n+                    Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))\n+                    & Q(type='model')\n+                    & Q(related_model_name=models.Category._meta.db_table)\n+                    & ~Q(slug__in=settings.HEADER_LINKS['exclude'])\n+                )\n             )\n+            .order_by('position')\n         )\n-        .order_by('position')\n-    )\n+\n+    @lru_cache(maxsize=1)\n+    def as_dict(self) -> DICT_TYPE:\n+        return {\n+            root: list(\n+                root.get_children()\n+                .filter(type='model')\n+                .filter(related_model_name=models.Category._meta.db_table)\n+            )\n+            for root in self.roots().iterator()\n+        }\ndiff --git a/shopelectro/templatetags/se_extras.py b/shopelectro/templatetags/se_extras.py\n--- a/shopelectro/templatetags/se_extras.py\n+++ b/shopelectro/templatetags/se_extras.py\n@@ -15,8 +15,8 @@\n \n \n @register.simple_tag\n-def roots():\n-    return logic.header.menu_qs()\n+def header_menu() -> logic.header.Menu:\n+    return logic.header.Menu()\n \n \n @register.simple_tag\n", "issue": "Render only first-leveled children at the header menu\nNow we have too many categories at the header menu\r\n![image](https://user-images.githubusercontent.com/3526796/65932829-d6c31280-e417-11e9-8b01-3ec7f32c76b5.png)\r\n\n", "before_files": [{"content": "from django.conf import settings\nfrom django.db.models import Q\n\nfrom pages import models as pages_models\nfrom shopelectro import models\n\n\ndef menu_qs() -> pages_models.PageQuerySet:\n    \"\"\"\n    QuerySet with header menu items.\n\n    Contains root categories.\n    Result can be tuned HEADER_LINKS settings option.\n    \"\"\"\n    return (\n        pages_models.Page.objects.active()\n        .filter(\n            Q(slug__in=settings.HEADER_LINKS['add'])\n            | (\n                # @todo #974:30m  Optimize the header menu query.\n                #  Fetch catalog page for the header menu at the same query.\n                #  root category pages.\n                Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))\n                & Q(type='model')\n                & Q(related_model_name=models.Category._meta.db_table)\n                & ~Q(slug__in=settings.HEADER_LINKS['exclude'])\n            )\n        )\n        .order_by('position')\n    )\n", "path": "shopelectro/logic/header.py"}, {"content": "import datetime\nimport math\n\nfrom django import template\nfrom django.conf import settings\nfrom django.contrib.humanize.templatetags.humanize import intcomma\nfrom django.template.defaultfilters import floatformat\nfrom django.urls import reverse\n\nfrom images.models import ImageMixin\nfrom pages.models import Page\nfrom shopelectro import logic\n\nregister = template.Library()\n\n\n@register.simple_tag\ndef roots():\n    return logic.header.menu_qs()\n\n\n@register.simple_tag\ndef footer_links():\n    return settings.FOOTER_LINKS\n\n\n@register.filter\ndef class_name(model):\n    \"\"\"Return Model name.\"\"\"\n    return type(model).__name__\n\n\n@register.simple_tag\ndef time_to_call():\n    def is_weekend(t):\n        return t.weekday() > 4\n\n    def is_friday(t):\n        return t.weekday() == 4\n\n    def not_yet_opened(t):\n        current_time = (t.hour, t.minute)\n        open_time = (10, 00)\n        return current_time < open_time and not is_weekend(t)\n\n    def is_closed(t):\n        current_time = (t.hour, t.minute)\n        closing_time = (16, 30) if is_friday(t) else (17, 30)\n        return current_time > closing_time\n\n    when_we_call = {\n        lambda now: is_weekend(now) or (is_friday(now) and is_closed(now)): '\u0412 \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a \u0432 10:30',\n        lambda now: not_yet_opened(now): '\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0432 10:30',\n        lambda now: is_closed(now) and not (is_friday(now) or is_weekend(now)): '\u0417\u0430\u0432\u0442\u0440\u0430 \u0432 10:30',\n        lambda _: True: '\u0412 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 30 \u043c\u0438\u043d\u0443\u0442'\n    }\n\n    time_ = datetime.datetime.now()\n    call = ' \u043f\u043e\u0437\u0432\u043e\u043d\u0438\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0438 \u043e\u0431\u0441\u0443\u0434\u0438\u0442 \u0434\u0435\u0442\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438.'\n    for condition, time in when_we_call.items():\n        if condition(time_):\n            return time + call\n\n\n@register.simple_tag\ndef full_url(url_name, *args):\n    return settings.BASE_URL + reverse(url_name, args=args)\n\n\n@register.filter\ndef humanize_price(price):\n    return intcomma(floatformat(price, 0))\n\n\n@register.filter\ndef show_price_in_units(item):\n    if (getattr(item, 'in_pack', 1) > 1):\n        return '\u0440\u0443\u0431 / \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0430'\n    return '\u0440\u0443\u0431 / \u0448\u0442'\n\n\n# Not good code, but duker at 06/10/2016 don't know how to fix it.\n# It makes Image model very complex.\n@register.simple_tag\ndef get_img_alt(entity: ImageMixin):\n    product_alt = '\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f {}'\n    logo_alt = '\u041b\u043e\u0433\u043e\u0442\u0438\u043f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Shopelectro'\n\n    if not isinstance(entity, Page):\n        return logo_alt\n\n    # try one of this attributes to get pages name\n    name_attrs = ['h1', 'title', 'name']\n    entity_name = next(\n        getattr(entity, attr)\n        for attr in name_attrs\n        if getattr(entity, attr)\n    )\n    return product_alt.format(entity_name)\n\n\n@register.simple_tag\ndef main_image_or_logo(page: Page):\n    \"\"\"Used for microdata.\"\"\"\n    if hasattr(page, 'main_image') and page.main_image:\n        return page.main_image.url\n    else:\n        return settings.STATIC_URL + 'images/logo.png'\n\n\n@register.inclusion_tag('catalog/product_feedbacks_icons.html')\ndef icon_stars(rating=0):\n    \"\"\"Render set of rating icons based on 1 through 5 rating values.\"\"\"\n    full_icons = int(math.floor(rating))\n    half_icons = 0 if rating == int(rating) else 1\n    empty_icons = 5 - full_icons - half_icons\n\n    return {\n        'full_icons': range(full_icons),\n        'half_icons': range(half_icons),\n        'empty_icons': range(empty_icons),\n    }\n", "path": "shopelectro/templatetags/se_extras.py"}], "after_files": [{"content": "import typing\nfrom functools import lru_cache\n\nfrom django.conf import settings\nfrom django.db.models import Q\n\nfrom pages import models as pages_models\nfrom shopelectro import models\n\n\nclass Menu:\n    DICT_TYPE = typing.Dict[models.CategoryPage, typing.List[models.CategoryPage]]\n\n    @staticmethod\n    def roots() -> pages_models.PageQuerySet:\n        \"\"\"\n        QuerySet with header menu items.\n\n        Contains root categories.\n        Result can be tuned HEADER_LINKS settings option.\n        \"\"\"\n        return (\n            pages_models.Page.objects.active()\n            .filter(\n                Q(slug__in=settings.HEADER_LINKS['add'])\n                | (\n                    # @todo #974:30m  Optimize the header menu query.\n                    #  Fetch catalog page for the header menu at the same query.\n                    #  root category pages.\n                    Q(parent=pages_models.CustomPage.objects.filter(slug='catalog'))\n                    & Q(type='model')\n                    & Q(related_model_name=models.Category._meta.db_table)\n                    & ~Q(slug__in=settings.HEADER_LINKS['exclude'])\n                )\n            )\n            .order_by('position')\n        )\n\n    @lru_cache(maxsize=1)\n    def as_dict(self) -> DICT_TYPE:\n        return {\n            root: list(\n                root.get_children()\n                .filter(type='model')\n                .filter(related_model_name=models.Category._meta.db_table)\n            )\n            for root in self.roots().iterator()\n        }\n", "path": "shopelectro/logic/header.py"}, {"content": "import datetime\nimport math\n\nfrom django import template\nfrom django.conf import settings\nfrom django.contrib.humanize.templatetags.humanize import intcomma\nfrom django.template.defaultfilters import floatformat\nfrom django.urls import reverse\n\nfrom images.models import ImageMixin\nfrom pages.models import Page\nfrom shopelectro import logic\n\nregister = template.Library()\n\n\n@register.simple_tag\ndef header_menu() -> logic.header.Menu:\n    return logic.header.Menu()\n\n\n@register.simple_tag\ndef footer_links():\n    return settings.FOOTER_LINKS\n\n\n@register.filter\ndef class_name(model):\n    \"\"\"Return Model name.\"\"\"\n    return type(model).__name__\n\n\n@register.simple_tag\ndef time_to_call():\n    def is_weekend(t):\n        return t.weekday() > 4\n\n    def is_friday(t):\n        return t.weekday() == 4\n\n    def not_yet_opened(t):\n        current_time = (t.hour, t.minute)\n        open_time = (10, 00)\n        return current_time < open_time and not is_weekend(t)\n\n    def is_closed(t):\n        current_time = (t.hour, t.minute)\n        closing_time = (16, 30) if is_friday(t) else (17, 30)\n        return current_time > closing_time\n\n    when_we_call = {\n        lambda now: is_weekend(now) or (is_friday(now) and is_closed(now)): '\u0412 \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a \u0432 10:30',\n        lambda now: not_yet_opened(now): '\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0432 10:30',\n        lambda now: is_closed(now) and not (is_friday(now) or is_weekend(now)): '\u0417\u0430\u0432\u0442\u0440\u0430 \u0432 10:30',\n        lambda _: True: '\u0412 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 30 \u043c\u0438\u043d\u0443\u0442'\n    }\n\n    time_ = datetime.datetime.now()\n    call = ' \u043f\u043e\u0437\u0432\u043e\u043d\u0438\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0438 \u043e\u0431\u0441\u0443\u0434\u0438\u0442 \u0434\u0435\u0442\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438.'\n    for condition, time in when_we_call.items():\n        if condition(time_):\n            return time + call\n\n\n@register.simple_tag\ndef full_url(url_name, *args):\n    return settings.BASE_URL + reverse(url_name, args=args)\n\n\n@register.filter\ndef humanize_price(price):\n    return intcomma(floatformat(price, 0))\n\n\n@register.filter\ndef show_price_in_units(item):\n    if (getattr(item, 'in_pack', 1) > 1):\n        return '\u0440\u0443\u0431 / \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0430'\n    return '\u0440\u0443\u0431 / \u0448\u0442'\n\n\n# Not good code, but duker at 06/10/2016 don't know how to fix it.\n# It makes Image model very complex.\n@register.simple_tag\ndef get_img_alt(entity: ImageMixin):\n    product_alt = '\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f {}'\n    logo_alt = '\u041b\u043e\u0433\u043e\u0442\u0438\u043f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Shopelectro'\n\n    if not isinstance(entity, Page):\n        return logo_alt\n\n    # try one of this attributes to get pages name\n    name_attrs = ['h1', 'title', 'name']\n    entity_name = next(\n        getattr(entity, attr)\n        for attr in name_attrs\n        if getattr(entity, attr)\n    )\n    return product_alt.format(entity_name)\n\n\n@register.simple_tag\ndef main_image_or_logo(page: Page):\n    \"\"\"Used for microdata.\"\"\"\n    if hasattr(page, 'main_image') and page.main_image:\n        return page.main_image.url\n    else:\n        return settings.STATIC_URL + 'images/logo.png'\n\n\n@register.inclusion_tag('catalog/product_feedbacks_icons.html')\ndef icon_stars(rating=0):\n    \"\"\"Render set of rating icons based on 1 through 5 rating values.\"\"\"\n    full_icons = int(math.floor(rating))\n    half_icons = 0 if rating == int(rating) else 1\n    empty_icons = 5 - full_icons - half_icons\n\n    return {\n        'full_icons': range(full_icons),\n        'half_icons': range(half_icons),\n        'empty_icons': range(empty_icons),\n    }\n", "path": "shopelectro/templatetags/se_extras.py"}]}