我正在使用Django 2.0,Python 3.7和MySql5。我有以下两个模型,第二个依赖于第一个模型。
class CoopType(models.Model):
name = models.CharField(max_length=200, null=False)
class Meta:
unique_together = ("name",)
class Coop(models.Model):
name = models.CharField(max_length=250, null=False)
type = models.ForeignKey(CoopType, on_delete=None)
address = AddressField(on_delete=models.CASCADE)
enabled = models.BooleanField(default=True, null=False)
phone = PhoneNumberField(null=True)
email = models.EmailField(null=True)
web_site = models.TextField()
我正在为第二个模型创建一些种子数据。我想知道是否有一种方法可以从第二个模型中自动为第一个模型生成数据。我试过了...
- model: maps.coop
pk: 1
fields:
name: "1871"
type:
pk: null
name: Coworking Space
address:
street_number: 222
route: 1212
raw: 222 W. Merchandise Mart Plaza, Suite 1212
formatted: 222 W. Merchandise Mart Plaza, Suite 1212
locality:
name: Chicago
postal_code: 60654
state:
code: IL
enabled: True
phone:
email:
web_site: "http://www.1871.com/"
latitude: 41.88802611
longitude: -87.63612199
但是运行种子数据时出现此错误...
(env) localhost:maps davea$ python scripts/parse_coop_csv.py ~/Downloads/chicommons_prep.xlsx\ -\ Mapping\ Sheet.csv > maps/fixtures/seed_data.yaml
(env) localhost:maps davea$ python manage.py loaddata maps/fixtures/seed_data.yaml
Traceback (most recent call last):
File "/Users/davea/Documents/workspace/chicommons/maps/env/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/env/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/env/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 928, in to_python
params={'value': value},
django.core.exceptions.ValidationError: ["'{'pk': None, 'name': 'Coworking Space'}' 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/env/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/env/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/env/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/env/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/env/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/env/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/env/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/env/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/env/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/maps/maps/fixtures/seed_data.yaml': ["'{'pk': None, 'name': 'Coworking Space'}' value must be an integer."]: (maps.coop:pk=1) field_value was '{'pk': None, 'name': 'Coworking Space'}'
seed_data.yaml文件中有什么方法可以优雅地做到这一点吗?
答案 0 :(得分:1)
解决方案: 按照以下步骤更新您的灯具
- model: test_app.coop
pk: 1
fields:
name: '1871'
type:
- Coworking Space
enabled: true
email: null
web_site: ''
- model: test_app.coop
pk: 2
fields:
name: '18715'
type:
- Coworking Space 2
enabled: true
email: null
web_site: ''
- model: test_app.coop
pk: 3
fields:
name: '187156'
type:
- Coworking Space 3
enabled: true
email: null
web_site: ''
并在您的CoopType
模型中添加自定义管理器
class CoopManager(models.Manager):
def get_by_natural_key(self, name):
return self.get_or_create(name=name)[0]
class CoopType(models.Model):
name = models.CharField(max_length=200)
objects = CoopManager()
class Meta:
unique_together = ("name",)
现在,当您加载夹具时,它将创建CoopType
对象(如果尚不存在),然后加载Coop
模型
说明:这是负责反序列化对象的Django代码
# Handle FK fields
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
model = field.remote_field.model
if field_value is not None:
try:
default_manager = model._default_manager
field_name = field.remote_field.field_name
if hasattr(default_manager, 'get_by_natural_key'):
if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
obj = default_manager.db_manager(db).get_by_natural_key(*field_value)
value = getattr(obj, field.remote_field.field_name)
# If this is a natural foreign key to an object that
# has a FK/O2O as the foreign key, use the FK value
if model._meta.pk.remote_field:
value = value.pk
else:
value = model._meta.get_field(field_name).to_python(field_value)
data[field.attname] = value
else:
data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
except Exception as e:
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
else:
data[field.attname] = None
来源:django.core.serializers.python第152行以上
如您所见,模型中是否提供了get_by_natural_key
函数,并且夹具具有嵌套数据,那么它将调用get_by_natural_key
函数来获取对象。因此,在get_by_natural_key
函数中,我们可以使用get_or_create
并返回实例。
请检查Coop
模型中的嵌套数据是否只有args
而不是kwargs
,因为Django代码在此函数中传递了args
。
PS:我不确定在get_or_create
函数中使用get_by_natural_key
有多正确,但这是目前唯一可行的解决方案。