0

Sur l'une de mes pages Web Django, j'affiche une icône pour chaque instance d'un modèle particulier (Meeting) dans la base de données (une icône par instance du modèle).Django formulaire __init__ méthode semble être appelée deux fois

Lorsque l'utilisateur clique sur l'une des icônes, un formulaire est affiché ailleurs sur la page pour permettre à l'utilisateur d'entrer des détails sur cette instance particulière du modèle. Une fois qu'ils ont entré tous les détails pour les champs de champs sur le formulaire, ils peuvent appuyer sur un bouton «Télécharger» pour télécharger les informations entrées dans la base de données (et enregistrer les informations à cette instance du modèle).

Lorsque le formulaire est soumis, la page est actualisée, affichant une icône pour chaque instance d'un modèle particulier. Si l'utilisateur clique sur une icône existante et modifie un des champs de son formulaire, puis clique sur "Télécharger", une nouvelle instance de ce modèle est créée avec le formulaire rempli avec ces champs modifiés.

Chaque clic sur le bouton 'Télécharger' devrait créer une instance supplémentaire du modèle Meeting dans la base de données. Chacun des champs du formulaire représente l'un des attributs du modèle Meeting.

J'ai deux boutons sur le formulaire, pour attacher des fichiers image à l'instance du Meeting, l'un d'entre eux fonctionne actuellement- lorsque je l'utilise pour joindre une image, et cliquez sur 'Télécharger', la page est actualisée, et l'image est affichée attachée au formulaire pour cette instance du modèle. Cependant, lorsque je clique sur "Télécharger" après avoir attaché une image à l'aide de l'autre bouton, la page est actualisée et plusieurs instances supplémentaires du modèle Meeting sont affichées sur la page Web, avec tous les champs de leurs formulaires laissés en blanc , et aucun fichier image joint (bien que l'un soit également créé avec tous les champs enregistrés comme saisis, et avec le fichier image joint). En essayant de comprendre pourquoi plus d'une instance de l'objet Meeting est créée lors du téléchargement d'une image via ce bouton particulier, j'ai ajouté un peu de débogage à mon code, en particulier, au formulaire que j'utilise pour télécharger ces informations & ces images à la base de données:

class BudgetPresentationForm(ValidatedForm): 
    """ Provides the form for the formset BudgetPresentationFormset """ 
    presentation_minutes = EasyText(field_class="medium", label='Client presentation notes') 
    presentation_date = MoonDateTimeField(required=False, widget=forms.DateTimeInput(format='%d/%m/%Y %H:%M', attrs=({'class':'datetimepicker presentation_date', 'name':'presentation_date2'}))) 
    presenter1 = forms.CharField() 
    presenter2 = forms.CharField() 
    presenter3 = forms.CharField() 
    presenter4 = forms.CharField() 

    class Meta: 
     model = Budget 
     fields = ('presentation_minutes', 'presenter1', 'presenter2', 'presenter3', 'presenter4', 'presentation_date', 'pdf_package_dep') 

    def __init__(self, *args, **kwargs): 
     self.instance = kwargs.get('instance', {}) 
     budget = self.instance 

     if hasattr(budget, 'id'): 
      self.presenters = budget.presenters.all() 

      if budget.presentation_date: 
       print("Budget meeting: ", budget.meeting) 
       pres_meeting = budget.meeting or Meeting.objects.create(project=budget.project, purpose='7') 
       print("Meeting created in projects/forms.py BudgetPresentationForm (line 1055): ", pres_meeting) 
       self.pres_meeting_id = pres_meeting.id 
       self.pres_meeting_creator = pres_meeting.event_creator or '' 
       if not budget.meeting: 
        budget.meeting = pres_meeting 
        budget.save() 
       if not budget.meeting or not pres_meeting.date: 
        pres_meeting.date = budget.presentation_date 
        pres_meeting.save() 
       print("Meeting object is: ", pres_meeting.id) 
       #print("Process ID: ", os.getpid()) 
     else: self.presenters = [] 

     super(BudgetPresentationForm, self).__init__(*args, **kwargs) 
     # if hasattr(self, 'pres_meeting_id'): self.fields['presentation_date'].widget.attrs['data-meeting-id'] = self.pres_meeting_id 
     self.fields['presentation_date'].widget.attrs.update({'data-meeting-id': getattr(self,'pres_meeting_id', ''), 'data-meeting-creator': getattr(self,'pres_meeting_creator', '')}) 

     initial_presenters = [(e.id, e.full_name) for e in self.presenters]+[None, None, None, None]#[(None, ''), (None, ''), (None, ''), (None, '')] # Always at least four so that first four can populate form fields 
     if initial_presenters[0]: self.fields['presenter1'] = FlexiSelect(initial=[initial_presenters[0]], current_id='', url_code='ee', choices=[], required=False, instant='', class_name="autocomplete", label='Who is presenting') 
     else: self.fields['presenter1'] = FlexiSelect(initial=[(None, '')], current_id='*', url_code='ee', choices=[], required=False, instant=' instant', class_name="autocomplete", label='Who is presenting') 
     if initial_presenters[1]: self.fields['presenter2'] = FlexiSelect(initial=[initial_presenters[1]], current_id='', url_code='ee', choices=[], required=False, instant='', class_name="autocomplete", label='') 
     else: self.fields['presenter2'] = FlexiSelect(initial=[(None, '')], current_id='*', url_code='ee', choices=[], required=False, instant=' instant', class_name="autocomplete", label='') 
     if initial_presenters[2]: self.fields['presenter3'] = FlexiSelect(initial=[initial_presenters[2]], current_id='', url_code='ee', choices=[], required=False, instant='', class_name="autocomplete", label='') 
     else: self.fields['presenter3'] = FlexiSelect(initial=[(None, '')], current_id='*', url_code='ee', choices=[], required=False, instant=' instant', class_name="autocomplete", label='') 
     if initial_presenters[3]: self.fields['presenter4'] = FlexiSelect(initial=[initial_presenters[3]], current_id='', url_code='ee', choices=[], required=False, instant='', class_name="autocomplete", label='') 
     else: self.fields['presenter4'] = FlexiSelect(initial=[(None, '')], current_id='*', url_code='ee', choices=[], required=False, instant=' instant', class_name="autocomplete", label='') 

BudgetPresentationFormset = inlineformset_factory(Project, Budget, form=BudgetPresentationForm, max_num=30, extra=1, can_delete=False) 

Mais quand je clique sur le bouton « Soumettre » pour ce formulaire, après avoir entré les informations dans tous les champs, et attaché les fichiers d'image à la forme, ma console montre que le code à l'intérieur:

if budget.presentation_date: 

est exécuté deux fois ... c'est-à-dire que j'obtiens la même sortie dupliquée dans la console avec ce qui devrait être une seule exécution de ce code (c.-à-d. quand il est exécuté lors du rechargement de la page Web, suite à la soumission du formulaire).

Les spectacles de sortie de la console:

('séance Budget:',)

('Réunion créé dans les projets/forms.py BudgetPresentationForm (ligne 1055):',)

('objet de la réunion est:', 11012L)

('séance budget:',)

('réunion créée en projec ts/formes.py BudgetPresentationForm (ligne 1055): »,)

('objet de la réunion est:', 11078L)

Ayant Google'd pourquoi cela peut se produire, il semble que cela pourrait être que le code est étant exécuté par deux threads séparés, et c'est pourquoi il est exécuté deux fois ...

Est-ce le cas? Pourquoi cela se passe-t-il si oui? Comment puis-je m'assurer que le code n'est exécuté qu'une seule fois et que je ne me retrouve pas avec des informations en double dans ma base de données?

Je n'ai pas travaillé avec des fils bien avant, alors je ne suis pas vraiment sûr de savoir comment/quoi faire à ce sujet ....

Modifier

Comme demandé dans le commentaire & la réponse- endroits où je me sers du formset sont- dans le view pour concept (qui est la page sur laquelle j'affichons ces présentations & le formulaire pour saisir les détails pour un Meeting):

def concept(request, project_id): 
    project = Project.objects.prefetch_related('budget_versions').get(id=project_id) 
    deposit = Deposit.objects.get_or_create(project=project)[0] 
    presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn') 
    end_details = EndDetails.objects.get_or_create(project=project)[0] 
    presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations) 
    drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created')) 

    context = { 
     'project': project, 
     'presentations': presentations, 
     'presentation_formset': presentation_formset, 
     'drawing_formset': drawing_formset, 
     'deposit_form': DepositInfoForm(instance=deposit), 
     'ended_form': EndDetailsForm(instance=end_details), 
     'budget_notes_form': BudgetNotesForm(instance=project.budget_overview), 
    } 

    return render(request, 'projects/concept.html', context) 

et dans le upload_budget_pdfs(request, project_id):view, (qui est le view utilisé pour essayer de télécharger les fichiers PDF au format (c.-à-d. ce que je me sers pour « attacher » un fichier PDF à la forme):

def upload_budget_pdfs(request, project_id): 
    project = Project.objects.get(id=project_id) 
    print("Value of project in 'upload_budget_pdfs()': ", project) 

    if request.method == 'POST': 

    presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn') 
    print("Value of presentations in 'upload_budget_pdfs()': ", presentations) 
    drawing_formset = DrawingUploadFormset(request.POST, request.FILES, prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created')) 

    if drawing_formset: 
     print "Before", [b.id for b in project.budget_versions.all()]   
     try: 
      for drawing_form in drawing_formset: #ERF(24/01/2017 @ 1610) This line is what's causing the MultiValueDictKeyError 
       print 'drawing for loop entered in upload_budget_pdfs() - line 1034 ' 
       if drawing_form.instance.budget: 
        print 'if statement entered - line 1036 ' 
        print 'Instance: ', drawing_form.instance.budget 
        drawing = drawing_form.save(commit=False) 
        drawing.budget = drawing_form.instance.budget 
        drawing.save() 
       print drawing, [b.id for b in project.budget_versions.all()] 
     except Exception as e: 
      print '%s (%s)' % (e.message, type(e)) 
    else: 
     print("Drawing formset not valid. ", drawing_formset.errors) 

    budget_formset = BudgetPresentationFormset(request.POST, request.FILES, instance=project, prefix="presentations") 

    if budget_formset: 
     try: 
      # Add a boolean so that budget is only added to form once 
      budgetSaved = False 
      for budget_form in budget_formset: 

       if budget_form: 
        if budgetSaved == False: 
         print 'if statement entered - line 1081 ' 

         budget = budget_form.save(commit=False) 

         budget.save() 
         budgetSaved = True 

     except Exception as e: 
      print '%s (%s)' % (e.message, type(e)) 
    else: 
     print("Budget formset not valid. ", budget_formset.errors) 

    return HttpResponseRedirect(reverse('projects:concept', args=[project_id])) 
+1

Non, une demande est desservie par un seul fil. Sûrement parce que vous avez un formset contenant plusieurs formes? –

+0

Ok - Oui, j'ai un formset contenant plusieurs formulaires - il y aura un formulaire pour chaque présentation affichée sur la page (c'est-à-dire un formulaire pour chaque objet 'Meeting'). Le formulaire n'est affiché sur la page que lorsque l'utilisateur clique sur le bouton 'Modifier' pour une présentation donnée ... Mais pour le moment, deux 'présentations' supplémentaires (représentatives de l'objet 'Meeting') sont affichées sur la page web chaque fois que je clique sur le bouton 'Télécharger' pour télécharger une image 'Budget' à la 'Réunion' ... des idées pourquoi? – someone2088

+0

Vous avez probablement besoin d'afficher la vue. –

Répondre

0

En ce qui signifie formset vous avez une forme qui sera répétée pour un ensemble d'éléments. Vous devez montrer le code où/comment vous utilisez ce formset. C'est peut-être là que réside le point d'origine du problème.

Link to Django Formsets

+0

Le formset est défini dans forms.py, juste en dessous de la définition du formulaire, comme indiqué dans mon OP: 'BudgetPresentationFormset = inlineformset_factory (Projet, Budget, form = BudgetPresentationForm, max_num = 30, extra = 1, can_delete = False)' . J'ai ajouté le 'views' où j'utilise le formulaire et formset à mon OP aussi. – someone2088