I'm having a problem where if I delete an object, another object is being deleted seemingly wrongly.
models.py
class Document(models.model):
file = models.FileField(upload_to=document_path, null=True, max_length=256)
ri_ct = models.ForeignKey(
ContentType, null=True, editable=False, related_name='documents_related_item', on_delete=models.PROTECT
)
ri_id = models.PositiveIntegerField(null=True, editable=False, db_index=True)
related_item = GenericForeignKey('ri_ct', 'ri_id')
class Invoice(models.model):
documents = GenericRelation(
Document, related_query_name='invoices', content_type_field='ri_ct', object_id_field='ri_id'
)
class BalanceUpdate(models.model):
related_item_ct = models.ForeignKey(
ContentType,
limit_choices_to=Q(app_label='main', model__in=('proformainvoice', 'invoice')),
related_name='balance_updates',
null=True,
on_delete=models.PROTECT,
)
related_item_id = models.PositiveIntegerField(null=True, blank=True, db_index=True)
related_item = GenericForeignKey(ct_field='related_item_ct', fk_field='related_item_id')
Now, if I do
Invoice.objects.filter(query).delete()
I'm getting a BalanceUpdate, which is related to Invoice, also deleted.
After a fair amount of debugging I've found that when deleting the Invoice, the document is being deleted (correctly due to the defined GenericRelation).
If we look at Collector.collect we have a recursive function which collects the objects to be deleted.
If I insert a print here, when the model is Document, sub_objs contains the BalanceUpdate object. How can this be the case? The Document obj surely should have sub_objs containing a BalanceUpdate, they are seemingly not linked?
Cheers in advance.
Related
I have the following models in my Django app:
class Dataset(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False
)
name = models.CharField(max_length=100, blank=False)
created_date = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
class Imagefile(models.Model):
uuid = models.CharField(max_length=36, default="")
name = models.CharField(max_length=100, default="")
file = models.FileField(upload_to=image_directory_path)
dataset = models.ForeignKey(
Dataset,
on_delete=models.CASCADE,
related_name="imagefiles",
blank=False,
null=False,
)
class Annotation(models.Model):
image = models.FileField(upload_to=image_annotation_directory_path)
json = models.JSONField(default=dict)
imagefile = models.ForeignKey(
Imagefile,
on_delete=models.CASCADE,
related_name="annotation",
blank=False,
null=False,
)
What I want to achieve is to store one Dataset that has multiple Imagefiles, and each Imagefile can have either 0 or 1 related Annotation.
I am able to create a Dataset and Imagefiles that belong to it. When I try to create the Annotation, however, it is not registered in the Imagefile. In other words, the Annotation refers to the Imagefile, but the Imagefile sees an empty Annotation.
This is how I create my test case:
dataset = Dataset.objects.get(uuid=..., name='test_dataset')
new_imagefile = Imagefile.objects.create(
uuid=...,
dataset=dataset,
name='test_image.png'
)
new_imagefile.file.save('/some/existing/path/image.png', open('test_image.png', "rb"))
new_annot = Annotation.objects.create(imagefile=new_imagefile)
new_annot.image.save('/some/other/existing/path/annot.png', open('annot.png', "rb"))
When the above process is done, printing new_imagefile.annotation results in dataset.Annotation.None. I've been fighting with this for several hours, any hint is appreciated.
Wow, I found the problem right after I posted my question -- in the definition of Annotation, I should have used OneToOneField instead of ForeignKey. That fixed my problem.
I hope this can help other people that have the same problem.
For more than a year, I construct many of my query using a Django Model where I have simple relation between none abstract model objects and everything was working perfectly :
class Taxon(models.Model):
parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, related_name='children')
rank = models.CharField(max_length=200, unique=False, default="NA")
name = models.CharField(max_length=200, unique=False, default="NA")
class Sequence(models.Model):
taxon = models.ForeignKey(Taxon, null=True, blank=True, on_delete=models.CASCADE)
amplicon = models.CharField(max_length=1000, unique=False)
sequence = models.CharField(max_length=1000, unique=False)
score = models.FloatField()
Exemple of queryset using my Model :
taxon.sequence_set.filter(stuff_filtering)
But recently I had to apply some modifications on my database and my Sequence objects are now derivated from an Abstract class called Observation, becoming this
class Observation(models.Model):
taxon = models.ForeignKey(Taxon, null=True, blank=True, on_delete=models.CASCADE)
class Meta:
abstract = True
class Sequence(Observation):
amplicon = models.CharField(max_length=1000, unique=False)
sequence = models.CharField(max_length=1000, unique=False)
score = models.FloatField()
def __str__(self):
return str((self.amplicon, self.sequence, self.score, self.taxon))
I didn't changed anything in my queryset because django documentation about abstract class (https://docs.djangoproject.com/en/3.2/topics/db/models/) say you can still use your chlid_set in a query. However i'm facing this error and I couldn't understand why.
AttributeError: 'QuerySet' object has no attribute 'sequence_set'
Knowing that in case of Abstract base classes, a table should be created in db for each child with parent attribute... So i have Sequence object with linked Taxon object
Apparently the solution to this problem if to retrieve the Taxon object with a get and not a filter (event if only one object is returned).
taxon = Taxon.objects.filter(...)
returning just one value became
taxon = Taxon.objects.get(...)
It's seems a pretty mysterious for me, as I still don't understand why it has worked perfectly with my previous model
I'm trying to create a workout tracking application where a user can:
Create an instance of an ExerciseTemplate model from a list of available Exercise models. I've created these as models so that the user can create custom Exercises in the future. There is also an ExerciseInstance which is to be used to track and modify the ExerciseTemplate created by the user, or someone else. I'm stripping the models of several unimportant fields for simplicity, but each contains the following:
class Exercise(models.Model):
# Basic Variables
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
def __str__(self):
return self.name
class ExerciseTemplate(models.Model):
# Foreign Models
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.SET_NULL,
null=True,
blank=True
)
recommended_sets = models.PositiveIntegerField(null=True, blank=True)
class ExerciseInstance(models.Model):
""" Foreign Models """
exercise_template = models.ForeignKey(
ExerciseTemplate,
on_delete=models.SET_NULL,
null=True,
blank=True
)
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
""" Fields """
weight = models.PositiveIntegerField(null=True, blank=True)
reps = models.PositiveIntegerField(null=True, blank=True)
Create a WorkoutInstance from a WorkoutTemplate. The WorkoutTemplate is made up of ExerciseTemplates. But the WorkoutInstance should be able to take the WorkoutTemplate and populate it with ExerciseInstances based on the ExerciseTemplates in the WorkoutTemplate. Here are the models that I have so far:
class WorkoutTemplate(models.Model):
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
date = models.DateTimeField(null=True, blank=True)
#category...
exercises = models.ManyToManyField(
Exercise,
through=ExerciseTemplate
)
def __str__(self):
return self.name
class WorkoutInstance(models.Model):
# Foreign Models
workout_template = models.ForeignKey(
'WorkoutTemplate',
on_delete=models.SET_NULL,
null=True,
blank=True
)
But this is where I get stuck. I'm not sure how to proceed. My intuition is one of the following:
I need to create a more simple architecture to do this. I'll take any suggestions.
I need to create a method within the model that solves this issue. If this is the case, I'm not sure what this would actually look like.
When you create a new WorkoutInstance object which references a given WorkoutTemplate object you get all its related ExerciseTemplate objects.
Then you just create a new object (row) for each ExerciseInstance in another model (table)
If you link your ExerciseInstance to WorkoutInstance via 'workout' you could do something like:
wt = WorkoutTemplate.get(id=1)
wi = WorkoutInstance.create(workout_template=wt)
for e in wt.exercisetemplate_set.all:
ExerciseInstance.create(exercise_template=e, workout=wi)
You can implent this in the method that creates the new WorkoutInstance or take a look at signals
https://docs.djangoproject.com/en/4.0/topics/db/optimization/#create-in-bulk
I wanted to have a list of foreign keys for a field, so I had used Django's ManyToManyField.
I have the following models:
models.py
class Community(models.Model):
posts = models.ManyToManyField('Post', null=True, blank=True, symmetrical=False)
members = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='+',
blank=True,
null=True,
symmetrical=False
)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=300)
content = models.TextField(max_length=50000, blank=True)
comments = models.ManyToManyField('Comment', null=True, blank=True, symmetrical=False)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
I'm able to view the list of foreign keys from the admin panel, but when I try to get the list of posts or members from the community object using community_object.members.all() and community_object.posts.all(), I get an empty list/queryset.
I'm new to Django and I don't think I understand ManyToManyFields very well.
I have some models and fk on them to others.
models.py
class ElementMessages(models.Model)
element = models.ForeignKey(Element, on_delete=models.CASCADE)
sender = models.ForeignKey(UserAccount, on_delete=models.SET_NULL, null=True)
text = models.TextField(max_length=512, null=True)
send_time = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=16, choices=MESSAGE_TYPES, default=SIMPLE)
type_dialog = models.CharField(max_length=10, choices=DIALOG_TYPE, default=DIALOG_TALK)
request = models.ForeignKey(ChatRequest, null=True, default=None, on_delete=models.CASCADE)
post_work = models.ForeignKey(PostWork, null=True, default=None, on_delete=models.CASCADE)
files = models.BooleanField(default=False)
class Element(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
artist = models.ForeignKey(Artist, on_delete=models.CASCADE, related_name='chat_element', null=True, blank=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='chat_element', null=True, blank=True)
element = models.ForeignKey('projects.Element', null=False, on_delete=models.CASCADE, related_name='chat_element')
When I try to delete Element object, it raises this:
django.db.utils.IntegrityError: insert or update on table "chat_elementmessages" violates foreign key constraint "chat_elementmessages_element_id_672e2ba2_fk_chat_element_id"
DETAIL: Key (element_id)=(87cdd8d7-47f0-4264-8aa7-ae21a8246fd8) is not present in table "chat_element".
But when I look at table in db, this key exists.
How to fix that?
As it turned out, problems were at Django pre_delete andpost_delete signals. They tried to refer to a non-existing object, that I'm try to delete. Fixed with simple check on the existence of the object.