首页 > 解决方案 > IntegrityError Django ORM

问题描述

我正在处理一个包含咨询和医疗数据的文件。我还在处理另一个只包含考试数据的文件。

作为一种好的做法,我将模型归一化,如下所示:

class Medico(models.Model):
    codigo_medico = models.IntegerField(primary_key=True, unique=True)
    nome = models.CharField(max_length=50)


class Consulta(models.Model):
    numero_guia = models.IntegerField(primary_key=True)
    data_consulta = models.DateField()
    valor_consulta = models.FloatField()
    codigo_medico = models.ForeignKey(Medico, on_delete=models.CASCADE)

    class META:
        ordering = ['data_consulta']


class Exame(models.Model):
    exame = models.CharField(max_length=30, null=False)
    valor_exame = models.FloatField()
    numero_guia_consulta = models.ForeignKey(Consulta, on_delete=models.CASCADE)

    class META:
        ordering = ['-valor_exame']

请注意,医疗模型的ID字段标记为unique = true,因为无论咨询如何,都只能有一个具有特定代码的医生。

我做了文件处理,效果很好。当试图运行同一个文件时,知道医生的数据是唯一的,我得到 IntegrationError (return Database.Cursor.execute (self, query, params) django.db.utils.IntegrityError: UNIQUE constraint failed: relatorio_medico.codigo_medico) 这个预料之中。我精确地进行了这个处理以获得重复的数据。问题是,如果某个特定的咨询文件到了,我的基地总会有一个已经注册的医生,所以我需要处理 IntegratedError 案例。

我尝试使用 try 和 except 但无济于事。

我是如何实现的:

from relatorio.models import Exam, Consultation, Doctor
from django.db import IntegrityError as IE
from sqlite3 import IntegrityError


class CreateDataExams:
    """
    Cria os dados no banco de dados a partir de um lote de dados de exames.
    """
    def __init__(self, data_exams):
        self.data_exams = data_exams

    def create_exams(self):
        exams = []
        for item in self.data_exams[1:]:
            new_item = item.split(';')
            obj_exams = Exame(numero_guia_consulta=new_item[0], exame=new_item[1], valor_exame=new_item[2])
            exams.append(obj_exams)
        Exame.objects.bulk_create(exams)


class CreateDataAppointment:
    """
        Cria os dados no banco de dados a partir de um lote de dados de consulta.
    """
    def __init__(self, data_appointment):

        self.data_appointment = data_appointment
    def create_appointment(self):
        appointment = []
        medico = []
        del self.data_appointment[-1]
        for item in self.data_appointment[1:]:
            new_item = item.split(';')
            obj_medico = Medico(codigo_medico=new_item[1], nome=new_item[2])
            medico.append(obj_medico)

        Medico.objects.bulk_create(medico, batch_size=1000)

        for item in self.data_appointment[1:]:
            new_item = item.split(';')
            obj_appointment = Consulta(numero_guia=int(new_item[0]), data_consulta=new_item[3],
                                       valor_consulta=new_item[4],
                                   codigo_medico=Medico.objects.get(codigo_medico=int(new_item[1])))
        appointment.append(obj_appointment)
    Consulta.objects.bulk_create(appointment)

下面是我正在处理的数据模型。考试:

在此处输入图像描述

预约:

在此处输入图像描述

请注意,某些医生的代码是重复的。

我的问题是:保存医生数据时如何处理这种情况,考虑到我正在批量处理,由于文件的大小超过 20k 记录?

我试着用

from django.db import IntegrityError 

try:
    Medico.objects.bulk_create(medico, batch_size=1000)
except IntegrityError:
    Medico.objects.bulk_update(medico, ['nome'], batch_size=1000)

但没有成功。发生同样的错误。错误:

在此处输入图像描述

标签: python-3.xdjangodjango-modelsunique

解决方案


如果它们不存在,最简单的选择是一个一个地创建它们:

obj, created = Medico.objects.get_or_create(codigo_medico=new_item[1], nome=new_item[2])

如果您的对象已经存在,则将从数据库中获取,否则将插入数据库。

您还使用了另一个我认为是名称的字段,因此寻找具有相同 id 和相同字符串的行很慢,因为您的nome字段没有被索引,除了它是一个额外的查找之外。因此,您可以删除名称并只使用查找速度非常快的 id。

exists = Medico.objects.filter(codigo_medico=new_item[1]).exists()
# only create a new object for bulk create if it doesn't exists
if not exists:
    obj_medico = Medico(codigo_medico=new_item[1], nome=new_item[2])
        medico.append(obj_medico)

为了使其更加优化,您可以获取所有 id 并仅在 id 不在该列表中时创建一个对象:

doctor_ids = list(Medico.objects.all().values_list('id', flat=True))

for item in self.data_appointment[1:]:
    new_item = item.split(';')
    if new_item[1] not in doctor_ids:
        obj_medico = Medico(codigo_medico=new_item[1], nome=new_item[2])
        medico.append(obj_medico)

推荐阅读