Problem in ajax when populate drop-down input from another

Hi all,
This is my problem

PRODUCT-FORM FIELDS:  pos_station <ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul>

UNIT-FORM FIELDS:  unit <ul class="errorlist"><li>This field is required.</li></ul>
UNIT-FORM FIELDS:  value <ul class="errorlist"><li>This field is required.</li></ul>
UNIT-FORM FIELDS:  uom_options <ul class="errorlist"><li>This field is required.</li></ul>

I’m using ajax to display toast messages. I have many forms to save them by one click on one save button. These are my forms

form = ProductForm(request.POST or None, request.FILES or None, prefix="pro")
price_form = ProductPriceForm(request.POST or None, prefix="price")
extension_form = ProductExtensionForm(request.POST or None, prefix="extension")
uom_form = UOMForm(request.POST or None, prefix="uom")
vendor_form = ProductVendorsForm(request.POST or None, prefix="ven")
cat_form = ProductCategoryForm(request.POST or None, prefix="cat")
img_form = ProductImageForm(request.POST or None, request.FILES or None, prefix="img")

So I have many fields, And I tried to pass their values and save them as follows but I failed

        match_name = Product.objects.filter(name=pro_name).exists()
        match_name_ar = Product.objects.filter(name=pro_name_ar).exists()
        if form.is_valid() and uom_form.is_valid():

            if not match_name : # and not match_name_ar 
                save_form = form.save(commit=False)
                save_form.user = request.user
                save_form.updated_user = request.user
                save_form.reference_code = save_form.pro_code
                save_form.pos_station_id = pos
                save_form.store_id = store
                save_form.expire_ref =  expire_ref #choices.HOUR
                save_form.hint_ref = hint_ref # choices.HOUR

                save_form.save()

                save_uom_form = uom_form.save(commit=False)
                save_uom_form.product_id = save_form.id
                save_uom_form.uom_options = [obj for obj in unit_options]
                save_uom_form.value = [obj for obj in unit_value]
                save_uom_form.unit_id = [obj for obj in unit]
                
                save_uom_form.save()

                data['pro_id'] = save_form.id 
                data['error'] = 'Product saved successfully ...'
                data['type'] = 'success'
                return JsonResponse(data)

The next code illustrate the ajax call to submit the from

