0

I have a form to create projects in my app. In this form the user must select a client in a and then a farm in another . How do I when selecting a client, the next only offers options from farms that are from the selected customer? I believe it's impossible to do this with just Django, am I right?

simplified models.py

class Project(models.Model):
            farm = models.ManyToManyField(Farm, related_name='farm_name',verbose_name='Propriedade beneficiada')
            client = models.ForeignKey(Clients, on_delete=models.CASCADE, related_name='project_client',default=None,null=True, verbose_name='Cliente')
        

class Farm(models.Model):
               client = models.ForeignKey(Clients, on_delete=models.CASCADE, related_name='client', null=True, default=None)
               name = models.CharField(max_length=100, verbose_name='Nome')

forms.py

class NewProjectForm(ModelForm):
    class Meta:
        model = Project
        fields = ['owner','farm','warranty','modal','harvest_year','culture','value','final_date']

    def __init__(self, *args,**kwargs):
        super(NewProjectForm, self).__init__(*args,**kwargs)
        self.fields['value'].required = False
        self.fields['final_date'].required = False
        self.fields['owner'].queryset = Owner.objects.all().order_by('name')
        farm_query = Farm.objects.all().order_by('name')
        self.fields['farm'].queryset = farm_query
        self.fields['warranty'].queryset = farm_query
        self.fields['final_date'].widget.attrs['data-mask'] = "00/00/0000"

        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
  • Correct, Django is for the back-end, so no you cannot do this with just Django. What you *can* do is use JavaScript on the front-end. Check out the answers to this [question](https://stackoverflow.com/questions/25706639/django-dependent-select). – raphael Mar 19 '22 at 20:22

1 Answers1

0

I found an answer that needs little jquery and uses logic in forms.py, it was exactly what I was looking for (since I only understand the basics of Java). Here is the updated code:

forms.py

class NewProjectForm(ModelForm):
    class Meta:
        model = Project
        fields = ['client','owner','farm','warranty','modal','harvest_year','culture','value','final_date']

    def __init__(self, *args,**kwargs):
        super(NewProjectForm, self).__init__(*args,**kwargs)
        self.fields['value'].required = False
        self.fields['final_date'].required = False
        self.fields['owner'].queryset = Owner.objects.all().order_by('name')
        self.fields['final_date'].widget.attrs['data-mask'] = "00/00/0000"

        self.fields['farm'].queryset = Farm.objects.none()
        if 'client' in self.data:
            try:
                client_id = int(self.data.get('client'))
                self.fields['farm'].queryset = Farm.objects.filter(client_id=client_id).order_by('name')
            except (ValueError, TypeError):
                pass
        elif self.instance.pk:
            self.fields['farm'].queryset = self.instance.client.farm_set.order_by('name')

        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'

url.py

(...)
path('new/',views.project_new,name='project_new'),

path('ajax/load-farms/',views.load_farms,name='ajax_load_farms'),     #AJAX

views.py

@login_required
def project_new(request):
    clients = Clients.objects.all().order_by('name')
    farms = Farm.objects.all().order_by('name')
    form = NewProjectForm()
    return render(request,'project_new.html',{'clients':clients,
                                              'farms':farms,
                                               'form':form})

def load_farms(request):
    client_id = request.GET.get('client_id')
    farms = Farm.objects.filter(client_id=client_id)
    return render(request, 'farm_dropdown_list_options.html', {'farms':farms})

farm_dropdown_list_options.html

<option value="">-----</option>
{% for farm in farms %}
    <option value="{{ farm.pk }}">{{ farm.name }}</option>
{% endfor %}

project_new.html

{% extends 'base.html' %}

{% block title %}
    <title>Novo Projeto</title>
{% endblock %}

{% block content %}

    <form name="form" id="form" method="POST" data-farm-url="{% url 'ajax_load_farms' %}">
        {% csrf_token %}
        {{ form }}
        <input type="submit" value="Enviar">
    </form>

<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script>
    $('#id_client').change(function()
    {
        const url = $('#form').attr('data-farm-url');
        const clientId = $(this).val();

        $.ajax({
            url: url,
            data: {
                'client_id': clientId
            },
            success: function(data){
                $("#id_farm").html(data);
                console.log('opa');
            }
        });
    });
</script>
{% endblock %}

I FOUNDED THIS LOGIC IN: GIT