Как загрузить данные только в том случае, если они не существуют в БД с помощью приспособлений Django

У меня есть некоторые начальные данные для загрузки с помощью команды ./manage.py loaddata. Она работает правильно, проблема в том, что когда я вызываю функцию loaddata, я хочу загрузить эти данные, если их там еще нет, если данные уже загружены, то я хочу пропустить этот шаг

my_app/models.py

class Person(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)

Решение 1

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

my_app/fixtures.json

[
  {
    "model": "my_app.Person",
    "pk": 1,
    "fields": {
      "first_name": "John",
      "last_name": "Lennon"
    }
  },
  {
    "model": "my_app.Person",
    "pk": 2,
    "fields": {
      "first_name": "Paul",
      "last_name": "McCartney"
    }
  }
]

Решение 2

Обернитесь вокруг реализации команды loaddata.

  1. Прочитайте исходный файл JSON
  2. Отфильтруйте элементы, которые уже существуют в вашей базе данных
  3. Запишите отфильтрованные элементы в новый (временный) JSON файл
  4. Продолжайте использовать исходную функциональность для loaddata
  5. Опционально, удалите временно созданный JSON файл

my_app/fixtures.json

[
  {
    "model": "my_app.Person",
    "fields": {
      "first_name": "John",
      "last_name": "Lennon"
    }
  },
  {
    "model": "my_app.Person",
    "fields": {
      "first_name": "Paul",
      "last_name": "McCartney"
    }
  }
]

my_app/management/commands/loaddata.py

import json
import os

from django.core.management.commands import loaddata

from my_app.models import Person


def should_add_record(record):
    if record['model'] != 'my_app.Person':
        return True

    return not Person.objects.filter(
        first_name=record['fields']['first_name'],
        last_name=record['fields']['last_name'],
    ).exists()


class Command(loaddata.Command):
    def handle(self, *args, **options):
        args = list(args)

        # Read the original JSON file
        file_name = args[0]
        with open(file_name) as json_file:
            json_list = json.load(json_file)

        # Filter out records that already exists
        json_list_filtered = list(filter(should_add_record, json_list))
        if not json_list_filtered:
            print("All data are already previously loaded")
            return

        # Write the updated JSON file
        file_dir_and_name, file_ext = os.path.splitext(file_name)
        file_name_temp = f"{file_dir_and_name}_temp{file_ext}"
        with open(file_name_temp, 'w') as json_file_temp:
            json.dump(json_list_filtered, json_file_temp)

        # Pass the request to the actual loaddata (parent functionality)
        args[0] = file_name_temp
        super().handle(*args, **options)

        # You can choose to not delete the file so that you can see what was added to your records
        os.remove(file_name_temp)

Выход

Пустая база данных

>>> Person.objects.all()
<QuerySet []>

Триггер loaddata

$ python manage.py loaddata my_app/fixtures.json
Installed 2 object(s) from 1 fixture(s)

Обновленная база данных

>>> Person.objects.all()
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
>>> Person.objects.values()
<QuerySet [{'id': 1, 'first_name': 'John', 'last_name': 'Lennon'}, {'id': 2, 'first_name': 'Paul', 'last_name': 'McCartney'}]>

Повторное выполнение loaddata

$ python manage.py loaddata my_app/fixtures.json
All data are already previously loaded
  • Явная печать будет показана только при использовании решения 2, в то время как обычная печать по умолчанию будет видна при использовании решения 1. В любом случае, оба решения не добавят никаких новых записей в базу данных.

Записи в базе данных остаются как есть

>>> Person.objects.all()
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
>>> Person.objects.values()
<QuerySet [{'id': 1, 'first_name': 'John', 'last_name': 'Lennon'}, {'id': 2, 'first_name': 'Paul', 'last_name': 'McCartney'}]>

Ссылка:

Вернуться на верх