26

Is it possible to make a ForeignKey to more than one model? I want to choose from different models like Parts and Machines Model.

I read this to combine multiple models into one list: How to combine multiple querysets in Django?

How can I get the foreign key to that list?

Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
Harry
  • 13,091
  • 29
  • 107
  • 167

4 Answers4

28

I know that you asked this over a year ago, but I had a similar problem and I want to share a link to the solution for future readers.

Generally the contenttypes framework solves this problem, and I guess this is what Daniel Roseman was talking about.

How to use dynamic foreignkey in Django?

Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
b3niup
  • 393
  • 3
  • 8
10

You need generic relations.

A generic relation allows you to dynamically the target model of the foreign key.

ygesher
  • 1,133
  • 12
  • 26
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • would you mind explaining how this will work with my example? – Harry Jan 26 '11 at 12:32
  • I might have been unclear. I want to be able to choose from multiple objects from different models. So its a combination of parts and machines. So in the dropdown list i would have ex: Drilling machine, Press, 1.5mm angle iron, 1v switch etc etc – Harry Jan 26 '11 at 12:33
  • This link is dead – ygesher Sep 20 '16 at 05:40
2

I'll provide a comprehensive answer for this question, I know its quite old, but it's still relevant.

We're gonna be using Generic Relations.

First, in settings.py make sure that django.contrib.contenttypes is included in the INSTALLED_APPS array.

Let's create a new model in models.py:

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation

With content_type we can associate Image with any other model class, while object_id will hold the other model instance.

class Image(models.Model):
    image = models.ImageField(
      upload_to="imgs/products", blank=True)

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()

To refer back to the Image model from a Company instance we need to make a reverse generic relation

class Company(models.Model):
  name = models.CharField(max_length=100)
  images = GenericRelation(Image)

In schema.py, we can create Images in a Company instance like:

company_instance = Company(name="Apple")
company_instance.save()
for img in imgs:
    #Image(image=img, content_object=company_instance)
    company_instance.images.create(image=img)
company_instance.images.all() # fetch all images

the company_instance.images field is just a GenericRelatedObjectManager (docs)

This is how the final Image table looks in the database: image table

ahmelq
  • 593
  • 7
  • 11
0

The Django-polymorphic library provides a simple solution that should work well with the admin and forms too using formsets.

For example:

from polymorphic.models import PolymorphicModel


class BookOwner(PolymorphicModel):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)

class StaffBookOwner(BookOwner):
    owner = models.ForeignKey(Staff, on_delete=models.CASCADE)

class StudentBookOwner(BookOwner):
    owner = models.ForeignKey(Student, on_delete=models.CASCADE)

With this, you can use the parent model to set the owner to either a Staff or Student instance or use the child models directly.

Timon
  • 18
  • 5