Consider two models:
from django.db import models
class File(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=256, unique=False)
class Comment(models.Model):
id = models.AutoField(primary_key=True)
file_name = models.ForeignKey(to=File, on_delete=models.CASCADE, to_field="name")
text = models.CharField(max_length=1000, unique=False)
and some data:
f1 = File.objects.create(id=1, name="a.xlsx")
f2 = File.objects.create(id=2, name="a.xlsx")
f3 = File.objects.create(id=3, name="b.xlsx")
c1 = Comment.objects.create(id=1, file_name="a.xlsx", comment="Comment 1")
c2 = Comment.objects.create(id=2, file_name="a.xlsx", comment="Comment 2")
c3 = Comment.objects.create(id=2, file_name="b.xlsx", comment="Comment 3")
From the above:
f1
is associated to two comments:c1
andc2
f2
is also associated to two comments:c1
andc2
f3
is associated to one comment:c3
But according to this, ForeignKey.to_field
requires File.name
to be unique but that's not the case. How can I achieve this relationship without creating any intermediary tables?
So ideally:
f1.comments
would returnc1
andc2
c1.files
would returnf1
andf2
etc
CodePudding user response:
class File(models.Model):
name = models.CharField(max_length=256)
class Comment(models.Model):
file_object = models.ForeignKey(File, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
c1 = Comment.objects.create(file_object=f1, comment="Comment 1")
c2 = Comment.objects.create(file_object=f2, comment="Comment 2")
The ID's or primary keys will be added automatically and will of course need to be unique. Also the default is that unique=False elsewhere. As you can see below I have provided some examples, and tried to make it clear that we are dealing with objects:
my_file_objects = File.objects.filter(name="a.xlsx").all()
for file_object in my_file_objects:
print(file_object.comment.text)
my_comment_objects = Comment.objects.filter(file_object__name="a.xlsx").all()
for comment_object in my_comment_objects:
print(comment_object.text)
print(comment_object.file_object.pk)
CodePudding user response:
Django does not allow referring to non-unique field in foreign key, which is a bad practice anyway. However, if you still want to refer to the foreign table with non-unique field then instead of creating a foreign key you can treat file_name as a normal attribute and then override delete and save functions of File and Comment models accordingly.
For example, if you want to achieve on_delete=CASCADE functionality of foreign key then you can override delete function of the File model and delete related comments in this function. Here is how you can declare your models
from django.db import models
class File(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=256, unique=False)
def delete(self, *args, **kwargs):
# you might want to add some conditions here based on your needs
# before deleting related comments
Comment.objects.filter(f_name=self.name).delete()
# deleting file object itself
super(File, self).delete(*args, **kwargs)
class Comment(models.Model):
id = models.AutoField(primary_key=True)
f_name = models.CharField(max_length=100)
text = models.CharField(max_length=1000, unique=False)