【问题标题】:Custom migrations in Django from JSON file?从 JSON 文件在 Django 中自定义迁移?
【发布时间】:2017-12-01 20:58:28
【问题描述】:

我正在尝试将一些初始数据从 JSON 文件导入 Django 中的数据库,但我终生无法弄清楚如何在自定义迁移中执行此操作。我的第一个函数返回与我的数据库中的模型Mineral 匹配的字段的字典。第二个函数的前两行取自关于自定义迁移的 Django 1.11 文档,其余的只是应该循环遍历 JSON 文件,使用第一个函数制作字典,然后 create() 他们,使用关键字参数来自字典。但是当我尝试运行它时,我得到django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

现在我的自定义迁移文件如下所示:

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),
    ]

非常感谢任何帮助。

注意:是的,我知道我可以使用**kwargs 删减大约 40 行代码,但不完全确定如何执行此操作(我还是新手);在这方面的任何建议也将不胜感激。

【问题讨论】:

    标签: python json django


    【解决方案1】:

    根据我的理解,我会说这是相当有限的,Django 中的事务由“原子部分”组成。基本上,整个交易可以分为该交易的所有步骤。如果 1 一路失败,这可以让您回滚这些步骤。

    默认情况下,Sqlite 和 Postgres 使用事务。 Django Migration 默认有atomic = True

    有几种方法可以解决这个问题。

    1. 设置迁移类 atomic = False 这将有效地运行迁移而无需事务。

    2. 将“事务尝试”包装在上下文管理器中 with transaction.atomic()

    3. 使用“事务尝试”创建一个函数并将该函数包装在一个装饰器中 @transaction.atomic

    这里看到的 2 和 3 Django Transactions

    我偏爱上下文管理器解决方案并保持交易完好无损。因为对于不使用事务的数据库,文档说:

    原子属性对不支持 DDL 事务的数据库(例如 MySQL、Oracle)没有影响。

    因此,对于您的代码示例,我将引入事务的导入。 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
    

    【讨论】:

      猜你喜欢
      • 2022-06-29
      • 2018-08-24
      • 1970-01-01
      • 2018-11-03
      • 2017-02-19
      • 1970-01-01
      • 2018-01-10
      • 2011-10-28
      • 2021-06-09
      相关资源
      最近更新 更多