• Стоит ли использовать get_user_model(), когда есть кастомная модель пользователя?

    @ilya_chch
    ничего страшного, если вы будете ее использовать, не случится
    но вообще, get_user_model() надо использовать, если вы пишете библиотеку для Django - поскольку неизвестно, будет ли пользовательская модель переопределена в проекте, куда эту библиотеку поставят

    но, если вы используете type hinting, функцию использовать нельзя, придется делать:
    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
        from ... import User
    
    
    def some_func(user: 'User') -> 'User':
        ...
    Ответ написан
    Комментировать
  • Как описать Generic класс?

    @ilya_chch Автор вопроса
    эксперименты показали, что, как вариант, наследников можно описывать так:

    class Service1(BaseService[ServicePayload, None]):
        payload_class = ServicePayload
        payload: ServicePayload
    
        def do_something(self) -> None:
            print(self.payload.some_string)  # например
    
    class Service2(BaseService[None, ServiceParams]):
        params_class = ServiceParams
        params: ServiceParams
    
        def do_something(self) -> None:
            print(self.params.some_int)  # например
    
    class Service3(BaseService[ServicePayload, ServiceParams]):
        payload_class = ServicePayload
        payload: ServicePayload
        params_class = ServiceParams
        params: ServiceParams
    
        def do_something(self) -> None:
            print(self.payload.some_string)  # например
            print(self.params.some_int)  # например


    но, возможно, есть более "правильный" это сделать?
    Ответ написан
    Комментировать
  • Как использовать UUID в url без тире?

    @ilya_chch Автор вопроса
    решил вопрос через
    force_str(urlsafe_base64_encode(force_bytes(uuid)))


    и обратно в uuid:
    force_str(urlsafe_base64_decode(encoded_uid))
    Ответ написан
    Комментировать
  • Как умножить число на проценты Python?

    @ilya_chch
    учитывая комментарий Сергей К, при условии, что надо указать сколько денег попросит разом:
    educational_grant = float(input("Введите месячную стипендию: ")) # месячная стипуха
    expenses = float(input("Введите месячный расход: ")) # расходы в месяц
    i = 0
    delta = 0
    while i < 9:
        delta += educational_grant - (expenses + (expenses) * 0.03 * i)  # на первой итерации при i = 0, повышения цен аффектит значение
        i += 1
    if delta < 0:
        print(f'нужно просить {-delta} на учебный год')
    else:
        print('денег просить не надо, может еще и останется')
    Ответ написан
    Комментировать
  • Как аннотировать тип классового атрибута, который будет переопределен?

    @ilya_chch Автор вопроса
    Решение нашлось:
    import abc
    from typing import ClassVar, Type, Dict, Generic, TypeVar
    from pydantic import BaseModel
    
    T = TypeVar('T', bound=BaseModel)
    
    
    class Abstract(abc.ABC, Generic[T]):
        context_class: ClassVar[Type[T]]
        error: ClassVar[Type[Exception]]
    
        def __init__(self, data: Dict) -> None:
            self.context = self.context_class(**data)
    
        @abc.abstractmethod
        def process(self) -> None:
            pass
    
    
    class Context(BaseModel):
        email: str
    
    
    class Concrete(Abstract[Context]):
        context_class = Context
    
        def process(self) -> None:
            print(self.context.email)
    Ответ написан
    Комментировать
  • Как правильно сформировать автоматические релизы на Github?

    @ilya_chch Автор вопроса
    в общем, решил вопрос:

    name: Release
    
    on:
      push:
        branches:
          - master
    
    jobs:
      release:
        if: github.event_name == 'push' && github.ref == 'refs/heads/master'
        name: Release
        runs-on: ubuntu-latest
        steps:
          - name: Getting code
            uses: actions/checkout@master
          - name: Getting Python
            uses: actions/setup-python@master
          - name: Cache pip
            uses: actions/cache@v2
            with:
              path: ~/.cache/pip
              key: ${{ runner.os }}-pip-${{ hashFiles('poetry.lock') }}
              restore-keys: |
                ${{ runner.os }}-pip-
          - name: Getting Poetry
            uses: dschep/install-poetry-action@v1.3
          - name: Getting PostgreSQL
            uses: harmon758/postgresql-action@v1
            with:
              postgresql db: 'test_db'
              postgresql user: 'postgres'
              postgresql password: 'postgres'
          - name: Installing dependencies
            run: poetry install
          - name: Running tests
            run: make coverage_run
          - name: Running coverage check
            run: make coverage_cmd_report
          - name: Running codestyle checks
            run: make check_black
          - name: Running types checks
            run: make check_mypy
    
          - name: Generate coverage report
            run: make coverage_xml_report
          - name: Upload coverage to Codecov
            uses: codecov/codecov-action@v1
            with:
              token: ${{ secrets.CODECOV_TOKEN }}
              file: ./coverage.xml
    
          - name: Getting package version
            id: get_version
            run: echo "::set-output name=version::$(poetry version)"
    
          - name: Getting package clear version
            id: get_clear_version
            run: echo "::set-output name=clear_version::$(poetry version | cut -d ' ' -f 2)"
    
          - name: Make release and publish
            run: make release USERNAME=${{ secrets.PYPI_USERNAME }} TOKEN=${{ secrets.PYPI_TOKEN }}
    
          - name: Get asset name
            id: get_asset_name
            run: echo "::set-output name=assert_name::$(ls dist | grep gz)"
    
          - name: Create Release
            id: create_release
            uses: actions/create-release@latest
            env:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
            with:
              tag_name: ${{ steps.get_clear_version.outputs.clear_version }}
              release_name: ${{ steps.get_version.outputs.version }}
              draft: false
              prerelease: false
    
          - name: Upload Release assets
            id: upload_gz
            uses: actions/upload-release-asset@latest
            env:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
            with:
              upload_url: ${{ steps.create_release.outputs.upload_url }}
              asset_path: dist/${{ steps.get_asset_name.outputs.assert_name }}
              asset_name: ${{ steps.get_asset_name.outputs.assert_name }}
              asset_content_type: application/tar+gzip
    Ответ написан
    Комментировать
  • Как организовать проект таким образом чтобы при разработке модулей для него не требовался сам проект?

    @ilya_chch
    Вы сами себе противоречите:
    Как организовать проект таким образом чтобы при разработке модулей для него не требовался сам проект?

    Модуль для своей работы дёргает контроллеры из основного проекта.


    Получается, что ваш модуль не сможет работать без проекта. Вообще.

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

    Посмотрите в сторону того, как устроен механизм Middleware в Django - есть список middleware и запрос последовательно передается в каждый из них, а возвращаемый модифицированный запрос передается в следующий.

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

    Для того, чтобы выстроить разработку таких модулей - обозначьте четкий интерфейс каждого типа модуля. Например, модули отвечающий за работу с пользователем, получают на вход объект пользователя и отдают тоже объект пользователя, но либо делают что-то по дороге, либо как-то модифицируют его.
    Ответ написан
    Комментировать
  • Как вызвать функцию в шаблоне?

    @ilya_chch
    если это система лайков, то я бы предложил написать простенький API эндпоинт, и JavaScript-ом отправлять туда POST запрос, в котором передавать id. если лайка нет и он успешно создался, API отдает статус 201 и что-нибудь типа {'like': 'OK'} и кнопка как-то изменяется. Если лайк был поставлен, лайк удаляется и возвращается статус 204 и ответ типа {'like': 'REMOVED'}.

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

    если API - не ваш вариант, можно сделать RedirectView, а кнопку, которая должна выполнять эту функцию повесить ссылку на эту вьюху. в методе get_redirect_url пишешь свою логику и вертаешь тот же url, с которого пришло через request.META.HTTP_REFERER
    Ответ написан
    Комментировать
  • Почему после двух активных юзеров бот не 'обслуживает' новых?

    @ilya_chch
    Позволю себе предложить вам использовать RQ или что-то подобное для обработки долгоиграющих запросов.
    Ответ написан
    Комментировать
  • Django Rest Framework: Для чего используется SCHEMAS?

    @ilya_chch
    Это используется для того, чтобы не хардкодить поля формы.
    Например, в случае изменения модели, требует изменения фронта, чтобы добавить, изменить или удалить поле.

    А с помощью схемы этот процесс можно автоматизировать. То есть, перед созданием формы, получается схема, из нее берутся поля и их типы, и строятся те или иные инпуты.
    Ответ написан
    Комментировать
  • Как средствами Python пройти двухшаговую аутентификация на сайте?

    @ilya_chch
    Он не обновляет страницу. Я думаю, стоит использоваться сессию и посмотреть, какие данные он отправляет и когда. И, собственно повторить их. Посмотрите в Network консоли разработчика. Вероятно, там достаточно будет скопировать POST запрос и сохранить где-нибудь токен.
    Ответ написан
    Комментировать
  • Как настроить интерпретатор в pycharm на linux mint?

    @ilya_chch
    в терминале введите:
    $ whereis python
    ну или какой вы хотите использовать...

    в Pycharm укажите руками по нужному пути
    Ответ написан
    Комментировать
  • Как управлять полем сериализатора Django Rest Framework?

    @ilya_chch Автор вопроса
    Как выяснилось, самый простой и надежный способ - Сделать второй сериализатор, который бы отдавал все объекты. а в представлении переопределить метод get_serializer, который бы подсовывал нужный сериализатор
    Ответ написан
    Комментировать
  • Как сделать formset для нескольких объектов БД?

    @ilya_chch Автор вопроса
    Нашел решение, может кому будет полезно:
    class ForeignObjFormSet:
        def get_form_kwargs(self, index):
            kwargs = super(ForeignObjFormSet, self).get_form_kwargs(index)
            kwargs['obj'] = self.form_kwargs['obj'][index]
            return kwargs
    
    # Во вьюхе
    def view(request):
        target_objects = Obj.objects.filter(foreign_obj__isnull=True)
        FormSet = formset_factory(forms.ForeignObjForm, formset=ForeignObjFormSet, extra=target_objects.count())
        form_set = FormSet(form_kwargs={'obj': list(target_objects)})
    # ...
    Ответ написан
    Комментировать
  • Как настроить 2 БД в Django?

    @ilya_chch Автор вопроса
    получилось обойти ошибку с помощью
    $ python manage.py migrate --fake
    теперь Django думает, что миграции сделаны и ошибки нет, однако хотелось бы попробовать найти решение, чтобы можно было просто запускать migrate и не париться
    Ответ написан
    Комментировать
  • Как организовать хранение файлов пользователей в Django?

    @ilya_chch
    в settings.py добавьте указание на расположение медиа
    MEDIA_URL = '/media/' #например
    MEDIA_ROOT = '/srv/files/media' #например


    media_url - часть урла, по которому будут находиться картинки, media_root - место на сервере, где nginx будет их искать.

    в модели:

    class ModelClass(models.Model):
        <поле> = models.ImageField(upload_to=rename_image, blank=True, verbose_name='...')
    
    def rename_image(instance, filename):
        image_name = md5(str(time.time()).encode()).hexdigest()
        image_type = filename.split('.')[-1]
        return 'imgs/{}.{}'.format(image_name, image_type)


    rename_image в моем случае переименовывает загружаемую картинку в хэш. и в return можно добавить путь. в моем случае будет загружаться в media_root/imgs/<что-то>.jpg #например (при условии, что media_root определен, все всегда будет падать туда)

    добавьте в путь подкаталог с именем user_{его id}. а вот насчет доступности только для этого пользователя - надо отдельно думать.
    Ответ написан
    Комментировать