[英]Django Import-Export: Issues importing to model with UUID for id field
我正在嘗試使用 Django-import-export 包(v3.0.0b4)通過 Django Admin 將 csv 文件(utf-8 編碼)導入 Django 模型。 我最初使用的是最后一個穩定版本,但被鼓勵嘗試預發布。 導入預覽看起來正確,但界面對 csv 的所有行顯示以下錯誤:
非特定字段“”不是有效的 UUID。
我嘗試了在 import_id_fields 中包含“id”或排除“id”字段並使用重命名的“unique_id”字段作為掛鈎的幾種排列方式。 我還嘗試在 csv 的“id”列和“unique_id”列中使用空白條目進行導入。 也完全從 csv 中省略了 id 字段。 出於某種原因,無論我是否填充 id 字段,都會返回一個空白字段。 我懷疑我做錯了什么,但我不清楚是什么。 resources.py、models.py 和 admin.py 包括在下面。 如果需要,很高興分享其他片段。
模型.py
from django.db import models
from django.db.models import Sum
import uuid
from datetime import datetime
class Purchase(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid4, editable=False)
date = models.DateField(blank=True,null=True)
seller = models.CharField(max_length=200,default='')
number = models.CharField(max_length=200,blank=True,default='')
customer = models.CharField(max_length=200,default='')
salesperson = models.CharField(max_length=200,blank=True,default='')
discount = models.FloatField(blank=True,default=0,null=True)
shipping = models.FloatField(blank=True,default=0,null=True)
tax = models.FloatField(blank=True,default=0,null=True)
file = models.FileField(blank=True,default='', upload_to='uploads/')
@property
def subtotal(self):
return LineItem.objects.filter(Purchase=self).aggregate(Sum('amount'))['amount__sum']
@property
def grand_total(self):
return round(self.subtotal+self.tax,2)
class Meta:
verbose_name_plural = "Purchases"
def __str__(self):
return self.seller+" "+self.number
class LineItem(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid4, editable=False)
purchase = models.ForeignKey(Purchase, on_delete= models.CASCADE, related_name="LineItem",default='',null=True)
product_id = models.CharField(max_length=200,blank=True,default='')
name = models.CharField(max_length=200,default='')
category = models.CharField(max_length=200,blank=True,default='')
qty = models.FloatField(null=True)
qty_uom = models.CharField(max_length=200,default='')
amount = models.FloatField(null=True)
pack_qty = models.FloatField(null=True)
pack_uom = models.CharField(max_length=200,default='')
@property
def date(self):
return format(self.purchase.date,f"%m/%d/%Y")
@property
def bulk_unit_price(self):
return round(self.amount/self.qty,2)
@property
def unit_price(self):
return round(self.bulk_unit_price/self.pack_qty,2)
class Meta:
verbose_name_plural = "LineItems"
def __str__(self):
return self.name
資源.py
from import_export import resources, widgets, fields
from django.db.models.query import *
from .models import LineItem, Purchase
class CharRequiredWidget(widgets.CharWidget):
def clean(self, value, row=None, *args, **kwargs):
val = super().clean(value)
if val:
return val
else:
raise ValueError('this field is required')
class FloatWidget(widgets.DecimalWidget):
def clean (self, value, row=None, *args, **kwargs):
if self.is_empty(value):
return None
return float(str(value))
class ForeignKeyWidgetWithCreation(widgets.ForeignKeyWidget):
def __init__(self, model, field="pk", create=False, **kwargs):
self.model = model
self.field = field
self.create = create
super(ForeignKeyWidgetWithCreation, self).__init__(model, field=field, **kwargs)
def clean(self, value, **kwargs):
if not value:
return None
if self.create:
self.model.objects.get_or_create(**{self.field: value})
val = super(ForeignKeyWidgetWithCreation, self).clean(value, **kwargs)
return self.model.objects.get(**{self.field: val}) if val else None
class LineItemResource(resources.ModelResource):
class Meta:
model = LineItem
import_id_fields = ['unique_id',]
exclude = ('id',)
fields = ('unique_id','purchase__seller','purchase__number','purchase__date','product_id','name','category','qty','qty_uom','amount','pack_qty','pack_uom',)
report_skipped = True
unique_id = fields.Field(column_name='unique_id', attribute='id',widget=CharRequiredWidget())
purchase__seller = fields.Field(attribute='purchase', widget=ForeignKeyWidgetWithCreation(model=Purchase,field='seller',create=True))
purchase__number = fields.Field(attribute='purchase', widget=ForeignKeyWidgetWithCreation(model=Purchase,field='number',create=True))
purchase__date = fields.Field(attribute='purchase',widget=ForeignKeyWidgetWithCreation(model=Purchase,field='date',create=True))
product_id = fields.Field(saves_null_values=False, attribute='product_id',widget=CharRequiredWidget())
name = fields.Field(saves_null_values=False, attribute='name',widget=CharRequiredWidget())
category = fields.Field(saves_null_values=False, attribute='category',widget=CharRequiredWidget())
qty = fields.Field(saves_null_values=False, attribute='qty',widget=FloatWidget())
qty_uom = fields.Field(saves_null_values=False, attribute='qty_uom',widget=CharRequiredWidget())
amount = fields.Field(saves_null_values=False, attribute='amount',widget=FloatWidget())
pack_qty = fields.Field(saves_null_values=False, attribute='pack_qty',widget=FloatWidget())
pack_uom = fields.Field(saves_null_values=False, attribute='pack_uom',widget=CharRequiredWidget())
管理員.py
from django.contrib import admin
from django.contrib import admin
from .models import Purchase, LineItem
from .resources import LineItemResource
from django.db import models
from import_export.admin import ImportExportModelAdmin
class LineItemAdmin(ImportExportModelAdmin):
resource_class = LineItemResource
list_display = ('id','purchase','product_id','name','category','qty','qty_uom','amount','pack_qty','pack_uom',)
admin.site.register(Purchase)
admin.site.register(LineItem, LineItemAdmin)
csv結構:
id,unique_id,purchase__date,purchase__seller,purchase__number,product_id,name,category,amount,qty,qty_uom,unit_price,pack_qty,pack_uom,$/unit
,4e157e12-9a92-e303-44af-ee494593f073,4/29/2022,Vendor 1, 1423840,733111,item 1, category 1, 153.92,9.65,lb,15.95,1,lb,15.95
錯誤:
Exception in thread django-main-thread:
Traceback (most recent call last):
File "\mysite\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 187, in __get__
rel_obj = self.field.get_cached_value(instance)
File "\mysite\venv\lib\site-packages\django\db\models\fields\mixins.py", line 15, in get_cached_value
return instance._state.fields_cache[cache_name]
KeyError: 'purchase'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "\mysite\venv\lib\site-packages\django\db\models\fields\__init__.py", line 2614, in to_python
return uuid.UUID(**{input_form: value})
File "\lib\uuid.py", line 177, in __init__
raise ValueError('badly formed hexadecimal UUID string')
ValueError: badly formed hexadecimal UUID string
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "\lib\threading.py", line 973, in _bootstrap_inner
self.run()
File "\lib\threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "\mysite\venv\lib\site-packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "\mysite\venv\lib\site-packages\django\core\management\commands\runserver.py", line 125, in inner_run
autoreload.raise_last_exception()
File "\mysite\venv\lib\site-packages\django\utils\autoreload.py", line 87, in raise_last_exception
raise _exception[1]
File "\mysite\venv\lib\site-packages\django\core\management\__init__.py", line 398, in execute
autoreload.check_errors(django.setup)()
File "\mysite\venv\lib\site-packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "\mysite\venv\lib\site-packages\django\__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "\mysite\venv\lib\site-packages\django\apps\registry.py", line 125, in populate
app_config.ready()
File "\mysite\venv\lib\site-packages\django\contrib\admin\apps.py", line 27, in ready
self.module.autodiscover()
File "\mysite\venv\lib\site-packages\django\contrib\admin\__init__.py", line 50, in autodiscover
autodiscover_modules("admin", register_to=site)
File "\mysite\venv\lib\site-packages\django\utils\module_loading.py", line 58, in autodiscover_modules
import_module("%s.%s" % (app_config.name, module_to_search))
File "\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "\mysite\main\admin.py", line 6, in <module>
from .resources import LineItemResource
File "\mysite\main\resources.py", line 175, in <module>
result = resource.import_data(
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 809, in import_data
return self.import_data_inner(
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 867, in import_data_inner
raise row_result.validation_error
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 707, in import_row
diff = self.get_diff_class()(self, original, new)
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 241, in __init__
self.left = self._export_resource_fields(resource, instance)
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 262, in _export_resource_fields
return [resource.export_field(f, instance) if instance else "" for f in resource.get_user_visible_fields()]
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 262, in <listcomp>
return [resource.export_field(f, instance) if instance else "" for f in resource.get_user_visible_fields()]
File "\mysite\venv\lib\site-packages\import_export\resources.py", line 920, in export_field
return field.export(obj)
File "\mysite\venv\lib\site-packages\import_export\fields.py", line 122, in export
value = self.get_value(obj)
File "\mysite\venv\lib\site-packages\import_export\fields.py", line 87, in get_value
value = getattr(value, attr, None)
File "\mysite\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 205, in __get__
rel_obj = self.get_object(instance)
File "\mysite\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 168, in get_object
return qs.get(self.field.get_reverse_related_filter(instance))
File "\mysite\venv\lib\site-packages\django\db\models\query.py", line 482, in get
clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
File "\mysite\venv\lib\site-packages\django\db\models\query.py", line 1071, in filter
return self._filter_or_exclude(False, args, kwargs)
File "\mysite\venv\lib\site-packages\django\db\models\query.py", line 1089, in _filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
File "\mysite\venv\lib\site-packages\django\db\models\query.py", line 1096, in _filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "\mysite\venv\lib\site-packages\django\db\models\sql\query.py", line 1502, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "\mysite\venv\lib\site-packages\django\db\models\sql\query.py", line 1532, in _add_q
child_clause, needed_inner = self.build_filter(
File "\mysite\venv\lib\site-packages\django\db\models\sql\query.py", line 1358, in build_filter
return self._add_q(
File "\mysite\venv\lib\site-packages\django\db\models\sql\query.py", line 1532, in _add_q
child_clause, needed_inner = self.build_filter(
File "\venv\lib\site-packages\django\db\models\sql\query.py", line 1448, in build_filter
condition = self.build_lookup(lookups, col, value)
File "\mysite\venv\lib\site-packages\django\db\models\sql\query.py", line 1273, in build_lookup
lookup = lookup_class(lhs, rhs)
File "\mysite\venv\lib\site-packages\django\db\models\lookups.py", line 27, in __init__
self.rhs = self.get_prep_lookup()
File "\mysite\venv\lib\site-packages\django\db\models\lookups.py", line 85, in get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
File "\mysite\venv\lib\site-packages\django\db\models\fields\__init__.py", line 2598, in get_prep_value
return self.to_python(value)
File "\mysite\venv\lib\site-packages\django\db\models\fields\__init__.py", line 2616, in to_python
raise exceptions.ValidationError(
django.core.exceptions.ValidationError: ['“” is not a valid UUID.']
乍一看,有一個空的id
字段這一事實似乎是相關的(盡管您說您試圖省略該字段)。 您可以嘗試從Resource
和 csv 中刪除對id
的所有引用,盡管您需要保持unique_id
聲明原樣。
您也可以在調試期間嘗試使用ForeignKeyWidget
而不是ForeignKeyWidgetWithCreation
。
您可以嘗試通過腳本而不是管理控制台導入。 例如:
with open('data.csv', 'r') as fh:
dataset = tablib.Dataset().load(fh)
resource = LineItemResource()
result = resource.import_data(
dataset,
raise_errors=True
)
print(result)
這可能有助於您理解錯誤,盡管發現錯誤的最快方法是使用調試器單步執行。
您還可以嘗試使用 2.8.1 版本來查看是否有所不同(如果這已在 v3 中引入)。
如果您可以在 django-import-export 示例應用程序中重現它,那將是非常有趣的。 在release-3-x
分支中,有一個名為UUIDBook
的測試模型。 如果您可以使用示例應用程序重現它,請提出問題,我們可以看看。
如果您發現錯誤的來源,請您回帖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.