$(document).ready(function () {
        $.ajaxSetup({
            headers: {
                "X-CSRFToken": '{{ csrf_token }}'
            }
        });

        $(document).on('submit', ".product-form", function (e) {
            // e.preventDefault();
            // console.log();
            let name = $('#id_pro-name').val(); 
            let nameAr = $('#id_pro-name_ar').val(); 
    
            var optionValues = $('.unit-options').map(function() {
                return $(this).find('select').val();
            }).get(); 
            
            var unitValues = $('.unit-select').map(function() {
                return $(this).find('select').val();
            }).get();

            var values = $('.unit-value').map(function() {
                return $(this).find('input').val();
            }).get();
            
            console.log(
                'submit button clicked successfully',
                'PRO-NAME :', name,
                'OPTIONS:', optionValues,
                'UNIT-VALUEs:', unitValues,
                'VALUES :', values,
            );

            $.ajax({
                type: 'POST',
                url: '{% url "products:add_product" %}', 
                data: {
                    'pro-branch': $('[name=pro-branch] option:selected').val(),
                    'pro-pos_station': $('[name=pro-pos_station] option:selected').val(),
                    'pro-store': $('[name=pro-store] option:selected').val(),
                    
                    'pro-name': name,
                    'pro-name_ar': nameAr,
                    'pro-barcode': $('#id_pro-barcode').val(),
                    'pro-reference_code': $('#id_pro-reference_code').val(),
                    'pro-is_deleted': $('[name=pro-is_deleted]').is(':checked'),
                    'pro-inactive': $('[name=pro-inactive]').is(':checked'),
                    'pro-consumable': $('[name=pro-consumable]').is(':checked'),
                    'pro-on_pos': $('[name=pro-on_pos]').is(':checked'),
                    'pro-purchased': $('#id_pro-purchased').is(':checked'), 
                    'pro-sold': $('#id_pro-sold').is(':checked'), 
                    'pro-favorite': $('#id_pro-favorite').is(':checked'), 
                    'pro-is_inventory': $('#id_pro-is_inventory').is(':checked'), 
                    'pro-sale': $('#id_pro-sale').is(':checked'), 
                    'pro-manufactured': $('#id_pro-manufactured').is(':checked'), 
                    
                    'pro-expiry': $('#id_pro-expiry').is(':checked'), 
                    'pro-has_limit_plus': $('#id_pro-has_limit_plus').is(':checked'), 
                    'pro-has_limit_minus': $('#id_pro-has_limit_minus').is(':checked'), 
                    'pro-expire_period': $('#id_pro-expire_period').val(),
                    'pro-expire_ref': $('#id_pro-expire_ref').val(),
                    'pro-expire_period_hint': $('#id_pro-expire_period_hint').val(),
                    'pro-hint_ref': $('#id_pro-hint_ref').val(),
                    
                    'pro-order_limit_plus': $('#id_pro-limit_plus').val(),
                    'pro-order_unit_plus': $('#id_pro-order_unit_plus').val(),
                    'pro-order_limit_minus': $('#id_pro-limit_minus').val(),
                    'pro-order_unit_minus': $('#id_pro-order_unit_minus').val(),
                    
                    'img-photo': $('#id_img-photo').val(),

                    'uom-uom_options': $('#uom-uom_options :selected').val(),// optionValues,
                    'uom-unit': $('#uom-unit :selected').val(), // unitValues,
                    'uom-value': $('#uom-value').val(), //values,
                },
                success: function (data) { 
                    console.log(
                        'WHAT IS GOING ON HERE FROM SUCCESS: ',
                        'DATA ERROR MSG --> ', data['error'],   
                        'AFTER-SUBMITTING:: ', optionValues, 
                        'AFTER-SUBMITTING:: ', unitValues, 
                        'AFTER-SUBMITTING:: ', values, 
                    );
                    
                    $(function() {
                        var Toast = Swal.mixin({
                            toast: true,
                            position: 'top-end',
                            showConfirmButton: false,
                            timer: 9000
                        });
                        var proId = data['pro_id']; 
                        if (data['type'] == 'error'){
                            console.log(data['type'])
                            toastr.error(data['error']);
                        } else if (data['type'] == 'success') {
                            toastr.success(data['error']);
                            console.log('PRO-ID: ', data['pro_id']);

                        } else if (data['type'] == 'info') {
                            toastr.info(data['error']);
                        }
                    });
                },
                error: function (){
                    console.log('ERROR with ajax request');
                },
            });
            e.preventDefault();
        });
        
    });

And use ajax also to populate the drop-down input(pos_station) based on the value of another drop-down input (branch) using this code snippet

$(document).on('change', '#id_pro-branch', function() {
            console.log('BRANCH CHANGED TRUE')
            let branchSelected = $(this).find('option:selected').val();
            
            $.ajax({
                url:'{% url "ajax_product_cat_tab" %}', 
                type:'POST',
                dataType:'json',
                data: {
                    'pro-branch': branchSelected,
                    
                },
                success: function (data) { 
                    console.log(
                        "Success from POST ",
                        );
                    $(function(){
                        var posNames = (data['pos_names']);              
                        $('#id_pro-pos_station').text('');
                        if (posNames.length > 0) {
                            // alert(values);
                            $('#id_pro-pos_station').append('<option>----------</option>');
                            for (var i = 0; i < posNames.length; i++) {
                                //show where value is same..
                                $('#id_pro-pos_station').append('<option>'+(posNames[i])+'</option>');
                            }
                        } 

                    });
                    
                },
                error: function (data) {
                        console.log(data, 'Something went wrong in POST !!!');
                }
            });
            
        });

and the view is

def ajax_product_cat_tab(request):
    branch_name = request.POST.get('pro-branch')

    pos_stations = PosStation.objects.values_list(
        'name', flat=True
    ).filter(
        branch=Branches.objects.select_related(
            'user'
        ).get(
            id=branch_name
        )
    )
    pos_names = [obj for obj in pos_stations]
    
   data = {
        'pos_names': pos_names,
    }
    return JsonResponse(data)

