Архив метки: Django

Блог на Django. Часть 1 — установка

Всем привет, решил попробовать сделать блог на Django и рассказать «пошаговость» Вам. Первое и самое главное — без чего невозможно будет работать — это установить Python и Django. О совместимостях версий писать не буду так как все есть в гугле)

Итак начнем с установки Python-a. Так как у меня виндовс и к тому же 8.1 будет пробовать делать все под нее. Для того чтоб скачать свежую версию я воспользовался ссылкой https://www.python.org/downloads/ и на данный момент там есть версия 3.5.1, вот ее и возьму.

Во время установки я отметил галочкой пункт Add Python 3.5 to PATH, чтобы cmd его тоже распозновала.

Потом нажав Customize installtion ждем окончания установки.
Дальше нам надо установить Django, для этого переходим по ссылке https://www.djangoproject.com/download/ и в правой колонке есть ссылка для скачивания последнего релиза — ее и кликаем. Вы скачаете архив с которого нужно распаковать папку «Django-1.9.4» а потом в ее корне запустить команду python setup.py install .
Для того чтоб установить джанго я воспользовался ГИТовой консолью запустив ее с правами администратора и написал приведенную выше команду. Запуск консоли с правами администратора — обязателен !!!

Теперь проверим работоспособность нашего установленного Джанго. Для этого я выполнил в папке выше следующие команды…
в консоли запускаем python, а далее пишем следующие команды
>>> import django
>>> django.VERSION
(1, 9, 4, 'final', 0)
Если у вас отобразилась версия, поздравляю — вы установили все как надо.

Вот впринципе на этом данная статья может быть закончена, далее мы рассмотрим процесс настройки с БД. Хочу попробовать на postgreSQL, но а там как получится. А вообще выбор между MySQL & PostgreSQL.

Помогите с выбором БД, пишите в комментах какой отдать предпочтения.
Так же я в гит буду выкладывать все шаги разработки или же лучше выложить вконце один готовый вариант ?

Автор: Няшный Человек
Дата публикации: 2016-03-06T10:41:00.000+02:00

Почему я не люблю конфигурацию в django-style

Введение

Сегодня работал над добавлением в aiohttp.webсвойства scheme для request object.

Идея простая: отвечать что request.scheme "http" для HTTP запросов, иначе "https".

У меня есть правило: перед началом погляди как другие уже справились с этой задачей.

У создателей популярных библиотек есть большой опыт по преодолению неочевидных проблем, учиться у мастеров — полезно.

Так вышло что сегодня я смотрел код Django.

И было в том коде примерно такое:

@property
def scheme(self):
if settings.SECURE_PROXY_SSL_HEADER:
try:
header, value = settings.SECURE_PROXY_SSL_HEADER
except ValueError:
raise ImproperlyConfigured(
'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.'
)
if self.META.get(header, None) == value:
return 'https'
return 'http'

В целом очень хорошо: Django показала, как работать с HTTP и что делать если сервер расположен за HTTPS Reverse Proxy (Nginx, например).

В последнем случае я сконфигурирую Nginx чтобы он добавил несколько полезных HTTP HEADERS для HTTPS connection:

  proxy_set_header        Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

По X-Forwarded-Proto я пойму что это был HTTPS.

В целом стандартная и всем (надеюсь) известная процедура.

У aiohttp свободы чуть больше: оно может понять что сокет, по которому подключились напрямую, сам уже SSL — но это пригодно только если мы готовы выставить наш aiohttp сервер прямо в веб.

Куда чаще его прячут за Nginx, HAProxy или похожим reverse proxyи там уже работают с сертификататами, проксируя обычный HTTP connection.

В общем всё прекрасно: Nginx выставит X-Forwarded-Proto HTTP HEADER который будет или "http" или "https".

Django глянет на settings.SECURE_PROXY_SSL_HEADER и если там ("X-Forwarded-Proto", "https") то scheme тоже будет "https".

Очень грамотно сделано, мне нравится.

Проблема

Так почему я этот пост написал?

А потому что settings.SECURE_PROXY_SSL_HEADER может быть чем угодно — строкой, числом или ещё какой непотребной константой.

Проверка выполняется на момент получения request.scheme.

Нам, питонщикам, плевать на производительность в данном случае — на самом деле try/except обходится дешево и никак не отразится на работе сайта.

Беда в другом — ошибка неправильной конфигурации выявится не на этапе старта приложения а тогда, когда его выкатят в production.

У тестов будет свой правильный settings.py, а на production serverадмин чуть-чуть ошибётся.

И это тоже не слишком большая проблема — при ручном тестировании команда QA, наверное, обнаружит ошибку очень быстро. Или на следующее утро — тут уж зависит от того как техроцесс построен.

