0

I have a Slider module that i want to include items from movies_movie and shows_show table. An item can either be a show or movie. How do i make user select between movie and show? Currently i have columns for movie and show but how do i force user to select between the two?

also title_en is a column in movie or tv show tables. So the title of the movie/show selected should display in row after save.

class Slider_items(models.Model):

    order = models.IntegerField(max_length=3, blank=True)
    movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True)
    show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True)

    def __str__(self):
        return self.title_en

    class Meta:
        verbose_name = "Slider Items Module"
        verbose_name_plural = "Slider Item Module"

Also if a show is selected and a movie isn't, how do i know title_en will be taken from show and not movie?

user892134
  • 3,078
  • 16
  • 62
  • 128

2 Answers2

1

I think you can do something like this:

from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _

class Slider_items(models.Model):
    
        order = models.IntegerField(max_length=3, blank=True)

        # don't forget to add null=True to both fields
        movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True, null=True)
        show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True, null=True)
        
        # see docs, https://docs.djangoproject.com/en/3.2/ref/models/instances/#django.db.models.Model.clean
        def clean(self):
            if self.movie and self.show:
               raise ValidationError({'movie': _('You can't select both types at the same time')})
            elif not self.movie and not self.show:
               raise ValidationError({'movie': _('You must select one type')})

        def __str__(self):
            return self.movie.title_en if self.movie else self.show.title_en 
    
        class Meta:
            verbose_name = "Slider Items Module"
            verbose_name_plural = "Slider Item Module"
Mahmoud Adel
  • 1,262
  • 2
  • 13
  • 23
0

You may consider using django contenttypes.

Imagine in the future, you have not just Movie, Show, but have new Class such as Book, Podcase, it might not be a good idea to keep adding new foreignkey to your Slider Model.

I have not used contenttype before, so I am referencing this SO answer.

(using python 3.6, django 3.2)

models.py

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class Movie(models.Model):
    title = models.CharField(max_length=50)
    director = models.CharField(max_length=50)

class Show(models.Model):
    title = models.CharField(max_length=50)
    date = models.DateField()

class Slider(models.Model):
    order = models.IntegerField(max_length=3, blank=True)
    choices = models.Q(model='movie') | models.Q(model='show')
    selection_type = models.ForeignKey(
        ContentType, limit_choices_to=choices,
        on_delete=models.CASCADE)
    selection_id = models.PositiveIntegerField()
    selection = GenericForeignKey('selection_type', 'selection_id')

    def __str__(self):
        return self.selection.title

admin.py

@admin.register(Slider)
class SliderAdmin(admin.ModelAdmin):
    pass

at django shell, the following is valid.

movie = Movie.objects.create(title='movie 1', director='ben')
show = Show.objects.create(title='show 1', date='2021-01-01')
s1 = Slider.objects.create(selection=movie, order=1)
s2 = Slider.objects.create(selection=show, order=2)

However, using limit_choices_to only restrict the choices in admin page, and there is no constraint at database level. i.e. the following are actually legal.

place = Place.objects.create(name='home')
s3 = Slider.objects.create(selection=s3, order=3)

I have not found a fix for this issue yet. Maybe doing some validation in save method is a way (see the comments under this).

Bensoft
  • 1
  • 3