开发者

How can I get some of the Django ORM benefits of using a ForeignKey without actually using one?

开发者 https://www.devze.com 2023-03-31 18:18 出处:网络
I have models that look like this (simplified of course): class Product(models.Model): product_code = Charfield(max_length=30)

I have models that look like this (simplified of course):

class Product(models.Model):
    product_code = Charfield(max_length=30)

class Change(models.Model):
    product = ForeignKey(Product)

My problem is that this won't work, because Products get deleted, but I need the reference in Change to remain (using on.delete to set it to null is not an option). So I have switched it to:

class Change(models.Model):
    product = CharField(max_length=30)

But 开发者_StackOverflow社区now I have lost the benefits of a Foreign Key field when querying. When I query for a change, I cannot select_related for Products or do any other join type action without digging into extra type clauses.

So my question, is there any good way to have my cake and eat it too? To be able to join on the field easily, but not have it be an FK? Seems like there must be some way besides FK type to say that fields are related. Perhaps through a manager?


I have this exact problem at hand... regrettably its priory was bumped pretty far down my list. However, I believe I have actually used a many-to-many field to retain a link in a different part of my application. Using the many-to-many field seems to address all of the issues I had come across. See my simplified models below.

With this setup I am able to:

  • Create a Card and link a number of Card_Tests to it (note that there can be duplicates)
  • Modify or Remove any one or all of the Card_Tests without it removing the Card's record.
  • Remove all of the Card_Tests by deleting the Card record.

Card Model

class Card(models.Model):
    serial_number = models.CharField(max_length=25)
    card_tests = models.ManyToManyField('Card_Test', through='Card_Test_List')

Through Model

class Card_Test_List(models.Model):
    card_id = models.ForeignKey('Card')
    card_test_id = models.ForeignKey('Card_Test')
    result       = models.TextField()

Card Test Model

class Card_Test(models.Model):
    name = models.TextField(max_length=100)
    description = models.TextField(max_length=200)


You could add a boolean flag deleted to the Product model. When you wish to 'delete' a product, set product.deleted=True instead of deleting from the database. That would allow you to use a regular foreign key from Change to Product.

I don't know whether this would be suitable for your project. You might have to change quite a lot of code, e.g. replace Product.objects.all() with Product.objects.exclude(deleted=True). Creating a manager where the queryset returns non-deleted items would help.

class Product(models.Model):
    product_code = Charfield(max_length=30)
    deleted = BooleanField(blank=True, null=True)

class Change(models.Model):
    product = ForeignKey(Product)
0

精彩评论

暂无评论...
验证码 换一张
取 消