Ppyyt
Ppyyt

Reputation: 125

Django modelformset_factory deleting objects marked by can_delete

Hello I have got question I have made modelformset_factory and in options I have choosen can_delete = True and now I don't know how to delete marked objects as 'DELETE' : True to delete them from database. I was trying to do this in some ways and it didnt work. I was looking for it also in django formsetmodels documentation but this didnt help me. With this option can_delete = True I get additional checkbox in my html page Delete and marking him only prints me in console on print: {'username': 'sw', 'email': '[email protected]', 'city': 'ss', 'code': 12345, 'id': , 'DELETE': False}

Saving forms to database is working but I dont know how to delete marked forms from database.

I would be very thankful for every help.

I have made modelformset_factory from model in models.py

class TestModel(models.Model):
username = models.CharField(max_length=120)
email = models.EmailField()
city = models.CharField(max_length=120)
code = models.IntegerField()
#W admin panelu za miast TestModel object bedzie username
def __str__(self):
    return self.username

Then I have added in my views.py function:

def django_modelformset(request):
TestModelFormset = modelformset_factory(TestModel, fields=['username', 'email', "city",
                                                           "code"], extra=1, can_delete=True)
formset = TestModelFormset(request.POST or None)

if formset.is_valid():
    for form in formset:
        print(form)

        print(form.cleaned_data)
        form.save()
context = {"formset": formset}
return render(request, "modelformset.html", context)

My modelformset.html looks like this:

<form method="POST" action="">
{% csrf_token %}

{{ formset.management_form}}
{% for form in formset %}
<div>

    {{ form.as_p }}
    <hr/>
</div>
{% endfor %}
<input type="submit" value="Save">

Upvotes: 4

Views: 3094

Answers (2)

Gaurav Nagar
Gaurav Nagar

Reputation: 371

It's work for me

view.py

Blog_MetaFormSet = modelformset_factory(Metas, form=MetaForm, extra=0, can_delete=True)
Blog_MetaQuerySet = Metas.objects.filter(blog=blog_obj).order_by('created_at')

contex={
"blog_meta_formset": Blog_MetaFormSet(request.POST,queryset=Blog_MetaQuerySet),
}


if blog_meta_formset.is_valid():
    for metaform in blog_meta_formset:
        meta_obj = metaform.save(commit=False)
        meta_obj.blog = blog_obj
        if metaform.cleaned_data["DELETE"]==True:
            meta_obj.delete()
        else:
            meta_obj.save()

In Templates

<div class="row">
    <div id="cfield-form-list"> {{ blog_meta_formset.management_form }} {% for meta_form in blog_meta_formset %}
        <div id="form-{{forloop.counter0}}" class="cfield-form xrow">
            <div class="col-md-12 mb-3">
                <div class="row d-flex align-items-center">
                    <div class="col-md-4">
                        <label class="form-label">Name</label> {{ meta_form.title|attr:"class:form-control"|attr:"type:text" }} </div>
                    <div class="col-md-4">
                        <label class="form-label">Value</label> {{ meta_form.value|attr:"class:form-control"|attr:"rows:2" }} </div>
                    <div class="col-md-4">
                        <div class="form-check custom-checkbox mb-3 checkbox-primary"> {{ meta_form.DELETE|attr:"class:form-check-input"|attr:"type:checkbox" }}
                            <label class="form-check-label" for="customCheckBox2">Delete</label>
                        </div>
                    </div>
                </div>
            </div> {{meta_form.id}} </div> {% endfor %} </div>
    <div id="empty_form" class="hidden">
        <div class="col-md-12 mb-3">
            <div class="row d-flex align-items-center">
                <div class="col-md-4">
                    <label class="form-label">Name</label> {{ blog_meta_formset.empty_form.title|attr:"type:text"|attr:"class:form-control" }} </div>
                <div class="col-md-4">
                    <label class="form-label">Value</label> {{ blog_meta_formset.empty_form.value|attr:"class:form-control"|attr:"rows:2" }} </div>
                <div class="col-md-4">
                    <div class="form-check custom-checkbox mb-3 checkbox-primary"> {{ blog_meta_formset.empty_form.DELETE|attr:"class:form-check-input"|attr:"type:checkbox" }}
                        <label class="form-check-label" for="customCheckBox2">Delete</label>
                    </div>
                </div>
                <div class="col-md-4">
                    <button type="button" class="btn btn-danger remove_cfield" rel="">Delete</button>
                </div>
            </div>
        </div>
    </div>
    <div class="col-md-12">
        <button type="button" id="add-cfield" class="btn btn-primary mb-3 mt-3 ">Add Custom Field</button>
    </div>
</div>

In js


const totalNewForms = document.getElementById('id_form-TOTAL_FORMS')

const addMoreBtn = document.getElementById('add-cfield')
addMoreBtn.addEventListener('click',add_new_form)

function add_new_form(event){
  if (event){
    event.preventDefault()
  }

  const currentCF_Forms = document.getElementsByClassName('cfield-form')
  console.log(currentCF_Forms)

  

  const currentCF_FormCount = currentCF_Forms.length //+ 1
  const formCopyTarget = document.getElementById('cfield-form-list')
  const copyEmptyFormEl = document.getElementById('empty_form').cloneNode(true)
  //remove class hidden
  copyEmptyFormEl.setAttribute('class','cfield-form xrow')
  copyEmptyFormEl.setAttribute('id',`form-${currentCF_FormCount}`)
  const regex = new RegExp('__prefix__','g')
  copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex,currentCF_FormCount)
  totalNewForms.setAttribute('value', currentCF_FormCount +1)
  //now add new empty form element to our html form
  formCopyTarget.append(copyEmptyFormEl)

Upvotes: 0

Asher
Asher

Reputation: 697

I haven't personally had to do this, but from the docs it seems you have a few options.

  1. Call save on the formset instead of each form.

    if formset.is_valid():
        formset.save()
    
  2. If you must loop through each form you could something like this.

    if formset.is_valid():
       for form in formset:
           print(form.cleaned_data)
           if form.cleaned_data["DELETE"]:
               # Do what you want with the form data
               # i.e. get the object from the database and delete it.
           else:
               form.save()
    
  3. Loop through the deleted forms separately.

    if formset.is_valid():        
        forms = formset.save(commit=False)
        for object in formset.deleted_objects:
            object.delete()
    

Upvotes: 7

Related Questions