Администратор Django выбирает элементы m2m на основе их тегов (поле элемента m2m)

Рассмотрим следующие модели:

class Library(models.Model):
    name = models.CharField(max_length=64)
    books = models.ManyToManyField(Book)

class Book(models.Model):
    name = models.CharField(max_length=64)
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    name = models.CharField(max_length=64)

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

Существующие варианты:

  1. Filter_horizontal — фильтрует по __str__, есть ли способ отфильтровать по tags__name?
  2. Raw_id_fields — работает с любыми фильтрами, указанными для Книги, но вы можете выбрать только 1 элемент. Есть ли способ разрешить выбор большего количества элементов? (галочки в таблице)

person Jura Brazdil    schedule 29.04.2019    source источник


Ответы (1)


В итоге я использовал виджет Django-fsm и переопределил его метод apply_filter_val в views.py. Теперь я могу отфильтровать ключ tag:tag_name, а затем просто выбрать все элементы. Я также добавил возможность фильтровать несколько слов, разделенных запятой.

def apply_filter_val(self, filter_val, queryset):

    if filter_val and 'tag:' in filter_val:

        tag_tuple = filter_val.split(':')
        _, name = tag_tuple

        params = {'tags__name': name}

        new_base = queryset.filter(**params)

    elif filter_val and ',' in filter_val:
        new_base = queryset.filter(id__in=filter_val.split(','))

    elif filter_val:
        q = [Q(**{f'{field}__icontains': filter_val}) for field in self.fields]
        if filter_val and q:
            new_base = queryset.filter(reduce(self.default_operator, q))
    else:
        # Return everything if no filter_val or fields are specified.
        # This allows for a very straightforward async request, but will
        # probably not behave as expected if no fields are specified.
        new_base = queryset

    if self.obj_limit:
        new_base = new_base[:self.obj_limit]

    return new_base
person Jura Brazdil    schedule 08.07.2020