How to create one form with multiple buttons in the loop - django

It is my form in template,
I am creating multiple forms with two buttons in the loop for voting particular item
and i think it is ugly, how can i avoid that using only one form for all buttons?
{% for bill_item in bill_items %}
<form action="{% url 'bills:change_quantity' bill_item.id %}" method="post">
{% csrf_token %}
<button name="up"></button>
<button name="down"></button>
</form>
{% endfor %}
It is my action in the view
def change_quantity(request, bill_item_id):
bill_item = BillItem.objects.get(pk=bill_item_id)
if 'up' in request.POST:
bill_item.increase()
elif 'down' in request.POST:
bill_item.decrease()
bill_item.save()
return HttpResponseRedirect('/bills/')

How about moving bill_item.id to button? Can't test this at the moment, so please treat this as unchecked suggestion
Like:
<form action="{% url 'bills:change_quantity' bill_item.id %}" method="post">
{% for x_id,bill_item in enumerate(bill_items) %}
<button name={% x_id %} value="up"></button>
<button name={% x_id %} value="down"></button>

Related

Hx-push-url doesn’t work on back button click

I am trying to integrate Htmx with django and achieve single page application behaviour. I am rewritting Djangoproject.com poll app with htmx. When I click on detail page link, content loads, htmx push a new url in address bar. When I press back button, it took me to index page perfectly for the first time, after that if I again go to detail page and click back button, url shows of the index, button index content doesn’t load, content remains same as detail page.
Here is my code
views.py
def index(request):
latest_question_list = Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/index/index.html', context)
else:
return render(request, 'main/index/index-full.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
print(request.headers.get("Hx-Request"))
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/detail/detail.html', {'question': question})
else:
return render(request, 'main/detail/detail-full.html', {'question': question})
index.html
<div id="index" class="">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><div class="has-text-link" hx-get="{% url 'main:detail' question.id %}" hx-push-url="true" hx-target="#index" hx-swap="outerHTML">{{ question.question_text }}</div></li>
{% endfor %}
</ul>
{% else %}
<p>
No polls are available.
</p>
{% endif %}
</div>
index-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/index/index.html' %}
{% endblock content %}
detail.html
<div id="detail" class="">
<form action="{% url 'main:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p>
<strong>{{ error_message }}</strong>
</p>
{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
</div>
detail-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/detail/detail.html %}
{% endblock content %}
I found no error in browser console, no error in terminal
Now, I know I can put a back button in detail page that can took me to index page. But user won't use that, they will just use the back button on their device.
Adding this javascript code you can reload the page when the user click the back button:
var auxBack = performance.getEntriesByType("navigation");
if (auxBack[0].type === "back_forward") {
location.reload(true);
}

how to process submit on django-tables2 with a class View with FilterView mixin

I have a django-tables2 FilterView.
The filter is templated in a form:
{% if filter %}
<form action="" method="get" class="form form-inline">
{% bootstrap_form filter.form layout='inline' %}
{% bootstrap_button 'filter' %}
</form>
{% endif %}
I have added a checkbox field to each row, and I have the table in a form:
<form action="table_selection" method="get" class="form form-inline">
{% csrf_token %}
{% render_table table 'django_tables2/bootstrap.html' %}
<button class="btn btn-primary red" type="submit" >Submit Rows</button>
</form>
When I submit, I get logging messages like:
GET /three_pl/threepl_fulfilments_filter/table_selection?csrfmiddlewaretoken=...
&select_row=198&select_row=158&select_row=159
so the select_rows are very interesting.
But I am lost with the class view, I can't grapple with how to process the form submission.
This is my view:
class FilteredThreePLFulfimentsView(SingleTableMixin,FilterView):
table_class = ThreePL_order_fulfilmentsTable
model = ThreePL_order_fulfilments
template_name = "three_pl/ThreePLFulfilmentsFilter.html" #three_pl/templates/three_pl/ThreePLFulfilmentsFilter.html
filterset_class = ThreePLFulfilmentsFilter
Answer: set up a url watching for /table_selection.
Make it before the url for the table render.
... url(r'^threepl_fulfilments_filter/table_selection',views.three_pl_fulfilments_selection,name='threepl_fulfilments_selection'),
...
and in the view:
if request.method == 'GET':
try:
selected_rows = request.GET.getlist('select_row')

django multi form and file field

I am currently using several differences forms on a single view. I am able to fill my forms but when I submit one of them, it seems that my form is invalid. I displayed the request.POST (it contains all my information) and my form (it contains my information except files parts.)
Could you explain me how to correct it?
Could it be linked to my models?
(I am using bootstrap 3 through django)
my view :
def view_addfiles(request):
try:
print(request.POST)
except:
{}
if request.method == 'POST' and 'search' in request.POST:
print("recherche")
recherche=searchbar(request.POST, prefix='search')
if recherche.is_valid():
print("recherche")
else :
recherche=searchbar(prefix='search')
if request.method == 'POST' and 'film' in request.POST:
print("film")
addfilm=Addfilms(request.POST,request.FILES, prefix='film')
print(addfilm)
if addfilm.is_valid():
print("film")
return redirect(view_accueil, inscription=3)
else :
print("dfsd")
addfilm=Addfilms(prefix='film')
if request.method == 'POST' and 'serie' in request.POST:
print("serie")
addserie=Addseries(request.POST,request.FILES, prefix='serie')
if addserie.is_valid():
print("serie")
return redirect(view_accueil, inscription=3)
else :
addserie=Addseries(prefix='serie')
return render(request, 'menuAjout.html',locals())
my html :
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{{ recherche.as_p }}
<input type="submit" id="validation" name="search"/>
</form>
<div id="films">
{% load bootstrap3 %}
{% bootstrap_css %}
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{% bootstrap_form addfilm %}
{% buttons %}
<button type="submit" class="btn btn-primary" id="submitbutton" name="film" value="submit">
{% bootstrap_icon "star" %} Ajouter
</button>
{% endbuttons %}
</form>
</div>
<div id="series">
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{% bootstrap_form addserie %}
{% buttons %}
<button type="submit" class="btn btn-primary" id="submitbutton" name="serie">
{% bootstrap_icon "star" %} Ajouter
</button>
{% endbuttons %}
</form>
</div>
my forms :
class Addseries(forms.ModelForm):
class Meta:
model = series
exclude = ('nbTelechargement','datedepot')
class Addfilms(forms.ModelForm):
class Meta:
model = series
exclude = ('nbTelechargement','datedepot')
class searchbar(forms.Form):
motclef=forms.CharField(max_length=15,widget=forms.TextInput(attrs={'placeholder': 'Search...','style':'background :#ededef url("/static/image/search.png") no-repeat;background-size: auto 90%;'}))
categorie=forms.ChoiceField(choices=(('films', 'films'),
('séries', 'séries'),
('jeux', 'jeux'),
('logiciels', 'logiciels'),
('livres', 'livres'),
('musiques', 'musiques')))
I see several things:
It's not a Django issue but a HTML one:
When a user submits a form, he/she submits only form.
Django receives in request.POST only the data sent by one form.
Your forms share the same fields' names.
Addseries.nbTelechargement and Addfilms.nbTelechargement will have the same key in request.POST
I just forgot to add enctype="multipart/form-data" in my form balise.
My request.FILES was empty because of that.
So my form was unvalid because of that.

Django-Bootstrap3 issues with inline form layout

Using the following code to render a form:
<div class="row">
<div class="col-lg-6 col-lg-offset-3">
<form action="{% url 'chartboard:chart_url' %}" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form layout='inline' %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
</form>
</div>
</div>
Here is the output:
And here it is when removing layout='inline'
Datepicking is done by adding a custom class upon form creation with form widgets and using a jquery datepicker (if that is of any relevance at all)
Why are field labels being hidden in the first case?
Why isn't the entire form displayed in a single line when opting for inline display?
Working with python 3.4 and the following venv:
Django==1.8.11
django-bootstrap3==7.0.1
flake8==2.5.4
mccabe==0.4.0
numexpr==2.5
numpy==1.10.4
pep8==1.7.0
pyflakes==1.0.0
requests==2.9.1
tables==3.2.2
You need to change the class of your <form> element to class="form-inline" and it should work. It doesn't seem to appear in the docs but check the example inline form on GitHub.

Why is this django formset not being submitted?

i have a formset as follows:
EduFormSet = formset_factory(forms.CandidateDegreeForm, can_delete=True)
edu_formset = EduFormSet(prefix='candidate_degree')
in the templates i am doing the following:
{% if edu_formset %}
{% for form in edu_formset %}
<div class="formset-form" style="visibility: visible;">
<form id="{{ form.prefix }}" method="POST" action="/degree/add/">
<h4>Some Heading Here</h4>
{% csrf_token %}
{% for field in form %}
{% include "form_field.html" %}
{% endfor %}
</form>
<script type="text/javascript">
jQuery(document).ready ( function(){
jQuery('{{ form.prefix }}').validationEngine();
});
</script>
<div class="clearfix"></div>
</div>
{% endfor %}
{{ edu_formset.management_form }}
<div class="button-container right">
<input class="button" type="submit" value="submit" />
</div>
{% endif %}
I am not sure why but nothing really happens when i hit the submit button.
Your submit button is not within the form, so the action is not triggered by the click!
Here's how the docs show you to render formsets:
<form method="post" action="">
<!-- Notice how the formset (below) and thus its submit button
is INSIDE the form (above) -->
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
You try to create multiple forms with the form.prefix for id. This could work but each form would have to be rendered with its own submit button. Formsets are designed to combine multiple forms into one and guarantee uniqueness of value names by said prefix. They would be enclosed in a singe form and share any submit triggers.