Also (expire_ref and hint_ref) don’t accept the value or initial (it appears on the form but I must choose from the drop-down list to avoid the error “This field is required.”) I don’t know why

self.fields['expire_ref'].widget.attrs['value']  = choices.HOUR 
self.fields['expire_ref'].initial = choices.DAY
self.fields['hint_ref'].widget.attrs['value'] = choices.HOUR 
self.fields['hint_ref'].initial = choices.DAY

Really I spent many times to fix this issue and I can use “HTML inputs” instead of django forms but I prefer forms to use its benefits .

May be I miss something here or there , I don’t know

Any suggestions thanks

You might want to render these forms as html to identify exactly what the names are for each of those fields, and to see what those form submit as the POST data when they’re submitted.

You can then use that information to verify that the data being submitted matches the “form and format” of the data being submitted by the html-based POST.

(And although it’s not precisely clear here whether this applies, I will point out that file uploads - e.g. images - are handled completely different than normal form data. You don’t treat those as just another form field.)

1 Like

Really I have many benefits from your previous answer to my ajax issue and I’m taking care about the fields name and ids of all the fields by using elements tab in my browser .

But it is OK I investigate then come back

Thanks sir for your help and advises to fix my problem

I have solved this issue by your guidance , Tomorrow I’ll explain what I have done to solve my problem .

thanks for your advises

Finally I figured it out, After I spent times with (“Select a valid choice. POS Station 1 is not one of the available choices.”) .
Any way, It’s the tax of success and experience.
But I have some inquires (need to be explained)

1- The above photo explains that I must go to “Unit Of Measure” tab (to add rows for unit otherwise I get UOM form is not valid).

2- The method I used to save UOM model is as follow

### The next lists are from ajax 
unit_list = request.POST.getlist("unit-list[]")
option_list = request.POST.getlist("option-list[]")
value_list = request.POST.getlist("value-list[]")

var optionValues = $('.unit-options').map(function() {
                return $(this).find('select').val();
            }).get(); 
            
            var unitValues = $('.unit-select').map(function() {
                return $(this).find('select').val();
            }).get();

            var values = $('.unit-value').map(function() {
                return $(this).find('input').val();
            }).get();


## the next is the original names of the form uom_form 
##(failed to get the fields list) it gives my the first row only as the above image indicated

 # unit_list = request.POST.getlist("uom-unit", [])
# option_list = request.POST.getlist("uom-uom_options", [])
# value_list = request.POST.getlist("uom-value", [])

I save uom_form by the next code

.....
if uom_form.is_valid():
            if not match_name : 
                uom = [
                    UOM.objects.create(
                        product_id=save_form.id,
                        uom_options= opt,
                        main_uom=True if opt == 'main' else False,
                        unit_id= int(un),
                        value= int(Decimal(val))
                    ) for opt, un, val in zip(option_list, unit_list, value_list)
                ]

But I tried the following and failed to save in the database

if uom_form.is_valid():
            if not match_name : 
                save_uom_form = uom_form.save(commit=False)
                save_uom_form.product_id = save_form.id
            # save_uom_form.uom_options = [obj for obj in option_list]
            # save_uom_form.value = [int(Decimal(obj)) for obj in value_list]
            # save_uom_form.unit_id = [int(obj) for obj in unit_list]
            
                 save_uom_form.save()
                 save_uom_form.uom_options.add(*([obj for obj in option_list]))
                 save_uom_form.value.add(*([int(Decimal(obj)) for obj in value_list]))
                 save_uom_form.unit_id.add(*([int(obj) for obj in unit_list]))    

The save_uom_form.uom_options.add(*([obj for obj in option_list])) gives me an error says " ‘str’ object has no attribute ‘add’ " … Here I tried something like that ( bulk_create) in an old project but I failed and create with zip() is more useful for my I need explaination
I’d like to learn some new techniques about saving form instead of using UOM.objects.create()

Till now these are my problems but it is OK for me I got rid of most annoying problem and I am so happy to fix it