Задать вопрос
Ответы пользователя по тегу Веб-разработка
  • Как разместить vue-ssr или nuxt приложение и laravel api на одном vps сервере/домене?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Решение в лоб - Nginx в качестве reverse proxy, но есть более современный и удобный вариант:
    - Laravel упаковать в один Docker контейнер, Vue во второй
    - запускать контейнеры с помощью Docker Compose
    - запросы роутить с помощью Traefik

    traefik-architecture.svg
    Ответ написан
    Комментировать
  • Как поднять несколько сайтов на одном сервере?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Категорически не согласен с ранее данными ответами. Докер отлично подходит для этой задачи, причём решает целый ряд проблем. Имеющиеся сайты могут оказаться привязаны к разным версиям одних и тех же программ, докеризация позволит изолировать их окружения. Упростится тестирование, деплой, и настройка dev окружений.

    В качестве tls proxy / load balancer рекомендую использовать Traefik - он автоматически подхватывает Docker контейнеры в соответствии с указанными в docker-compose.yml правилами, получает tls сертификаты для всех адресов с помощью letsencrypt, эффективно роутит запросы между контейнерами, позволяет балансировать нагрузку между несколькими контейнерами (docker-compose --scale).

    Время, потраченное на изучение Docker и Traefik, с лихвой окупится колоссальной экономией времени в будущих проектах.
    Ответ написан
    7 комментариев
  • Как реализовать на сайте таблицу мер продуктов?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Для каждого продукта питания необходимо хранить калорийность в пересчете на грамм, а для единиц измерения указывать вес в граммах:

    5c8901b18f654618880623.png

    Единицы измерения не имеют смысла безотносительно продуктов питания, т.к. между десятком яиц, столовой ложкой муки, и одним бананом среднего размера (200 гр с кожурой, 150 гр мякоти) нет ничего общего.

    Пример реализации на Django:

    models.py
    import decimal
    
    from django.core.validators import MaxValueValidator, MinValueValidator
    from django.db import models
    
    
    class Foodstuff(models.Model):
        name = models.CharField(max_length=200)
        kcal_per_gram = models.DecimalField(
            # the most calorie-dense food is fat cattle - 925 kcal per 100 gram (9.25 kcal/gram)
            max_digits=3,
            decimal_places=2,
            validators=[
                MaxValueValidator(decimal.Decimal('9.99')),
                MinValueValidator(decimal.Decimal('0.00')),
            ],
        )
    
        @property
        def kcal_per_100_gram(self):
            return int(self.kcal_per_gram * 100)
    
        def __str__(self):
            return self.name
    
        class Meta:
            ordering = ['name']
    
    
    class FoodstuffUnit(models.Model):
        foodstuff = models.ForeignKey(
            Foodstuff,
            models.CASCADE,
        )
        name = models.CharField(max_length=200)
        net_weight = models.DecimalField(
            max_digits=6,
            decimal_places=2,
            validators=[
                MinValueValidator(decimal.Decimal('0.01')),
            ],
        )
    
        @property
        def kcal(self):
            return int(self.foodstuff.kcal_per_gram * self.net_weight)
    
        def __str__(self):
            return self.name
    
        class Meta:
            ordering = ['name']
            unique_together = ('foodstuff', 'name')
    
    
    class Dish(models.Model):
        name = models.CharField(max_length=200)
    
        @property
        def kcal(self):
            return sum(i.kcal for i in self.dishingredient_set.all())
    
        def __str__(self):
            return self.name
    
        class Meta:
            ordering = ['name']
            verbose_name_plural = 'dishes'
    
    
    class DishIngredient(models.Model):
        dish = models.ForeignKey(
            Dish,
            models.CASCADE,
        )
        foodstuff = models.ForeignKey(
            Foodstuff,
            models.PROTECT,
        )
        foodstuff_unit = models.ForeignKey(
            FoodstuffUnit,
            models.PROTECT,
            blank=True,
            null=True,
        )
        amount = models.DecimalField(
            max_digits=6,
            decimal_places=2,
            validators=[
                MinValueValidator(decimal.Decimal('0.00')),
            ],
        )
    
        @property
        def kcal(self):
            weight = self.amount
            if self.foodstuff_unit is not None:
                weight *= self.foodstuff_unit.net_weight
            return int(self.foodstuff.kcal_per_gram * weight)
    
        def __str__(self):
            unit = 'гр' if self.foodstuff_unit is None else f'{self.foodstuff_unit}'
            return f'{self.dish}: {self.foodstuff}, {unit} - {self.amount}'
    
        class Meta:
            ordering = ['id']


    admin.py
    from django.contrib import admin
    
    from . import models as app_models
    
    
    class FoodstuffUnitInline(admin.TabularInline):
        model = app_models.FoodstuffUnit
        extra = 0
        readonly_fields = (
            'kcal',
        )
    
    
    @admin.register(app_models.Foodstuff)
    class FoodstuffAdmin(admin.ModelAdmin):
        list_display = (
            'name',
            'kcal_per_100_gram',
        )
        inlines = (
            FoodstuffUnitInline,
        )
        readonly_fields = (
            'kcal_per_100_gram',
        )
    
    
    class DishIngredientInline(admin.TabularInline):
        model = app_models.DishIngredient
        extra = 0
        readonly_fields = (
            'kcal',
        )
    
    
    @admin.register(app_models.Dish)
    class DishAdmin(admin.ModelAdmin):
        list_display = (
            'name',
            'kcal',
        )
        inlines = (
            DishIngredientInline,
        )
        readonly_fields = (
            'kcal',
        )
    Ответ написан
  • Какая идеальная структура каталога для картинок и почему?

    neatsoft
    @neatsoft
    Life is too short for bad software
    В качестве имён файлов можно использовать хэш содержимого, файлы распределять по подкаталогам, имена которых образованы первыми символами имен файлов. Пример:
    /34c/82a/416/34c82a416fca4cf3a1215ad5e8f2d782.jpg
    Ответ написан
    Комментировать
  • Какой язык/фреймворк выбрать?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Фреймворки нужны для упрощения и ускорения разработки - избавления от бойлерплейта и защиты от типичных ошибок. Можно ли всё тоже самое сделать вручную? Можно, но не нужно - большая часть времени уйдет на изобретение велосипедов, некоторые из которых будут медленными или небезопасными.

    По моему опыту, Django позволяет реализовывать типичные задачи вдвое быстрее, чем Laravel (использовал оба). Во многом это заслуга Python и сложившейся вокруг него экосистемы. Здесь выбор очевиден.

    VueJS скорее с ReactJS нужно сравнивать, а не с Angular, т.к. Angular это фреймворк, а VueJS и ReactJS - библиотеки. Все три помогают быстро и эффективно создавать фронтенд современных веб приложений, но делают это по разному. В качестве первого мягко (ненастойчиво) рекомендую изучить VueJS.

    p.s. Вне зависимости от выбора, не стоит заниматься веб-разработкой под windows. Стандартные среды - Ubuntu 18.04 (либо любой другой, но не слишком маргинальный дистрибутив) и MacOS.
    Ответ написан
    5 комментариев
  • Как сделать синхронизацию клиента и сервера?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Soft delete - для фильтрации элементов использовать поле is_deleted (default=False), при удалении присваивать ему значение True, физически строки из базы не удалять (либо удалять после синхронизации со всеми клиентами). При обмене данными опираться на значение поля updated_at (в котором нужно хранить дату последнего редактирования / удаления).
    Ответ написан
    Комментировать