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

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

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

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

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

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

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


Сценарий

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

Мы получим информацию об этих сортах пива из бесплатного API по адресу

Скриншот пивного приложения

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


Джанго Модели

В приложении 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
Войти в полноэкранный режим

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


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

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

Цитата из Документация Джанго

Для этого добавьте в приложение каталог 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 для данных, которые затем будут записаны в базу данных. Мы также будем использовать Запросы библиотека.

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

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?

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

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 метод, который возвращает кортеж, где объект — это созданный или обновленный объект, а created — это логическое значение, указывающее, был ли создан новый объект.


Вывод

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

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


Ресурсы