Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Quelle méthode utiliser pour faire une mise à jour à partir d'une sélection d'objet depuis une liste?

+2 votes

Je souhaite afficher une liste d'objets contenu dans ma table.

Pour chaque ligne de ma liste j'ai ajouté une checkbox pour pouvoir sélectionner la ligne dont je souhaite faire la mise à jour.

J'ai créé une fonction qui fait ça.
Voici le code.

Views.py

@login_required
def invoice_list_with_no_Piece_number(request):
   """
       Mise à jour des numéro de pièce comptable dans le module facturation
   """
   log_id = request.user.id
   invoice_list = Facture.objects.filter(user_id = log_id, piece_number = '').order_by('-    Payment_date')

   if not invoice_list:
      messages.info(request,"No update today!")

   if request.method == 'POST' and ('piece_number' in request.POST):
      mes_code = 0

      piece_number = request.POST['piece_number']

      # test de la validité du numéro de pièce saisie
      pattern = re.compile("[R](201[5-9]|202[0-9])\-(0[1-9]|1[0-2])\-[0-9]{3}")
      if  pattern.match(piece_number) is None and mes_code == 0:
          mes_code = 1
          messages.info(request,"Le numéro de pièce n\'est pas valide, "
                                "Saisissez un numéro de pièce valide (ex: R2015-11-017)")

      # test si la partie compteur n'est pas égale à zéro
      if piece_number[10:].isnumeric() and int(piece_number[10:]) == 0 and mes_code == 0:
         mes_code = 1
          messages.info(request,"Le numéro de pièce ne doit pas être nul")

      # test si numéro de pièce déjà utilisé
      if mes_code == 0:
          my_piece_number_owner = list(Facture.objects.filter(piece_number=piece_number))
          if my_piece_number_owner:
              mes_code = 1
              messages.info(request,"Ce numéro de pièce à déjà été utilisé")

      choices = request.POST.getlist('pnum_to_up')
      if (choices is None or choices == []) and mes_code == 0:
          mes_code = 1
          messages.info(request,"Aucune selection actuellement!")

      if mes_code == 0:
          for choice in choices:
              _pk = int(choice)
              Facture.objects.filter(pk=_pk).update(piece_number = piece_number, modification_date = timezone.now())
          messages.success(request,"Updated with success!")

  else:
      messages.info(request,"Saisissez un numéro de pièce valide (ex: R2015-11-017) ")

  return render_to_response('consult/list_pnum_invoice.html', { 'invoice_list': invoice_list},
                          context_instance=RequestContext(request))

list_pnum_invoice.html.html

{% block content %}
   <form action="{% url 'url_list_pnum_invoice' %}" method="POST">.
        {% csrf_token %}
   <fieldset>

    <div class="col-md-12" >
        {% if messages %}
            <ul class="messages">
            {% for message in messages %}
                <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
            {% endfor %}
            </ul>
        {% endif %}


        <legend>
            <span class="glyphicon glyphicon-question-sign"></span>
            {% trans "Facture sans numéro de pièce" %}
        </legend>

        <br>

        <span style="display: inline-block">
            <input type="checkbox" onClick="checkAll(this)" /> {% trans "Tout selectionner" %}<br/>
            <input type="text" class="text-left" name="piece_number" placeholder="RSSAA-MM-999"/>
            {% trans "indiquer le numéro de pièce" %}
        </span>

        <table class="table table-striped table-hover">
            <tr>
                <th>{% trans "Selection" %}</th>
                <th>{% trans "Nom du patient" %}</th>
                <th>{% trans "Date de la consultation" %}</th>
                <th>{% trans "Montant de la consultation" %}</th>
                <th>{% trans "Payé par" %}</th>
            </tr>
        {% for item in invoice_list %}
            <tr>
                <td><input type="checkbox" name="pnum_to_up" value= {{ item.pk}}></td>
                <td>{{ item.consultation.patient'] }}</td>
                <td>{{ item.consultation.consultation_date }}</td>
                <td class="amount">{{ item.fees }} €</td>
                <td>{{ item.Payment_method }}</td>
            </tr>
        {% endfor %}
        </table>

    </div>

    <input type="submit" value="Enregistrer la selection" >
   </fieldset>
</form>


<script type="text/javascript">
function checkAll(ele) {
     var checkboxes = document.getElementsByTagName('input');
     if (ele.checked) {
         for (var i = 0; i < checkboxes.length; i++) {
             if (checkboxes[i].type == 'checkbox') {
                 checkboxes[i].checked = true;
             }
         }
     } else {
         for (var i = 0; i < checkboxes.length; i++) {
             console.log(i)
             if (checkboxes[i].type == 'checkbox') {
                 checkboxes[i].checked = false;
             }
         }
     }
}
</script>



{% endblock %}

Est ce que mon approche est la bonne méthode?

Au départ j'ai souhaité afficher ma liste via LISTVIEW mais j'ai été bloqué pour l'update.
Est-il possible de faire de même avec la cbv LISTVIEW?

D'après la doc seule la méthode get () est proposée.
Il n'y a pas de méthode post (). c'est ce qui m'a freiné pour utiliser cette CBV.

Pourriez vous me conseiller ou critiquer mon approche afin que je m'améliore?

demandé 22-Jan-2016 par Victor (218 points)
edité 2-Fev-2016 par foxmask

hmm de quoi parles-tu donc? quelle techno utilises tu ? (perso au premier coup d'oeil je n'arrive pas à cerner de quoi tu parles en terme de techno, et sauter des lignes ça ne fait pas de mal ;p )

sans un bout de code , c'est du charabia là

encore un qui "vote contre" sans se justifier...

@bobilinux ; tu aurais dû commenter, parce que tu réponds pas à rien là, peut-etre la raison du downvote

@foxmask

C'est juste un fail, je voulais mettre en com's et me rends compte que c'est une réponse :o (je viens de régler ça)

@Victor : merci pour les sauts de ligne, les yeux piquent moins tout d'un coup..

J'ai modifié ma requête. C'est effectivement plus parlant maintenant.

Si le but est de sélectionner une entrée à modifier, une ancré suffit au lieu d'une checkbox. Si le but est de faire une modification groupée alors OK pour la checkbox

2 Réponses

+2 votes

Si le but est de sélectionner une entrée à modifier, une ancre suffit au lieu d'une checkbox. Du coup une simple ListView fait l'affaire, ce qui donne

dans views.py :

class MaListView(ListView):
        model = MoModel

puis faire un template dans templates/monappli/malistview_list.html

Mais j'ai l'impression que ce dont vous avez besoin en regardant le dernier bout de votre template c'est une CBV UpdateView avec un inlineformset_factory

ca s'utilise alors comme ceci :

models.py

1) on a 2 modèles liés par une FK
2) on defini le formset_factory qui permettra d'avoir dans son formulaire, une liste de champs à remplir (un sous formulaire)

