Memorize

Полезные Javascript функции и приемы

Полезные Javascript функции и приемы

Решил собрать в одном месте часто используемые функции и приемы Javascript, которые применяются при создании сайтов. Большинство из них в той или иной мере относятся к популярной библиотеке jQuery, но есть и на чистом Javascript.

React JS: Загрузка файла на сервер

Продолжаем заметки про React JS. Сегодня речь о том, как загрузить на сервер файл вместе с кучей другой информации.

В интернете в основном описывается способ загрузки только одного файла. Поэтому себе в заметку как отправить одновременно и файл и данные. Для этого нужно использовать класс FormData, в который добавляется объект файла и данные.

React JS: событие onChange и автокомплит в Safari

В замечательном Javascript фреймворке React, кроме множества плюсов, есть один неожиданный и неприятный минус. Если при заполнении поля ввода используется автокомплит браузера Safari, то событие onChange не срабатывает. Например в коде:

render: function() {
    return (
        <input type="text" value={this.state.value} onChange={this.onInputChange} />
    );
}

метод this.onInputChange не будет вызван, если пользователь при вводе в текстовое поле выберет значение из автокомпликта браузера Safari.

Одно из решений, которое встречается в интернете - это использование refs ссылок. Но у меня он не сработал. В моем случае помогло использование onBlur события.

...
render: function() {
    return (
        <input type="text" value={this.state.value} onChange={this.onInputChange} onBlur={this.onInputChange} />
    );
}

Link plugin for TinyMCE 4

В стандартной конфигурации плагин для вставки линка в редакторе TinyMCE 4 не позволяет назначить CSS класс для создаваемого линка. Чтоб исправить это упущение достаточно лишь немного изменить Javascript код плагина, добавив новое поле и его обработку.

Тестирование сообщений в Django

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

Django ORM и Group By

Формирование сложных запросов с использованием Django ORM без написания SQL кода может быть не всегда очевидной вещью. Например, подсчет количества одинаковых записей в базе, отфильтрованных согласно определенному критерию. В SQL это решается просто с использованием GROUP BY и COUNT(). В Django ORM для этого имеются агрегации.

Flask, SQLAlchemy и Mysql

Переписывая сайт с картами Шри Ланки, столкнулся с забавной ошибкой Mysql: “Server has gone away”. Причем возникала она довольно часто. Сайт написан на Flask (python). Для работы с Mysql используется SQLAlchemy. Не сталкиваясь ранее с подобными вещами, немного удивился - с чего это Mysql отваливается. Как оказалось соединение просто не обновляется.

Решение - использовать пул соединений, который периодически обновляется. Для этого достаточно указать в настройках проекта количество соединений (SQLALCHEMY_POOL_SIZE) и время их жизни (SQLALCHEMY_POOL_RECYCLE), после которого они обновляются.

app = Flask(__name__)
app.config["SQLALCHEMY_POOL_SIZE"] = 5
app.config["SQLALCHEMY_POOL_TIMEOUT"] = 20
app.config["SQLALCHEMY_POOL_RECYCLE"] = 60

В данном примере пул состоит из 5 соединений, которые обновляются через 60 сек.

Spree: Напоминание об оплате

Возникла необходимось в нашем аюрведическом интернет-магазине SpiceGarden.ru сделать напоминание об оплате заказа. Пользователи не редко делают заказ и забывают или тянут с оплатой. Поэтому решили их ограничит всего 5 днями для оплаты. Потом заказ аннулируется.

Сам магазин построен на базе Spree (оно же в свою очередь есть ни что иное как Ruby On Rails). Поэтому добавление такого функционала не представляет ничего сложного. Буквально несколько шагов.

Сложные запросы в Django ORM

Задача сделать выборку списка продуктов из базы данных, цена которых находиться в некотором диапазоне, задаваемом пользователем. Сложность заключается в том, что в базе цены хранятся в различных валютах. Нет, хранить в одной валюте не подходит, т.к. курсы меняются, а пользователи из разных стран… И им удобнее оперировать со своей валютой. Итак. Поскольку кроме этого имеются еще куча фильтров для того же списка, то отказываемся от raw sql. Воспользуемся объектом Q (django.db.models.Q) из Django ORM. from django.db.models import Q

Product.objects.filter(
    Q(currency="EUR") & Q(price__gte=price_min_eur) |
    Q(currency="USD") & Q(price__gte=price_min_usd) |
    Q(currency="EUR") & Q(price__lte=price_max_eur) |
    Q(currency="USD") & Q(price__lte=price_max_usd))

В результате получаем:

SELECT *
FROM products
WHERE (currency="EUR" AND price>=%s) OR
      (currency="USD" AND price>=%s) OR
      (currency="EUR" AND price<=%s) OR
      (currency="USD" AND price<=%s)

Тестирование и South

Если в проекте используется система миграций South, то при тестировании проекта Django каждый раз прогоняет все миграции. Это занимает достаточно времени. Для отключения этого достаточно выставить в settings.py переменные:

SKIP_SOUTH_TESTS = True
SOUTH_TESTS_MIGRATE = False

Первая отключает тесты самого South. Вторая - миграции при прогоне собственных тестов. Т.е. Django будет сразу создавать актуальную структуру базы данных.