微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

django-import-export 库的 Django 外键问题IntegrityError at /import/ FOREIGN KEY 约束失败

如何解决django-import-export 库的 Django 外键问题IntegrityError at /import/ FOREIGN KEY 约束失败

我对 Django 比较陌生,不是高级程序员,所以请原谅我的无知。

什么是有效的: 我有一个 Django 应用程序,它使用一个主模型,该模型通过外键连接到两个辅助模型。应用程序可以从模板和管理员正确创建公司,并且可以使用 Category 模型的外键正确显示“niche”下拉字段,并且可以使用 CompanyImage 模型的外键正确显示图像。

什么不起作用: django-import-export 库可以从前端和管理员正确导入 XLS 文档,但前提是我禁用依赖外键的 Category 和 CompanyImage 模型。该库确实使用我的主要公司模型中的认 user=models.ForeignKey(User) 正确导入,但连接到辅助模型的外键导致外键错误:/import/ FOREIGN KEY 约束失败的 IntegrityError。

我需要什么 我正在导入的 XLS 表不会导入使用外键的字段,因此我想禁用这些字段以避免外键错误。导入一个利基/类别字段会很好,但我可以不用。

我的尝试 我花了两天时间试图解决这个问题。 我试过阅读 django-import-export 文档。 我已经尝试在 Meta 类中为 Resource 模型添加 list_filterexclude。 我已通读Dealing with import of foreignKeys in django-import-export。 我已通读foreign key in django-import-export

如果有人能帮我指引正确的方向,我将不胜感激。谢谢。

Models.py

from django.db import models
from django.contrib.auth.models import User

from phonenumber_field.modelfields import PhoneNumberField
#had to use pip install django-phone-verify==0.1.1
from django.utils import timezone

import uuid
from django.template.defaultfilters import slugify

class Category(models.Model):
    kind = models.CharField(verbose_name='Business Type',max_length=100,blank=True,)

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        return self.kind    

class Company(models.Model):
    #BASIC
    title = models.CharField(verbose_name='company name',blank=True)
    contact = models.CharField(verbose_name='director',blank=True)
    phone_number = PhoneNumberField(blank=True) 
    email = models.EmailField(max_length=200,blank=True)
    email_host = models.CharField(max_length=200,blank=True)
    website = models.URLField(max_length=200,blank=True)
    facebook = models.URLField(max_length=200,blank=True)
    memo = models.TextField(blank=True)
    niche = models.ForeignKey(Category,default=0000,on_delete=models.SET_DEFAULT)

    #UPLOADS
    profile_picture = models.ImageField(upload_to='prospects/images/',blank=True)
    image = models.ImageField(upload_to='prospects/images/',blank=True)
    file = models.FileField(upload_to='prospects/uploads',blank=True)

    #TIME
    date = models.DateField(default=timezone.Now)
    created = models.DateTimeField(auto_Now_add=True)
    updated = models.DateTimeField(auto_Now=True)
    datecompleted = models.DateTimeField(null=True,blank=True) #null for datetime object 

    #BOOLIANS
    important = models.BooleanField(default=False)
    cold = models.BooleanField(default=False,verbose_name='these are cold leads')
    warm = models.BooleanField(default=False,verbose_name='these are warm leads')
    hot = models.BooleanField(default=False,verbose_name='these are hot leads')
    
    #USER
    user = models.ForeignKey(User,on_delete=models.CASCADE,null=True,blank=True)

    #TEST MODEL
    decimal = models.DecimalField(max_digits=5,decimal_places=2,default=00.00)
    integer = models.IntegerField(blank=True,default=0000)
    positive_int = models.PositiveIntegerField(null=True,default=0000)
    positive_small_int = models.PositiveSmallIntegerField(null=True,default=0000)
  

  
    #ADMIN CONSOLE
    class Meta:
        verbose_name_plural = "Companies"
        

    def __str__(self):
        if self.title == "":
            print('empty string')
            return "No Name"
        elif type(self.title) == str:
            return self.title
        else:
            return "No Name" 
    # this makes the title appear in admin console instead of object number


