Reputation: 19
I am new to Django and was looking for an efficient way to retrieve and post to a ManytoMany relation using an intemrediary table.
models:
from django.db import models
# Create your models here.
class Actor(models.Model):
name = models.CharField(max_length = 50, primary_key = True)
bio = models.CharField(max_length=150)
class Movie(models.Model):
name = models.CharField(max_length=100)
release = models.CharField(max_length=100)
class NormActors(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
actor = models.ForeignKey(Actor, on_delete=models.CASCADE)
I have checked the documentation and it got confusing, so any reference would be helpful as well. If on request, I want to send -
Should the ORM query look something like this?
actor = Actor.objects.get(name="XYZ")
movies = actor.movie_set.all()
How should I go about fr the first one?
Upvotes: 0
Views: 424
Reputation: 177
If you want to get all the movies related to an actor, you need to have ManyToMany relationship with Movie model with respect to Actor model.
class Movie(models.Model):
name = models.CharField(max_length=100)
release = models.CharField(max_length=100)
class Actor(models.Model):
name = models.CharField(max_length = 50, primary_key = True)
bio = models.CharField(max_length=150)
movies = models.ManyToManyField(Actor)
Remember, you need to define Movie model before you creating a manytomany relationship with the Actor model.
actor = Actor.objects.get(name="XYZ")
movies = actor.movies.all()
Upvotes: 1
Reputation: 15778
To help me avoid confusion, I always call a "through
" table by the name of 2 other tables. Thus, in your case, I would have done:
class Actor(models.Model):
name = models.CharField(max_length = 50, primary_key = True)
bio = models.CharField(max_length=150)
movies = models.ManyToMany('Movie', through='ActorMovie',
related_name='actors')
class Movie(models.Model):
name = models.CharField(max_length=100)
release = models.CharField(max_length=100)
class ActorMovie(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
actor = models.ForeignKey(Actor, on_delete=models.CASCADE)
Notes:
related_name
is important and imagine it's the reverse direction: you declared the ManyToMany in Actor
so reverse is Movie -> Actor
'Movie'
in quote because it's declared after this declaration. You can remove quotes but then declare Movie
class first.ActorMovie
ManyToMany
declared this way you can access in both directions (= from Actor
but also from Movie
) in a very clear way, for example two working and very clean queries.Examples:
# get all film with Harrison Ford:
for movie in Actor.objects.filter(name="Harrison Ford").movies.all():
pass # do whatever with movie
# get all actors from Die Hard movie:
for actor in Movie.objects.filter(name__istartswith="Die Hard").actors.all():
pass # do whatever with actor
Upvotes: 1
Reputation: 599490
Firstly, you should explicitly declare the m2m and identify the through table as such:
class Movie(models.Model):
...
actors = models.ManyToManyField('Actor', through='NormActor')
Now for any movie you can do movie.actors.all()
, and for any actor you can do actor.movie_set.all()
.
Note, if you only have those two fields on NormActor, you don't actually need to declare it explicitly; you can remove that model and the through
attribute and Django will manage it for you, with the added bonus that in the admin interface you can now edit actors inline with movies.
Upvotes: 1