Django это фреймворк, при помощи которого быстро пишутся сайты. Так ли это?
Фичи джанги:
- Админка
- куча аппликэйшинов
- Шаблоны
- ORM
- DebugToolbar
Админка
Из коробки у вас есть админка. Для простых сайтов её нужно кастомайзить долго и упорно, правда, обычно, это делается один раз. В сайте среднего уровня жангоадминка уже не прокатит. Вывод админка даёт профит в простых сайтах.
Аппликашины
Обычно очень посредственного качества и не совместимы друг с другом, поэтому танцы с бубном и велосипеды наше всё + djangosnippetsШаблоны
- нету break, continue
- рекурсия Jinja
<ul class="sitemap"> {% for item in sitemap recursive %} <li><a href="{{ item.href|e }}">{{ item.title }}</a> {% if item.children -%} <ul class="submenu">{{ loop(item.children) }}</ul> {% endif %}</li> {% endfor %} </ul>
- не работает вызов функций типа item() (лолшто?)
- [:-1] не работает, нужно писать |latest
для js выражение типа:
- коменты {# #} неработают в несколько строк
- вместо {{ list[5] }} -> {{ arr.5 }}
- для словарей {{ dict.foo }} не работает, да здравствует template tag
- для itertools.chain можно сосать лапу с таким фокусом {{ list[5] }}
- о джанга ты прекрасна {{ myval|add:"-5" }} вместо уродского {{ myval - 5 }}
- нельзя сделать так {{ dir(foo) }}
- как узнать длинну itertools? в jinje делается так {{ list(foo).length }}
ORM
- Page.objects.filter(parent__in=objects) вместо DBSession.query(Page).filter(parent in objects)
- великолепный foomodel_set__barmodel__name лолшто?!
- Entry.objects.all()[:1].get() вместо DBSession.query(Entry).first() или one()
- добавляем в модель: class Meta: app_label = 'asdasda' и переходим к разделу дебаг!
Debug
Дебаг джанго кормит вас! Потому что вы Django программист и половину рабочего времени пытаетесь понять что за !@#$% произошла, получая за это зарплату.class Meta: app_label = 'asdasda' генерит трейс:
django.core.management.base.CommandError: One or more models did not validate:
gallery.galleryimage: 'gallery' has a relation with model <class 'gallery.models.Gallery'>, which has either not been installed or is abstract.
Шыкарные красные ошибки джанги. Очень информативно, ищется аникейством и вспоминанием чё правил.
Я запилил небольшой пример что бы вы могли поднять его и посмотреть на эту магию.
Квик старт
- Установка по
pip install -r requirements.txt
-
Далее введим python manage.py syncdb и видим
ImportError: cannot import name SEOModel
Супер информативный вывод, все сразу стало понятно.
- 2.1 Прошел все модели в проекте, SEOModel не нашел, при учете что у меня gallery стоит в virtualenv
- 2.2 может во вью? Во вью то же нету
- 2.3 ищем по проекту тупо по всем файлам, нету.
- 2.4 идем в settings/apps.py и смотрим какое г может это содержать(так на угад), смотрим common опа вот он в моделях, осталось найти где он импортируется неправильно.
-
2.5 ради интереса запускаю сервер
python manage.py runserver
и получаю:
File ".../local/lib/python2.7/site-packages/gallery/models.py", line 12, in <module> from website.models import SEOModel, VisibleModel ImportError: cannot import name SEOModel
Pages
- захожу в pages в админке
- добавляю дерево
- тыкаю по дереву(вложенность 2го уровня) что бы развернуть список и получаю:
Error while loading the data from the server.
и трэйс:Internal Server Error: /admin/pages/page/tree_json/ Traceback (most recent call last): File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py", line 50, in wrapper return self.admin_site.admin_view(view)(*args, **kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view response = view_func(request, *args, **kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/views/decorators/cache.py", line 89, in _wrapped_view_func response = view_func(request, *args, **kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 202, in inner return view(request, *args, **kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py", line 157, in tree_json_view node = self.model.objects.get(id=node_id) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/manager.py", line 143, in get return self.get_query_set().get(*args, **kwargs) File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/query.py", line 404, in get self.model._meta.object_name) DoesNotExist: Page matching query does not exist. [16/Dec/2013 23:42:28] "GET /admin/pages/page/tree_json/?node=5&_=1387215746550 HTTP/1.1" 500 22668
бесполезный трейс и непонятная ошибка КРУТО!
Если я зайду на адрес /admin/pages/page/tree_json/?node=5&_=1387215746550 то получу статический trace и хер знает куда bp вставить что бы хоть за че-то зацепиться.
Ставлю
django-extension
через pip и wergzeug
что бы получить хоть какой то интерактив на том же трэйсе.Запускаю командой
python manage.py runserver_plus
, отваливается debug_toolbar
. Но и интерактивный трейс мало чем помогает в этом случае. Джанга каким то чудом обходит то место которое все ломает, ГРЕБАННЫЙ СТЫД!
Ошибка ищется тупым эникейством. Предполагая что django
идеальна и в ней нет ошибок, django_mptt_admin
на example работает хорошо, может быть что то в Pages
??? Ад же какойто?
> В сайте среднего уровня жангоадминка уже не прокатит.
ОтветитьУдалитьЕще как прокатит. Не для сайтов "под заказ" с требованием к интуитивной админке, а для обычных "продуктовых компаний" джанго-админка просто неоценима.
> Обычно очень посредственного качества и не совместимы друг с другом, поэтому танцы с бубном и велосипеды наше всё + djangosnippets
ОтветитьУдалитьСнова-таки. Вот как простейший пример -- gargoyle. Подключаешь -- получаешь функциональность фича-свитчей плюс админку. Да, пусть она не идеальна в интерфейсе, но с т.з. экономии времени на разработку сама по себе эта вещь уже экономит неделю-другую времени (попробуй по-быстрому что-то подобное написать со всеми фронт-эндами и бэк-эндами -- быстро надоест, по крайней мере я уж точно этим заниматься не хотел бы).
В остальном (особенно ОРМ) согласен, код джанги оставляет желать лучшего, и множество неочевидных моментов также. Ну, вроде что-то народ пилить продолжает, проект не стоит на месте, одно решение проблемы с моделью юзеров чего стоит. Плюс миграции скоро будут "встроенными". Так что, желаем проекту развития в правильном направлении.
ОтветитьУдалитьЮзеры да это конечно реально проблема аж с 2007 года была, аж просто кастыли какие-то. Видимо джанга страдает из-за своего гигантизма. А вчём профит встроенных миграций?
УдалитьВполне обоснованный вопль души, но, как говорил герой Леся Подэрэвянских, "яка цьому разумная альтернатива?". Где же та серебряная пуля которая которая спасет python разработчиков? Ответа на этот вопрос я не увидел.
ОтветитьУдалитьЛюби джанго!!!!
ОтветитьУдалитьhttp://youtu.be/LoIJ4W7kXiQ
> для js выражение типа:
ОтветитьУдалить> var foo = [{% for item in items %}{{ item.paren }}{% endfor %}]
> не работает, потому что js выполняется до рендеринга таких {%%} конструкций.
Вы что курили? JS рендерится ДО того, как рендерится шаблон на сервере? мдааааа
> вместо {{ list[5] }} -> {{ arr.5 }}
а почему нет? вас смущает точка? или вы видимо хотели в квадратные скобки вставить индекс-переменную? ага...
> для словарей {{ dict.foo }} не работает, да здравствует template tag
вы явно чтото курили
> нельзя сделать так {{ dir(foo) }}
в шаблнах логика представления, а не бизнес логика
> коменты {# #} неработают в несколько строк
ОтветитьУдалить{% comment %} че никак? печатать долго? используйте code templates
ORM и шаблонизатор можно заменить на что угодно. и jinja и алхимия - ради бога.
Сколько уже пишут контрибьютеры о таких людях, как вы, которые чтото там поносят, выступают.
Вам никто ничего не должен, поймите. Не нравится - не используйте. Хотя бы не захламляйте заведомо неверной инфой, типо "потому что js выполняется до рендеринга таких {%%} конструкций"
можно то оно можно и джинджу и алхимию - но пофигачатся совместимость с аппликухами.
Удалить> Entry.objects.all()[:1].get()
ОтветитьУдалитьЭто что за ересь?
Entry.objects.all()[:1] # может так?
Удалили бы вы пост а? и не позорились бы
> LeoK
УдалитьВ вас столько энергии, это так хорошо!
script>
var foo = ({% for item in foo %}'{{ item }}',{% endfor %}0);
alert(foo);
alert('{{foo}}');
/script>
{{ foo }}
Вы вообще знакомы с http?))) JS рендерится на клиенте, в браузере! Как могут СЕРВЕРНЫЕ шаблоны джанги рендерится после JS? (шок)
УдалитьНу ок, с анонимом не поспорить, можно я вычеркну этот пункт )
УдалитьДа тут одним пунктом не обойдётесь однозначно. тут надо все в утиль и выпрямить руки, извиняюсь за резкость
Удалитьтоже отказался от джанги - юзаю фласк и пирамиду. джанга удивительно топорна местами.
ОтветитьУдалитьорм страшнее атомной войны
шаблоны более чем средненькие
реально полезных аппликух хорошо если десяток.
я немного подпилил инит у пирамиды и стало просто отлично. близкий метод в этом блоге пробегал - у меня немного и ная структура
щас вот крупный проект на пирамиде с развидой админкой(dojo) - радует
но юниору есть свои бонусы
Удалить>бесполезный трейс и непонятная ошибка КРУТО!
УдалитьКак это бесполезный??? Всё же написано:
DoesNotExist: Page matching query does not exist.
Видимо есть у вас модель Page, и где то вы пытаетесь вызвать для нее метод get не подумав обернуть вызов в блок try/except искомая запись не была найдена, соответственно джанга сгенерировала исключение.
> джанга удивительно топорна местами
УдалитьУ вас напильник не того размера просто.
> реально полезных аппликух хорошо если десяток
У джанги сотни полезных аппликух включая девелоперские, рассылки, оплаты, автовризация, парсинг, комментарии, асинхронными задачи. Практически для всего что есть в открытом доступе есть 1,2,3 аппликухи.
>бесполезный трейс и непонятная ошибка КРУТО!
По мне так тоже все ясно, во въю пытается сделать get по несуществующим параметрам, идем во въю и смотрим что там происходит.
>File "/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py", line 157, in tree_json_view
node = self.model.objects.get(id=node_id)
вот прямо написано на чем поломалось
> анон
Удалитьу вас очень правильное направление мышления, осебенно про try/except, но к сожалению не завершенное. То что какой то get где то там что то видимо изза неподумав исключил потомушта get. Это так оно, но где чё править то?
> node = self.model.objects.get(id=node_id)
> вот прямо написано на чем поломалось
или вот прямо здесь return self.get_query_set().get(*args, **kwargs)
илиили здесь self.model._meta.object_name)
закончите свой ход мыслей(репа с кодом есть)
я же вам помогу таким примером:
1) есть такой апп django-filebrowser, добавьте в нем объект и допишите в начале пути к файлу "/", ну например так "uploads/foo.jpg" -> "/uploads/foo.jpg"
2) предайте объект в шаблон и напишите следующее img src="{% version foo_obj.file 'small' %}" />
3) далее появится понятный трейс с ошибкой:
Attempted access to '/uploads/foo.jpg' denied
Если не знать 1 пункт и некие секреты посвящённых "контрибьюторами", то может возникнуть много вопросов что означает "Попытка доступа". Посмотрим откуда это исключение, а оно из django/core/files/storage.py которого в понятном трейсе нет.
функция:
def path(self, name):
----try:
--------path = safe_join(self.location, name)
----except ValueError:
--------raise SuspiciousOperation("Attempted access to '%s' denied." % name)
----return os.path.normpath(path)
далее нужно закоментить try/except и получим новые подробности.. а знаете как я это нашел? при помощи pdb, удачи вам.
Просто у Дмитрия случился разрыв шаблона :) После пирамиды, джинджа и алхимии. Джанго, нативные темплейты и ОРМ.
ОтветитьУдалить> То что какой то get где то там
ОтветитьУдалитьЭто не какой-то гет где то там, а вполне конкретный в конкретной view. Надо просто знать что DoesNotExists генерится им. Точно так же как dict выкидывает KeyError. Информация конкрентая где и что сломалось осталось пойти и понять почему.
> raise SuspiciousOperation("Attempted access to '%s' denied." % name)
Выброшен кастомный Exception. Лезешь по странному пути, и путь. Какую инфу вам надо предоставить чтобы было понятнее? Программист знал и предусмотрел что здесь могут быть некорректные данные и предупреждает об этом. Дескать проверь что там у тебя. При этом выше это можно перехватить и не ломать все приложение, А отключить то место где это используется. И это правильно. Ошибка не критическая, остальная функциональность должна работать.
> Информация конкрентая где и что сломалось осталось пойти и понять почему.
УдалитьА помните ту серию из саучпарка где гномы воруют трусы. У них были замечательные аргументы...
где чё править то, что бы заработало?
> где чё править то, что бы заработало?
УдалитьВы как шестилетка, дайте и быстро и чтобы работало.
Вам указано, сломалось здесь, почему сломалось, разбирайтесь. Я стесняюсь спросить, а как вообще чинить баги? Ну если ни идти к источнику проблемы?
> ув. ping
Удалитьрешение проблемы я знаю, но путь к источнику проблемы - это аникей технология(с чем я в пирамиде, пайлонсе или web2py не сталкивался). Хотелось что бы вы нашли проблему и описали свою последовательность действий (как это делается правильно).