class CompanyImage(models.Model):
    company = models.ForeignKey(Company,default=None,on_delete=models.CASCADE)
    image = models.FileField(upload_to = 'prospects/images/',blank=True)

    def __str__(self):
        return self.company.title

resource.py

from import_export import resources
# from import_export import fields
from import_export.fields import Field
from import_export.fields import widgets
from .models import Company

from django.utils.encoding import force_str,smart_str


# The following widget is to fix an issue with import-export module where if i import any number from an xls file,it imports as a float with a trailing,0
#Could keep it a number and use trunc function to take away decimal but will make string
class DecimalWidget(widgets.NumberWidget):
    def clean(self,value,row=None,*args,**kwargs):
        print()
        print(f"type of value is {type(value)}")
        print()
        if self.is_empty(value):
            return ""
        elif type(value) == float:
            new_string = force_str(value)
            seperator = '.'
            new_string_witout_0 = new_string.split(seperator,1)[0]
            print()
            print(f"the new type of value is {type(value)}")
            print(f"the new value is {value}")
            print()
            return new_string_witout_0
        else:
            print("Aborting! it's not a float or empty string. will just return it as it is.")
            return value
            print()
            print(f"type of value is {type(value)}")
            print(f" the value returned is {value}")
            print()



class CompanyResource(resources.ModelResource):
    title = Field(attribute='title',column_name='name',widget=DecimalWidget())
    contact = Field(attribute='contact',column_name='contact',widget=DecimalWidget())
    phone_number = Field(attribute='phone_number',column_name='phone',widget=DecimalWidget())
    # niche = Field(attribute='niche',column_name='niche',widget=DecimalWidget())
    class Meta:
        model = Company
        exclude = ('niche')
        fields = ('id','title','contact','phone_number','email','email_host','website','facebook')
        export_order = ['id','facebook']
        # fields = ( 'id','weight' )

admin.py

from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export import resources


# from import_export import resources
from .models import Company,Category,CompanyImage
from.resources import CompanyResource

class CompanyResource(resources.ModelResource):

    class Meta:
        model = Company
       
class CompanyImageAdmin(admin.StackedInline):
    model = CompanyImage

class CompanyAdmin(ImportExportModelAdmin):
    resource_class = CompanyResource
    inlines = [CompanyImageAdmin]


# Register your models here.
admin.site.register(Category)
admin.site.register(Company,CompanyAdmin)

@admin.register(CompanyImage)
class CompanyImageAdmin(admin.ModelAdmin):
    pass

views.py

def importcompanies(request):
    if request.method == 'GET':
        return render(request,'prospects/import.html')
    else:
        file_format = request.POST['file-format']
        company_resource = CompanyResource()
        dataset = Dataset()
        new_companies = request.FILES['myfile']

        if file_format == 'CSV':
            imported_data = dataset.load(new_companies.read().decode('utf-8'),format='csv')
            result = company_resource.import_data(dataset,dry_run=True,raise_errors=True)
        elif file_format == 'XLSX':
            imported_data = dataset.load(new_companies.read(),format='xlsx')
            result = company_resource.import_data(dataset,raise_errors=True)

        elif file_format == 'XLS':
            imported_data = dataset.load(new_companies.read(),format='xls')
            result = company_resource.import_data(dataset,raise_errors=True)

        if result.has_errors():
            messages.error(request,'Uh oh! Something went wrong...')

        else:
            # Import Now
            company_resource.import_data(dataset,dry_run=False)
            messages.success(request,'Your words were successfully imported')

    return render(request,'prospects/import.html')

解决方法

  1. 您在两个地方定义了 CompanyResource,因此这可能是您问题的根源。从 admin.py 中删除声明,看看是否有帮助。

  2. 如您所说,fieldsexclude 用于定义要导入的模型字段。 fields 是白名单,而 exclude 是黑名单,因此您不应同时需要。

  3. 设置调试器(如果您还没有)并逐步了解正在发生的事情(这可以节省数天的工作量)。

  4. 如果仍然无效,请更新您的答案并尝试具体说明问题的性质(请参阅with_subelements)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。