Создание пользовательской команды manage.py в Django

Если вы когда-либо использовали Django, вы, вероятно, использовали его команды manage.py для выполнения различных действий, например:

  • python manage.py runserver
  • python manage.py migrate
  • python manage.py createsuperuser

Существует множество полезных встроенных команд, которые вы можете использовать, если посмотрите в документации (django-admin и manage.py). Например:

  • dumpdata — экспортировать данные из приложения в JSON или другой формат
  • loaddata — импортировать данные в базу данных
  • migrate — синхронизировать базу данных с текущим набором моделей и миграций.

Вы также можете создать свою собственную команду для административных задач, которые у вас могут возникнуть. Например, если вам нужно провести плановое обслуживание, вы можете создать такую команду и запустить ее как запланированное задание (например, через celery).

В этой статье я покажу вам, как вы можете создать свою собственную команду manage.py для заполнения данных из API-запроса в вашу базу данных.

Полный исходный код этого примера приложения Django можно найти на GitHub

Сценарий

Допустим, мы по какой-то причине хотим заполнить имеющуюся у нас модель базы данных данными о пиве из API. Если вы интересуетесь пивом, вы можете вспомнить, что у Brewdog была серия сортов пива под названием «Hello, my name is…».

Мы будем получать информацию об этих сортах пива из бесплатного API на сайте https://punkapi.com.



Предварительный просмотр данных о пиве

Модель Django

В приложении Django постройте модель для данных:

# models.py
from django.db import models


class Beer(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.CharField(max_length=200)
    first_brewed = models.CharField(max_length=20)
    description = models.TextField()
    added = models.DateTimeField(auto_now_add=True)
    edited = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'Beer: {self.name}'

Войдите в полноэкранный режим Выход из полноэкранного режима

Перенесите модель в базу данных.

$ python manage.py makemigrations beers

$ python manage.py migrate
Войти в полноэкранный режим Выйти из полноэкранного режима

Создание пользовательской команды

Для добавления новой команды создайте структуру папок в папке apps в проекте.

Цитата из документации Django

Для этого добавьте каталог management/commands в приложение. Django зарегистрирует команду manage.py для каждого модуля Python в этом каталоге, имя которого не начинается с символа подчеркивания.

Поэтому в данном случае создайте update_beers.py в следующей папке:

beers/
    __init__.py
    models.py
    management/
            __init__.py
            commands/
            update_beers.py 

Войти в полноэкранный режим Выйти из полноэкранного режима

Код команды

Код команды должен включать класс Command, который является подклассом Djangos BaseCommand. BaseCommand имеет один метод, который должен быть реализован, и это метод handle. Он будет содержать логику нашей команды.

Основная структура необходимого кода показана ниже.

from django.core.management import BaseCommand
from beers.models import Beer

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)

    help = "Update Beer table from punkapi.com"

    def handle(self, *args, **options):
            # Implement the logic here
            pass

Вход в полноэкранный режим Выйти из полноэкранного режима

В данном случае мы хотим делать запросы к API для получения данных, которые затем будут записаны в базу данных. Мы также будем использовать библиотеку requests.

Полный код команды может выглядеть следующим образом. (Это просто для демонстрации. В реальном мире мы, вероятно, не будем использовать название пива для запроса, если оно уже существует в базе данных).

from django.core.management import BaseCommand

import requests

from beers.models import Beer


class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)

    help = "Update Beer table from punkapi.com"

    def handle(self, *args, **options):
        # Request data from the beer API
        response = requests.get('https://api.punkapi.com/v2/beers/?beer_name=my_name_is')

        # Loop through the response
        for beer in response.json():
            try:
                beer_row = Beer.objects.get(name=beer['name'])
            except Beer.DoesNotExist:
                beer_row = None

            if beer_row:
                # Beer already exists - do nothing
                self.stdout.write(f'{beer_row.name} already exists.')
                continue
            else:
                # Add beer to db
                self.stdout.write('Create new row')
                beer_row = Beer()
                beer_row.name = beer['name']
                beer_row.tagline = beer['tagline']
                beer_row.first_brewed = beer['first_brewed']
                beer_row.description = beer['description']
                beer_row.save()

        self.stdout.write('#########################')
        self.stdout.write('Updated Beer list')
        self.stdout.write('#########################')

Войти в полноэкранный режим Выход из полноэкранного режима

Здесь мы проверяем, существует ли пиво в базе данных. Если нет, мы добавляем его в базу данных.

Выполнение пользовательской команды

Выполните пользовательскую команду, запустив ее:

python manage.py update_beers
Войти в полноэкранный режим Выйти из полноэкранного режима

В результате будет показан результат:


Результат выполнения команды

Если все прошло успешно, API будет запрошен для получения данных о пиве, и данные будут записаны в базу данных.

Другой способ сделать это

Что если мы хотим получать из api любые обновления для существующего пива?

Перепишите метод handle следующим образом.

def handle(self, *args, **options):
        response = requests.get('https://api.punkapi.com/v2/beers/?beer_name=my_name_is')

        for beer in response.json():

            object, created = Beer.objects.update_or_create(
                name=beer['name'],
                defaults={
                    'tagline': beer['tagline'],
                    'first_brewed': beer['first_brewed'],
                    'description': beer['description']
                }
            )

            object.save()

            if created:
                self.stdout.write('New beer added')
            else:
                self.stdout.write(f'{beer["name"]} updated')
Вход в полноэкранный режим Выйти из полноэкранного режима

Здесь мы используем метод Djangos update_or_create, который возвращает кортеж, где object — это созданный или обновленный объект, а created — булево число, указывающее, был ли создан новый объект.

Заключение

В этой статье я показал, как вы можете создать свою собственную пользовательскую команду manage.py в Django. В статье показано, как можно создать пользовательскую команду для получения данных из API через библиотеку requests и хранения их в базе данных.

Если вы хотите настроить пользовательскую команду как запланированную задачу, посмотрите на последний ресурс по ссылке ниже.

Ресурсы

  • Написание пользовательских команд django-admin (документация Django)
  • Полный исходный код этого приложения Beer на GitHub
  • Обработка периодических задач в Django с помощью Celery и Docker

Оцените статью
devanswers.ru
Добавить комментарий