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.

Django - problème implémentation de formset

+2 votes

J galère grave sur l'implémentation d'un formset...

Au départ je renseigne un template patient, banal.Je récupère son id et je le balance bien dans le model consultation pour le lien entre les deux tables.
Ensuite j'enchaine sur un template consultation, un peu comme Django Jeu, FormSet et match issu de "My glucose manager"

Ce template consultation se découpe en deux donc.
en 1er la consultation
en 2eme mon fameux formset ou je dois choisir dans mon dico des actes ceux pratiqués par le médecin pendant la consultation.

Pour le moment j'affiche bien mon template consultation et mes formsets.
Je me suis borné à deux formset.
Lors de la validation j'attends:
1- La création de mon record consultation --> ça c'est ok!
2- La création de deux actes, suivants mes selections --> not ok!!!!!
Je ne sais pas enregistrer dans ma BDD acte_viste parce que mon formset n'est pas valide... car p_ss, p_s2 et coef sont obligatoires.

En fait de mes selections je dois en extraire les prix... donc les champs obligatoires.
Le problème est que je ne sais pas "assigner" les prix extrait dans les champs correspondant de acte_visite.

Je ne sais pas assigner p_ss et p_s2.
Pour coef, ce champ est calculé en suivant une fonction qui pour l'heure n'est pas le problème.

Ci dessous, mon code.
Si besoin n'hésitez pas à me demander des compléments!

models.py

class Dict_acte(CommonInfo):
    over_specialize = models.ForeignKey(Surspe)
    treatname = models.CharField(max_length=255, verbose_name="Nom de l'acte")
    treatcode = models.CharField(max_length=10, verbose_name="code CCAM")
    p_base_ss = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="Tarif S.Sociale")
    p_secteur2 = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="Tarif secteur 2")

    def __str__(self):
        return "%s %s, base SS: %s €, secteur 2: %s €" %(self.over_specialize, self.treatname, self.p_base_ss, self.p_secteur2)

class Consultation(CommonInfo):
    patient = models.ForeignKey(Patient)
    consultation_date = models.DateField(null=True, blank=True, verbose_name="Date de la visite")
    médecin_demandeur = models.ForeignKey(Medecin)
    #
    nbr_of_treat = models.IntegerField(verbose_name="nbr actes", default = 0)
    motive = models.CharField(max_length=255, blank=True, verbose_name="motif de la visite")
    new_rdv = models.BooleanField(default= False, verbose_name="Nouvelle consultation prévue")
    feuille_soin_délivrée = models.BooleanField(default=True)

    def __str__(self):
        return "%s en consultation le    pour %s" % (self.patient, self.motive)


class Acte_visite(CommonInfo):
     consultation = models.ForeignKey(Consultation)
    acte = models.ForeignKey(Dict_acte)
    p_ss = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="Tarif S.Sociale")
    p_s2 = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="Tarif secteur 2")
    coef = models.DecimalField(max_digits=3, decimal_places=2, verbose_name="Coefficient", default= 1)

    def __str__(self):
        return "acte: %s , tar SS: %s, tar S2: %s" % (self.acte, self.p_ss, self.p_s2)

forms.py

class ConsultationForm(forms.ModelForm):

    class Meta:
    model = Consultation
    fields = ( 'consultation_date', 'médecin_demandeur', 'motive', 'feuille_soin_délivrée',
    'new_rdv')


class ActevisiteForm(forms.ModelForm):

    class Meta:
    model = Acte_visite
    fields = ('acte', )

voici mon formset

ActevisiteFormSet = inlineformset_factory(Consultation, Acte_visite, extra= 2)

views.py

class ConsultCreateView(CreateView):
    model = Consultation

    template_name = 'consult/consultation.html'
    form_class = ConsultationForm

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
    return super(ConsultCreateView, self).dispatch(*args, **kwargs)

    queryset = Patient.objects.all()

    def get_object(self):
    # Call the superclass
    #objet
    id_patient = super(ConsultCreateView, self).get_object()
    # Return the object
    return id_patient  #objet

    def form_valid(self, form):
    formset = ActevisiteFormSet((self.request.POST or None), instance=self.object)
    visite = form.save(commit=False)
    if form.is_valid():
        print("validation de la consultation")
        visite.user = self.request.user

        # je récupère patient_id pour le lien avec le record de consultation
        visite.patient = self.get_object()
        visite.save()

    for fs in formset:
        # je récupère ma selection issue du dictionnaire d'acte (Dict_acte)
        dictacte = fs.cleaned_data['acte']

        # j'extrais mes données, prix_ss et prix_secteur_2
        prices = get_price_acte(dictacte.id)

        # une fois que j'ai extrais mes prix je dois les injecter dans les champs correspondant
        # avant que je ne sauve dans ma BDD acte_visite avec le lien consultation_id
        --> je dois renseigner fs["p_ss"] = prices[0]
        --> je dois renseigner fs["p_s2"] = prices[1]
        --> je dois renseigner fs["coef"] = fct(du nb extra)

        if  fs.is_valid():
                    print("validation des actes selectionnés")
                    self.object = form.save(user=self.request.user)
                    fs.instance = self.object
                    fs.save()
        else:
        print("erreur:",fs.errors)

    return HttpResponseRedirect(reverse('home'))

    def get_context_data(self, **kw):

    context = super(ConsultCreateView, self).get_context_data(**kw)
    context['action'] = 'add_visite'

    if self.request.POST:
        print("request.POST OK")
        context['actedetails_form'] = ActevisiteFormSet(self.request.POST)
    else:
        print("request.POST Not OK")
        context['actedetails_form'] = ActevisiteFormSet(instance=self.object)
    return context

    def get_price_acte(id):
    record_acte = Dict_acte.objects.get(pk = id)
    return  [record_acte.p_base_ss, record_acte.p_secteur2]
