jazzband / django-polymorphic

Improved Django model inheritance with automatic downcasting

Home Page:https://django-polymorphic.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error during deleting

oleksandr-shvab opened this issue · comments

Hi all! I just had a strange error in my work project. It's an ML project where user can create projects, upload datasets and then work with them.

First of all, we have a Project model:

class Project(CustomModel):
    name = models.CharField(max_length=30)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

Here is nothing special, just CustomModel where we extend create and update methods to call full_clean().

The next one is the DatasetFolder model where uploaded files lay:

class DatasetFolder(CustomModel):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    ...

Then go first polymorphic model. It's the parent model that describes all the uploaded files:

class OriginalFile(PolymorphicModel, CustomModel):
    dataset_folder = models.ForeignKey(DatasetFolder, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    content_type = models.CharField(max_length=100)
    size = models.PositiveIntegerField()

And from this polymorphic model, we have 3 inherit models for images, datasets, and relation files. A relation file it's file that described all relations between multiplay datasets ( if relations exist) (Can be one csv file without any relation, or can be some file like tables in DB that are connected to each other)

class DatasetRelation(OriginalFile):
    file = models.FileField(max_length=500, upload_to=project_directory_path)
    original_file_name = models.CharField(max_length=100)

class OriginalDataset(OriginalFile):
    dataset_relation = models.ForeignKey(
        DatasetRelation, on_delete=models.SET_NULL, blank=True, null=True
    )
    file = models.FileField(max_length=500, upload_to=project_directory_path)
    original_file_name = models.CharField(max_length=100, null=True, blank=True)
    table_name = models.CharField(max_length=100, null=True, blank=True)
    rows_number = models.PositiveIntegerField()
    dataset_metadata = models.JSONField()

class OriginalImage(OriginalFile):
    original_file_name = models.CharField(max_length=100)
    file = models.ImageField(max_length=500, upload_to=project_directory_path)

Now about the problem. If I just create project and after that delete it, all works fine. But if I upload file ( dataset folder and original_dataset instances created), and then I try to delete the project ( all inheritance instances should be deleted too) I got error:

AttributeError: 'NoneType' object has no attribute 'attname'

Full traceback:

2023-07-07T12:00:29.168850977Z Traceback (most recent call last):
2023-07-07T12:00:29.168858053Z   File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 534, in thread_handler
2023-07-07T12:00:29.168865749Z     raise exc_info[1]
2023-07-07T12:00:29.168871498Z   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 38, in inner
2023-07-07T12:00:29.168876303Z     response = await get_response(request)
2023-07-07T12:00:29.168881665Z   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
2023-07-07T12:00:29.168887489Z     response = await wrapped_callback(request, *callback_args, **callback_kwargs)
2023-07-07T12:00:29.168893254Z   File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 479, in __call__
2023-07-07T12:00:29.168899697Z     ret: _R = await loop.run_in_executor(
2023-07-07T12:00:29.168903449Z   File "/usr/local/lib/python3.9/site-packages/asgiref/current_thread_executor.py", line 40, in run
2023-07-07T12:00:29.168907397Z     result = self.fn(*self.args, **self.kwargs)
2023-07-07T12:00:29.168924991Z   File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 538, in thread_handler
2023-07-07T12:00:29.168928691Z     return func(*args, **kwargs)
2023-07-07T12:00:29.168932184Z   File "/usr/local/lib/python3.9/contextlib.py", line 79, in inner
2023-07-07T12:00:29.168935815Z     return func(*args, **kwds)
2023-07-07T12:00:29.168939356Z   File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
2023-07-07T12:00:29.168943047Z     return view_func(*args, **kwargs)
2023-07-07T12:00:29.168946534Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py", line 125, in view
2023-07-07T12:00:29.168950276Z     return self.dispatch(request, *args, **kwargs)
2023-07-07T12:00:29.168955073Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
2023-07-07T12:00:29.168961096Z     response = self.handle_exception(exc)
2023-07-07T12:00:29.168966571Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
2023-07-07T12:00:29.168972964Z     self.raise_uncaught_exception(exc)
2023-07-07T12:00:29.168978464Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
2023-07-07T12:00:29.168995178Z     raise exc
2023-07-07T12:00:29.169001808Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
2023-07-07T12:00:29.169008146Z     response = handler(request, *args, **kwargs)
2023-07-07T12:00:29.169013223Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/mixins.py", line 91, in destroy
2023-07-07T12:00:29.169019635Z     self.perform_destroy(instance)
2023-07-07T12:00:29.169025352Z   File "/usr/local/lib/python3.9/site-packages/rest_framework/mixins.py", line 95, in perform_destroy
2023-07-07T12:00:29.169031328Z     instance.delete()
2023-07-07T12:00:29.169037074Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 966, in delete
2023-07-07T12:00:29.169043395Z     collector.collect([self], keep_parents=keep_parents)
2023-07-07T12:00:29.169048678Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/deletion.py", line 297, in collect
2023-07-07T12:00:29.169054536Z     field.remote_field.on_delete(self, field, sub_objs, self.using)
2023-07-07T12:00:29.169060804Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/deletion.py", line 24, in CASCADE
2023-07-07T12:00:29.169066836Z     collector.collect(
2023-07-07T12:00:29.169073577Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/deletion.py", line 295, in collect
2023-07-07T12:00:29.169078650Z     if sub_objs:
2023-07-07T12:00:29.169083662Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 284, in __bool__
2023-07-07T12:00:29.169088857Z     self._fetch_all()
2023-07-07T12:00:29.169095209Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1324, in _fetch_all
2023-07-07T12:00:29.169102496Z     self._result_cache = list(self._iterable_class(self))
2023-07-07T12:00:29.169108867Z   File "/usr/local/lib/python3.9/site-packages/polymorphic/query.py", line 64, in _polymorphic_iterator
2023-07-07T12:00:29.169114872Z     real_results = self.queryset._get_real_instances(base_result_objects)
2023-07-07T12:00:29.169120061Z   File "/usr/local/lib/python3.9/site-packages/polymorphic/query.py", line 390, in _get_real_instances
2023-07-07T12:00:29.169126018Z     if base_object.polymorphic_ctype_id == self_model_class_id:
2023-07-07T12:00:29.169131806Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query_utils.py", line 144, in __get__
2023-07-07T12:00:29.169137635Z     instance.refresh_from_db(fields=[field_name])
2023-07-07T12:00:29.169142980Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 650, in refresh_from_db
2023-07-07T12:00:29.169149359Z     db_instance = db_instance_qs.get()
2023-07-07T12:00:29.169155154Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 431, in get
2023-07-07T12:00:29.169160495Z     num = len(clone)
2023-07-07T12:00:29.169170547Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 262, in __len__
2023-07-07T12:00:29.169177251Z     self._fetch_all()
2023-07-07T12:00:29.169183088Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1324, in _fetch_all
2023-07-07T12:00:29.169189447Z     self._result_cache = list(self._iterable_class(self))
2023-07-07T12:00:29.169195989Z   File "/usr/local/lib/python3.9/site-packages/polymorphic/query.py", line 64, in _polymorphic_iterator
2023-07-07T12:00:29.169201966Z     real_results = self.queryset._get_real_instances(base_result_objects)
2023-07-07T12:00:29.169207735Z   File "/usr/local/lib/python3.9/site-packages/polymorphic/query.py", line 457, in _get_real_instances
2023-07-07T12:00:29.169214069Z     real_objects_dict = {
2023-07-07T12:00:29.169219539Z   File "/usr/local/lib/python3.9/site-packages/polymorphic/query.py", line 458, in <dictcomp>
2023-07-07T12:00:29.169226109Z     getattr(real_object, pk_name): real_object for real_object in real_objects
2023-07-07T12:00:29.169232278Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query_utils.py", line 142, in __get__
2023-07-07T12:00:29.169238607Z     val = self._check_parent_chain(instance)
2023-07-07T12:00:29.169244488Z   File "/usr/local/lib/python3.9/site-packages/django/db/models/query_utils.py", line 158, in _check_parent_chain
2023-07-07T12:00:29.169251278Z     return getattr(instance, link_field.attname)
2023-07-07T12:00:29.169257175Z AttributeError: 'NoneType' object has no attribute 'attname'

I use:

  • django==3.2.14
  • django-polymorphic==3.1.0

Maybe someone knows where is the problem and I can fix this. For now, I create a temporary fix but it's now perfect. Thanks for your help!

Hey there 👋 Are you able to write a test so we can reproduce this issue in the repo? That would be a big first step to getting this fixed. If it's not an issue for your project feel free to close this issue.