【问题标题】:Django call 'id' expected a number but got stringDjango call 'id' 需要一个数字,但得到了字符串
【发布时间】:2020-01-27 19:18:36
【问题描述】:

django-import-export 库的 Django 错误。

我想通过 django admin 将数据从 excel 导入到 db。我使用它 django-import-export,但我得到了字段 'id' 预期的数字,但得到了 'HPI'。

Excel 文件包含

我找到了答案,我必须添加 exclude = ('id',),但它没有帮助。我也做了迁移,它也没有帮助。 如何修复它并能够通过 django admin 将 6 列数据从 excel 导入到 db?

models.py


    from django_mysql.models import JSONField, Model
    from django.db import models



    class Category(Model):
        title = models.CharField(max_length=100)

        class Meta:
            ordering = ('-id',)
            verbose_name = 'Category'
            verbose_name_plural = 'Categories'

        def __str__(self):
            return self.title


    class Tag(Model):
        title = models.CharField(max_length=100)

        class Meta:
            ordering = ('-id',)

        def __str__(self):
            return self.title


    class Type(Model):
        title = models.CharField(max_length=100)

        class Meta:
            ordering = ('-id',)
            verbose_name = 'Type'
            verbose_name_plural = 'Types'

        def __str__(self):
            return self.title


    class Macro(Model):
        type = models.ForeignKey(
            Type,
            max_length=100,
            null=True,
            blank=True,
            on_delete=models.SET_NULL)
        tags = models.ManyToManyField(Tag, blank=True)
        category = models.ForeignKey(
            Category, null=True, blank=True, on_delete=models.SET_NULL)
        abbreviation = models.CharField(max_length=100, unique=True)
        title = models.CharField(max_length=100, verbose_name='Title')
        content = models.TextField(max_length=1000, null=True, blank=True)

        class Meta:
            ordering = ('-id',)

        def __str__(self):
            return self.title

admin.py


    from django.contrib import admin

    from import_export import resources
    from import_export.admin import ImportExportModelAdmin

    from .models import Category, Tag, Type, Macro


    class MacroResource(resources.ModelResource):

        class Meta:
            model = Macro
            skip_unchanged = True
            report_skipped = True
            exclude = ('id', )
            export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')


    @admin.register(Macro)
    class MacroAdmin(ImportExportModelAdmin):
        resource_class = MacroResource
        list_display = ('id', 'type', 'tags_list', 'category', 'abbreviation', 'title', 'content')
        search_fields = ('title', 'category__title', 'type__title', 'abbreviation', 'content', )

        def tags_list(self, obj):
            tags = [t for t in obj.tags.all()]
            return ' '.join(str(tags)) if tags else '-'


    @admin.register(Category)
    class CategoryAdmin(admin.ModelAdmin):
        list_display = ('id', 'title')


    @admin.register(Tag)
    class TagAdmin(admin.ModelAdmin):
        list_display = ('id', 'title')

        def __str__(self):
            return self.title


    @admin.register(Type)
    class TypeAdmin(admin.ModelAdmin):
        list_display = ('id', 'title')

【问题讨论】:

  • 顺便说一句,你是如何从导入导出中得到如此好的错误报告的?我只得到一个堆栈跟踪列表。
  • @GregKaleka 我不知道,这只是管理仪表板中的错误报告

标签: python django django-admin django-import-export


【解决方案1】:

问题出在数据库模型的 ForeignKey 和 ManyToMany 字段上。因此 django-import-export 库需要获取该字段的小部件。

更多信息在这里:https://django-import-export.readthedocs.io/en/latest/api_widgets.html#import_export.widgets.ForeignKeyWidget

解决方案: 管理员.py


        class MacroResource(resources.ModelResource):

            type = fields.Field(
                column_name='type',
                attribute='type',
                widget=ForeignKeyWidget(Type, 'title'))

            category = fields.Field(
                column_name='category',
                attribute='category',
                widget=ForeignKeyWidget(Category, 'title'))

            tags = fields.Field(
                column_name='tags',
                attribute='tags',
                widget=ManyToManyWidget(Tag, field='title'))

            class Meta:
                model = Macro
                skip_unchanged = True
                report_skipped = True
                exclude = ('id', )
                import_id_fields = ('title',)

                fields = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')

而不是


        class MacroResource(resources.ModelResource):

            class Meta:
                model = Macro
                skip_unchanged = True
                report_skipped = True
                exclude = ('id', )
                export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')


【讨论】:

    【解决方案2】:

    Django-import-export 期望第一列是id。

    如果这些是新对象,只需将 id 列留空即可。否则,将对象的数据库 ID 放在该字段中。

    如果您无法修改文件,或者不想修改文件,并且您将总是向数据库添加新行(而不是修改现有行),您可以创建一个通过覆盖方法 before_import 并强制 get_instance 始终返回 False,在资源类中动态地添加 id 字段。

    class MacroResource(resources.ModelResource):
    
        def before_import(self, dataset, using_transactions, dry_run, **kwargs):
            dataset.insert_col(0, col=["",]*dataset.height, header="id")
    
        def get_instance(self, instance_loader, row):
            return False
    
        class Meta:
            model = Macro
            skip_unchanged = True
            report_skipped = True
            export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')
    

    【讨论】:

    • 谢谢,但我得到了错误“before_import() 需要 3 个位置参数,但给出了 4 个”。我删除了 dry_run 并得到“before_import() 需要 2 个位置参数,但给出了 4 个”。你能帮忙吗?
    • 我将 using_transactions 添加到 before_import() 中,但出现了类似的错误“某些行无法验证,请在可能的情况下更正数据中的这些错误,然后使用上面的表格重新上传。”和“字段 'id' 需要一个数字,但得到了 'HPI'。”
    • 啊,是的,对不起 - using_transactions 确实需要在呼叫签名中。至于仍然出现错误 - 我认为我们还需要覆盖 get_instance 方法。我更新了我的答案。如果这不起作用,您可以深入了解堆栈跟踪并查看错误的根源吗?
    • 不幸的是,这没有帮助。我在控制台中没有收到错误,只有这个“POST /admin/macros/macro/import/HTTP/1.1”200 15554。我在管理仪表板中看到一条错误消息,例如“某些行无法验证,请更正如果可能,您的数据中会出现这些错误,然后使用上面的表格重新上传。”和“类型字段 'id' 需要一个数字,但得到了 'HPI'。”
    【解决方案3】:

    您在模型中使用外键的属性, 您需要指定父模型的 id 而不是 xlsx/csv 文件中的值。

    【讨论】:

    • 能否请您详细说明如何在ForeignKeyWidget中使用的属性中指定父模型的id?这对我会有帮助。谢谢
    • 我们知道每个对象都有一个唯一的 id(主键)。所以我们需要指定该对象的 id 而不是对象的名称。如果有两个具有相同名称的对象,为了避免该错误,我们在表中使用它们的主键/唯一 ID。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-04-23
    • 2021-09-13
    • 2022-01-12
    • 2021-08-31
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多