custom template form fields django - django

i tried to use my own template style instead of default django form style , it work fine for creating post but doesnt work for update my formsets (inlineformset) , it also work if i use default django form style
this my views.py
class TitleQuestionAnswer(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
model = Title
form_class = TitleForm
template_name = 'template/update_title_question.html'
def get_context_data(self,*args,**kwargs):
context = super(TitleQuestionAnswer,self).get_context_data(*args,**kwargs)
if self.request.POST:
context['questions'] = QA_InlineFormset(self.request.POST,instance=self.object)
else:
context['questions'] = QA_InlineFormset(instance=self.object)
return context
def form_valid(self,form):
context = self.get_context_data()
context = context['questions']
self.object = form.save()
if context.is_valid() and context.cleaned_data !={}:
response = super().form_valid(form)
context.instance = self.object
context.save()
return response
print('errors : ',context.errors, 'data : ',context.cleaned_data)#updated
return super().form_invalid(form)
def get_success_url(self):
return reverse_lazy('q-answer:post',kwargs={'pk':self.object.pk})
and this is my template
<form method="POST">{% csrf_token %}
<div class="col-6 inp text-center">
{{form.name | add_class:'col-12 text-center'}}
{% if form.name.errors %}
<div class="error col-3 mx-auto">{{form.name.errors}}</div>
{% endif %}
</div>
</div>
<!-- order -->
<div class="col-12 p-0 border-top border-light ">
<table class="customeTable col-12 table-responsive-sm info text-center table1 mx-auto mb-2 ">
<tbody class="tbody tb1 " id="form_set">
{{questions.management_form}}
{% for form in questions.forms %}
{{form.errors}} <!--updated-->
{{questions.errors}}
{{questions.non_form_errors}}
{{form.id}}
<tr class="p-0 col-12">
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{form.field_a | add_class:'col-12'}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{form.field_b | add_class:'col-12'}}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</form>
but if i change it to only {{questions.management_form}} {% for form in questions.forms %} {{form}}{%
endfor %}
this style works fone for my CreateView !
it will work fine !? is there something i missed ? or should i add or remove something in my code ?
i appreciate your helps ..

Related

HTMX form submission produces a duplicate form