А теперь представьте что вы ошиблись в другой настройке. Очень редко используемой, но при этом важной.

Решение

Проблему вроде бы можно выявить рано, перестроив процесс запуска программы.

Для начала нужно отказаться от использования общего конфига в API.

Строить код библиотеки так, чтобы она никогда не лезла в settings.py(это и Flask касается если что).

Пусть все нужные классы принимают конфигурационные параметры явно, прямо в конструкторах.

Тогда можно быстро понять, что формат параметра не тот или IP address недоступен.

Разделение на этапы:

  • чтение конфига, анализ его и подготовка приложения к работе
  • запуск и работа

помогает избежать досадных недоразумений.

Плюс, к тому же, на явном этапе подготовки к старту можно позволить себе довольно дорогостоящие проверки на корректное функционирование системы (послать PING чтобы убедится что Redis живой, например).

Автор: Andrew Svetlov

South. Документация. Конвертирование приложения

Конвертирование приложения

Конвертировать приложение для  использования South очень легко:
  • Отредактируйте ваш settings.py и укажите south в INSTALLED_APPS (мы предполагаем, что Вы установили south туда, куда нужно)
  • Запустите ./manage.py syncdb для того, чтобы загрузить таблицу South в БД. Обратите внимание, что теперь syncdb не такой как раньше — South его изменил
  • Запустите ./manage.py convert_to_south myapp — South автоматически подготовит и выполнит первую миграцию
Обратите внимание, что Вы должны конвертировать приложение до того, как Вы сделаете изменения; South обнаруживает изменения по сравнению с замороженным состоянием последней миграции, так что он не сможет обнаружить изменения, сделанные до конвертирования в South.

Конвертирование других установок и серверов

Команда convert_to_south рабоатет целиком на первой машине, на которой Вы его запустите. После того, как Вы подтвердите начальную миграцию, которую он сделал, в системе управления версиями, Вы должны запустить ./manage.py migrate myapp 0001 —fake на всех машинах, которые содержат копию кода (убедитесь, что они имеют обновлённый код и схему).
(Для тех, кому интересно, это нужно поскольку начальная миграция, которую делает convert_to_south, проверит и создат все существующие таблицы; вместо этого Вы говорите South, что это уже сделано при помощи —fake, так что следующие миграции будут применены корректно).
Помните, что новые установки кода после этого не потребуют этих шагов, Вам нужно будет лишь сделать syncdb а, затем, провести нормальную миграцию.

Автор: Ishayahu Lastov

Документация South — Перевод. Часть 4: Пользовательские поля

В South 0.7 появилось радикальное отличие от предыдущих версий. До сих пор, если у Вас было пользовательское поле, South пытался использовать очень сильное колдунство для того, чтобы определить, как «замораживать» это поле,так что оно могло быть отклонено в миграции (и это было не очень красивое колдунство — комбинация регулярных выражений и модуля parser).
Хотя это, как ни странно, работало хорошо у большинства пользователей, тем не менее в некоторых случаях что-то шло не так, и Вы даже не знали об этом, пока не проходило несколько недель… В целях большей вменяемости и меньшей магии теперь Вы должны указать South как замораживать ваши пользовательские поля.
Не волнуйтесь, это достаточно просто и Вам надо сделать это лишь раз для каждого поля.

Наше поле

В этом примере мы будем использовать пользовательское поле, которое хранит список тегов в БД. Мы будем просто хранить их в TEXT колонке с некоторым разделителем (по умолчанию мы будем использовать |, но можно использовать и любой другой символ — просто передайте его как именованный аргумент).
Вот класс этого поля. Я разместил его в appname/fields.py (более подробно о создании собственных полей смотрите документацию Django):
 from django.db import models

class TagField(models.TextField):

description = "Stores tags in a single database column."

__metaclass__ = models.SubfieldBase

def __init__(self, delimiter="|", *args, **kwargs):
self.delimiter = delimiter
super(TagField, self).__init__(*args, **kwargs)

def to_python(self, value):
# If it's already a list, leave it
if isinstance(value, list):
return value

# Otherwise, split by delimiter
return value.split(self.delimiter)

def get_prep_value(self, value):
return self.delimiter.join(value)
Для того, чтобы рассказать South об этом поле, Вам нужно сообщить две вещи: что этот класс можно использовать и как получить именованный аргумент из экземпляра поля.

Именованные аргументы