Exemple :

2 modeles Env et Database

# Form that displays one environment and
# its database definition
EnvDatabaseFormSet = inlineformset_factory(Env,
                       Database,
                       fields=('server_name',
                           'listen_port',
                           'oracle_sid'),
                       extra=2)

fields() contient les champs que je veux utiliser dans le "sous" formulaire.
extra contient le nombre de lignes vide que j'affiche dans mon sous formulaire

3) views.py

class EnvUpdate(UpdateView):
    model = Env
    form_class = EnvForm
    template_name = 'env_form.html'

    def get_context_data(self, **kwargs):
        context = super(EnvUpdate, self).get_context_data(**kwargs)
        if self.request.POST:
            context['env_db_form'] = EnvDatabaseFormSet(self.request.POST,
                            prefix='database')
        else:
            context['env_db_form'] = EnvDatabaseFormSet(instance=self.object,
                            prefix='database')
        return context      

4) le template env_form.html

je passe sur l'affichage du simple formulaire "environnement" pour montrer la partie sur laquelle on itere pour obtenir le sous formulaires "database"

    <div role="tabpanel" class="tab-pane fade" id="database">
        <div class="panel panel-default">
        {{ env_db_form.management_form }}
        <table class="table table-striped table-hover">
        <tr>
            <th>Serveur</th>
            <th>ORACLE SID</th>
            <th>Port</th>
        </tr>
        {% for form in env_db_form %}
        <tr>
            <td>{{ form.id }}
                <div class="input-group{% if form.server_name.errors %} has-error{% endif %}">
                    {{ form.server_name }}
                    {% if form.server_name.errors %}
                    <div class="alert alert-danger" role="alert">{{ form.server_name.errors }}</div>
                    {% endif %}
                </div>
            </td>
            <td>
                <div class="input-group{% if form.oracle_sid.errors %} has-error{% endif %}">
                    {{ form.oracle_sid }}
                    {% if form.oracle_sid.errors %}
                    <div class="alert alert-danger" role="alert">{{ form.oracle_sid.errors }}</div>
                    {% endif %}
                </div>
            </td>
            <td>
                <div class="input-group{% if form.listen_port.errors %} has-error{% endif %}">
                    {{ form.listen_port }}
                    {% if form.listen_port.errors %}
                    <div class="alert alert-danger" role="alert">{{ form.listen_port.errors }}</div>
                    {% endif %}
                </div>
            </td>
        </tr>
        {% endfor %}
        </table>
        </div>
    </div>

ici on retrouve env_db_form passé au context via get_context_datapar EnvDatabaseFormSet

Ensuite ce qui se passera lorsque l'utilisateur va enregistrer le formulaire :
Django enregistre les données à destination des modeles "env" et "database"
Dans l'état actuel on ne se préoccupe pas de déterminer ce qui a été changé, on enregistre tout LE formulaire.

Voilà, j'espere que ca eclairera un peu mieux les possibilités du framework

répondu 2-Fev-2016 par foxmask (2,880 points)

Merci pour cette réponse détaillée! Elle me servira pour la suite

+1 vote

Bien que la réponse de Foxmask soit la plus générique, elle fait appelle à une connaissance avancée des CBV et des formsets. Dans ton cas, un approche manuelle comme tu l'as faite a plusieurs avantages:

  • facile à coder;
  • facile à debug;
  • facile à comprendre;
  • on peut y revenir plus tard ou mettre un autre dev dessus sans froncer les sourcils.

Donc oui, ta vue n'est pas générique, mais j'ai envie de dire on s'en bat les steak, elle fait le job.

répondu 3-Fev-2016 par Sam (4,984 points)
...