How to filter choices from a field based on choices from another form field in Django?

Asked

Viewed 107 times

-1

In Django Admin I have a model who has two fields: Unidade and Localizacao. Where Unidade has a ManyToManyField for Localizacao, as follows below

class Unidade(models.):
    nome = models.CharField('Nome', max_length=200)
    localizacao = models.ManyToManyField(Localizacao)
    ordem = models.PositiveSmallIntegerField('Ordem', unique=True, blank=False)

class Localizacao(models.Model):
    nome = models.CharField('Nome', max_length=200)
    .
    .

And in the registration below I have to select a Unit and I wanted only the locations of that unit to appear as an option for me, however appear all locations. I tried to do something using javascript, but this way I only got the name of the Unit and not the location it has in it. Someone would show me a way to do that? inserir a descrição da imagem aqui

2 answers

0


0

Leonardo, I will answer by following your question "How to filter choices from a field based on choices from another form field in Django?" using Javascript pq did not understand your description of your problem.

At first I consider that the units (branches, States, sector...) are already registered and that the items that refer to them (employees, cities, products...) are already duly registered also.

That is, when choosing a state, you will list all the cities of that state. choose a branch, present all employees. Choose a sector and all the related products appear.

first step

  • create a templates folder in the app directory.
  • create a name html file you want "cad_alunos.html"

second step

  • copy the html code that is in the change_form file located in: /home/?? /. virtualenvs/SEU_PROJETO/lib/python3.7/site-Packages/Django/contrib/admin/templates/admin/change_form.html
  • glue the code to your "cad_alunos.html"

third step

  • locate on cad_student.html <form {% if has_file_field %}enctype= and add: data-local-url="{% url 'ajax_choose_path' %} in this way:
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post"
    id="{{ opts.model_name }}_form" data-local-url="{% url 'ajax_escolha_local' %} novalidate>
  • locate {% block field_sets %} and paste before finishing the block <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  • paste the script right after
    <script>
       $("#id_localizacao").change(function () {
          var url = $("#{{ opts.model_name }}_form").attr("data-local-url");
          var localizacaoId = $(this).val();
            $.ajax({
              url: url,
              data: {
                'id_localizacao': localizacaoId
                },
                success: function (data) {
                  $("#id_unidade").html(data);
                }
              });

            });
    </script>

fourth step

  • create a file Forms.py and a pro form class (don’t forget to make the imports according to your project)
from django import forms
from outroapp.models import Localizacao, Unidade
from .models import CadastroAluno


class CadastroAlunoForm(forms.ModelForm):
    unidade = forms.ModelChoiceField(queryset=Unidade.objects.all())

    class Meta:
        model = CadastroAluno
        fields = ('mensagem', 'texto1', 'texto2', 'unidade', 'localizacao')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['localizacao'].queryset = Cidades.objects.none()

        if 'unidade' in self.data:
            try:
                unidade_id = int(self.data.get('unidade'))
                self.fields['localizacao'].queryset = Localizacao.objects.filter(id_unidade=unidade_id)
            except (ValueError, TypeError):
                pass 
        elif self.instance.pk:
            self.fields['localizacao'].queryset = self.instance.localizacao

In this case, the model Student register in question does not have the Unit, only the location, so I can use on Forms to list, but when registering, not be used. If you need to register, just take the reference before the class meta and add the item there in models.py

fifth step

  • in the templates folder create an html file any "choose_de_location.html"
  • paste this code that will list the Dropdown exactly in the location item
<option value="">---------</option>
{% for local in localizacao %}
<option value="{{ local.pk }}">{{ local.nome }}</option>
{% endfor %}

It’s just that bit right... no header without footer, no load, that’s all

sixth step

  • in py views. vc will reference the html that will update Dropdown when you choose Drive
from django.shortcuts import render
from outroapp.models import Localizacao

def nome_que_eu_quiser(request):
    unidade_id = request.GET.get('unidade')
    localizacao = Localizacao.objects.filter(id_unidade=unidade_id)
    return render(request, 'escolha_de_localizacao.html', {'localizacao': localizacao})

step seven

  • assuming you don’t have a file py. in the app, you can enter py. there from the project directory even the following path:
[...outros imports]
from django.urls import path
from app_que_está_o_cadastro_de_alunos import views

 path('admin/', admin.site.urls),
 [...]
 path('ajax/escolha-unidades/', views.nome_que_eu_quiser, name='ajax_escolha_local'),

8th step

  • in the admin py. just make the record
from django.contrib import admin
from .models import CadastroAluno, 
from .forms import CadastroAlunoForm


@admin.register(CadastroAluno)
class CadastroAlunoAdmin(admin.ModelAdmin):
    form = CadastroAlunoForm
    list_filter = ('mensagem', 'texto1')
    add_form_template = 'cad_alunos.html'
    change_form_template = 'cad_alunos.html'

An alternative exclusively in Django, I have not yet managed to do. I hope I helped and I haven’t forgotten anything...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.