不使用固定装置的 Django 1.10 种子数据库
Posted
技术标签:
【中文标题】不使用固定装置的 Django 1.10 种子数据库【英文标题】:Django 1.10 seed database without using fixtures 【发布时间】:2018-04-28 00:54:24 【问题描述】:所以我查看了documentation、SO question 和django-seed package,但这些似乎都不符合我的目标。
基本上,我想通过外部 API 以编程方式播种我的 Games
模型,但我能找到的所有信息似乎都依赖于首先生成一个夹具,这似乎是一个不必要的步骤。
例如,在 Ruby/Rails 中,您可以直接写入 seed.rb
并以任何所需的方式为数据库播种。
如果 Django 中提供了类似的功能,还是需要先从 API 生成夹具,然后再导入?
【问题讨论】:
Django 的manage.py loaddata
只是解析您的文本文件并将其插入到您的数据库中。您可以通过初始迁移以编程方式执行此操作,就像它在 linked documentation 底部推荐的那样。
是的,但我试图避免制作文本文件。似乎没有必要。
迁移不需要包含任何硬编码的初始数据,它们只是 Python 脚本。您可以只使用RunPython
迁移并创建一个函数,该函数从您的 API 流式传输数据并将其插入到您的数据库中。它会在初始迁移运行时自动运行,并且由于迁移会自动使用事务,因此可以防止损坏您的数据库状态。
现在和你在一起。我没有意识到 Django 的文档建议创建数据迁移。仍然习惯于不断变化的术语。感谢您花时间解释。
【参考方案1】:
您可以为此使用数据迁移。首先为您的应用创建一个空迁移:
$ python manage.py makemigrations yourappname --empty
在您的空迁移中,创建一个函数来加载您的数据并添加一个migrations.RunPython
操作。这是Django documentation on migrations的修改版本:
from __future__ import unicode_literals
from django.db import migrations
def stream_from_api():
...
def load_data(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
Person = apps.get_model('yourappname', 'Person')
for item in stream_from_api():
person = Person(first=item['first'], last=item['last'], age=item['age'])
person.save()
class Migration(migrations.Migration):
dependencies = [('yourappname', '0009_something')]
operations = [migrations.RunPython(load_data)]
如果您有很多简单的数据,您可能会从批量创建方法中受益:
from __future__ import unicode_literals
from django.db import migrations
def stream_from_api():
...
def load_data(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
Person = apps.get_model('yourappname', 'Person')
def stream_people():
for item in stream_from_api():
yield Person(first=item['first'], last=item['last'], age=item['age'])
# Adjust (or remove) the batch size depending on your needs.
# You won't be able to use this method if your objects depend on one-another
Person.objects.bulk_create(stream_people(), batch_size=10000)
class Migration(migrations.Migration):
dependencies = [('yourappname', '0009_something')]
operations = [migrations.RunPython(load_data)]
迁移具有自动包含在事务中的额外好处,因此您可以随时停止迁移,并且不会使您的数据库处于不一致状态。
【讨论】:
在您的load_data
函数中,无论如何要使用apps.get_model()
加载基本用户模型?我知道有,只是不知道怎么做。
@Tunn: apps.get_model('auth', 'User')
应该可以工作。【参考方案2】:
在创建数据的Games
模型上编写一些类方法对您有用吗?推测此方法查询外部 API,将 Games()
对象打包为名为 games
的列表,然后使用 Games.objects.bulk_create(games)
将其插入数据库。
【讨论】:
这似乎相当理想。谢谢。以上是关于不使用固定装置的 Django 1.10 种子数据库的主要内容,如果未能解决你的问题,请参考以下文章