I can't import Django-taggit tags using Django-import-export.
This error is when the value is entered.
Line number: 1 - invalid literal for int() with base 10: 'def'
Also, this error is when the value is blank.
Line number: 2 - Cannot add <QuerySet []> (<class 'django.db.models.query.QuerySet'>). Expected <class 'django.db.models.base.ModelBase'> or str.
I also posted question in This issue .
xlsx table there is an id column too.
models.py
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
class KnowHow(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField(blank=True)
file = models.FileField(blank=True,upload_to='explicit_knowhows')
free_tags = TaggableManager(blank=True)
def __str__(self):
return self.title
admin.py
from django.contrib import admin
from import_export import resources
from import_export import fields
from import_export.admin import ImportExportModelAdmin
from .models import KnowHow
# Register your models here.
class KnowHowResource(resources.ModelResource):
class Meta:
model = KnowHow
import_id_fields = ['id']
@admin.register(KnowHow)
class knowHowAdmin(ImportExportModelAdmin):
resource_class = KnowHowResource
My solution:
Custom widget:
from import_export import fields
from import_export import widgets
from taggit.forms import TagField
from taggit.models import Tag
class TagWidget(widgets.ManyToManyWidget):
def render(self, value, obj=None):
return self.separator.join(
[obj.name for obj in value.all()]
)
def clean(self, value, row=None, *args, **kwargs):
values = TagField().clean(value)
return [
Tag.objects.get_or_create(name=tag)[0]
for tag in values
]
Then we have to override field as well:
class TagFieldImport(fields.Field):
def save(self, obj, data, is_m2m=False):
# This method is overridden because originally code
# getattr(obj, attrs[-1]).set(cleaned, clean=True) doesn't unpack cleaned value
if not self.readonly:
attrs = self.attribute.split('__')
for attr in attrs[:-1]:
obj = getattr(obj, attr, None)
cleaned = self.clean(data)
if cleaned is not None or self.saves_null_values:
if not is_m2m:
setattr(obj, attrs[-1], cleaned)
else:
# Change only here
getattr(obj, attrs[-1]).set(*cleaned, clean=True)
And then to use in the resource like that:
tags = cure_widgets.TagFieldImport(
attribute="tags",
column_name="tags",
widget=cure_widgets.TagWidget(Tag, separator=", ")
)
Another possible solution / workaround I use.
Define a helper model text-field to store the comma-separated tag list. Let's call it "tags_char". Then override the save method of the model to convert the comma-separated list to Tag objects.
# models.py
from django.db import models
from taggit.managers import TaggableManager
class Book(models.Model):
tags_char = models.TextField(blank=True)
tags = TaggableManager(blank=True)
def save(self, *args, **kwargs):
if ',' in self.tags_char and self.pk:
for tag in self.tags_char.split(','):
self.tags.add(tag)
super(Book, self).save(*args, **kwargs)
The final step is to adjust the ModelResource. We exclude tags from import and instead import to tags_char from the file. Knowing that the conversion will happen afterwards once the objects are saved.
#admin.py
class BookResource(resources.ModelResource):
class Meta:
model = Book
exclude = ('id', 'tags')
Unfortunately there's one problem with this workaround. Beacuse of the way django import-export works the save() method is called prior to objects being assigned an id (pk). And a tag can not be added if an id does not eixst. This is the reason for checking if self.pk exists in the save method. if ',' in self.tags_char and self.pk
There are three alternatives to get around the issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.