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:
- when a
Product
is added to the database, there is an option to link it to an existingVenue
- 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.
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 CharField
s, 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.)