Home > Mobile >  Django - Models - Linking models to another and vice versa
Django - Models - Linking models to another and vice versa

Time:10-03

I am trying to link venues to the products they supply. The products supplied are not unique to each venue.

As a result, Venue 1 and 2 could both provide Product A.

The outcome I am looking for is twofold:

  1. when a Product is added to the database, there is an option to link it to an existing Venue
  2. When looking at a venue in particular, I would like to have the list of all the product that can be supplied

Outcome 1. and current problem

I tried using Foreign Keys and ManyToManyFields but this only seems to add all the products available to the database to all the venues without leaving a choice.

enter image description here

This is what venue = models.ManyToManyField(Venue, blank=True, related_name="available_products") renders in the admin panel. In this example, by adding ManyToMany Field all Venues have been added to Product 1. Whereas I would like the possibility to add only specific venues (not all)

Outcome 2. and current problem

The second problem is obviously referring to Product from the Venue model. If I input a foreign key or any form of relation in it, Django gets upset and tells me Product is not defined.

I thought of creating a 3rd model, that could combine both Venue and Products, but it feels like there must be something more sophisticated that could done.

(edit: I replaced the FK by ManyToManyField as suggested by David Schultz)

class Venue(models.Model):
    name = models.CharField(verbose_name="Name",max_length=100, null=True, blank=True)
   
class Product(models.Model):
    name = models.CharField('Product Name', max_length=120, null=True)
    venue = models.ManyToManyField(Venue, blank=True, related_name="available_products")
    

CodePudding user response:

A ManyToManyField should in fact be perfect for what you want to do. It only associates those objects to one another for which relations have been explicitly created, e.g. in the admin or programmatically. The fact that your admin shows you all objects at once does not mean that they have been assigned, but just that they are available. In the list from your screenshot, selection can be done by Ctrl Mouseklick, and when you then save the Product and reload the page, precisely the Venues you selected before should now again show up with a distinct background color – this means that they have indeed been saved.

Regarding your second problem: The argument related_name works differently than you apparently think: In your last line of code, you should rather write something like related_name="available_products", because related_name becomes the name of an attribute of your Venue instances, by which you can then access all Product objects that have been associated to that Venue object, e.g. like so: venue.available_products.all()

related_name works the same for ManyToManyField and ForeignKey.

You can define your ManyToManyField either on Product or on Venue; some more info is in the documentation page. So all in all, you should do something like:

class Venue(models.Model):
    name = models.CharField(verbose_name="Name",max_length=100, blank=True)

class Product(models.Model):
    name = models.CharField('Product Name', max_length=120, blank=True)
    venues = models.ManyToManyField(Venue, blank=True, related_name="available_products")

(Side note: For CharFields, it is recommended not to set null=True and instead only use blank=True, because otherwise there would be two different options for "no data", namely Null and an empy string. Details in the docs.)

  • Related