Debian, AngularJS, Django, Python

Делюсь опытом в описанных технологиях. Блог в первую очередь выполняет роль памяток для меня самого.

CSRFToken в Angular 1.4

В новом Angular 1.4 одно из приятных изменений - возможность задавать куку и заголовок для CSRF-токена. Раньше делали так:

angular.module('app', ['ngCookies']).run(['$http', '$cookies', function($http, $cookies){
    var token = $cookies.csrftoken;
    $http.defaults.headers.common['X-CSRFToken'] = token;
    $http.defaults.headers.post['X-CSRFToken'] = token;
}]);

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

angular.module('app', []).config(['$httpProvider', function($httpProvider){
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

Оригинальная документация - здесь. Проверял работу на Django 1.8.

EMACS - начало

Введение

Я не буду здесь рассказывать в деталях, чем плоха та или иная IDE или чем мне не угодили VIM и Sublime Text. Начнём лучше с того, чем EMACS хорош.

EMACS хорош в первую очередь тем, что это не просто текстовый редактор, а настоящий конструктор, из которого можно сделать как полноценную IDE для разработки практически на любом языке, так и издательскую систему или текстовый процессор. Основная фишка - возможность расширять возможности редактора путём написания сценариев на языке EMACS Lisp. К счастью, всё уже написано до нас, и лично мне ни разу не приходилось писать что-то своё, однако при этом я смог превратить EMACS в IDE для WEB- и Python-разработки. Да, эту статью я тоже пишу в нём.

Во-вторых, он быстр. Он не требует JRE для своей работы, написан на C и EMACS Lisp, запускается и работает очень быстро.

Это свободное ПО, что для обычного российского пользователя означает как раз "Free beer".

Он не перегружен меню, диалоговыми окнами, кучей разных панелей и т.д. Лаконичный интерфейс легко может быть расширен или сведён к пугающему минимализму - выбор за вами.

Огромная база готовых пакетов. Там есть практически всё, что нужно, от поддержки редких языков до веб-браузера и игр. Серьёзно!

Установка

Установка в Windows предельно проста - нужно зайти на этот сайт и скачать архив с последней версией. Распаковываем её в любое нужное место, находим в каталоге bin файл runemacs.exe и создаём для него ярлык на Рабочем столе.

Установка в Linux может быть чуть сложнее. Как правило, в Debian и Ubuntu LTS идёт устаревшая версия дистрибутива. Я рекомендую использовать не ниже 24.0, в противном случае часть пакетов (можно считать их плагинами) не будет работать. Если в официальном репозитории слишком старая версия, придётся собирать EMACS из исходных кодов, что заслуживает отдельной статьи. Здесь на этом останавливаться не буду.

Помимо самого EMACS необходимо иметь в системе установленную систему контроля версий Git. Пользователи Windows могут скачать здесь.

Комбинации клавиш

Оригинальные комбинации клавиш EMACS устарели. Нажимать [Ctrl] (в любом руководстве по EMACS эта клавиша обозначается как [C]) мизинцем неудобно. Когда-то [Ctrl] располагался на месте сегодняшнего [Alt], и пользоваться им было удобно, но времена мэйнфреймов давно прошли... Подробный разбор того, почему комбинации клавиш в EMACS такие, какие есть, и почему это плохо, производится здесь [EN]. Нет смысла изучать дефолтные настройки комбинаций клавиш, всё равно придётся потом переучитваться. Однако, в экстренных ситуациях может пригодиться как минимум две команды:

Комбинация Действие
[M-X] Вход в минибуфер для ввода команд
[C-X, C-C] Завершение работы редатора

После установки и активации пакета ergoemacs-mode комбинации клавиш будут переопределены. Рекомендую сделать это как можно быстрее, т.к. отвыкнуть от Ctrl+X, Ctrl+C и Ctrl+V очень тяжело, да и нет смысла этого делать.

Терминология

Буфер - аналог вкладки с документом в других тектовых редакторах и IDE. Так же это область, куда выводятся сообщения плагинов или самого редактора.

Минибуфер - самый маленький буфер, расположенный в нижней части окна EMACS. В него вводятся различные команды. Для входа в него следует использовать комбинацию клавиш [M-X] без установленного и включенного пакета ergoemacs-mode, либо [M-A]. После ввода команда запускается на выполнение нажатием [Enter] (в документации EMACS эта клавиша называется [RET])

Пакет - аналог плагина в других редаторах и IDE. Представляет собой сценарий или набор сценариев на языке EMACS Lisp. Часть пакетов является встроенной в редактор и поставляется вместе с ним, другие нужно скачивать из репозитриев. Отметим, что сейчас практически не используется способ установки пакета ручным клонированием репозитория с GitHub, далее под репозиториями будут пониматься специализированные хранилища пакетов.

Основной режим - определяет поведение EMACS для буфера. От этого режима зависит поведение различных клавиатурных комбинаций и набор доступных дейстий. Например, при написании этой статьи я использую web-mode, что даёт подсветку синтаксиса, автоматическое форматирование и применение Emmet для создания разметки. Основной режим может быть лишь один (имеется пакет, позволяющий включить сразу несколько основных режимов для одного буфера, но я им ни разу не пользовался).

Дополнительный режим - в то время, как основной режим может быть лишь один, дополнительных режимов можно включить столько, сколько нужно. Например, сюда относятся средства проверки орфографии, возможность автокомплита, автоформатирование кода и т.д. Большая часть пакетов для EMACS работает именно в дополнительном режиме.

Первоначальная настройка

Настройка EMACS может производиться как минимум двумя способами.

Настройка через правку файла конфигурации .emacs

Основной файл настроек EMACS называется .emacs и располагается в домашнем каталоге пользователя. В случае с Windows это как правило каталог вроде этого:

C:\Users\xPhoenix\AppData\Roaming\.emacs

Однако, можно переопределить домашний каталог для хранения настроек (важно понимать, что файл .emacs станет вашей прелессссстью, которую вы будете оберегать и лелеять), создав для текущего пользователя системную переменную под именем HOME, и указав в ней путь к каталогу, который следует считать домашним для EMACS (возможно, работает и для других программ из мира Linux, не проверял). У меня эта переменная выглядит так:

D:\xphoenix\

Кроме этого файла EMACS при работе создаёт так же создаёт в домашнем каталоге папку .emacs.d. В ней будут храниться скачанные пакеты, сниппеты, файлы .desktop и т.д. Не надо его удалять!

В любом случае, в наш .emacs следует поместить как минимум вот эти строки:

(defalias 'yes-or-no-p 'y-or-n-p)

(setq package-archives '(
                         ("elpy" . "http://jorgenschaefer.github.io/packages/")
                         ("gnu" . "http://elpa.gnu.org/packages/")
                         ;; ("melpa" . "http://melpa.milkbox.net/packages/")
                         ("melpa-stable" . "http://melpa-stable.milkbox.net/packages/")
                         ("org" . "http://orgmode.org/elpa/")
                         ))

Первая строка указыает на то, что вместо ввода строк yes и no в ответы на запросы системы можно просто нажать [y] или [n] соответственно.

Чуть ниже идёт указание репозиториев для поиска пакетов. Репозиторий MELPA очень популярен и в Интернете, вы будете часто встречать отсылки именно к нему, но использовать его опасно, т.к. пакеты туда попадают прямо из ветки master с GitHub. Поэтому я предпочитаю MELPA-STABLE. Пусть пакеты старые и их гораздо меньше, зато ничего не сломается при очередном обновлении. Впрочем, в редких случаях я пользуюсь MELPA, например, если пакета вообще нет в STABLE или тот, что есть, слишком старый. Так же существует репозиторий MARMELADE, но я не вижу смысла его использовать, т.к. некоторые пакеты в нём даже более старые, чем в MELPA-STABLE.

Настройка через customize

В одной из версий EMACS в стандартную поставку стал входить пакет sustomize. Просто выполните одноименную команду, и попадете в буфер, где будет поле для поиска и множество гиперссылок для перехода к нужным настройкам. Отмечу лишь, что настройка некоторых параметров через customize конфликтует с ручной правкой .emacs, однако, в ряде случаев является более удобной. Некоторые параметры EMACS можно настроить только ручным редактированием .emacs, в customize вы просто не найдёте нужного раздела.

Установка пакетов

Указав в вашем .emacs репозитории так, как указано выше, перезапустите редактор (можно сделать и без перезапуска, но не буду усложнять) и выполните команду list-packages. Откроется буфер, содержащий список пакетов в доступных репозиториях. Выбор пакета для установки осуществляется нажатием клавиши [I], отмена выбора - [U], пометка на удаление - [D]. После того, как будет выбрано, что делать с пакетами, следует нажать клавишу X для запуска операций. EMACS установит и при необходимости выполнит компиляцию нужных пакетов.

Есть несколько пакетов, которые я настоятельно рекомендую к установке.

  • auto-complete - предназначение ясно из названия. Через него работают многие другие пакеты, например, jedi.
  • autopair - автоматически закрывает скобки
  • company - ещё одно средство для автокомплита, через него работают некоторые пакеты, которые не работают с auto-complete
  • emmet-mode - незаменимое средство для верстальщиков. Рекомендую ставить из MELPA, т.к. в STABLE очень старая версия, которая работает хуже и многого не умеет.
  • ergoemacs-mode - пакет, устанавливающий комбинации клавиш, удобные для использования людьми, а не Ричардом Столлманом. Подробное описание клавиш здесь.
  • flycheck - модуль проверки чего угодно на лету. На самом деле по-тихому вызывает имеющиеся в системе средства проверки и статического анализа кода. Имеет возможность конфигурирования того, какие средства и с какими параметрами следует использовать. Является более новым и прогрессивным в сравнении с загнивающим flymake.
  • jedi - автокомплит для Python-разработчиков. Настройка данного пакета достойна отдельной статьи.
  • js2-mode - расширенный по сравнению с js-mode режим правки JavaScript-кода. Ставить js3-mode не рекомендую, т.к. проект давно загнулся.
  • less-css-mode - не вижу смысла объяснять назначение данного пакета.
  • monokai - тема из Sublime Text 2, пожалуй, лучшая, что мне приходилось видеть.
  • neotree - порт плагина NerdTree из VIM, отображает слева (или справа, настраивается) дерево каталогов и файлов. Лучше ставить из MELPA.
  • rainbow-mode, rainbow-delimiters - в паре подсвечивают скобки и другие элементы разными цветами, позволяет легко находить ошибки типа "Забыл закрыть скобку".
  • web-beautify - доступен только из MELPA, позволяет автоматически форматировать JS, CSS и HTML-файлы. Для работы требует установленный в системе NodeJS и его пакет web-beautify.
  • web-mode - добавляет в EMACS возможность редактировать файлы XML, HTML, XHTML и др. Обеспечивает подсветку синтаксиса и т.д.

JavaScript и Object.defineProperty()

Хочу сказать пару слов о методе из ECMAScript 5, который называется Object.defineProperty().

Во-первых, он очень хорошо описан в разных источниках:

Во-вторых, можно же определять свойства у прототипа (о чём в указанных статьях ни слова)! К своему стыду замечу, что эта идея пришла мне в голову довольно поздно.

Пример использования

(function () {
    "use strict";
    var people1, people2;

    function Item(firstname, lastname){
        this.firstname = firstname;
        this.lastname = lastname;
    }

    Object.defineProperty(Item.prototype, 'fullname', {
        get: function(){
            return this.firstname + ' ' + this.lastname;
        },
        writable: false
    });

    people1 = new Item("Сухомлинов", "Сергей");
    people2 = new Item("Дунаевский", "Максим");

    console.log(people1.fullname); //Сухомлинов Сергей
    console.log(people2.fullname); //Дунаевский Максим
}(this));

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

Получение аргументов URL в сериализаторах Django REST Framework

Небольшая заметка о том, как в ClassBasedView Django REST Framework получить значение параметра из URL.

Допустим, наши URL сконфигурированы таким образом:

urls.py
from django.conf.urls import url

from .api import ArticleListCreateView
from .api import ArticleDetailView
from .api import ArticleCommentListCreateView

urlpatterns = [
    url(r'^article/$', ArticleListCreateView.as_view()),
    url(r'^article/((\d+))/$', ArticleDetailView.as_view()),
    url(r'^article/((\d+))/comment/$', ArticleCommentListCreateView.as_view()),
]

Делать какую-либо работу для вида ArticleDetailView не приходится - достаточно создать класс, унаследованный от RetrieveUpdateDestroyAPIView.

Получить доступ к параметру pk в виде не проблема, достаточно переопределить метод get_queryset(), например, так:

article.comment.api.py
from rest_framework.generics import RetrieveUpdateDestroyAPIView

from article.models import Article
from .models import ArticleComment


class ArticleCommentListCreateView(RetrieveUpdateDestroyAPIView):

    model = ArticleComment

    # Возвращаем только комментарии к указанной статье
    def get_queryset(self):
        return ArticleComment.objects.filter(article=self.kwargs['pk])

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return ArticleCommentReadSerializer
        return ArticleCommentWriteSerializer

А вот получить в сериализаторе значение параметра pk можно не вполне очевидным способом:

serializers.py
from django.shortcuts import get_object_or_404
from rest_framework import serializers

from .models import ArticleComment
from article.models import Article

# ArticleReadSerializer не описан из-за своей простоты

class ArticleCommentWriteSerializer(serializers.ModelSerializer):

    article = serializers.PrimaryKeyRelatedField(
        queryset=Article.objects.all(),
        default=None
    )

    # Заменяем валидатор поля article таким образом, чтобы всегда
    # подставлялось значение из URL
    def validate_article(self, value):
        # Кто бы мог подумать???
        article_id = self.context['view'].kwargs['pk']
        return get_object_or_404(Article, pk=article_id)

    class Meta:
        model = ArticleComment

Расширение контроллеров в Angular

Краткое содержание

В статье рассказывается о том, как в Angular можно реализовать наследование контроллеров.

Суть проблемы

Мне приходится писать довольно много кода на Angular, при этом заметил, что от контроллера к контроллеру меняются, порой, лишь незначительные части. Например, везде, где я использую ngInfiniteScroll, в $scope приходится помещать переменные allLoaded и loading, а так же обработчик loadMore(), выполняющий загрузку новых элементов. По незнанаю, приходилось многократно дублировать практически одинаковый код. Однако, один из пользователей StackOverflow нашёл очень хорошее решение данной проблемы.

Решение

Решение оказалось на удивление простым и заключается в использовании сервиса $controller.

BaseClass.js
(function (A){
    "use strict";
    // Базовый контроллер, который содержит код, общий для всех других контроллеров,
    // которые будут наследоваться от него
    A.module('App').controller('ListController', ['$scope', function($scope){
        $scope.allLoaded = false;
        $scope.items = [];
        $scope.loading = false;

        $scope.loadMore = function(){
            if ($scope.loading){
                return;
            } 
            // Тут какая-то работа по загрузке данных
        };

        $scope.refresh = function(noPlease){
            if (noPlease){
                return;
            }
            $scope.items.length = 0; // Более правильное решение, нежели $scope.items = [];
                                     // т.к. в этом случае сохраняется ссылка на оригинальный
                                     // объект
        };    
    }]);
}(this.angular));
ChildClass.js
(function(A){
    "use strict";
    A.module('App').controller('UserListController', [ '$controller', '$scope', function($controller, $scope){

            // Расширяем контроллер
            $controller('ListController', {
                $scope: $scope
            });

            // Теперь можно собственные свойства описывать
        }]);
}(this.angular));

Схема БД или таблицы в PostgreSQL

Всё время забываю, как в PostgreSQL сделать дамп схемы БД, без данных. Команда на удивление проста:

pg_dump -s -d %DATABASE_NAME% -U %USER_NAME% > %FILE_NAME%
Параметр Назначение
-s Ключ указывает на то, что нужно сделать копию только схемы БД
-d Ключ, задающий имя БД, с которой нужно работать.
-U Ключ, указывающий пользователя, от имени которого будет делаться копия схемы. Пользователь должен иметь доступ хотя бы на чтение данной БД.
%FILE_NAME% Файл, в который следует сохранить вывод. В противном случае вся схема будет выведена на экран.

А если вместо -s указать -t и потом имя таблицы, то будет снята схема только с неё, например:

pg_dump -d project -U xphoenix -t auth_users > auth_users_shema.sql

Проблемы с кириллицей в имени пользователя Windows

При использовании Atom столкнулся с тем, что некоторые плагины отказывались работать, выдавая странные сообщения в консоль. Сначала я решал проблему тем, что правил переменную PATH на уровне системы и на уровне пользователя, однако, это особого эффекта не имело, т.к. стоило только поставить более новую версию io.js, как PATH тут же сбрасывалась к примерно такому виду:

    C:\Python34\;C:\Python34\Scripts;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\Git\cmd;C:\Program Files (x86)\iojs\;C:\Users\%30o$321\AppData\Roaming\npm

Из этого видно, что портится путь к текущей системной папке пользователя. Изменение свойств папок "Видео", "Изображения", "Документы" и т.д. тут не может ничем помочь. Я использую учётную запись Microsoft со всеми её удобствами вроде OneDrive, WindowsPhone и т.д. и отказываться от неё в пользу локальной учётной записи не хотел (не за то деньги плачены). Поиск привёл меня к решению.

На первом этапе нам нужно создать дополнительную учётную запись типа "Администратор". Способ создания значения не имеет, я рекомендую через "Панель управления" (пользователи Windows 8.1 непрофессиональной редакции выбора не имеют). Теперь нужно загрузиться в безопасном режиме и войти в систему под новосозданной учётной записью. После этого нужно запустить редактор реестра - Regedit. Следует открыть раздел реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList. В нём содержится несколько подразделов. Если щёлкнуть на одном из них, то появится список ключей, одним из которых будет ProfileImagePath. Заменяем имеющееся значение на нужное, например, вот так:

C:\Users\Максим -> C:\Users\xPhoenix

Так же следует обязательно переименовать имеющуюся папку профиля. После этого следует перезагрузить компьютер и при необходимости удалить созданную ранее дополнительную учётную запись администратора.

Проблема с кириллицей в имени пользователя наблюдается и в некоторых других программах. Насколько помню, из-за неё среда MATLAB 7.5 вообще отказывалась сохранять файлы.