I'm having a hard time understanding the import concept.
How can I create the board after the person and organization were imported?
Where is the final board creation missing? i.e. Board(person=p, organization=p)
Current result: OrderedDict([('new', 0), ('update', 0), ('delete', 0), ('skip', 0), ('error', 0), ('invalid', 1)])
class Person(BaseModel):
organizations = models.ManyToManyField("Organization",
blank=True,
through="Board")
class Organization(BaseModel):
people = models.ManyToManyField("Person", blank=True, through="Board")
class Board(BaseModel):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
from django.test import TestCase
import tablib
from import_export import resources
class BoardResource(resources.ModelResource):
def before_import_row(self, row, **kwargs):
org_name_1 = row["organization"]
o=Organization.objects.get_or_create(name_1=org_name_1, defaults={"name_1": org_name_1})
person_firstname = row["person"]
p=Person.objects.get_or_create(firstname=person_firstname, defaults={"firstname": person_firstname})
class Meta:
model = Board
dataset = tablib.Dataset(['','john','acme'], headers=['id','person','organization'])
class TestCase(TestCase):
def test_basic_import(self):
board_resource = BoardResource()
result = board_resource.import_data(dataset, dry_run=False)
print(result.totals)
assert not result.has_errors()
The documentation points to this thread though I'm unable to apply anything to my case
Env:
I'm having a hard time understanding the import concept.
How can I create the board after the person and organization were imported?
Where is the final board creation missing? i.e. Board(person=p, organization=p)
Current result: OrderedDict([('new', 0), ('update', 0), ('delete', 0), ('skip', 0), ('error', 0), ('invalid', 1)])
class Person(BaseModel):
organizations = models.ManyToManyField("Organization",
blank=True,
through="Board")
class Organization(BaseModel):
people = models.ManyToManyField("Person", blank=True, through="Board")
class Board(BaseModel):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
from django.test import TestCase
import tablib
from import_export import resources
class BoardResource(resources.ModelResource):
def before_import_row(self, row, **kwargs):
org_name_1 = row["organization"]
o=Organization.objects.get_or_create(name_1=org_name_1, defaults={"name_1": org_name_1})
person_firstname = row["person"]
p=Person.objects.get_or_create(firstname=person_firstname, defaults={"firstname": person_firstname})
class Meta:
model = Board
dataset = tablib.Dataset(['','john','acme'], headers=['id','person','organization'])
class TestCase(TestCase):
def test_basic_import(self):
board_resource = BoardResource()
result = board_resource.import_data(dataset, dry_run=False)
print(result.totals)
assert not result.has_errors()
The documentation points to this thread though I'm unable to apply anything to my case
Env:
I'm wondering if your data model can be improved. My assumptions may be wrong, but I think they are as follows:
Therefore you don't need to declare a reference to Person from Organization.
class Person(BaseModel):
organizations = models.ManyToManyField("Organization",
blank=True,
through="Board")
class Organization(BaseModel):
name = models.CharField(max_length=255)
class Board(BaseModel):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
Now you import a Board instance which contains a reference to a Person (by first name) and an Organization by name. The Person and / or Organization may not exist and may need to be created during import.
The Board instance may or may not exist during import (it will be identified by the 'id' field), and either a new or existing Board instance will be loaded here.
However, now you need to implement the logic to create the Person / Organization and link it with the instance.
UPDATE I rewrote my original answer as follows:
The best way to create an instance is to create a subclass of ForeignKeyWidget
which handles the creation of the instance if it does not exist:
class PersonForeignKeyWidget(ForeignKeyWidget):
def clean(self, value, row=None, **kwargs):
try:
val = super().clean(value)
except Person.DoesNotExist:
val = Person.objects.create(firstname=row['person'])
return val
Do the same for Organization
as well.
Then declare these widgets in your Resource
:
person = fields.Field(
widget=PersonForeignKeyWidget(Person, "firstname"))
organization = fields.Field(
widget=OrganizationForeignKeyWidget(Organization, "name"))
Now the import logic will continue and persist the Board instance with the correct relations.
There's a few questions like what if people share a firstname... and this obviously doesn't handle creation of other fields (e.g. like what's in BaseModel).
If it is still failing with 'invalid', you will need to inspect the source of the error. See docs for techniques on reading errors.
As always with import_export the best way to understand it is to set a debugger and step through an import.