• Как правильно сидеть?

    neatsoft
    @neatsoft
    Life is too short for bad software
    1. Биде либо гигиенический душ для профилактики геморроя. Это единственное что может уберечь от выпадания кишок представителя сидячей профессии в долгосрочной перспективе.
    2. Силовые тренировки на спину раз в неделю. Достаточно курсами по 1-2 месяца раз в пол-года, но лучше постоянно.
    3. Защитный коврик на пол - www.ikea.com/ru/ru/catalog/products/44881100
    4. Табуретка или стул с твёрдым сидением (отлично подходят кухонные стулья, обтянутые толстой кожей). Не шатающийся, крепкий стол (чтобы на него можно было безбоязненно облокачиваться). Высота сидения должна соответствовать длине голени, высота стола - высоте локтя в сидячем положении. Монитор с диагональю 27-32 дюйма - https://market.yandex.ru/product/13873246 (лучше три - помимо дополнительного удобства это заставляет крутить головой). Центр монитора ниже уровня глаз.

    59d319b619131855831375.jpeg

    Правильное сидячее рабочее место должно вынуждать двигаться, поэтому сидение должно быть устойчивым, и не иметь одного явно выраженного удобного положения тела. Коленные стулья фиксируют ноги, а "эргономичные" кресла слишком подвижны, и не дают возможности кардинально менять позу. Обычный стул позволяет разминаться не отрываясь от работы - наклониться вбок / вперед / назад (зацепившись лодыжками за передние ножки) не опасаясь упасть, и заставляет как минимум раз в час встать и пройтись.

    ps. Стаж сидячей работы больше 20 лет, до сих пор иногда случаются запилы по 15-20 часов (при входе в поток). Перепробовал много разных кресел, лишь кухонный стул позволил почувствовать себя по-настоящему комфортно.
    pps. Перестаньте работать водителем. Вождение автомобиля - ещё худшая нагрузка для тела чем сидячая работа. Если есть возможность, нужно заменить его ходьбой, если нет - пользуйтесь велосипедом, такси, или общественным транспортом.
    ppps. Перестаньте работать грузчиком. Переноска тяжёлых пакетов и коробок с продуктами - это не тренировка, а ещё один способ поиздеваться над своим телом. Для этого есть специальные люди (интернет магазины с доставкой продуктов на дом).
    Ответ написан
  • Как спроектировать веб-интерфейс управления процессами?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Django, celery, celery beat и/или Django Channels. Скрипт будет исполняться в отдельном воркере.
    Для очень простых случаев иногда подходит Django Background Tasks или cron + management commands, но лучше сразу выбрать одно из "взрослых" решений.
    Ответ написан
    3 комментария
  • Есть идеи, как реализовать создание/хранение приходной/расходной накладной на Django?

    neatsoft
    @neatsoft
    Life is too short for bad software
    В одной таблице должны храниться документы, во второй - строки табличной части (всех документов).

    models.py:
    from django.db import models
    from django.db.models import Max, Sum
    from django.utils.translation import ugettext_lazy as _
    
    
    class Product(models.Model):
        name = models.CharField(
            _('Name'),
            max_length=200,
            db_index=True,
        )
    
        def __str__(self):
            return self.name
    
    
    class Document(models.Model):
        INVOICE = 'I'
        WAYBILL = 'W'
        TYPE_CHOICES = (
            (INVOICE, _('Invoice')),
            (WAYBILL, _('Waybill')),
        )
        type = models.CharField(
            _('Type'),
            max_length=1,
            choices=TYPE_CHOICES,
        )
        number = models.CharField(
            _('Number'),
            blank=True,
            max_length=50,
        )
        created_at = models.DateTimeField(
            _('Created'),
            auto_now_add=True,
            db_index=True,
        )
    
        @property
        def total(self):
            return self.items.aggregate(sum=Sum('total'))['sum']
    
        class Meta:
            ordering = ['-created_at']
    
    
    class DocumentItem(models.Model):
        document = models.ForeignKey(
            Document,
            models.CASCADE,
            related_name='items',
        )
        position = models.PositiveIntegerField(
            verbose_name=_('Position'),
            editable=False,
            db_index=True,
        )
        product = models.ForeignKey(
            Product,
            models.PROTECT,
        )
        price = models.DecimalField(
            _('Price'),
            max_digits=12,
            decimal_places=2,
        )
        quantity = models.DecimalField(
            _('Quantity'),
            max_digits=10,
            decimal_places=3,
        )
        total = models.DecimalField(
            _('Total'),
            max_digits=12,
            decimal_places=2,
        )
    
        def save(self, *args, **kwargs):
            if not self.position:
                position = self.document.items.aggregate(Max('position'))['position__max'] or 0
                self.position = position + 1
            super(DocumentItem, self).save(*args, **kwargs)


    admin.py:
    from django.contrib import admin
    
    from .models import Product, Document, DocumentItem
    
    
    @admin.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        pass
    
    
    class DocumentItemInline(admin.TabularInline):
        model = DocumentItem
        fields = (
            'position',
            'product',
            'price',
            'quantity',
            'total',
        )
        readonly_fields = (
            'position',
        )
        ordering = ['position']
    
    
    @admin.register(Document)
    class DocumentAdmin(admin.ModelAdmin):
        inlines = [
            DocumentItemInline,
        ]
        list_display = (
            'type',
            'number',
            'created_at',
            'total',
        )
        list_filter = (
            'type',
        )
        search_fields = (
            '=number',
        )


    Стандартная админка - для примера, вообще она не для этого (обычным пользователям она не должна быть доступна). Но реальные формы строятся по тому же принципу.

    Код накидал прям здесь, не проверял, поэтому возможны незначительные ошибки.
    Ответ написан
    4 комментария
  • Как синхронизировать базу и миграции Django?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Информация о примененных миграциях хранится в самой базе данных (таблица django_migrations). Поэтому если скрипты миграций вручную не менялись и не удалялись, то никаких проблем при деплое не возникнет. Более того, дальнейшие изменения структуры БД можно без проблем накатывать с помощью python manage.py migrate - в этом и заключается прелесть миграций.
    Ответ написан
    5 комментариев
  • Стоит тратить свое личное время стартующему фрилансеру на клиента?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Личный опыт: перед тем как начать поиск интересных проектов, нужно взять несколько небольших fixed-price заказов ($50-100), и качественно их отработать - профиль будет непустой, приличные клиенты перестанут его игнорировать.
    На этапе подготовки к сделке вопросы должен задавать исполнитель, а не заказчик. Исполнителю это позволяет лучше оценить трудоемкость и скорректировать цену до начала работ, заказчику - вменяемость исполнителя.
    Работа должна начинаться после заключения сделки. Обсуждение проекта - сколько угодно (в разумных пределах), наброски - за отдельную плату.
    Ответ написан
    Комментировать
  • Каковы максимальные рейты на Toptal?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Toptal - агентство. Размер комиссии, при которой агентство оказывается жизнеспособным, составляет от 70 до 90 процентов. Человека с рейтом $70/h они попытаются продать за 100, значит на руки такой работник будет получать максимум 30. Это вариант для ярко выраженных интровертов, панически боящихся общения с клиентами на финансовые темы.
    На upwork.com или freelancer.com около 6 месяцев потребуется на то чтобы осмотреться и понять принципы работы, после этого толковому fullstack-разработчику можно рассчитывать на постоянный поток long-term проектов. Дальнейшая работа будет минимум вдвое более выгодной, чем на Toptal, и помимо денег будет приносить постоянных клиентов.
    Ответ написан
    8 комментариев
  • Как в Django 1.11 создать дополнительные поля к связи многие-ко-многим?

    neatsoft
    @neatsoft
    Life is too short for bad software
    т.к. класс Ingredients на момент использования еще не объявлен, его название нужно взять в кавычки:
    ...
        ingridients = models.ManyToManyField(
            Food,
            through='Ingredients',
            through_fields=('recipe', 'food')
        )
    ...

    lazy relationships
    Ответ написан
    1 комментарий
  • Как сделать API для веб-приложения написанном на Django?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Django REST framework
    Quickstart
    Tutorial
    Ответ написан
    Комментировать
  • Где найти сайт с арендой большого диск. пространства и абузоустойчивостью?

    neatsoft
    @neatsoft
    Life is too short for bad software
    И объем, и производительность, и абузоустойчивость в одном месте найти непросто, поэтому я предлагаю разделить задачу: для хранения данных использовать недорогой "белый" выделенный сервер с емкими дисками и жирным каналом ( https://www.online.net/en/dedicated-server ) а доступ к нему организовать через абузоустойчивый сервер (или vps), работающий в режиме reverse proxy. Для reverse proxy сгодится самое тухлое железо, лишь бы хватало пропускной способности и трафика.
    Anti DDOS защита зависит от типа и интенсивности атак.
    Ответ написан
    3 комментария
  • Аналог IrfanView для Ubuntu. Как быстро вырезать и сохранить фрагмент?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Shift+PrtSc, выделение нужной области, Save
    Ответ написан
    Комментировать
  • Как слегка изменить live-usb с Ubuntu, обновив образ под свои нужды?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Существует два способа осуществления массовых инсталляций - клонирование и автоматизированная установка.

    Автоматизированная установка Debian и Ubuntu производится с помощью Preseed:
    Debian Installer Preseed
    Automating the installation using preseeding
    Preseed позволяет заранее задать ответы на вопросы инсталлятора, и выполнить дополнительные команды в процессе установки. При необходимости можно добавить в образ диска все необходимые пакеты, и сделать установку полностью автономной (без необходимости подключения к сети).

    Клонирование работает быстрее - полностью установленная и настроенная система просто копируется при этом с помощью dd на новый носитель, но имеет свои недостатки. Некоторые пакеты должны быть сконфигурированы в процессе установки уникальным образом, и не должны быть идентичными на разных компьютерах. Например, random-seed, base-passwd, и udev persistent-net. Можно написать скрипт, который будет подменять конфигурационные файлы после клонирования, но для для обычной Ubuntu это в любом случае будет костылем (хотя бывают специальные образы для облачных систем, которые изначально на это рассчитаны).

    Оба способа требуют довольно много времени на подготовку образа (т.к. приходится осуществлять множество итераций установка-проверка-исправление), и оправданы только в том случае, если требуется производить значительное количество установок. Для Ubuntu Desktop и Ubuntu Server лучше использовать Preseed.
    Ответ написан
    4 комментария
  • Как получить всех людей начинающихся с перечня букв?

    neatsoft
    @neatsoft
    Life is too short for bad software
    import operator
    import functools
    
    from django.db.models import Q
    
    from .models import Item
    
    
    def get_items(letters=''):
        items = Item.objects.filter(active=True)
        items = items.exclude(id__lt=100).exclude(id__gt=200)
        if letters:
            q = functools.reduce(operator.or_, (Q(name__istartswith=l) for l in letters))
            items = items.filter(q)
        return items
    
    get_items('abc')


    from django.db.models import Q
    
    from .models import Item
    
    
    def get_items(letters='', active=None):
        q = Q()
        if len(letters) == 3 and letters[1] == '-':
            letters = (unichr(c) for c in range(ord(letters[0]), ord(letters[2]) + 1))
        for letter in letters:
            q |= Q(name__istartswith=letter)
        if active is not None:
            q &= Q(active=active)
        return Item.objects.filter(q)
    
    get_items(u'абвгд')
    get_items(u'в-д')
    get_items(u'а-я', True)
    Ответ написан
  • Как отформатировать флешку под Убунтой?

    neatsoft
    @neatsoft
    Life is too short for bad software
    флэшка - это всего лишь последовательность байт (для операционной системы)
    если она исправна, то отформатировать ее можно следующим образом - Как удалить разбиение live-флешки?
    Ответ написан
    Комментировать
  • Аренда дешевого дискового пространства, подскажете?

    neatsoft
    @neatsoft
    Life is too short for bad software
    https://www.online.net/en/dedicated-server/dedibox-sc
    1 TB за €8.99 в месяц, хороший канал, неограниченный трафик
    Ответ написан
    Комментировать
  • Проблемна ли инвалидация кэша в Nginx?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Только что закончил систему кэширования для высоконагруженного проекта на django + nginx, никаких проблем с инвалидацией не испытал. memcached + nginx microcaching. Принцип работы следующий:
    • nginx проверяет наличие данных в memcached с помощью memcached_pass, если нашел - возвращает;
    • django при рендеринге страницы помещает результат в memcached, при изменении - удаляет.

    В исходном виде у этой связки есть только одна проблема - обработка конкурирующих запросов. Если несколько клиентов одновременно попытаются запросить одну и ту же "непрогретую" страницу, то все запросы уйдут в бэкенд (ab -n 1000 -c 100). К счастью, nginx легко позволяет это предотвратить с помощью микрокэширования (uwsgi_cache_valid any 1s; uwsgi_cache_use_stale updating;). В бэкенд при этом уходит только самый первый запрос, параллельные получают результат из файлового кэша, последующие - из memcached. Не слишком элегантно, появляется дополнительный слой кэширования (файловый), но работает отлично. На реальных данных удалось получить ускорение в 1200 раз и неограниченную возможность масштабирования (с помощью дополнительных серверов с nginx в режиме микрокэширования между клиентом и основным сервером).
    Ответ написан
    Комментировать
  • Какой USB wifi-адаптер выбрать, чтобы без проблем работал на Ubuntu 16.04?

    neatsoft
    @neatsoft
    Life is too short for bad software
    TP-Link TL-MR3020 с LEDE (OpenWrt) в режиме клиента. Это, конечно, не совсем usb wi-fi адаптер, но зато работает без проблем. При подключении к usb дополнительный блок питания не требуется, потребление в пределах 200mA. Использую этот вариант более двух лет для подключения к сети нескольких Raspberry Pi в режиме 24x7.

    Если требуется поддержка 5GHz, MIMO, или 802.11ac, то либо Intel (M.2 или Mini PCIe), либо точка доступа с внешним питанием.

    P.S. Официальные драйвера - это то что есть в ядре, ath9k, например, или iwlwifi. Все остальное - шлак. Перед покупкой любое оборудование нужно гуглить.

    upd 2017: В продаже появился TP-Link TL-WR902AC - обновленный TL-MR3020 с поддержкой 5GHz и 802.11ac. Отлично работает под LEDE 17.01.2 ( https://lede-project.org/ ), энергопотребление низкое. Есть пошаговая инструкция по настройке клиентского режима - https://wiki.openwrt.org/doc/recipes/relayclient , в нижней части страницы ("Doing this via the Web GUI instead").
    Ответ написан
    Комментировать
  • Как включить компьютер через 3g модем?

    neatsoft
    @neatsoft
    Life is too short for bad software
    TP-Link TL-MR3020, OpenWrt, Wake-on-LAN
    на роутер нужно установить OpenWrt, подключить и настроить модем
    на компьютере настроить и проверить Wake-on-LAN, подключить роутер к компьютеру витой парой и кабелем питания (usb)

    По моему опыту, некоторые сетевые карты прекрасно работают с WOL без всякой настройки, некоторые не позволяют выполнять холодный старт (в этом случае может помочь опция boot after power failure), некоторые не поддерживают WOL вообще. Перед покупкой железо желательно гуглить, если уже куплено - нужно проверить поддержку WOL до начала построения системы.
    Ответ написан
    Комментировать
  • Возможно ли развернуть два веб-сервера на 1 домене?

    neatsoft
    @neatsoft
    Life is too short for bad software
    кусок конфигурации с реального сервера:
    server {
        ...
        location /services {
            proxy_pass http://127.0.0.1:8080;
            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;
        }
        ...
    }

    Документация: nginx reverse proxy
    Ответ написан
    5 комментариев
  • Нужно ли дополнительно настраивать сервер под django?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Выполнить шаги, описанные в Django deployment checklist

    Настроить ssh:
    • запретить доступ для пользователя root
    • настроить авторизацию с помощью ключа
    • запретить авторизацию с помощью пароля


    Настроить firewall:
    • разрешить входящие соединения на 22, 80, и 443 порты (ssh, http, https)
    • запретить все остальные входящие соединения


    Настроить ssl:
    • приобрести ssl сертификат
    • сделать переадресацию с http на https


    Если у пользователей есть возможность загрузки файлов на сайт, то:
    • приобрести отдельный домен для хостинга этих файлов
    • настроить nginx для раздачи media_root с этого домена
    • проверить недоступность media с основного домена
    Security in Django - User-uploaded content

    ps. В будущих проектах попробуйте вместо Gunicorn использовать uWSGI, а вместо CentOS 7 - Ubuntu 16.04 server.
    Ответ написан
    Комментировать
  • Чем отличается бесплатный ssl сертификат от платного?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Тем что в случае оформления сертификата через cloudflare:
    • cloudflare будет обладателем приватного ключа - сможет просматривать и модифицировать трафик по своему усмотрению;
    • соединение будет зашифровано только на участке между клиентом и cloudflare (для шифрования соединения между cloudflare и сервером потребуется настоящий сертификат - самоподписанные никакой дополнительной защиты не обеспечивают, т.к. не проверяются);
    • сертификат будет действителен сразу для нескольких совершенно не связанных друг с другом доменов (для которых опция ssl на cloudflare была включена в одно и то же время).


    Если нужен нормальный сертификат:
    https://letsencrypt.org/ - бесплатно, сокращенный срок действия, автоматизированный перевыпуск
    https://www.ssls.com/ - $4.99/год (PositiveSSL, при оплате за 3 года)
    Никакой разницы между "domain validated" сертификатами за $5 и за $100 нет - они будут работать совершенно одинаково.

    Более дорогой сертификат может потребоваться если:
    • необходима поддержка нескольких доменов;
    • хочется получить "зеленую плашку" для большего доверия со стороны клиентов (такой сертификат выдается только после проверки документов).
    Ответ написан
    16 комментариев