0

I'm trying to create an editable bootstrap table where each cell represents a json value. I've defined a Django Model with this JSONField (not the Postgres's one) This is my Model:

class Extracted_Tables(models.Model):
...
content = JSONField(blank=True, null=True)

My Template

<tbody>
            {% for form in formset.forms %}
                <tr>
                    {% for field in form %}
                        {% if field.is_hidden %}
                        <input type="hidden" >{{ field }}</input>
                        {% else %}
                            {% for k,v in field.value.items %}
                                <td>{{v}}</td>
                            {% endfor %}
                        {% endif %}
                    {% endfor %}
                </tr>
            {% endfor %}
        </tbody>

This template renders the following HTML

<tr>
<td>Jamaica</td>
<td>Kingston</td>
<td>North America</td>
<td>11424</td>
<td>2500000</td>
<input type="hidden"><input type="hidden" name="formset_1-0-id" value="353" id="id_formset_1-0-id">
</tr>

To have a better idea on why it's not working: I've used a Django Model where my cells were this model's attributes. I had no problem editing the cells in this case as I was editing the model's fields This time, my cells are not the model's fields themselves: the only model field I have is a JSONField and I'm trying to edit the cells that are that json's values.

Model:

class Extracted_Variables(models.Model):
    variables = models.CharField(max_length=500)
    values = models.CharField(max_length=500)

The Template:

    <tbody>

        {% for form in formset.forms %}
            <tr>
                {% for field in form %}
                    {% if field.is_hidden %}
                    <input type="hidden" >{{ field }}</input>
                    {% else %}
                    <td>{{ field }}</td>
                    {% endif %}
                {% endfor %}
            </tr>
        {% endfor %}
    </tbody>

The rendered template:

<tr>
<td><input type="text" name="form2-0-variables" value="variable 1" maxlength="500" class="form-control" id="id_form2-0-variables"></td>
<td><input type="text" name="form2-0-values" value="whatever" maxlength="500" class="form-control" id="id_form2-0-values"></td>
<input type="hidden"><input type="hidden" name="form2-0-id" value="1" id="id_form2-0-id">
</tr>

We see that the form was created by adding Ids and specific attributes based on the model fields whereas none of the that happened when I displayed the JSONField's values.

Should I try to create those fields manually while creating the form in the Template? Or what approach should I have here ?

1 Answers1

1

I finally found a way to make the update possible.

This is my View:

if formset.is_valid():
        answer = request.POST
        #'answer' est la liste des clées récupérées depuis le post. Elles contiennent 4 elements au début dont on a pas besoin
        # et un dernier element "submit" dont on a pas besoin non plus. On retirant tout ces elements, il ne reste que les élements
        # des objets postés qu'on veur récupérer pour faire l'update. Je l'ai appelé 'keys'
        keys = list(answer.keys())[5:-1]
        d = {} # dictionary to hold 'content' for each new Extracted_Variable to update
        list_new_content = []
        list_ids = []
        for idx,k in enumerate(keys): # idx commence de 0
            # print("k: {} v: {}".format(k,v)) retourne ce résultat: (exemple)
            # k: formset_1-0-content__Name v: Argentina babe
            # k: formset_1-0-content__Capital v: Buenos Aires
            # k: formset_1-0-content__Country List Continent v: South America
            # k: formset_1-0-content__Area v: 2777815
            # k: formset_1-0-content__Population v: 32300003
            # k: formset_1-0-id v: 610
            # 1er element : Name, 2ème element: Capital ... et 6ème et dernier element l'id. 
            # len(keys) : c'est le nombre de clées totales récupérées.
            # len(objects.object_list) : c'est le nombre d'objets affichées sur la page. Notes bien que même si on affiche 10 objets
            # par page et que par exemple on n'a que 19 elements, sur la 2ème page, on n'a que 9 élements. Donc len(objects.object_list)
            # nous retourne le nombre exact d'objets sur la page
            # pour un objet Extracted_Variable donnée, son attribut 'content' contient un certain nombre de clées
            # Pour connaitre ce nombre de clées, on divise le nombre de clées présentes sur la page, sur le nombre d'objets figurant
            # sur cette page. Si par exemple 10 elements sont affichées sur la page, on a 60 keys en tout. Cette division nous donnerait
            # donc 6. 6 est constituée de 5 premiers elements qui sont ce qui compose son attribut 'content' et le dernier element
            # est celui de l'id

            v = answer[k]
            indicator = (idx+1) % (len(keys) / len(objects.object_list)) # if idx+1/(60/10)==0 c'est que c'est le 6ème element: id 
                # De même, 1er element (Name) sera distinguée par == 1

            if k.rpartition('__')[0]!= '':
                d[k.rpartition('__')[2]] = v


            if (idx+1) % (len(keys) / len(objects.object_list)) == 0: # 6th element. if idx+1/(60/10)==0 c'est que c'est le 6ème element: 
                # id . De même, 1er element (Name) sera distinguée par == 1

                list_ids.append(v)

                list_new_content.append(d.copy())


        for current_id, new_content in zip(list_ids,list_new_content):
            # print("current_id: {} \t content: {}".format(current_id, new_content))
            obj = Extracted_Tables.objects.get(pk=current_id)
            if obj.content != new_content:
                obj.content = new_content
                obj.save()
        formset = Extracted_TablesFormSet(queryset=page_query,prefix='formset_1')

And I modified my Template to:

       <tbody>
            {% for form in formset.forms %}
                <tr>
                    {% for field in form %}
                        {% if field.is_hidden %}
                        <input type="hidden" >{{ field }}</input>
                        {% else %}
                            {% for k,v in field.value.items %}
                            <td>
                                <input type="text" name="formset_1-{{ forloop.parentloop.parentloop.counter0 }}-content__{{ k }}" value="{{ v }}" maxlength="500" class="form-control" id="formset_1-{{ forloop.parentloop.parentloop.counter0 }}-content__{{ k }}">
                            </td>

                            {% endfor %}
                        {% endif %}
                    {% endfor %}
                </tr>
            {% endfor %}
       </tbody>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459