how to save two model formsets together(relates to each other) in one view

i’m trying to implement two modelformset_factory in one view , one of the formsets should be pop up modal form : here is the models

class MobileCollection(models.Model):
    mobile = models.ForeignKey(ModelCategory,on_delete=models.PROTECT,related_name='model_category')
    qnt = models.IntegerField()
    price = models.DecimalField(decimal_places=3,max_digits=20)

class Imei(models.Model):
    mobile = models.ForeignKey(MobileCollection,on_delete=models.PROTECT)
    imei = models.CharField(max_length=15,unique=True)
    serial_no = models.CharField(max_length=7,unique=True,blank=True,null=True)
    status = models.BooleanField(default=True)
    def __str__(self):
        return f'{self.mobile}-{self.imei}'

if quantity = 10 then we have 10 unique imei , for each mobile item we have multiple imei , the im ei should be inserted in a pop up modal

@login_required
def create_collection(request):
    item_formset = mcollection(queryset=MobileCollection.objects.none())
    imei_formset = imei_modelformset(queryset=Imei.objects.none())
    if request.POST:
        item_formset = mcollection(request.POST)
        imei_formset = imei_modelformset(request.POST)

        if imei_formset.is_valid() and item_formset.is_valid() and request.user.is_superuser:                                                
            for item in item_formset:
                item_obj = child.save(commit=False)
                item_obj.save()
                for imei in imei_formset:
                    imei_obj = imei.save(commit=False)
                    imei_obj.mobile = item_obj
                    imei_obj.save()
            return JsonResponse({'success':True})                                    
        else:
            return JsonResponse({       
'success':False,'error_child_msg':item_formset.errors,'error_imei_msg':imei_formset.errors})
    context = {
        'item_formset':item_formset,
        'imei_formset':imei_formset
    }
    return render(request,'storage/collection.html',context)  

but it only saves the last item entry and doesnt save imei , only its instance(from the item) will be saved

and here is my formsets

mcollection = modelformset_factory(
    MobileCollection,form=MobileCollectionForm,fields= 
['mobile','qnt','price'],can_delete=True,extra=1)
imei_modelformset = modelformset_factory(Imei,form=ImeiForm,fields= 
['imei'],extra=1,can_delete=True)

and also i’m not sure how to use the empty_formset for the imei formsets .
here is my html and jquery

    const addNewRow = document.getElementById('add-more')    
    const totalNewForms = document.getElementById('id_form-TOTAL_FORMS')
    
    addNewRow.addEventListener('click',add_new_row);
    function add_new_row(e){
        if(e){
            e.preventDefault();
        }  
        const currentFormClass = document.getElementsByClassName('child_forms_row')
        const countForms = currentFormClass.length
        const formCopyTarget = document.getElementById('form-lists')

        const empty_form = document.getElementById('empty-form').cloneNode(true);        
        empty_form.setAttribute('class','child_forms_row')
        empty_form.setAttribute('id',`form-${countForms}`)
        const rgx = new RegExp('__prefix__','g')
        empty_form.innerHTML = empty_form.innerHTML.replace(rgx,countForms)

        totalNewForms.setAttribute('value',countForms + 1)
        formCopyTarget.append(empty_form)
        const imeiBtn = document.getElementById('IMEIBTN')
        imeiBtn.setAttribute('id',`IMEIBTN-${countForms}`)
        $(`#IMEIBTN-${countForms}`).attr('data-target',`#IMEI${countForms}`)
        const my_modal = document.getElementById('IMEI0').cloneNode(true)
        my_modal.setAttribute('id',`IMEI${countForms}`)
        const main_modal =  document.getElementsByClassName('allModal')

        main_modal.append(my_modal)



    }

            <form action="" method="POST" id="create-collection">{% csrf_token %}                                                                     
            </div>            
            {{item_formset.management_form}}
            <div id="form-lists">
                {% for mform in item_formset %}
                {{mform.id}}
                <div class="child_forms_row">

                    <div class="row no-gutters table-bordered">
                        <div class="col-md-3">
                            <div class="form-group">
                                {{mform.mobile | add_class:'form-control'}}
                            </div>
                        </div>
                        <div class="col-md-1">
                            <div class="form-group">
                                {{mform.qnt}}
                            </div>
                        </div>
                        <div class="col-md-1">
                            <div class="form-group">
                                {{mform.price}}
                            </div>
                        </div>                                     
 
                        <div class="col-md-1">
                            <div class="form-group row justify-content-center">
                                  <button type="button" class="btn btn-info"
                                  name="" id="IMEIBTN-0" 
                                 data-target="#IMEI0"  data-toggle="modal">IMEI</button>                                  
                            </div>
                        </div>                                                                        
                    </div>
                </div>
                {% endfor %}
            </div>
            <div id="empty-form" class="hidden">
                <div class="row no-gutters table-bordered">
                    <div class="col-md-3">
                        <div class="form-group">
                            {{item_formset.empty_form.mobile | add_class:'form-control'}}
                        </div>
                    </div>
                    <div class="col-md-1">
                        <div class="form-group">
                            {{item_formset.empty_form.qnt}}
                            <div class="text-danger text-center" hidden></div>
                        </div>
                    </div>
                    <div class="col-md-1">
                        <div class="form-group">
                            {{item_formset.empty_form.price}}
                        </div>
                    </div>      
                    <div class="col-md-1">
                        <div class="form-group row justify-content-center">
                            <button 
                            type="button" id="IMEIBTN" name="imei" class="btn btn-info" value="IMEI"
                            data-target="#IMEI0"  data-toggle="modal">IMEI</button>
                        </div>
                    </div>                                                                   
                </div>

            </div>
            <button type="button" class="btn btn-lg" id="add-more">add new row</button>
            <!-- /.row -->

            <div class="allModal">

                <div id="IMEI0" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="my-modal-title" aria-hidden="true">
                    <div class="modal-dialog" role="document">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h5 class="modal-title" id="my-modal-title">IMEI</h5>
                                <p class="close" data-dismiss="modal" aria-label="Close">
                                    <span aria-hidden="true">&times;</span>
                                </p>
                            </div>
                            <div class="modal-body modal0">
                                {{imei_formset.management_form}}
                                {% for imei in imei_formset %}
                                <div class="row">
                                    {{imei.imei | add_class:'form-control'}}   
                                </div>
                                {% endfor %}
                            </div>
                        </div>
                    </div>
                </div>             
            </div>            

            <div class="card-footer">
                <div class="row justify-content-center">
                    <button type="submit" class="btn btn-lg btn-success">save</button>
                </div>
            </div>
        </form>

