Reputation: 451
I am using Django 2.1.1.
I have a model Analysis
that, among other fields, contains a ForeignKey to a MyFile
model (a model I wrote to handle files):
from polymorphic.models import PolymorphicModel
from django.db.models import Model, DateTimeField, FileField, SET_NULL
from django.db.models.signals import pre_delete
class MyFile(Model):
file = FileField(upload_to='./', null=False, blank=False)
description = CharField(max_length=255, null=True, blank=True)
date_added = DateTimeField(auto_now_add=True)
@receiver(pre_delete, sender=MyFile)
def mymodel_delete(sender, instance, **kwargs):
"""
To delete the file connected to the `sender` class: receive the pre_delete signal
and delete the file associated with the model instance.
"""
instance.file.delete(False)
class Analysis(PolymorphicModel):
# ... other fields ...
file_results = ForeignKey(MyFile, on_delete=SET_NULL,
related_name='file_results',
null=True, blank=True)
Analysis
is a PolymorphicModel
for reasons related to the bigger project.
In Analysis.file_results
I set on_delete=SET_NULL
because I want to allow an Analysis
instance to exist even without a file_result
, which can be populated later.
Let's suppose I have added a few files (the MyFile
table has a few rows) and a few Analysis
instances. Now, if I want to delete the file related to one of the instances of Analysis
I do:
a = Analysis.objects.get(pk=0)
a.file_results.delete()
a.save()
but I get the following error:
File "/Users/mtazzari/djangos/views.py" in update_job_refs
377. a.save()
File "/Users/mtazzari/anaconda/envs/djangos/lib/python3.6/site-packages/polymorphic/models.py" in save
83. return super(PolymorphicModel, self).save(*args, **kwargs)
File "/Users/mtazzari/anaconda/envs/djangos/lib/python3.6/site-packages/django/db/models/base.py" in save
670. "unsaved related object '%s'." % field.name
ValueError: save() prohibited to prevent data loss due to unsaved
related object 'file_results'.
The mymodel_delete
function that is called on pre_delete
signal works correctly as the file gets actually deleted from the file system.
However, I really don't understand how to solve the ValueError
.
Interestingly, I notice that the following lines work fine, i.e. do not raise any ValueError, get the file deleted from the file system, and the FK in a.file_results
set to Null:
a = Analysis.objects.get(pk=0)
tmp = a.file_results
a.file_results = None
tmp.file_results.delete()
a.save()
But, is this a proper way of doing this? What is the best practice for deleting a related object?
Thanks!
Upvotes: 3
Views: 5813
Reputation: 48952
First, note that you don't need to save()
just because of the delete()
. The delete()
will update the database as required.
That said, it's reasonable to want to continue using the instance to do other operations, leading to a save()
. The reason you're getting the error is that the a.file_results
Python object still exists, and references a database row that is now missing. The documentation for delete()
mentions this:
This only deletes the object in the database; the Python instance will still exist and will still have data in its fields.
So if you want to continue to work with the instance object, just set the attribute to None
yourself. Similar to your code above, except you don't need the temp object.
a = Analysis.objects.get(pk=0)
a.file_results.delete()
a.file_results = None
# ... more operations on a
a.save() # no error
Upvotes: 10