South замораживает поля сохраняя их имя класса и модуль (таким образом можно получить сам класс поля) и именованные аргументы, которые Вы используете для конкретного экземпляра класса (например, CharField(max_lengh=50) не то же самое, что CharField(max_lengh=150)).
Так как Python не хранит именованные аргументы, переданные конструктору класса, South должен восстановить их уже из полученного экземпляра класса. Например, мы знаем что значение именованного аргумента max_length класса CharField хранится в атрибуте self.max_lenght, тогда как ForeignKeys хранят свои именованные аргументы to (определяющие модель, на которую они указывают, так же первый позиционный аргумент) как self.rel.to.
South знает все эти правила для стандартных полей Django, но Вам необходимо объяснить все это касательно своих полей. Хорошая новость состоит в том, что South может отследить цепочку наследования, так что о полях, определённых в родительских классах говорить заново в дочерних классах не надо (или надо сообщить только о тех дополнительных именованных аргументах, которых не было в родительском классе).
В нашем примере мы определяем только один дополнительный именованный аргумент — delimiter. Вот код, который мы добавляем для того, чтобы South мог обработать наше новое поле. Чуть позже мы его объясним:

 from south.modelsinspector import add_introspection_rules
add_introspection_rules([
(
[TagField], # Класс(ы) к которым это применимо
[], # позиционные аргументы (не используется)
{ # именованные аргументы
"delimiter": ["delimiter", {"default": "|"}],
},
),
], ["^southtut.fields.TagField"])

Как Вы можете видеть, для того, чтобы рассказать South о вашем новом поле Вам нужно вызвать функцию south.modelsinspector.add_introspection_rules. Вы должны разместить этот код рядом с определением вашего поля. Так как последнее, что Вы хотели бы — это импортировать поле, но чтобы этот код не был выполнен.
add_introspection_rules принимает два аргумента: список правил и список регулярных выражений. Список регулярных выражений используется South для того чтобы понять, можно ли исследовать это поле. Просто иметь правило, которое подходит для поля недостаточно, так как наследование правил подразумевает, что любой пользовательский класс поля будет иметь хотя бы одно правило, под которое он подпадает (
опять — «(as they will inherit from «Field«, if not something more specificlike «CharField«), and some custom fields can get by with only those inherited rules (more on that shortly)«).
Первый аргумент — список правил. Каждое правило — это кортеж (или список) с тремя элементами:

  1. Список классов к которым применимы эти правила. Практически наверняка у Вас будет тут только одно поле, например, то, про которое мы сейчас говорим.
  2. Спецификация позиционных аргументов. Практически наверняка будет пустым списком — []
  3. Спецификация именованных аргументов: это словарь, где ключ — имя аргумента, а значение — список или кортеж (имя_аргумента, опции)
Имя аргумента определяет место, где может быть найдено значение именованного аргумента — в нашем случае это delimiter, так как значение именованного аргумента мы храним в self.delimiter. (Если бы это было правило ForeignKey, то тут бы стояло rel.to)
Опции- это словарь. Вы можете безопасно оставить этот аргумент пустым, но можно и использовать его для определения значения по умолчанию и если South обнаружит значение, соответствующее этому, то он не будет указывать это ключевое слово в определении заморозки, что позволит это определение сделать более простым и читаемым.

Простые наследования

Если ваше поле наследуется напрямую из другого поля Django, например, CharField, и не добавляет других именованных аргументов, то Вам не нужно добавлять какие-либо правила в add_introspection_rules. Вы можете просто сказать South, что с этим полем всё в порядке:
 class UpperCaseField(models.TextField):
"Убеждаемся, что содержимое всегда в верхнем регистре."

def to_python(self, value):
return value.upper()

def get_prep_value(self, value):
return value.upper()

from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^southtut.fields.UpperCaseField"])

Больше информации

Более подробную документацию на эту тему можно обнаружить в разделе Extending introspection.

Автор: Ishayahu Lastov

Django 1.5 и Python 3 (Перевод)

Django 1.5 уже «полностью» поддерживает Python 3, как минимум с технической точки зрения. Поддержка реализована, проверена и работает. Я планирую поместить свой сайт на Django 1.5 / Python 3.3 уже в этом году. Так что в этом смысле всё «готово».
Однако, это не значит, что я рекомендую делать это другим.
У мы даём серьёзные обещания обратной совместимости и мы ещё не на 100% хорошо соответствуем Python 3 API. Есть маленькая (не нулевая) вероятность, что надо будет что-то изменить между 1.5 и 1.6; и мы бы хотели сохранить возможность обратной несовместимости (для Python 3).
Кроме того, есть маленькая (но, опять же, не нулевая) вероятность что есть 1-3 серьёзрых бага в поддержке Python 3 и мы не хотим, чтобы люди с этим столкнулись.
Наконец, значительная часть «хорошести» Django — сторонние приложения, многие из которых не поддерживают ещё Python 3. И это серьёзная проблема для Django / Py3, так как многие сайты используют большое количество сторонних приложений. Так что перед переходом на Python 3 Вы должны решить для себя вопрос: «Готов ли я отказаться от этого приложения или готов портировать его на Python 3 и внести патч?»
В случае моего сайта я к этому готов. Я достаточно хорошо знаю Django, чтобы не бояться потенциальных багов и обратной несовместимости и я могу заняться патчами для Python 3.
Но к большинству пользователей это не относится, так что я надеюсь, что большая часть пользователей Django дождётся 1.6 перед тем, как начать использовать Python 3.
У нас пока нет твёрдых сроков. Я думаю, что 1.6 можно ждать где-то через 6-9 месяцев, но это зависит от слишком многих факторов. Реально срок может быть и год и 3-4 месяца. Увидим 🙂

