0

When importing with 'delete' field, it gives error:

BaseBoqItem has no field named 'delete'

I am also aware that this model doesn't have that field. That model should not have that field for sure, that is not a mistake. I need to add 'delete' field so that user can mark rows those he/she wants to delete, then when importing django-import-export deletes those rows. I followed documentation of django-import-export, and did exactly same. At the end all I get is this error.

BaseBoqItem has no field named 'delete'

It is working when I import exactly same file that I exported without any changes. This is probably because I have skip_unchanged=True.

It is working if I import after I set some column['delete'] to 1. It successfully deletes related instances.

It is NOT working whenever I make changes in columns other that delete. I mean if I try to update rows/instances, then this error occurs.

What am I missing here?

Here is my model:

```
class BaseBoqItem(models.Model):
    lot = models.ForeignKey(BaseLot, on_delete=models.PROTECT, related_name='boq_items')

    code = models.CharField(max_length=20, null=True)
    name_tm = models.CharField(max_length=255)
    name_ru = models.CharField(max_length=255, null=True)
    name_en = models.CharField(max_length=255, null=True)
    name_original = models.CharField(max_length=255, null=True)
    quantity = models.DecimalField(max_digits=12, decimal_places=2)
    unit = models.ForeignKey(BaseUnit, on_delete=models.PROTECT)
    material_unit_price = models.DecimalField(max_digits=12, decimal_places=2)
    labor_unit_price = models.DecimalField(max_digits=12, decimal_places=2)
    transport_unit_price = models.DecimalField(max_digits=12, decimal_places=2, null=True)
    
    def __str__(self) -> str:
        return f'{self.code} - {self.name_tm}'

Here is my resource:


class BaseBoqItemResource(resources.ModelResource):
    lot = fields.Field(
        column_name='lot', attribute='lot', 
        widget=ForeignKeyWidget(BaseLot, field='code'))
    unit = fields.Field(
        column_name='unit', attribute='unit', 
        widget=ForeignKeyWidget(BaseUnit, field='code_tm'))
    delete = fields.Field(readonly=True)
    def for_delete(self, row, instance):
        return self.fields['delete'].clean(row)
    
    class Meta:
        model = BaseBoqItem
        skip_unchanged = True
        use_bulk = True
        fields = (
            'id', 'lot', 'code', 
            'name_tm', 'name_ru', 'name_en', 'name_original', 
            'quantity', 'unit', 
            'material_unit_price', 'labor_unit_price', 'transport_unit_price'
        )
        exclude=('delete', )
        export_order = (
            'id', 'lot', 'code', 
            'name_tm', 'name_ru', 'name_en', 'name_original', 
            'quantity', 'unit', 
            'material_unit_price', 'labor_unit_price', 'transport_unit_price', 
            'delete'
        )

Here is view:

class BaseBoqItemModelViewset(ModelViewSet):
    queryset = BaseBoqItem.objects.all()
    serializer_class = BaseBoqItemModelSerializer
    filterset_class = BaseBoqItemFilterSet
    pagination_class = CustomPagination

    @action(detail=False, methods=['get'])
    def exporttoexcel(self, request, *args, **kwargs):
        base_boq_item_resource = BaseBoqItemResource()
        dataset = base_boq_item_resource.export()
        response = HttpResponse(dataset.xlsx, content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = 'attachment; filename="base_boq_items.xlsx"'
        return response
    
    @csrf_exempt
    @action(detail=False, methods=['post'])
    def importfromexcel(self, request, *args, **kwargs):
        excel = request.FILES['excel']
        dataset = Dataset().load(excel)
        base_boq_item_resource = BaseBoqItemResource()

        result = base_boq_item_resource.import_data(dataset, dry_run=True, raise_exception=True)
        if not result.has_errors():
            base_boq_item_resource.import_data(dataset, dry_run=False, raise_errors=True)
            return Response({'status': 'Imported successfully'})
        return Response({'status': 'Error when importing'}, status=status.HTTP_400_BAD_REQUEST)

Here is stack Trace:

System check identified no issues (0 silenced).
January 19, 2024 - 15:09:34
Django version 4.2.8, using settings 'core.settings' 
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Internal Server Error: /api/v1/baseboqitems/importfromexcel/
Traceback (most recent call last):
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\db\models\options.py", line 681, in get_field
    return self.fields_map[field_name]
KeyError: 'delete'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\views\decorators\csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\views\decorators\csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\common\views.py", line 280, in importfromexcel
    result = base_boq_item_resource.import_data(dataset, dry_run=True, raise_errors=True)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\import_export\resources.py", line 896, in import_data
    result = self.import_data_inner(
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\import_export\resources.py", line 1020, in import_data_inner
    self.bulk_update(
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\import_export\resources.py", line 452, in bulk_update
    self.handle_import_error(result, e, raise_errors)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\import_export\resources.py", line 446, in bulk_update
    self._meta.model.objects.bulk_update(
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\db\models\query.py", line 854, in bulk_update
    fields = [self.model._meta.get_field(name) for name in fields]
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\db\models\query.py", line 854, in <listcomp>
    fields = [self.model._meta.get_field(name) for name in fields]
  File "C:\Users\a.soyunjaliyev\Documents\coding\smetcik\backend\venv\lib\site-packages\django\db\models\options.py", line 683, in get_field
    raise FieldDoesNotExist(
django.core.exceptions.FieldDoesNotExist: BaseBoqItem has no field named 'delete'
[19/Jan/2024 15:09:38] "POST /api/v1/baseboqitems/importfromexcel/ HTTP/1.1" 500 149979

django-import-export==3.3.4

In case, it is open source repository, if anyone wants to help, you can analyze code from github more closely (would appreciate that):

https://github.com/amanmyrats/smetcik

1 Answer 1

0

I cannot reproduce your issue using the example app. With the example app, I can import a xlsx file with a 'delete' column set to '1', and it will correctly delete the row, as per the documentation.

Perhaps you could get it working in the example app, and work back from there to understand your issue.

I can't see what is wrong with your code, perhaps you can post a stack trace. What version of django-import-export are you using?

It is clear that the issue is because the resource instantiation is trying to link the 'delete' field to the model, and the 'delete' field is not present on the model, hence the error. However I cannot reproduce this.

btw the param to import_data() is raise_errors not raise_exception.

Sign up to request clarification or add additional context in comments.

4 Comments

If i don't make any changes to any rows and mark delete row with 1 then it deletes without problem. Likewise i f I don't changes absolutely anything and import it back again no issue.(this is probably i have skip_unchanged to true, but in the former one it works even if i change delete column.). Problem starts whenever i do changes in other columns of row. That is strange
Best advice (if not already) is always to setup debugger, and step through and see if you can identify what the issue is.
Debugged as you suggested, then I realized that error happens in bulk_update() method of class.objects, this bulk update needs the list of fields those must be updated. Strangely get_bulk_update_fields() method return 'delete' as well. so I removed 'delete' from the list and returned.: ``` def get_bulk_update_fields(self): original_fields = super().get_bulk_update_fields() try: original_fields.remove('delete') except: pass return original_fields ```
I can't reproduce it. If you can reproduce in the example app, please raise an issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.