I've got 2 models :
class Fund(LabsManagerBudgetMixin, ActiveDateMixin):
ref= models.CharField(max_length=30, blank=True, verbose_name=_('Reference'))
start_date=models.DateField(null=True, blank=True, verbose_name=_('Start Date'))
end_date=models.DateField(null=True, blank=True, verbose_name=_('End Date'))
class Fund_Item(LabsManagerBudgetMixin, CachedModelMixin):
amount=models.DecimalField(max_digits=12, decimal_places=2, verbose_name=_('Amount'), default=0, null=True)
type=models.ForeignKey(Cost_Type, on_delete=models.CASCADE, verbose_name=_('Type'))
fund=models.ForeignKey(Fund, on_delete=models.CASCADE, verbose_name=_('Related Fund'))
the mixins add some other fields, methods, managers ....
For the second one (Fund_Item) the admin extends "ImportExportModelAdmin" and the ressource class (see below) identify the foreignkey in the before_import_row method from a ref field.
The csv from which I update FundItem objects contains the 'ref', 'start_date', 'end'date' of the foreingkey linked object Fund.
I would like to update alongside the Fund_Item object the value dates of the foreign objects Fund.
I would point it as a value to update if needed at the file upload and parsing, and update the value on the import finalisation.
The doc states: "…using a ForeignKeyWidget has the advantage that it can not only be used for exporting, but also importing data with foreign key relationships."
But I'm only able to update the foreingkey of the current model and not the foreign model attributes.
I don't know where to start digging which method to override. Could point me out a direction?
class FundItemAdminResource(labResource, SkipErrorRessource):
fund=FundField(
column_name=_('Ref'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'ref'),
readonly=False
)
type=Field(
column_name=_('type'),
attribute='type',
widget=widgets.ForeignKeyWidget(Cost_Type, 'short_name'),
readonly=False
)
start_date=FundField(
column_name=_('Start Date'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'start_date'),
readonly=False
)
end_date=FundField(
column_name=_('End Date'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'end_date'),
readonly=False
)
amount=FundItemField(
column_name=_('Budget'),
attribute='amount',
widget=widgets.DecimalWidget(),
readonly=False
)
def before_import_row(self, row, row_number=None, **kwargs):
query = Q(amount__gte=-1)
refI = row.get('Ref', None)
if refI is not None:
query = query & Q(fund__ref=refI)
typeC = row.get('type', None)
if typeC is not None:
query = query & Q(type__short_name=typeC)
fu = Fund_Item.objects.filter(query)
if fu is not None and fu.count()==1:
row["id"] = fu.first().pk
else:
row["id"] = None
return fu
class Meta:
"""Metaclass"""
model = Fund_Item
skip_unchanged = True
clean_model_instances = False
exclude = [ '' ]
export_order=[
'start_date',
'end_date',
'type',
'fund',
'amount',
]
I've tryeid to tweak clean and save method of a custom field, but I land on issues or error each time
class FundField(Field):
def clean(self, data, **kwargs):
query = Q(amount__gte=-1)
refI = data.get('Ref', None)
if refI is not None:
query = query & Q(ref=refI)
fu = Fund.objects.filter(query).first()
return fu
class FundDateField(FundField):
def clean(self, data, **kwargs):
fu = super(FundField, self).clean(data, **kwargs)
return getattr(fu, self.widget.field, None)
def save(self, obj, data, is_m2m=False, **kwargs):
# self.attribute=self.attribute+"__"+self.widget.field
super(FundField, self).save(obj, data, is_m2m, **kwargs)
for the resource field defined as :
start_date=FundDateField(
column_name=_('Start Date'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'start_date'),
readonly=False
)
[Edit]
I've use the clues from matthew below, I've implemented a custom Field which handle the column check and save from the clean method
class FundDateField(FundField):
def clean(self, data, **kwargs):
fu = super().clean(data, **kwargs)
field = self.widget.field
attr =getattr(fu, field, None)
nAttr=data.get(self.column_name)
if attr!=nAttr:
setattr(fu, field, nAttr)
fu.save()
print(" - fu : "+str(fu))
return fu
and apply it to the resource date fields
start_date=FundDateField(
column_name=_('Start Date'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'start_date'),
readonly=False
)
end_date=FundDateField(
column_name=_('End Date'),
attribute='fund',
widget=widgets.ForeignKeyWidget(Fund, 'end_date'),
readonly=False
)