Изучая django, я неожиданно столкнулся с проблемой. Я постоянно меняю структуру сайта (url.py) и мне приходиться постоянно вводить в адресной строке браузера новые url. И тут я подумал, что неплохо было добавить к моему тестовому сайту менюшку, которая будет брать список URL из url.py. Первым делом я начал смотреть готовые решения, которых, кстати, не оказалось. Также был вариант использовать БД и sitemap для редактирования ссылок. А что делать, если я не хочу использовать БД? Загуглив еще разок я нашел замечательную функцию get_resolver из django.core.urlresolvers и решил написать собственный генератор списка url.
Задача стояла следющая: автоматически генерировать список URL, которые находятся в url.py
и добавлять эти URL в собственный шаблон в виде меню.
В результате получилась следующая функция
-
- import socket
-
- def get_links():
- links = []
-
- address = socket.gethostbyname_ex(socket.gethostname())[-1][0] # for IP
- #address = socket.gethostbyname_ex(socket.gethostname())[0] # for name
-
- resolver = get_resolver(None).reverse_dict.items()
-
- for i in sorted(resolver, key=lambda resolve: resolve[1]):
- short_url = i[1][0][0][0]
- url_desc = {"url":str(address) + "/" + short_url}
- url_desc["name"] = str(i[0]).split(' ')[1]
- links.append(url_desc)
- return links
-
Тут необходимо немножко пояснить:
Для того чтобы все ссылки были абсолютными, а не относительными используется функция gethostbyname.
иначе при переходе на ссылку «http://localhost/main_page/" сгенериется динамически меню с ссылкой:
localhost/main_page/main_page
Поэтому я решил использовать абсолютный путь для генерирования меню.
также если в /etc/hosts вы указали, что localhost это mysite.com, то можно писать
-
- address = "mysite.com"
-
По умолчанию get_links () берет url из urlpatterns, а имя ссылки соответствует названию функции,
что не всегда этично. Для того чтобы указать назавания ссылок можно использовать простой if.
-
- def set_name(url, default_value):
- if url == r'':
- return 'root'
- elif url == r'custom_hello/':
- return 'Custom menu name 2'
- else:
- return default_value
-
Тогда вместо
-
- url_desc["name"] = str(i[0]).split(' ')[1]
-
следует писать
-
- url_desc["name"] = set_name(short_url, str(i[0]).split(' ')[1])
-
Теперь в каждой функции представления мы можем писать
-
- links = get_links()
- return render_to_response('template.html',locals())
-
В шаблоне реализуем меню (при необходимости можно добавить чуть-чуть javascript):
-
- {% for link in links %}
- <a href="http://{{ link.url }}">{{ link.name }}</a>
- {% if not forloop.last %}|{% endif %}
- {% endfor %}
-
Но, определять в каждом представлении переменную links, это не очень кошерно.
Получается что links = get_links () будет присутствовать в каждом предствлении.
И если мы его забудем добавить, то меню не сгенерируется меню в шаблоне.
Отсюда еще одна задача.
Добавить links = get_links () в locals ().
Для этого пишем еще одну функцию:
-
- def get_locals_with_links(local_dict):
- new_d = {}
- for i in dict(local_dict).copy().items():
- if str(i[0]).find("__") == -1:
- new_d[str(i[0])] = i[1]
- new_d.update({'links':get_links()})
- return new_d
-
После этого мы можем использовать ее при генерации шаблона:
-
- from URL_helper import get_locals_with_links
-
- def hello(request):
- hello = "Hello, World!!!"
- return render_to_response('template.html',get_locals_with_links(locals()))
-
Ремарка: статья называется „простое меню…“, потому что в функции get_links () отсутвует парсинг регулярных выражений.
Но этого вполне достаточно для того, чтобы понять, как извлекать значения urlpatterns из ulr.py.
Исходники проеакта на django.