ИМ
22 декабря 2018 г. 6:44

Подскажите по фильтрации объектов в админ-панели

django

Доброго времени суток. У меня ситуация следующая, имею 3 модели которые принадлежат один ко многим:

  1. class Serial(models.Model):
  2. class Meta:
  3. db_table = 'serial'
  4. verbose_name = 'Сериал'
  5. verbose_name_plural = 'Сериалы'
  6.  
  7. name = models.CharField(verbose_name='Название', max_length=200)
  8. orig_name = models.CharField(verbose_name='Оригинальное название', max_length=200, blank=True)
  9. poster = models.ImageField(
  10. # upload_to=curry(upload_to_media, prefix='posters'),
  11. upload_to=upload_to_media,
  12. blank=True,
  13. verbose_name='Постер'
  14. )
  15. category = models.ForeignKey(CategorySerial, on_delete=models.CASCADE, verbose_name='Категория', null=True, blank=True)
  16. year = models.DateField(verbose_name='Дата выхода', default='2000-01-01')
  17. country = models.CharField(verbose_name='Страна', max_length=300, default='Неизвестно')
  18. translate = models.CharField(verbose_name='Перевод', max_length=300, default='Русский')
  19. create = models.DateTimeField(verbose_name='Дата публикации', default=timezone.now)
  20. update = models.DateTimeField(verbose_name='Дата обновления', default=timezone.now)
  21. description = models.TextField(verbose_name='Описание')
  22. moder = models.BooleanField(verbose_name='Модерация', default=False)
  23. votes = GenericRelation(LikeDislike, related_query_name='serials')
  24.  
  25. def public(self):
  26. self.date = timezone.now()
  27. self.save()
  28.  
  29. def __str__(self):
  30. return self.name
  31.  
  32. def get_absolute_url(self):
  33. return reverse('serial:serial_detail', args=[self.id])
  34.  
  35. def get_bookmark_count(self):
  36. return self.bookmarkserial_set.all().count()
  37.  
  38.  
  39. class Playlist(models.Model):
  40. class Meta:
  41. db_table = 'playlist'
  42. verbose_name = 'Плейлист'
  43. verbose_name_plural = 'Плейлисты'
  44. name = models.CharField(max_length=250, verbose_name='Имя плейлиста')
  45. serial = models.ForeignKey(Serial, on_delete=models.CASCADE)
  46.  
  47. def __str__(self):
  48. return self.name
  49.  
  50.  
  51.  
  52. class Seria(models.Model):
  53. class Meta:
  54. db_table = 'seria'
  55. verbose_name = 'Серия'
  56. verbose_name_plural = 'Серии'
  57.  
  58. playlist = models.ForeignKey(Playlist, on_delete=models.CASCADE)
  59. serial = models.ForeignKey(Serial, on_delete=models.CASCADE)
  60. video = models.FileField(
  61. # upload_to=curry(upload_to_media, prefix='movies'),
  62. upload_to=upload_to_media,
  63. verbose_name='Видео'
  64. )

В админ панели ситуация следующая:
Создал я плейлист в одной сериале, и добавляя видео в другом сериале у меня плейлисты с предыдущего

Вопрос заключается в следующем: как отображать плейлисты только принадлежащие к определенному сериалу а не весь список плейлистов.

2

Вам это нравится? Поделитесь в социальных сетях!

12
Evgenii Legotckoi
  • 22 декабря 2018 г. 17:06

Добрый день.

Это делается через установку кастомной формы для model.Admin

Смысл в том, чтобы в соответствующем поле отфильтровать только те серии, или плейлисты, которые отностятся к данном сериалу

  1. class SeriaAdminForm(forms.ModelForm):
  2.  
  3. def __init__(self, *args, **kwargs):
  4. super().__init__(*args, **kwargs)
  5.  
  6. try:
  7. self.fields['playlist'].queryset = self.instance.serial.playlist_set.all()
  8. except Playlist.DoesNotExist:
  9. pass
  10.  
  11.  
  12. class SeriaAdmin(PostAdmin):
  13. form = SeriaAdminForm
  14.  
  15.  
  16. admin.site.register(Seria, SeriaAdmin)

