Customizar Widget no Django Admin para ManyToManyField e manter a opção de adicionar novos itens

Fazia muito tempo que eu não trabalhava em algum projeto que utilizasse o Django Admin, e nessa última experiência me deparei com um problema ao o customizar os widgets dos campos ManyToManyField.

O problema ocorria sempre que eu mudava o widget padrão do Django Admin para os campos ManyToManyField (acredito que para ForeignKey isso também ocorre). Ao invés de um simples “select multiple”, eu precisava que os campos utilizassem o widget FilteredSelectMultiple, porém ao fazer isso, sumia a opção de adicionar novos itens, como na imagem:

Por algum motivo o Django Admin não estava utilizando, por default, o FilteredSelectMultiple para o field documents ¯\_(ツ)_/¯

O problema parece ocorrer pois, para campos de relacionamento (ForeignKey e ManyToManyField), o Django utiliza como intermediário do widget o RelatedFieldWidgetWrapper. Pelo que eu entendi, essa classe é a responsável por lidar com as permissões (do usuário logado), determinando se disponibiliza, ou não, a opção de adicionar novos itens nesse relacionamento.

A solução que eu encontrei foi fazer manualmente a utilização do RelatedFieldWidgetWrapper para esses campos que eu havia customizado o widget.

Na classe utilizada para registrar o model no admin (que possui também as informações sobre as permissões do usuário), injetei no ModelForm a variável admin_site, conforme o código:

@admin.register(Book)
class BookAdmin:
    ...

    def __init__(self, model, admin_site):
        super().__init__(model, admin_site)
        self.form.admin_site = admin_site

E meu ModelForm ficou assim:

from django.contrib.admin.widgets import RelatedFieldWidgetWrapper


class BookAdminForm(forms.ModelForm):
    ...

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['documents'].widget = RelatedFieldWidgetWrapper(
            self.fields['documents'].widget,  # posso fazer a customização do widget diretamente aqui
            Book._meta.get_field('documents').remote_field,
            self.admin_site
        )

 

Referência: https://dashdrum.com/blog/2012/07/relatedfieldwidgetwrapper/

Leave a Reply

Your email address will not be published. Required fields are marked *