Известно мнение, что Джанго не подходит для написания "наколеночных" проектиков, которым не нужно ничего особенно, кроме вывода HTML'а. Создание скелета проекта на Джанго считается работой, достаточно существенной для того, чтобы не заниматься ею ради пары функций.
Мне всегда было "очевидно", что это не так, но недавно по оброненной коллегой фразе я понял, что это не значит, что это очевидно всем. Многие просто не задумываются об этом. Ну, вы знаете, как это бывает… Поэтому я хочу продемонстрировать создание Джанго-проекта минимальными усилиями.
Упрощение
-
Нужно отказаться от команды startproject. Она создаёт хороший скелет проекта с аннотированным файлом настроек, но если вы Джанго-проект видите не впервые, этим можно пренебречь.
-
Файл manage.py — тоже не нужен, это просто локальный хелпер для django-admin.py
-
Не нужно думать о проекте, как о контейнере для приложений, а следовательно не нужно оформлять свой код, как подключаемое приложение. Приложения — одна из самых сильных архитектурных черт Джанго, но для мелких задач эта гибкость никогда не понадобится.
В итоге мы имеем что-то такое:
-
settings.py:
DEBUG = True ROOT_URLCONF = 'urls' TEMPLATE_DIRS = ['.']
-
urls.py:
from django.conf.urls.defaults import * import views urlpatterns = patterns('', (r'^$', views.index), (r'^test/(\d+)/$', views.test), )
-
views.py:
from django.shortcuts import render def index(request): return render(request, 'index.html', {}) def test(request, id): return render(request, 'test.html', {'id': id})
Это — полностью рабочий Джанго-проект. Запускается командой:
django-admin.py --settings=settings runserver
Вы получаете джанговский конвейер request-response, шаблоны. Также ничто не должно мешать работать такой хорошей вещи, как библиотека форм, хотя реально я не проверял. Что вы теряете — так это ORM и завязанные на него приложения. Но на то эта задача и "микро".
Экстремальщина
Чтобы нащупать границу того, когда идея дойдёт до абсурда, я решил ещё собрать всё приложение в один самозапускающийся файл. И у меня вышло:
- web.py:
#### Setup from django.conf import settings if not settings.configured: settings.configure( DEBUG = True, ROOT_URLCONF = 'web', TEMPLATE_DIRS = ['.'], ) from django.conf.urls.defaults import patterns urlpatterns = patterns('', (r'^$', 'web.index'), (r'^test/(\d+)/$', 'web.test'), ) #### Handlers from django.shortcuts import render def index(request): return render(request, 'index.html', {}) def test(request, id): return render(request, 'test.html', {'id': id}) #### Running if __name__ == '__main__': from django.core.management import execute_from_command_line execute_from_command_line()
Файл запускается так:
python web.py runserver
Впрочем, особенной радости от такой сборки я не увидел. Чтобы файл читался, его приходится делить на именованные секции, что как бы говорит нам о том, что это таки должны быть разные файлы. Плюс, написать такой файлик из головы я бы всё равно не смог из-за того что много надо делать по памяти: защита от двойной конфиграции настроек, длинные импорты и т.д.
Но как факт — забавно :-).
Побочная идея
Копаясь с инициализацией проекта я обнаружил, что настройка ROOT_URLCONF
используется в самом ядре обработки запроса. Это привязывает работу Джанго к наличию реального модуля с определённой в нём переменной urlpatterns
. Джанго была бы гибче, если бы конфигурацию URL'ов можно было инициализировать программно простым списком:
settings.configure(
DEBUG = True,
urlconf = [
(r'^$', index),
],
)
Это, наверное, было бы даже полезно на практике, когда среду нужно уметь создавать на лету. Например, при тестировании.
Комментарии: 30
I have a feeling there should be a comma: "In tests, for example".
Кончится всё конкурсом в стиле "во сколько байт можно запихнуть работающую программу на джанго?" :)
Что мешает подключить? :) Я всегда рассматривал Django не как монструозный швейцарский нож, а как конструктор, по умолчанию собранный в самой удобной конфигурации. Да, некоторые его части не совместимы со сторонними кубиками, но это не проблема. Этакий Lego от веб-разработки.
Для этого уже нужно приложение с собственным именем и models.py. Не то чтобы это было плохо, но это уже не "простенькое" решение.
При всем уважении к django, я думаю, что для таких мелочей приятнее использовать webpy.org, так как ~50k кода фреймворка дают возможность делать небольшие и гибкие штуковины и не подталкивают к написанию еще чего-то, потому что фреймворк дает возможность это сделать. Конечно никаких сомнений нету, что при помощи django все это тоже можно реализовать, но имея кучу инструментов тяжело остановится на только действительно необходимых и сделать задачу не "приукрасив" ее.
Легким движением руки Джанго превращается... превращается... Джанго превращается... в Синатру! http://www.sinatrarb.com/
Ну это на правах холивара, разумеется :)
Всё равно получается несколько громоздко. Как мне кажется, для подобных задач лучше всё-таки использовать что-нибудь вроде Flask или webpy. И с wsgi вопрос сразу решается :)
Я бы предпочёл Bottle.py для таких задач.
Спасибо! Действительно получаются довольно красивые микро-решения.
Хотя я в последних двух подходящих случаях пользовал tornado.
Про manage.py и startproject - точно, нафиг не нужны.
А вот заголовок у поста обманчивый. Это микроприложение, а не микрофреймворк. Точно так же как никто не обязывает писать огроменные энтерпрайзы там, где достаточно
Иван, спасибо за эксперементирование. Я считаю, что уж если на сервере стоит Django, то смысла ставить Flask или webpy немного. В них надо копаться, натыкаться на ограничения и тонкости. А тут - всё же привычная среда.
Или можно использовать пирамиду[1], в отличии от этого урезанного комбайна.
Николай Яремко упоминал на субботнике подобный (свой) проект: http://www.github.com/makiwara/protosome Правда он чуть-чуть больше, ну и сложнее соответственно.
А запускать лучше указав каталог проекта: django-admin.py runserver --pythonpath=/myprojects/mini --settings=settings
а еще можно нафиг удалить файл views.py и использовать 'direct_ to_template' в urls.py:
оффтоп: оказывается если слово начинается и заканчивается нижним подчеркивание, в нотации markdown оно превращается в слово. Что еще хуже — 'direct(нижнее подчеркивание)to(нижнее подчеркивание)template' превращается в 'directtotemplate'
Very cool, I hadn't realized django could be so compact. Coming from a rails standpoint, this reduces the number of files I'd expect in a micro-project by a ridiculous amount
Отличный пост! Сделал один проект на Bottle, компактно, конечно, но концепция DRY там не работает ( Написал кучу всего, что обычно в джанге не делал. И не нравится в Bottle, что нарушается концепция "Явное лучше, чем неявное". Там дюжина способов извлечь данные запроса! Не хорошо ( Вывод: если знаешь Django, то используй его. В микро, макро, и любом другом масштабе. Это реально хороший фреймворк.
This seems super cool and pretty much exactly something I was looking out for. As a novice beginner in Python and learning Django, I often wondered about the heavy boot-strapping Django did for small learning projects. This definitely helps my concern. Though, am still grasping many of the entities used in this post. It would be great help if you could wrap all this in a script and create a utility out of it for someone like me. Many thanks again for this post and explanation.
Thanks for showing this. I always had trouble understanding what Micro-frameworks are for if everything is doable with a stripped Django.
You can use models too.
Ah! long needed. Many thanks
Just for fun, I decided to see how easy it would be to factor what was left of the boilerplate in your single-file example into its own reusable chunk. It turned out to be pretty straightforward, and yielded something like this:
The source of the reusable chunk is here.
Andrew, this is totally cool! May be it's even getting close to be actually useful :-).
Yeah... I'm curious to see if it's possible to encapsulate the application state in an object, like Flask does, rather than having everything be global and having to hang all sorts of stuff like urlpatterns off of the main file. I think Simon Willison experimented with some of this a couple of years ago, so I might look into how he did it. I think getting models working would also be pretty cool (and I see that there are some tips on that in Luka's comment), because I don't think it would be that big of a stretch to be able to build single-file projects that leverage existing reusable apps, like the admin.
Nice post. I wish I could speak another language as well as you appear to speak English!
Some of this seems out of date, e.g., at least in Ubuntu it's now just django-admin instead of django-admin.py, and the 3-file version doesn't run out of the box (apologies, I saw the problem on someone else's machine and don't have the errors to hand).
It'd be great if you could fix it up somehow for the next gullible fool who says "just search for 'minimal django example' and run what you see"
This post is more than three years old, of course it's out of date :-)
oh, amazing! what a long time ago this was obvious for some clever people :)))
@Luka Zakrajsek suggested model connection. A little less hacky solution could be as follows: