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]))
Non, une demande est desservie par un seul fil. Sûrement parce que vous avez un formset contenant plusieurs formes? –
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
Vous avez probablement besoin d'afficher la vue. –