如何解决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_filter
和 exclude
。
我已通读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')
解决方法
-
您在两个地方定义了
CompanyResource
,因此这可能是您问题的根源。从admin.py
中删除声明,看看是否有帮助。 -
如您所说,
fields
和exclude
用于定义要导入的模型字段。fields
是白名单,而exclude
是黑名单,因此您不应同时需要。 -
设置调试器(如果您还没有)并逐步了解正在发生的事情(这可以节省数天的工作量)。
-
如果仍然无效,请更新您的答案并尝试具体说明问题的性质(请参阅
with_subelements
)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。