Получение "значение должно быть целым числом" при попытке заполнить данные YAML - PullRequest
4 голосов
/ 06 февраля 2020

Я использую Django 2, Python 3.7 и модуль django -address (https://pypi.org/project/django-address/). Я пытаюсь вставить некоторые начальные данные. У меня есть этот YAML ...

- model: address.locality
  pk: 1
  fields:
    name: "Chicago"
    postal_code: "60053"
    state:
      name: IL
      country:
      - United States

Когда я запускаю свою начальную команду

python manage.py loaddata maps/fixtures/seed_data.yaml

Я получаю эту ошибку ...

localhost:web davea$ python manage.py loaddata maps/fixtures/seed_data.yaml
Traceback (most recent call last):
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 923, in to_python
    return int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/python.py", line 157, in Deserializer
    data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 928, in to_python
    params={'value': value},
django.core.exceptions.ValidationError: ["'{'name': 'IL', 'country': ['United States']}' value must be an integer."]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 365, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/base.py", line 335, in execute
    output = self.handle(*args, **options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 72, in handle
    self.loaddata(fixture_labels)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 113, in loaddata
    self.load_label(fixture_label)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 168, in load_label
    for obj in objects:
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/pyyaml.py", line 73, in Deserializer
    yield from PythonDeserializer(yaml.load(stream, Loader=SafeLoader), **options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/python.py", line 159, in Deserializer
    raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
django.core.serializers.base.DeserializationError: Problem installing fixture '/Users/davea/Documents/workspace/chicommons/maps/web/maps/fixtures/seed_data.yaml': ["'{'name': 'IL', 'country': ['United States']}' value must be an integer."]: (address.locality:pk=1) field_value was '{'name': 'IL', 'country': ['United States']}'

Я добавил это в файле maps / monkey_patching.py, чтобы помочь с автоматическим созданием сущностей на основе уникальных идентификаторов ...

from address import State
from address import Country

def country_get_by_natural_key(self, name):
    return self.get_or_create(name=name)[0]

def state_get_by_natural_key(self, name, country_id):
    return self.get_or_create(name=name, country_id=country_id)[0]

Country.add_to_class("get_by_natural_key",country_get_by_natural_key)
State.add_to_class("get_by_natural_key",state_get_by_natural_key)

Редактировать: включая трассировку стека по запросу Шивама ...

(venv) localhost:maps davea$ python web/manage.py loaddata web/maps/fixtures/seed_data.yaml 
Traceback (most recent call last):
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 923, in to_python
    return int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/python.py", line 157, in Deserializer
    data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 928, in to_python
    params={'value': value},
django.core.exceptions.ValidationError: ["'['IL', 'United States']' value must be an integer."]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "web/manage.py", line 21, in <module>
    main()
  File "web/manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 365, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/base.py", line 335, in execute
    output = self.handle(*args, **options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 72, in handle
    self.loaddata(fixture_labels)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 113, in loaddata
    self.load_label(fixture_label)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 168, in load_label
    for obj in objects:
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/pyyaml.py", line 73, in Deserializer
    yield from PythonDeserializer(yaml.load(stream, Loader=SafeLoader), **options)
  File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/core/serializers/python.py", line 159, in Deserializer
    raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
django.core.serializers.base.DeserializationError: Problem installing fixture '/Users/davea/Documents/workspace/chicommons/maps/web/maps/fixtures/seed_data.yaml': ["'['IL', 'United States']' value must be an integer."]: (address.locality:pk=1) field_value was '['IL', 'United States']'

Ответы [ 3 ]

2 голосов
/ 11 февраля 2020

Проблема с естественным ключом

get_by_natural_key метод доступен на уровне менеджера, но вы добавляете метод на уровне модели. Таким образом, вместо вышесказанного, вам нужно сделать так:

from django.db import models
from address.models import State

class CustomManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get_or_create(name=name)[0]

State.add_to_class('objects', CustomManager())

Проблема с приборами

Вложенные данные приборов должны содержать только аргументы, а не kwargs. Проверьте Есть ли способ в файле seed_data.yaml для автоматического создания моделей, от которых зависит первая модель? для получения более подробной информации. И после этого вам нужно соответствующим образом спроектировать вашу get_by_natural_key функцию. Так что для locality модель светильников будет выглядеть как

- model: address.locality
  pk: 1
  fields:
    name: "Chicago"
    postal_code: "60053"
    state: ['I', 'United States']

А переопределенный менеджер будет

class CustomManager(models.Manager):
    def get_by_natural_key(self, state_name, country):
        country = Country.objects.get_or_create(name=country)[0]
        return State.objects.get_or_create(name=state_name, country=country)[0]

setattr(State._meta, 'default_manager', CustomManager())
1 голос
/ 16 февраля 2020

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

Эта команда работает с предоставленными вами образцами данных - может потребоваться незначительная корректировка, если в вашем файле YAML больше, чем просто address.locality объектов:

import yaml

from django.core.management.base import BaseCommand

from address.models import Country, State, Locality


class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('file', nargs=1, type=str)

    def handle(self, *args, **options):
        f = options['file'][0]
        with open(f, 'r') as yamlfile:
            data = yaml.load(yamlfile)

        for row in data:
            if row['model'] == 'address.locality':
                state_name = row['fields']['state']['name']
                country_name = row['fields']['state']['country'][0]

                country_obj, _ = Country.objects.get_or_create(name=country_name)
                state_obj, _ = State.objects.get_or_create(country=country_obj, name=state_name)

                Locality.objects.get_or_create(
                    pk=row['pk'], 
                    state=state_obj, 
                    postal_code=row['fields']['postal_code'], 
                    name=row['fields']['name']
                )

(Сторона примечание - формат вашего YAML немного странный, поскольку он предоставляет список для country. Я бы подумал, что государство может принадлежать только одной стране?).

0 голосов
/ 06 февраля 2020

В исходном коде этого пакета поле Locality.state связано с State моделью как foreignKey. Итак, ваше поле данных state должно быть целым числом от имени связанной таблицы.

См. django -адрес исходного кода

PS: в вашем случае Вы должны построить все связанные модели, с которыми связана Locality модель. Если нет, у вас будет ошибка целостности данных ... И все другие ошибки.

...