0

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")
    
PhilM
  • 249
  • 1
  • 11
  • are you adding those data from admin? – mubtasimfuad Oct 01 '22 at 12:31
  • Eventually, I will need to do it through the app. But to start with, yes. (I am also trying to teach myself to code, so doing it in this order feels like the right thing to do, but I am happy to take advice) – PhilM Oct 01 '22 at 12:56

1 Answers1

1

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.)

David S.
  • 457
  • 2
  • 13
  • Hi David, thanks for the help, I think this helped me understand a bit more. My two problem however remain. To strat with the first one, by adding the 'ManyToManyField' in Product, Product A will now show all the Venues listed in the Database and not necessarily those that can offer product A. (I edited my initial post to add a picture so hopefully I am more clear with my problem) – PhilM Oct 01 '22 at 16:34
  • 1
    I think there are currently no assignments at all in the database. Instead, what the admin is showing you are the *choices* that are available, i.e. what Venues you *can* assign to the current Product – namely, all Venues. You now have to select a subset of this list (Ctrl+Mouseclick) and save it via the admin. Then you will have succeeded in assigning a selection of Venues to this Product. (After you have done this, I believe the assigned Venues will be displayed with a different background color in the list from your screenshot.) – David S. Oct 01 '22 at 16:45
  • 1
    That would be a good explaination! Im on my phone, I will try this when I get home tomorrow! Thanks for the help! – PhilM Oct 01 '22 at 16:54
  • 1
    Thanks for the help, I am trying to implement the second bit you advised ("venue.available_products.all()"). Currently its not working, but I am going to rack my brain for a few days as I am sure I can figure out the problem. Failling that, I might post a question on that at the end of the week :) – PhilM Oct 02 '22 at 15:10
  • 1
    This could elucidate the usage of `related_name` further: https://stackoverflow.com/questions/2642613/what-is-related-name-used-for Good luck. :) – David S. Oct 02 '22 at 20:18