简体   繁体   English

从JSON文件在Django中进行自定义迁移?

[英]Custom migrations in Django from JSON file?

I'm trying to import some initial data into a database in Django from a JSON file and can't for the life of me figure out how to do it in a custom migration. 我正在尝试从JSON文件将一些初始数据导入Django中的数据库,并且无法终生搞清楚如何在自定义迁移中进行操作。 My first function returns dictionaries with fields that match up with the model Mineral in my database. 我的第一个函数返回的字典中的字段与数据库中的Mineral模型匹配。 The first two lines of the second function are taken from the Django 1.11 docs on custom migrations, and the rest is just supposed to loop through the JSON file, make dictionaries with the first function, and then create() them, with the keyword arguments coming from the dictionary. 第二个函数的前两行摘自有关自定义迁移的Django 1.11文档,其余的仅应循环遍历JSON文件,使用第一个函数create()字典,然后使用关键字arguments对其进行create()来自字典。 But when I try to run it I get django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block. 但是,当我尝试运行它时, django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block. django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

Right now my custom migration file looks like this: 现在,我的自定义迁移文件如下所示:

from __future__ import unicode_literals

from django.db import migrations, IntegrityError

import json


def make_mineral_dict(mineral):
    """Make a dictionary out of a mineral object from JSON file"""
    fields = {
        'name': None,
        'image filename': None,
        'image caption': None,
        'category': None,
        'formula': None,
        'strunz classification': None,
        'crystal system': None,
        'unit cell': None,
        'color': None,
        'crystal symmetry': None,
        'cleavage': None,
        'mohs scale hardness': None,
        'luster': None,
        'streak': None,
        'diaphaneity': None,
        'optical properties': None,
        'refractive index': None,
        'crystal habit': None,
        'specific gravity': None,
        'group': None,
    }

    for key, value in mineral.items():
        fields[key] = value
    return fields


def load_data(apps, schema_editor):
    Mineral = apps.get_model("minerals", "Mineral")
    db_alias = schema_editor.connection.alias
    with open('minerals.json', encoding='utf-8') as file:
        minerals = json.load(file)
        for mineral in minerals:
            try:
                fields = make_mineral_dict(mineral)
                Mineral.objects.using(db_alias).create(
                    name=fields['name'],
                    image_filename=fields['image filename'],
                    image_caption=fields['image caption'],
                    category=fields['category'],
                    formula=fields['formula'],
                    strunz_classification=fields['strunz classification'],
                    crystal_system=fields['crystal system'],
                    unit_cell=fields['unit cell'],
                    color=fields['color'],
                    crystal_symmetry=fields['crystal symmetry'],
                    cleavage=fields['cleavage'],
                    mohs_scale_hardness=fields['mohs scale hardness'],
                    luster=fields['luster'],
                    streak=fields['streak'],
                    diaphaneity=fields['diaphaneity'],
                    optical_properties=fields['optical properties'],
                    refractive_index=fields['refractive index'],
                    crystal_habit=fields['crystal habit'],
                    specific_gravity=fields['specific gravity'],
                    group=fields['group']
                )
            except IntegrityError:
                continue



class Migration(migrations.Migration):

    dependencies = [
        ('minerals', '0002_mineral_group'),
    ]

    operations = [
        migrations.RunPython(load_data),
    ]

Any help is greatly appreciated. 任何帮助是极大的赞赏。

Note: Yes, I know I could cut out around 40 lines of code by using **kwargs , but not exactly sure how to do that (I'm still very new); 注意:是的,我知道我可以使用**kwargs削减约40行代码,但不确定如何做到这一点(我还是很新); any suggestions on that front would be appreciated as well. 在这方面的任何建议也将不胜感激。

From my understanding, which I would say is fairly limited, a transaction in Django is composed of "atomic parts". 根据我的理解,我认为这是相当有限的,Django中的事务由“原子部分”组成。 Basically the transaction as a whole can be divided up into all the steps for that transaction. 基本上,整个交易可以分为该交易的所有步骤。 Which lets you roll back those steps if 1 fails along the way. 如果1失败,则可以回退这些步骤。

By default, Sqlite and Postgres use transactions. 默认情况下,Sqlite和Postgres使用事务。 Django Migration by default has atomic = True . Django迁移默认情况下具有atomic = True

There are a few ways to solve the issue surrounding this. 有几种方法可以解决此问题。

  1. Setting the Migration class atomic = False this would effectively run migration with no transactions. 将Migration类设置为atomic = False这将有效地进行没有事务的迁移。

  2. Wrapping the "transaction attempt" in a context manager with transaction.atomic() with transaction.atomic()在上下文管理器中包装“事务尝试”

  3. Creating a function with the "transaction attempt" and wrapping that function in a decorator @transaction.atomic 使用“事务尝试”创建函数,并将该函数包装在装饰器@transaction.atomic

2 and 3 as seen here Django Transactions 2和3,如此处所示Django Transactions

I am partial to the context manager solution and keeping transactions in-tact. 我偏爱上下文管理器解决方案并保持事务完整。 Because for databases that dont use transactions the docs say: 因为对于不使用事务的数据库,文档说:

The atomic attribute doesn't have an effect on databases that don't support DDL transactions (eg MySQL, Oracle). 原子属性对不支持DDL事务的数据库(例如MySQL,Oracle)没有影响。

So for your code example I would throw in the import for transaction. 因此,对于您的代码示例,我将导入导入以进行事务处理。 from django.db import transaction

from django.db import transaction
# imports at the top...

def load_data(apps, schema_editor):
    Mineral = apps.get_model("minerals", "Mineral")
    db_alias = schema_editor.connection.alias

    with open('minerals.json', encoding='utf-8') as file:
        minerals = json.load(file)
        for mineral in minerals:
            try:
                fields = make_mineral_dict(mineral)

                # Wrapping this line around...
                with transaction.atomic():
                    Mineral.objects.using(db_alias).create(
                        name=fields['name'],
                        image_filename=fields['image filename'],
                        image_caption=fields['image caption'],
                        category=fields['category'],
                        formula=fields['formula'],
                        strunz_classification=fields['strunz classification'],
                        crystal_system=fields['crystal system'],
                        unit_cell=fields['unit cell'],
                        color=fields['color'],
                        crystal_symmetry=fields['crystal symmetry'],
                        cleavage=fields['cleavage'],
                        mohs_scale_hardness=fields['mohs scale hardness'],
                        luster=fields['luster'],
                        streak=fields['streak'],
                        diaphaneity=fields['diaphaneity'],
                        optical_properties=fields['optical properties'],
                        refractive_index=fields['refractive index'],
                        crystal_habit=fields['crystal habit'],
                        specific_gravity=fields['specific gravity'],
                        group=fields['group']
                    )
            except IntegrityError:
                continue

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM