django-import-export 库的 Django 外键问题(/import/ FOREIGN KEY 约束失败时出现 IntegrityError)

问题描述 投票:0回答:1

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

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

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

我尝试过的 我花了两天时间试图解决这个问题。 我尝试阅读 django-import-export 文档。 我尝试在资源模型的 Meta 类中添加

list_filter
exclude
。 我已经阅读了处理 django-import-export 中的外键导入。 我已经通读了 django-import-export 中的 外键

我将非常感激有人能帮助我走向正确的方向。谢谢你。

模型.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',max_length=100,blank=True)
    contact = models.CharField(verbose_name='director',max_length=100,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, blank=True, default=00.00)
    integer = models.IntegerField(blank=True, default=0000)
    positive_int = models.PositiveIntegerField(null=True, blank=True, default=0000)
    positive_small_int = models.PositiveSmallIntegerField(null=True, blank=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

资源.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','title','contact','phone_number', 'email','email_host','website','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, dry_run=True, raise_errors=True)

        elif file_format == 'XLS':
            imported_data = dataset.load(new_companies.read(),format='xls')
            result = company_resource.import_data(dataset, dry_run=True, 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')

django django-models foreign-keys django-import-export
1个回答
0
投票
  1. 您在两个地方定义了

    CompanyResource
    ,所以这可能是问题的根源。从
    admin.py
    中删除声明,看看是否有帮助。

  2. 正如您所说,

    fields
    exclude
    用于定义要导入的模型字段。
    fields
    是白名单,而
    exclude
    是黑名单,因此您不需要同时使用两者。

  3. 设置调试器(如果您还没有)并逐步了解发生了什么(这可以节省数天的精力)。

© www.soinside.com 2019 - 2024. All rights reserved.