Passing instance of a model to another model

How can i pass the current instance of a model(Movie) to Seat model as a foreignkey?
Here’s a sample code:

class Movie(models.Model):

    title = models.CharField(max_length=150, unique=True)

    def _create_seats(self):

        seat = Seat.objects.update_or_create(

            movie="Here is my problem",

        )

    def save(self, *args, **kwargs):

        self._create_seats()

        super(Movie, self).save(*args, **kwargs)

class Seat(models.Model):

    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)

So Seat is a one-to-many relationship to Movie - the concept of “update_or_create” doesn’t seem to make a lot of sense here.

I’d be looking at doing this in my view or a utility function, not in the model.

Ken

1 Like

I am trying to generate a data for a seats when a movie is created, the update_or_create; just to verify if the seat was already created else, update it when the customer paid the seat.

So you’re going to have a view that results in creating the Movie - at that point, create the related seats. Likewise, when a user pays for the seat, that occurs in a view - that’s where you want to update the seat. You have all the information you need at that point.

The purpose of doing this is, when i deleted the movie; all the seats for that movie will be deleted automatically.

That’s the purpose of the “CASCADE” option on the on_delete clause. You don’t have to do anything to have that happen once that’s specified.

Here’s my code for the models:

class Movie(models.Model):
    theater = models.OneToOneField(Theater, on_delete=models.CASCADE)
    movie_title = models.CharField(max_length=150, unique=True)
    movie_price = models.IntegerField()
    movie_length = models.DurationField()
    movie_banner = models.ImageField(upload_to='movie_banner')
    movie_description = models.TextField()
    movie_link = models.URLField()
    start_date = models.DateField()
    end_date = models.DateField()

    def _create_seats(self):
        start_date = self.start_date
        end_date = self.end_date
        span = end_date - start_date

        seat_row_range = 10
        seat_label = [chr(letter) for letter in range(65, 91)]
        seat_col_range = self.theater.capacity // seat_row_range
    
        for day in range(span.days + 1):
            date_display = start_date + timedelta(days=day)
            for time in self.theater.theater_time.all():
                row_track = 0
                col_track = 0
                for capacity in range(self.theater.capacity):
                    row_track += 1
                    
                    if row_track > seat_row_range:
                        row_track = 1
                        if col_track < seat_col_range:
                            col_track += 1

                    display = "{}-{}".format(seat_label[col_track], row_track)

                    if not date_display < date.today():
                        cinema_seat = CinemaSeat.objects.update_or_create(
                            theater=self.theater, 
                            seat=display, 
                            movie=self.movie_title, 
                            time=time,
                            date=date_display.strftime('%B %d, %Y - %A'),
                        )

    def clean(self):    
        if self.start_date > self.end_date:
            raise ValidationError("- Dates are incorrect!")
    
    def __str__(self):
        return self.movie_title

    def save(self, *args, **kwargs):
        self._create_seats()
        super(Movie, self).save(*args, **kwargs)

class CinemaSeat(models.Model):
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    theater = models.ForeignKey(Theater, on_delete=models.CASCADE)
    seat = models.CharField(max_length=5)
    time = models.CharField(max_length=150)
    date = models.CharField(max_length=150)
    paid = models.BooleanField(default=True)

    def __str__(self):
        return "{} | {} | {} - {}".format(
                self.theater, self.seat, 
                self.time, self.date
            )

(When you’re posting code, enclose it between lines consisting of only three backtick ` characters - that keeps the formatting cleaner and makes it easier to read. So you’ll have a line of ```, your code, and then another line of ```. Make sure you use the backtick - ` and not the apostrophe - '. If you would, please edit your prior reply, thanks.)

Ok, so in the context of your real code, what’s the issue you’re trying to address?

Basically the flow, is i have the Movie class and CinemaSeat class, these two classes can only be access in admin panel. So every-time i create a movie for example(“Marvel”) then i save it; this Movie class will call the CinemaSeat class to generate/create a seat for a theater.

I already did the entire database, im just refactoring some things to make it clean and efficient.

To clarify, your question concerns this:

Are you asking how you set the movie attribute? If so, it looks like you’re already setting it.
If not, what is the question you’re trying to get answered?

Yes that is exactly my current problem, i cannot set a value to a movie, since in CinemaSeat, the movie field is set as a foreignkey. That one throws an error. It says "Cannot assign "'Marvel'": "CinemaSeat.movie" must be a "Movie" instance."

Ok, so CinemaSeat.movie is an FK to a Movie.

This instance that this function is running in is an instance of Movie, with a standard attribute named self.

cinema_seat = CinemaSeat.objects.update_or_create(
                            theater=self.theater, 
                            seat=display, 
                            movie=self, 
                            time=time,
                            date=date_display.strftime('%B %d, %Y - %A'),
                        )

I did test it but its not working. It says

ValueError at /admin/cinema_app/movie/add/

save() prohibited to prevent data loss due to unsaved related object ‘movie’.

That’s a different issue. That error sounds like you’re trying to save the seats before you save the movie.

I think because the movie is not existed yet. So basically, what i am trying to do is not possible? Because i have to create the movie first then override the save() to generate a seats, but the CinemaSeat requires a movie which is a foreignkey

No, it’s entirely possible.

Where in your code (just copy a couple lines as a snippet) are you saving the Movie instance? Make sure you’re trying to save the seats after that.

1 Like

I just override the save() method in Movie class


        self._create_seats()

        super(Movie, self).save(*args, **kwargs)

and that _create_seats() function generate the CinemaSeats

Ok, so based upon what I’ve said, what do you think you need to do here?


When i click the save button is should generate something like this