2👍
In ForeignKeyWidget
you have method
def clean(self, value):
val = super(ForeignKeyWidget, self).clean(value)
return self.model.objects.get(**{self.field: val}) if val else None
you could try to override it to do something like get_or_create
…
it should look something like this…
from import_export.widgets import ForeignKeyWidget
class MyCustomizationToFKWidget(ForeignKeyWidget):
def clean(self, value):
val = super(ForeignKeyWidget, self).clean(value)
HERE SOME LOGIC OVERRIDEN
2👍
Provided the ForeignKey of your model can be null :
MyForeignKeyName = Models.ForeignKey(<modelclass>,blank=True, null=True)
You can add a before_import_row() method in your Resource class :
def before_import_row(self,row) :
fieldname = 'MyForeignKeyName'
if not( <modelclass>.objects.filter(pk=row[fieldname]).exists() ) :
# print(row['id'],row[fieldname],'unknown key !') # console log
row[fieldname ] = None # or something else.. *
*.. compliant with your foreignkey configuration [ python None = SQL null ]
I’m a bit new to Django so maybe it’s not the better way, but this solves my problem.
There’s also something about db_constraint=False that can be added to ForeignKey’s arguments (some info @stackoverflow and @django) but well, I did not find my way with it.
- [Django]-Django: related_name attribute (DatabaseError)
- [Django]-Django Queryset Count
- [Django]-Django urlpatterns frustrating problem with trailing slashes
- [Django]-Django mongodbforms exception when rendering embedded formset management_form
2👍
I found the best way to do this is with custom widgets. I found a thread on the django-import-export GitHub project here that contained a lot of useful information. From that I pieced together these two custom widgets that support creation of new objects. These should both work as-is by adding them to your admin.py
module:
from import_export.widgets import ManyToManyWidget
from django.db.models import QuerySet
class ForeignKeyWidgetWithCreation(ForeignKeyWidget):
"""
Taken from a GitHub post.
https://github.com/django-import-export/django-import-export/issues/318#issuecomment-139989178
"""
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 ManyToManyWidgetWithCreation(ManyToManyWidget):
"""
Taken from a GitHub post.
https://github.com/django-import-export/django-import-export/issues/318#issuecomment-139989178
"""
def __init__(self, model, field="pk", create=False, **kwargs):
self.model = model
self.field = field
self.create = create
super(ManyToManyWidgetWithCreation, self).__init__(model, field=field, **kwargs)
def clean(self, value, **kwargs):
# If no value was passed then we don't have anything to clean.
if not value:
return self.model.objects.none()
# Call the super method. This will return a QuerySet containing any pre-existing objects.
# Any missing objects will be
cleaned_value: QuerySet = super(ManyToManyWidgetWithCreation, self).clean(
value, **kwargs
)
# Value will be a string that is separated by `self.separator`.
# Each entry in the list will be a reference to an object. If the object exists it will
# appear in the cleaned_value results. If the number of objects in the cleaned_value
# results matches the number of objects in the delimited list then all objects already
# exist and we can just return those results.
object_list = value.split(self.separator)
if len(cleaned_value.all()) == len(object_list):
return cleaned_value
# If we are creating new objects then loop over each object in the list and
# use get_or_create to, um, get or create the object.
if self.create:
for object_value in object_list:
_instance, _new = self.model.objects.get_or_create(
**{self.field: object_value}
)
# Use `filter` to re-locate all the objects in the list.
model_objects = self.model.objects.filter(**{f"{self.field}__in": object_list})
return model_objects
You can use these in your import-export model resource class like this:
class SomeModelResource(Resource):
my_fk_field = fields.Field(
attribute='my_fk_field',
widget=ForeignKeyWidgetWithCreation(
model=models.OtherModel,
field='name',
create=True))
my_m2m_field = fields.Field(
attribute="my_m2m_field",
widget=ManyToManyWidgetWithCreation(
model=models.OtherM2MModel,
field="name",
separator="|",
create=True,
),
default="",
)
- [Django]-Syntax error whenever I put Python code inside a Django template
- [Django]-Gmail not rendering email with html breaks properly when sent from Django
- [Django]-Django Quill Editor Display Saved Field
1👍
You can create missing foreign key entries in the before_import_row() method of your Resource class:
class ProductResource(resources.ModelResource):
...
def before_import_row(self, row, **kwargs):
Store.objects.get_or_create(
store_name=row.get('store_name')
)
- [Django]-Subversion doesn't see my updates via python script
- [Django]-Show request.DATA in Django 500 error caused by Rest Framework
- [Django]-Many to many field django add the relationship both way
- [Django]-Difference between request.user vs. get_user(request) in Django?
- [Django]-Django SendGrid how to pass unique_args in EmailMultiAlternatives mail object