Como evitar a auto-seleção (recursivo) para campos FK / MTM no Django admin

votos
10

Dado um modelo com ForeignKeyField (FKF) ou campos ManyToManyField (MTMF) com um ForeignKey para 'eu' como posso evitar auto selecção (recursivo) dentro do Django admin (admin).

Em suma, deve ser possível para evitar auto-seleção (recursiva) de uma instância de modelo na administração. Isto aplica-se ao editar instâncias existentes de um modelo, não a criação de novas instâncias.

Por exemplo, ter o seguinte modelo para um artigo em um aplicativo de notícias;

class Article(models.Model):           
    title = models.CharField(max_length=100)
    slug = models.SlugField()
    related_articles = models.ManyToManyField('self')

Se há 3 Articlecasos (título: a1-3), ao editar um já existente Articleinstância através da administração do related_articlescampo é representado por padrão por uma caixa de seleção html (múltipla), que fornece uma lista de todos os artigos ( Article.objects.all()). O usuário só deve ver e ser capaz de selecionar Articleoutros do que em si casos, por exemplo Ao editar Articlea1, related_articlesdisponíveis para selecionar = a2, a3.

Eu atualmente pode ver 3 potencial de maneiras de fazer isso, por ordem decrescente de preferência;

  1. Fornecer uma maneira de definir o queryset fornecendo opções disponíveis no campo de formulário admin para o related_articles(através de um filtro de consulta exclui, por exemplo, Article.objects.filter(~Q(id__iexact=self.id))para excluir a instância atual sendo editado na lista de related_articles um usuário pode ver e escolher. Criação / configuração do Queryset usar poderia ocorrer dentro do construtor ( __init__) de um costume Article ModelForm, ou, através de algum tipo de dinâmica limit_choices_to Modelopção. Isso exigiria uma maneira de agarrar a instância que está sendo editado para usar para filtragem.
  2. Substituir a save_modelfunção do Article Modelou ModelAdminclasse para procurar e remover-se do related_articlesantes de salvar a instância. Isto ainda significa que os usuários de administração podem ver e selecionar todos os artigos, incluindo a instância que está sendo editado (para artigos existentes).
  3. Filtrar auto referências quando necessário para uso fora do admin, por exemplo, modelos.

A solução ideal (1) é actualmente possível fazer por meio de formas de model fora do administrador como é possível passar em uma variável queryset filtrada para o exemplo a ser editado para o construtor forma modelo. A pergunta é, você pode obter na Articleinstância, ou seja, 'eu' que está sendo editado o administrador antes do formulário é criada para fazer a mesma coisa.

Poderia ser eu estou lidando com isso da maneira errada, mas se a sua permissão para definir um FKF / MTMF para o mesmo modelo, então deve haver uma maneira de ter o admin - fazer a coisa certa - e impedir que um usuário selecionando-se por excluindo-o na lista de opções disponíveis.

Nota: Solução 2 e 3 são possíveis de fazer agora e são fornecidos para tentar evitar estes como respostas, Idealmente, eu gostaria de obter uma resposta a solução 1.

Publicado 15/05/2009 em 18:12
fonte usuário
Em outras línguas...                            


3 respostas

votos
9

Carl está correto, aqui está uma amostra de cortar e colar o código que iria em admin.py

Acho navegar as relações Django pode ser complicado se você não tem uma sólida compreensão, e um exemplo vivo pode valer 1000 Tempo mais do que um "ir ler este" (não que você não precisa entender o que está acontecendo) .

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myManyToManyField'].queryset = MyModel.objects.exclude(
            id__exact=self.instance.id)
Respondeu 08/12/2009 em 22:18
fonte usuário

votos
2

Você pode usar um ModelForm personalizado no admin (definindo o atributo "forma" de sua subclasse ModelAdmin ). Então você fazê-lo da mesma maneira na administração como faria em qualquer outro lugar.

Respondeu 16/05/2009 em 17:23
fonte usuário

votos
0

Você também pode substituir o get_formmétodo da ModelAdmin assim:

def get_form(self, request, obj=None, **kwargs):
    """
    Modify the fields in the form that are self-referential by
    removing self instance from queryset
    """
    form = super().get_form(request, obj=None, **kwargs)
    # obj won't exist yet for create page
    if obj:
        # Finds fieldnames of related fields whose model is self
        rmself_fields = [f.name for f in self.model._meta.get_fields() if (
            f.concrete and f.is_relation and f.related_model is self.model)]
        for fieldname in rmself_fields:
            form.base_fields[fieldname]._queryset =
                form.base_fields[fieldname]._queryset.exclude(id=obj.id)
    return form

Note-se que este é um-tudo em tamanho único solução que encontra automaticamente auto-referência campos modelo e remove auto de todos eles :-)

Respondeu 28/09/2016 em 15:45
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more