please if you know something about that let me know, i much appreciate your helps … Thank you in advance

Let me see if I understand the situation correctly.

You have a formset on a page. This formset is for MobileCollection.

  • On this page, do these instances of MobileCollection already exist?
  • Or is it possible (likely?) that you’re adding instances of MobileCollection on this page?

Also on this page, you have a formset for Imei.

  • Is it one formset for each instance of MobileCollection? Or is it one formset of Imei for the page? (Asking the same question in a different way - Does each MobileCollection have its own set of Imei, or do all MobileCollection share the same set of Imei?)

I’m asking this because what you’ve written implies the former to me, while the code you’ve posted looks to implement the latter.

thank you for your reply , in the page we adding new instance of MobileCollection , and
each MobileCollection have its own set of imei , in another way if
qnt = 10 then we have to add 10 imei , and the MobileCollection should also by dynamic
i much appreciate your helps
is it make sense ?

Ok, so if each instance of MobileCollection has its own Imei, and you’re adding new instances of MobileCollection, you can’t “pregenerate” the Imei formset. Each time you add an instance of MobileCollection, you need to create a new instance of the Imei formset to be associated with that instance of MobileCollection. Since you’re going to have multiple formsets of the same type on a page, each formset needs to be built with a different prefix.

We have a system where we need to do something similar to this. Our solution was to create a view that only creates the nested formset (in your case, the Imei formset) with a custom prefix, returning it as HTML.

When a new row of the outer formset is created (your MobileCollection), the JavaScript makes an AJAX call to that view. It passes the new row index as a parameter, getting back the new formset, which it then inserts into the page.

You will then have a bit of additional work needed to validate all these forms once they’ve been submitted.

Side note: I know you want to present this new formset as a modal, but I strongly recommend you implement it as all visible on the page first, while you’re trying to get this working. This is not a trivial task and there are a number of potential “gotchas”.

Once you’ve got this built and tested, then you can convert those injected formsets to become modal dialogs. You’re going to find it a lot easier to get it working this way. (Breaking big tasks down into smaller discrete tasks.)

1 Like

is the view is correct please , if we add its custom prefix ? and if you have a sample code please let me know , and is it possible ; for example : qnt = 10 , then 10 imei forms will be create instead of press the button ? if it requires i’ll pay for the sample code
i much appreciate your replies

Your view is not correct, you’re only creating one Imei formset, when your situation requires a separate Imei formset for each instance of MobileCollection.

Doing this correctly is likely to require at least two views.

I’m sorry, I can’t provide code.

it an urgent task from a client , i dont have any idea about that , if there is any tutorial , blog post please let me know , i searched alot before the post , i found nothing

please i need your help , i understand that you want to me to solve it by myself in order to get more experience , but this one is different case , i dont want to lose the client , i have to finish it on time . i’ll pay the price

@KenWhitesell please i need your help …