demandé 4-Avr-2015 par Victor (218 points)
edité 8-Avr-2015 par Sam

Il manque le modèle ActeVisite.
Pour tout ce qui est calcul ça doit se passer dans la fonction save du ModelForm concerne

Hello victor. Bienvenu. J'ai retiré une parti du texte (formules de politesses) car on ne les utilises pas sur ce site, ça va plus vite. Je vais aussi bouger ta réponse dans la zone commentaire, car là tu es dans la zone pour répondre à ta propre question.

Merci pour ce commentaire qui m'as bien fait avancer!
Le modèle Acté _ visite est bien là à moins que j'ai oublié quelque chose.
Ma class CommonInfo fait référence notamment au champ user (fk de User).

Mon souci est qu'à la validation,
Mon form est sauvegardé (consultation) mais je n'arrive pas à renseigner "user" de mon formset et du coup formset. Save () plante avec user.id inconnu, bien que je le renseigne. Si je ne m'en sort pas je mettrai plus de détail.
Je donnerai plus de detail

Il y a trop de problèmes distincts. Il faudrait les prendre un à un. Là on va perdre du temps à stabiliser un bout puis un autre... Reprend du début un seul problème ;)

1 Réponse

+3 votes
 
Meilleure réponse

J'ai réussit enfin à implémenté ce formset!
Merci pour vos conseils qui m'ont vraiment bien aidé!
Pour ceux que ça pourrait intéresser voici mon code. Surtout, et je suis sur que c'est possible, n'hésitez pas à me faire remonter des commentaires pour simplifier le code.

forms.py

class SelectActevisiteForm(forms.ModelForm):

    class Meta:
        model = Acte_visite
        fields = ('acte', )
        exclude = ('user','consultation')

    def __init__(self, *args, **kwargs):
        super(SelectActevisiteForm, self).__init__(*args, **kwargs)

    def save(self, commit=True,user=None):
        instance = super(SelectActevisiteForm,self).save(commit=False)
        choice_acte = self.cleaned_data.get('acte')
        instance.p_s2 = choice_acte.p_secteur2
        instance.p_ss = choice_acte.p_base_ss
        instance.user = user
        if  commit:
            instance.save()
        return instance

Mon formset
ActevisiteFormSet = inlineformsetfactory(Consultation, Actevisite, form=SelectActevisiteForm,
fk_name="consultation", extra= 2)

Views.py

class ConsultCreateView(CreateView):
    model = Consultation
    template_name = 'consult/consultation.html'
    form_class = ConsultationForm

    @method_decorator(login_required)
    def dispatch(self,*args, **kwargs):
        return super(ConsultCreateView, self).dispatch(*args, **kwargs)

    queryset = Patient.objects.all()
    def get_object(self):
        id_patient = super(ConsultCreateView, self).get_object()
        return id_patient

    def form_valid(self, form):
        visite = form.save(commit=False)

        if form.is_valid():
            visite.patient = self.get_object()
            visite.user = self.request.user
            visite.save()
            formset = ActevisiteFormSet((self.request.POST or None), instance=visite)
            if  formset.is_valid():
                for fs in formset:
                    fs.save(user=self.request.user)
            else:
                print("erreur:",formset.errors)

        return HttpResponseRedirect(reverse('home'))

    def get_context_data(self, **kw):
        data = Consultation.objects.all()

        context = super(ConsultCreateView, self).get_context_data(**kw)
        context['action'] = 'add_visite'
        context['data'] = data
        if self.request.POST:
            print("request.POST OK")
            context['actedetails_form'] = ActevisiteFormSet(self.request.POST)
        else:
            print("request.POST Not OK")
            context['actedetails_form'] = ActevisiteFormSet(instance=self.object)
        return context
répondu 11-Avr-2015 par Victor
sélectionné 12-Avr-2015 par Sam

Si c'est la solution il reste a valider la réponse pour que tout le monde sache que la question est résolue

Je valide ta réponse.

Merci d'avoir pris le temps de l'a poster.

...