По идее так должно работать правильно.

    ИМ
    • 22 декабря 2018 г. 19:22

    Так то оно работает, но я использую Inline. В inline не хочет, пишет:

    1. serial.models.Seria.serial.RelatedObjectDoesNotExist: Seria has no serial.
      Evgenii Legotckoi
      • 22 декабря 2018 г. 19:31
      • (ред.)

      Ну, полагаю, что весь прикол в том, что здесь просто не обработано это исключение. Поскольку при создании нового объекта там никакой объект не создан.

      А если так? Нужно тогда обработать это исключение и всё

      1. class SeriaAdminForm(forms.ModelForm):
      2.  
      3. def __init__(self, *args, **kwargs):
      4. super().__init__(*args, **kwargs)
      5.  
      6. try:
      7. self.fields['playlist'].queryset = self.instance.serial.playlist_set.all()
      8. except Playlist.DoesNotExist:
      9. pass
      10. except Seria.serial.RelatedObjectDoesNotExist:
      11. pass

      Там скорее всего понадобится сначала установить сериал, сохранить все объекты, а потом уже появится возможность выбора плейлистов.

      Дальше я бы покопал в сторону обновления queryset плейлистов в случае изменения внешнего ключа на сериал.

        ИМ
        • 22 декабря 2018 г. 20:24

        Я ошибся. Вышеуказанные формы не работают.
        А с добавлением except Seria.serial.RelatedObjectDoesNotExist: пропускает ошибку, и в выпадающем списке все плейлисты.

          Evgenii Legotckoi
          • 22 декабря 2018 г. 20:32

          Возможно, тогда стоит установить пустой queryset в том случае если нет внешнего ключа на сериал.

          1. class SeriaAdminForm(forms.ModelForm):
          2.  
          3. def __init__(self, *args, **kwargs):
          4. super().__init__(*args, **kwargs)
          5.  
          6. try:
          7. self.fields['playlist'].queryset = self.instance.serial.playlist_set.all()
          8. except Playlist.DoesNotExist:
          9. pass
          10. except Seria.serial.RelatedObjectDoesNotExist:
          11. self.fields['playlist'].queryset = Playlist.objects.none()

          В любом случае, пока не установлен ключ на сериал, то по логике вы не можете установить какой-либо плейлист туда

            ИМ
            • 22 декабря 2018 г. 20:39

            А так в выпадающем списке ничего нет(

              Evgenii Legotckoi
              • 22 декабря 2018 г. 20:54
              • Ответ был помечен как решение.

              Нужно тогда усложнять код, поскольку серия ещё не создана, то нужно сначала получить внешний ключ на парента

              1. class MyFormSet(BaseInlineFormSet):
              2. def get_form_kwargs(self, index):
              3. kwargs = super().get_form_kwargs(index)
              4. kwargs['parent_object'] = self.instance
              5. return kwargs
              6.  
              7.  
              8. class MyForm(forms.ModelForm):
              9. def __init__(self, *args, parent_object, **kwargs):
              10. self.parent_object = parent_object
              11. super(MyForm, self).__init__(*args, **kwargs)
              12.  
              13. try:
              14. self.fields['playlist'].queryset = parent_object.playlist_set.all()
              15. except Playlist.DoesNotExist:
              16. pass
              17.  
              18.  
              19. class MyChildInline(admin.TabularInline):
              20. formset = MyFormSet
              21. form = MyForm

              что-то вроде такого должно получиться.

                ИМ
                • 22 декабря 2018 г. 21:49
                • (ред.)

                Вместо parent_object подставлять serial?

                UPD: У меня отступы сдвинулись.

                  ИМ
                  • 22 декабря 2018 г. 21:59

                  Так все работает. Спасибо вам огромное. Учусь с вами потихоньку.

                    Evgenii Legotckoi
                    • 23 декабря 2018 г. 1:01

                    Отступы? какие отступы? в админке? это уже детали, которые просто нужно будет дооправить в дальнейшем.

                      ИМ
                      • 23 декабря 2018 г. 1:05

                      У меня try сьехал влево, сначала не за метил и получал ошибки. Почудилось мне что нужно свои переменные подставлять))

                        Evgenii Legotckoi
                        • 23 декабря 2018 г. 1:10

                        А копировали просто с моего комментария. Там действительно съехал на один пробел. Ну я редактировал сразу в форме комментария текст.

                          Комментарии

                          Только авторизованные пользователи могут публиковать комментарии.
                          Пожалуйста, авторизуйтесь или зарегистрируйтесь
                          • Последние комментарии
                          • IscanderChe
                            12 апреля 2025 г. 17:12
                            Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
                          • AK
                            1 апреля 2025 г. 11:41
                            Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
                          • Evgenii Legotckoi
                            9 марта 2025 г. 21:02
                            К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
                          • VP
                            9 марта 2025 г. 16:14
                            Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
                          • ИМ
                            22 ноября 2024 г. 21:51
                            Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…