Автор: Ishayahu Lastov

Документация South — Перевод. Часть 3: Дополнительные команды и миграция данных

Последовательная работа с миграцией

Иногда Вы можете обнаружить, что изменения в модели требуют некоторых улучшений. Предположим, Вы определили модель:
 class Group(models.Model):
name = models.TextField(verbose_name="Name")
facebook_page__id = models.CharField(max_length=255)

и вы создали и применили миграцию:
 ./manage.py schemamigration southtut --auto
./manage.py migrate southtut

После чего Вы обнаружили, что: name на самом деле должно быть CharField, а не TextField, а facebook_page__id содержит двойное подчёркивание, а не одинарное, как Вы хотели. Тогда можно исправить эти проблемы и выполнить:
  ./manage.py schemamigration southtut --auto --update
+ Added model southtut.Group
Migration to be updated, 0026_auto__add_group, is already applied, rolling it back now...
previous_migration: 0025_auto__foo (applied: 2012-05-25 21:20:47)
Running migrations for southtut:
- Migrating backwards to just after 0025_auto__foo.
< partner:0026_auto__add_group
Updated 0026_auto__add_group.py. You can now apply this migration with: ./manage.py migrate southtut

Что произошло? South удалил последнюю миграцию, которая создала модель, но в которой были ошибки, и заменил её новой миграцией, которая уже не содержит этих ошибок.
Стоит так же обратить внимание на то, что та миграция, которая была уже применена, была автоматически откачена назад. Вы можете теперь применить последнюю версию миграции чтобы получить правильный вариант модели:
 ./manage.py migrate southtut

Можно повторять этот процесс так часто, как требуется, внося необходимые изменения и в итоге получить лишь одну миграцию, где будут учтены все ваши пожелания.

Просмотр текущих миграций

Часто бывает полезно посмотреть, какие миграции были применены на данный момент и какие доступны для использования. Для этой причины есть команда ./manage.py migrate —list. Вот результат выполнения этой команды для нашего проекта:
 $ ./manage.py migrate --list

southtut
(*) 0001_initial
(*) 0002_auto__add_field_knight_dances_whenever_able
(*) 0003_auto__add_field_knight_shrubberies
(*) 0004_auto__add_unique_knight_name
Наличие звёздочки (*) говорит о том, что миграция была применена, а отсутствие — что ещё нет. Соответственно, чтобы увидеть только те миграции, которые были применены, воспользуйтесь командой ./manage.py migrate —list | grep -v «*»
Если у Вас есть несколько приложений, работающих при помощи миграций, то можно задать и имя приложения для просмотра миграций только для него.

Перенос данных

До сих пор мы говорили только о «миграции схемы», то есть об изменении колонок и индексов. Но есть и другой тип миграции — «миграция данных».
Миграция данных используется для изменения данных, сохранённых в вашей БД для приведения их в соответствие с новой схемой или предоставления новых возможностей. Например, если Вы сохраняете пароль в виде обычного текста (если это и правда так, то немедленно исправьте это. НЕМЕДЛЕННО!!!) и теперь хотите хранить его в виде солёного хеша, то Вам могут потребоваться эти три шага (причём каждый шаг — это одна миграция):
  • Создаём две новые колонки: password_salt и password_hash (миграция схемы)
  • Используя содержимое колонки password вычисляем соль и хеш для каждого пользователя (миграция данных)
  • Удаляем старую колонку password (миграция схемы)
Как провести первую и последнюю миграцию Вы уже и сами знаете: изменяете models.py и запускаете ./manage.py schemamigration —auto myapp. Главное не удаляйте сразу колонку password, так как нам понадобятся данные из неё для заполнения двух новых колонок (всегда, всегда делайте бакуп вашей БД перед тем, как сделать любое изменение, которое может попортить данные. Потому что однажды именно так и будет).
Давайте возьмём реальный пример. Создадим новое приложение под именем southtut2. Добавим его в INSTALLED_APS и создадим его модель:
 from django.db import models

class User(models.Model):

username = models.CharField(max_length=255)
password = models.CharField(max_length=60)
name = models.TextField()
Сде