{% extends "IntakeApp/base3.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block heading %}
<h2>Allergies for {{request.session.report_claimant}}</h2>
{% endblock %}
{% block content %}
<form hx-post="{% url 'allergy' %}" hx-target="#allergy_target" hx-swap="outerHTML">{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-2 mb-0">
{{ form.allergen|as_crispy_field }}
</div>
</div>
<button type="submit" class="btn btn-primary">Add</button>
</form>
<div class="container-fluid">
<table class="table table-striped table-sm" id="med-table">
<thead>
<tr>
<th>Allergen</th>
</tr>
</thead>
<tbody id="allergy_target">
{% for allergy in allergy_list %}
<tr>
<td>{{allergy.allergen}}</td>
<td>
<form method="POST" action="{% url 'allergy-delete' allergy.id %}">{% csrf_token %}
<input class="btn btn-danger btn-sm" type="submit" value="Delete">
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
class AllergyCreateView(generic.CreateView):
model = Allergy
template_name = 'IntakeApp/allergy_form.html'
form_class = AllergyForm
def form_valid(self, form):
form.instance.assessment = Assessment.objects.get(id=self.request.session['assessment_id'])
return super(AllergyCreateView, self).form_valid(form)
def get_success_url(self):
return reverse_lazy("allergy")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
assessment_id = self.request.session['assessment_id']
allergy_list = Allergy.objects.filter(assessment=assessment_id)
context["allergy_list"] = allergy_list
return context
I tried to all the different hx-swap options, but none fix it...It does post correctly and the swap does work, just not sure why I am getting another form in there. Please help
I added the View above. I think thats were my issue is...not sure if I am supposed to be doing this way or not?
Seems like you're trying to render the same html content in your view, which instead should only take a specific element.
You can try to use hx-select="#allergy_target" so htmx will only fetch the table content.

Django: Certain users get random 404 error

I'm facing a strange issue that I can't handle on my own.
In normal cases when users click on a link, then they are directed to a page where they can edit their hook baits (objects). However, certain users get 404 errors, but I don't know why because the page is rendered for most users.
html where the link is
<div class="row justify-content-center mx-2" >
<div class="col-12 p-0">
<ul class="list-group text-center custom-borders m-2 p-0">
{% if own_hookbaits.count == 0 %}
<a href="{% url 'user_profile:hookbaits' request.user.fisherman.fisherman_id %}" class="list-group-item" >No hook baits yet</a>
{% else %}
{% for hookbait in own_hookbaits %}
{{ hookbait.name }}
{% endfor %}
{% endif %}
</ul>
</div>
views.py
class HookBaitUpdateView(UpdateView):
model = HookBait
template_name = "user_profile/hookbaits.html"
form_class = HookBaitForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['formset'] = HookBaitFormset(queryset=HookBait.objects.filter(fisherman=self.request.user.fisherman))
return context
def post(self, request, *args, **kwargs):
formset = HookBaitFormset(request.POST)
if formset.is_valid():
return self.form_valid(formset)
else:
return self.form_invalid(formset)
def form_valid(self, formset):
instances = formset.save(commit=False)
for instance in instances:
instance.fisherman = self.request.user.fisherman
instance.save()
return super().form_valid(formset)
def form_invalid(self, formset):
return HttpResponse("Invalid")
def get_success_url(self):
return reverse('user_profile:profile', args=(self.kwargs['pk'],))
urls.py
app_name = "user_profile"
urlpatterns = [
path("profile/<int:pk>/", views.ProfileView.as_view(), name="profile"),
path("profile/<int:pk>/hookbaits/", views.HookBaitUpdateView.as_view(), name="hookbaits"),
]
rendered html
<div class="row justify-content-center m-0">
<div class="col-12 col-md-6 col-lg-4 p-0">
<div class="row mx-3 my-3 justify-content-center text-center">
<div class="card p-2 custom-borders">
<div class="card-body p-2">
<form method="POST">
{% csrf_token %}
<table class="d-flex justify-content-center">
{{ formset.management_form }}
{% for form in formset %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td class="pb-2">
{% if form.instance.pk %}{{ form.DELETE }}{% endif %}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" class="btn btn-primary w-50 mt-1" style="background-color: #00754B;" value="Mentés">
</form>
</div>
</div>
</div>
</div>
</div>
Any suggestions what the solution would be? Thanks!
there are some possibilities
the wrong link clicked like if your trying access this URL profile/25/hookbaits/
and in the data index there is no HookBait with the id of 25
in HookBaitUpdateView you are trying to get queryset=HookBait.objects.filter(fisherman=self.request.user.fisherman)
maybe there is no hookbait associate with user.fisherman
404 page mostly served when you call get_object_or_404(HookBait, pk=25)
and update view may call this method

form doesn't submit productbacklogs to database

here is my project code .
I after posting data by form nothing happens.
#model.py
from django.db import models
from projectapp.models import Project
class Productbacklog(models.Model):
project=models.ForeignKey(Project,on_delete=models.CASCADE,default=None)
pbId=models.IntegerField(primary_key=True)
pbTitle=models.CharField(max_length=100)
pbPriority=models.IntegerField(blank=True, null=True)
class Meta:
unique_together=('project','pbId')
def __str__(self):
return self.pbTitle
#forms.py
from django import forms
from productbacklogapp.models import Productbacklog
from projectapp.models import Project
class ProductbacklogForm(forms.ModelForm):
class Meta:
model = Productbacklog
exclude=('pbId','project')
fields=['pbTitle']
#views.py
def productbacklogall(request):
if request.method == 'POST':
form = ProductbacklogForm(request.POST)
if form.is_valid():
form.instance.manage = Project.objects.get_or_create(cname=form.cleaned_data['manage_id'])
form.save()
messages.success(request, ('new productbacklog added'))
return redirect('productbacklogall')
else:
pb_all=Productbacklog.objects.all()
return render(request, 'productbacklogall.html', {'pb_all':pb_all})
I think that issue is on forms.py or views.py but I can't find it.
I'm so greatful if anyone can help me.
here is also my html code,when I submit something the method is post but I don't know why it doesn't go to data basse.
#productbacklogall.html
{%extends 'base.html'%}
{%block title%}
<title>backlog all</title>
{%endblock title%}
{%block content%}
</br>
{% if messages %}
{% for message in messages %}
<div class="alert alert-primary" role="alert">
{{ message }}
×
</div>
{% endfor %}
{% endif %}
<div class="container">
<form method="POST" class="row">
{% csrf_token %}
<label class="col-lg-4"></label>
<input type="text" class="form-control" name="Project" placeholder="project title?"/>
<input type="number" class="form-control" name="pbId" placeholder="backlog id?"/>
<input type="text" class="form-control" name="pbTitle" placeholder="pb title?"/>
<button type="submit" class="btn btn-primary col-lg-2">add project</button>
</form>
</div>
</br>
</br>
<table class="table table-bordered text-center">
<thead class="thead-dark">
<tr>
<th scope="col"> backlog-title</th>
<th scope="col">Edit</th>
<th scope="col">delivarable_task</th>
<th scope="col">related project</th>
</tr>
</thead>
<tbody>
{% load static %}
{% if pb_all %}
{% for obj in pb_all %}
<tr>
<td>{{ obj.pbTitle }}</td>
<td><a href='{% url "delete_productbacklog" obj.pbId %}'>delete</a></td>
<td> <a href=#> delivarabletask </a></td>
<td>{{ obj.project.pbTitle }}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
{%endblock content%}
Your form data are not valid, to see them, add this code to your views :
else:
messages.error(request, "Error")
like this :
def productbacklogall(request):
if request.method == 'POST':
form = ProductbacklogForm(request.POST)
if form.is_valid():
form.instance.manage = Project.objects.get_or_create(cname=form.cleaned_data['manage_id'])
form.save()
messages.success(request, ('new productbacklog added'))
else:
messages.error(request, "Error")
return redirect('productbacklogall')
else:
pb_all=Productbacklog.objects.all()
return render(request, 'productbacklogall.html', {'pb_all':pb_all})

Django Nested inline formset-- nested form does not save to DB, no errors thrown

We have a few nested inline formsets in an application. Ideally, the goal is to allow for dynamic and unlimited population of these fields so that users can add an arbitrary number of notes. The form renders, the JS calls are populating; however, I am not seeing the update on the nested from manager.
This is my first Django project and I am not finding anything regarding what is causing the hang up. The Organization is saved in the DB, but the notes are not.
Thanks in advance for any help
Model.py:
class Organization(models.Model):
//irrelevant organization information//
class OrganizationNote(AbstractNotes):
note = models.TextField(blank=True)
org = models.ForeignKey(Organization, on_delete=models.CASCADE,blank=True, null=True)
modelforms.py:
class OrganizationForm(AbstractBigThree):
class Meta:
model = custModels.Organization
fields = '__all__'
orgNoteFormSet = inlineformset_factory(custModels.Organization, custModels.OrganizationNote,
form=OrganizationForm, extra=0)
ModelView.py
class OrganizationCreateView(CreateView, AbstractOrganizationView):
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
org_note_form = orgNoteFormSet()
return self.render_to_response(
self.get_context_data(form=form,
org_note_form=org_note_form))
def get_context_data(self, **kwargs):
data = super(OrganizationCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['notes'] = orgNoteFormSet(self.request.POST)
else:
data['notes'] = orgNoteFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
notes = context['notes']
with transaction.atomic():
self.object = form.save()
if notes.is_valid():
notes.instance = self.object
notes.save()
return super(OrganizationCreateView, self).form_valid(form)
def get_success_url(self):
return '/portal'
template:
{% extends 'base.html' %}
{% load i18n widget_tweaks %}
{% block __file__ %}
<!-- filename == organization_create_form.html -->
{% endblock %}
{% block container %}
<script type="text/javascript">
$(function() {
$(".inline.{{ org_note_form.prefix }}").formset({
prefix: "{{ org_note_form.prefix }}",
})
})
</script>
<div class="content">
<div class="thermometer">
<div style="float:left;padding:10px;">
Dashboard
</div>
<div style="float:left;padding:10px;">
>><a class="back-link" style="padding-left:10px;"href="">Organization List</a>
</div>
</div>
<div class="col-md-7 main">
<h1>Create Organization</h1>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
<div id = "form_set">
<legend>Notes</legend>
</div>
<input type="button" value="Add Note" id="add_more">
<div id="form_set">
{{ org_note_form.management_form }}
{{ org_note_form.non_form_errors}}
{% for form in org_note_form.forms %}
{{form.non_field_errors}}
{{form.errors}}
<table class='no_error'>
{{ form }}
</table>
{% endfor %}
</div>
<div id="empty_form" style="display:none">
<table class='no_error'>
<fieldset>
{{ org_note_form.empty_form}}
<div class="inline {{ org_note_form.prefix }}">
{{ form.note.errors }}
{{ form.note.label_tag }}
{{ form.note }}
</div>
</fieldset>
</table>
</div>
<div>
<input style="margin-top: 30px;" type="submit" class="btn btn-primary" value="Save" />
</div>
</form>
</div>
</div> {% endblock %}
{% block javascripts %}
<script type="text/javascript">
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
{% endblock %}
<script> $('#add_more').click(function() {
var form_idx = $('#id_organizationnote_set-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_organizationnote_set-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});</script>
the issue was solved by editing the prefix of the model manager. By default django names the prefix as table_set which was missing from above.
add another option to your code:
def form_invalid(self, form):
print(form.errors)
...
to see if you have any validation errors in your form, don't forget to check errors in your inline

I can't get the selected student in widget tweaks render_field using CreateView

I am using the following code in views.py:
class MatriculaCreateView(CreateView):
template_name = "website/matricula.html"
model = CursoPeriodoEstudante
form_class = MatriculaMembroForm
success_url = reverse_lazy("website:lista_estudantes")
def get_context_data(self, **kwargs):
context = super(MatriculaCreateView, self).get_context_data(**kwargs)
context['estudante'] = Estudante.objetos.filter(id=self.kwargs['pk'])
context['pk'] = self.kwargs['pk']
return context
I create the following in forms.py:
class MatriculaMembroForm(forms.ModelForm):
class Meta:
# Modelo base
model = CursoPeriodoEstudante
# Campos que estarão no form
fields = [
'estudante',
'cursoPeriodo'
]
And finally in the template I created this page:
{% extends "website/_layouts/base.html" %}
{% load widget_tweaks %}
{% block title %}Matricula de Membros{% endblock %}
{% block conteudo %}
<div class="container mt-5">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Matrícula de Membros</h5>
<p class="card-text">
Complete o formulário abaixo para matricular
um <code>Membro</code> em um evento.
</p>
<p>Membro: {{ estudante }} </p>
<form method="post">
<!-- Não se esqueça dessa tag -->
{% csrf_token %}
<!-- Estudante -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Estudante</span>
</div>
{% render_field form.estudante class+="form-control" %}
</div>
<hr>
<!-- Curso -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Evento</span>
</div>
{% render_field form.cursoPeriodo class+="form-control" %}
</div>
<hr>
<div class="text-right">
Voltar
<button class="btn btn-primary">Enviar</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
The problem is, when the page opens, I want the field "Estudante" already filled with the one I selected in the view through the get_context_data (This field can be fixed). But the field always comes like this:printscreen from page. How can I fix to come with the student like this. What can I do? Thank you!
Ps.: I tried to put the following, but nothing happened...
class MatriculaCreateView(CreateView):
template_name = "website/matricula.html"
model = CursoPeriodoEstudante
form_class = MatriculaMembroForm
success_url = reverse_lazy("website:lista_estudantes")
def get_initial(self):
return {'estudante': Estudante.objetos.filter(id=self.kwargs['pk'])}
def get_context_data(self, **kwargs):
context = super(MatriculaCreateView, self).get_context_data(**kwargs)
context['estudante'] = Estudante.objetos.filter(id=self.kwargs['pk'])
context['pk'] = self.kwargs['pk']
return context
Override the get_initial() method of CreateView to set initial values for your model:
def get_initial(self):
return {'estudante': Estudante.objects.get(id=self.kwargs['pk'])}
I got it!
I should change the view to get, instead of filter (a query).
Thanks!