Passing data back to Django view - django

Inside of a table in my template I have the following which works great:
<tbody>
{% for item in items %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.status }}</td>
<td>{{ item.start_time }}</td>
<td>{{ item.end_time }}</td>
</tr>
</tbody>
I would like to add a form that posts the items to a view. I've tried this:
<form align="center" action="{% url 'app:doit' %}" method="post" ><b></b>
{% csrf_token %}
<input type="hidden" name="items" value="{{ items}}" />
<input type="submit" name="export" value="Export" >
</form>
but that doesn't work as I expected it would. The data comes into the view as a sequence of characters, something like this, ",..." How do I pass {{items}} back to a view so I can process the items as python objects?
The export method in my view contains this:
if 'items' in request.POST:
my_items = request.POST['items']

You cannot POST a QuerSet back to a view. HTML form cannot understand a Django QuerySet. That would be nice, though!
What you can do is to create a custom template tag that would generate this:
<input type="hidden" name="items" value="{% my_items items %}" />
to this:
<input type="hidden" name="items" value="1,2,5,7,8" />
where these numbers are the id of each item. You can also use the name field if you like, since it's not very secure to expose the ids.
Then, once POSTed, inside the view I would do:
if 'items' in request.POST:
# my_item_values is a str
my_item_values = request.POST['items']
try:
my_item_values = my_item_values.split(',')
except TypeError:
# Handle error of conversion from string to list here
else:
# typecast succedded. Get your items!
items = Item.objects.filter(id__in=my_item_values) # This is a QuerySet
# or this (if you used the names)
items = Item.objects.filter(name__in=my_item_values) # This is a QuerySet
The custom template tag would look like this:
#register.simple_tag()
def my_items(items):
return ','.join([item.name for item in items])

Related

Bootstrap Table not sending selected checkbox values in POST request in Django app

I am using Bootstrap Table (https://bootstrap-table.com/) to display a product list in a Django app. I would like the user to select some products and click the button to submit. Using Bootstrap Table seems to prevent the checked checkboxes being sent in the POST request.
views.py
class ProductProcessView(View):
def post(self, request):
products = request.POST.getlist('product_checkboxes')
# process the chosen products
return redirect('product-list')
html template
<form method="post">
{% csrf_token %}
<table class="table-striped"
data-toggle="table"
>
<thead>
<tr>
<th data-field="product_id" data-checkbox="true"></th>
<th data-field="product">Product</th>
</tr>
</thead>
{% for product in product_list %}
<tr>
<td><input type="checkbox" name="product_checkboxes" value="{{ product.id }}"></td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
If I remove the line data-toggle="table" this correctly sends the selected product IDs in the POST request, but with that line included it does not send any IDs at all. Bootstrap Table requires the data-toggle="table" attribute to initialise the table so without it there is no formatting.
This is the request.body with data-toggle="table" included:
<QueryDict: {'csrfmiddlewaretoken': ['fOma6gtvG2ETw1hrVYMdIuSUWuE1RA2jpX2Tae7ntipMPGX4yKNYEGgkHD0Jcuco'], 'btSelectItem': ['on', 'on']}>
This is without it:
<QueryDict: {'csrfmiddlewaretoken': ['Si6UyiTZ4yAJNYKKQ9FtA8dk0gNPGTPp2rMDCgxRROlC6DqntVGewkBKLp9x1NZu'], 'product_checkboxes': ['43004', '43006']}>
I would be very grateful for any ideas about how I can use the Bootstrap Table framework with it's formatting and widgets, but still be able to use checkboxes to collect the product data.
You can't rely on your HTML because it is dynamically replaced by BootstrapTable.
So you need to use its API to retrieve the values. The simplest way is to add script to the page which will get values from table and assign on some (hidden) element in the form.
Then - on Python side you will read this field and process the data.
See example (uses JQuery but can be converted to plain JS):
<script>
$(document).ready(function () {
$('#product-form').on('submit', function () {
const table = $('#products').bootstrapTable('getSelections')
$('#checkboxes').val(JSON.stringify(table))
})
})
</script>
Some corrections to the template:
Add ID to form
Include product ID as hidden column
Add hidden element which will pass content via form
html template:
<form method="post" id="product-form">
{% csrf_token %}
<table id="products" class="table-striped" data-toggle="table">
<thead>
<tr>
<th data-field="product_check" data-checkbox="true"></th>
<th data-field="product_id" data-visible="false">ID</th>
<th data-field="product">Product</th>
</tr>
</thead>
<input id="checkboxes" name="product_checkboxes" style="display: none">
{% for product in product_list %}
<tr>
<td><input type="checkbox" data-id="{{ product.id }}" value="{{ product.id }}"></td>
<td>{{ product.id }}</td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button id="select-products" onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
And finally - getting the data in views.py:
def post(self, request):
products = json.loads(request.POST.get('product_checkboxes'))
# process the chosen products
return redirect('product-list')
Note that in this case products will be a list of objects. Each object has values that are correspondent to columns

Django Form Not Validating my Date fields

I have a Search form that includes the query box, some checkbox items, and a start and end date. I am getting my information when I enter a query, so I know it is performing the search_results action, but the start and end date is not getting validated at all. I have yet to add the code to handle the start and end date in my results, but the issue is there is no client side validation happening on the form.
My form looks like this:
class SearchForm(forms.Form):
q = forms.CharField(max_length=64,required=False)
service_choices = forms.MultipleChoiceField(
required=True,
widget=forms.CheckboxSelectMultiple,
choices=CustomUser.SERVICE_CHOICES,
)
start_date = forms.DateField(required=False)
end_date = forms.DateField(required=False)
I tried using Class Based View, but did not get any fields at all, so I
tried using a function based view to get my search criteria.
The view looks like:
def get_search(request):
form = SearchForm()
return render(request, 'get_search.html', {'form':form})
My template is:
<!-- templates/get_search.html -->
{% extends "base.html" %}
{% block title %}Search{% endblock title %}
{% block content %}
{% if user.is_authenticated %}
<br><br>
<TABLE BORDER="0" WIDTH="100%">
<TR>
<TD ALIGN="Left"><B>Track X - search</B></TD>
<TD ALIGN="Center"><B>User: {{ user }}</B></TD>
<TD ALIGN="Right"><B>Service: {{ user.service }}</B></TD>
</TR>
</TABLE>
<form action="{% url 'search_results' %}" method="get"">
{% csrf_token %}
<TABLE BGCOLOR="#66CCCC" Border="2" WIDTH="100%">
<TR>
<TD ALIGN="Left" WIDTH="100"> Services:</TD>
<TD ALIGN="Right">Search expression:</TD>
<TD ALIGN="Left">
{{ form.q }}
<button type="submit" name="submit">Search TrackX</button>
</TD>
</TR>
<TR>
<TD WIDTH="100"> {{ form.service_choices }} </TD>
<TD COLSPAN="2" ALIGN="Center"> Start Date: {{ form.start_date }}
End Date: {{ form.end_date }}</TD>
</TR>
</TABLE>
</form>
{% else %}
<p>You are not logged in</p>
Log In |
Sign Up
{% endif %}
{% endblock content %}
The Search_results view just uses the query to build some Q Filter
queries, and it seems to be working correctly.
It originally used a GET Method, and was passing the parameters into the search results view just fine. It just doesn't validate the dates (or anything else I assume) before passing the parameters into the view.
Can anyone tell me what am I missing here?
As I see on the view that your posted, you are not actually checking if the form is valid, you can do that by using:
if request.method == 'POST':
form = SearchForm(request.POST)
form.is_valid()
This method will validate all your fields, and return the boolean value representing if its valid or not.

Form in a dynamic HTML table

I am trying to create a HTML table, with a 2 fields on each row for the user to fill in (sports matches predictions). It loads data from one table(List) and should write into another one (Predictions)
Right now I have a cycle which loops through the matches and based on that creates the HTML table.
input.html
{% block body %}
<form method="post">
{% csrf_token %}
<table class="table">
<tr>
<th>Round</th>
<th>Date</th>
<th>Time</th>
<th>Home</th>
<th class="col-md-1"></th>
<th class="col-md-1"></th>
<th class="col-md-1"></th>
<th>Away</th>
</tr>
{% for item in query_results %}
<tr>
<td>{{ item.match_round }}</td>
<td>{{ item.match_date }}</td>
<td>{{ item.match_time }}</td>
<td>{{ item.home_team_name }}</td>
<td>{{ form.home_goals_predictions|add_class:"form-control"}}</td>
<td class="text-center">:</td>
<td>{{ form.away_goals_predictions|add_class:"form-control"}}</td>
<td>{{ item.away_team_name }}</td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}
This is works and displays the table excatly as I want.
However I am not able to extract the data as I want from it - to be more exact, when submiting the form, the data from the last row gets assigned to all the rows.
views.py
query_results = List.objects.all()
form = PredictionsForm()
if request.method == 'POST':
form = PredictionsForm(request.POST)
if form.is_valid():
user_prediction = form.save(commit = False)
for result in query_results.all():
for home_goals_predictions, away_goals_predictions in form.cleaned_data.items():
user_prediction.id = result.id
user_prediction.match_round = result.match_round
user_prediction.home_team_name = result.home_team_name
user_prediction.away_team_name = result.away_team_name
user_prediction.user_id = request.user.id
user_prediction.home_goals_predictions = form.cleaned_data['home_goals_predictions']
user_prediction.away_goals_predictions = form.cleaned_data['away_goals_predictions']
user_prediction.save()
return redirect('/matches/')
else:
return redirect('/matches/')
else:
template = loader.get_template('matches/input.html')
context = {
'query_results': query_results,
'form': form
}
return HttpResponse(template.render(context, request))
forms.py
class PredictionsForm(forms.ModelForm):
home_goals_predictions = forms.IntegerField(widget=forms.Textarea(attrs={'cols': 1, 'rows': 1, 'maxlength': '2'}))
away_goals_predictions = forms.IntegerField(widget=forms.Textarea(attrs={'cols': 1, 'rows': 1, 'maxlength': '2'}))
class Meta:
model = Predictions
fields = ('home_goals_predictions', 'away_goals_predictions')
I would really appreciate the help, as I am stuck on this problem and cannot figure out correct solution using formset/for loop.
I'm not entirely sure what's going on in your code since I can't see the definition of query_results but I'm pretty sure that what you are looking for is formsets. In short, a form submit's one thing / record. A formset is as the name suggest a set of forms, see the documentation for a full example. Also take a look at modelformsets, depending on your usecase this might really come in handy as well.
Edit:
Yeah so I would definitely go the modelformset route. Here's a short example of what that would like
in your views.py (the GET request).
from django.forms import modelformset_factory
ListFormSet = modelformset_factory(List, form=ListForm, extra=0)
list_formset = ListFormSet(queryset=List.objects.all())
Then during POST you can just do
ListFormSet = modelformset_factory(List, form=ListForm, extra=0)
list_formset = ListFormSet(request.POST, queryset=List.objects.all())
if list_formset.is_valid():
for list_form in list_formset:
list_form.save()
analogue to how a normal single form works.
Then in your template
<form enctype="multipart/form-data" method="post">
{{ list_formset.management_form }}
{% for list_form in list_formset %}
...
{{ list_form.instance.match_round }}
...
{{ list_form.home_goals_predictions }} #formfield
{{ list_form.away_goals_predictions }} #formfield
{% endfor %}
</form>
As you can see it is possible to access the query data via .instance
note: I typed this from memory so you might have to debug some typo's.

Django, I want to take an input from a form and contents of the template should be according to the input

models.py
class Transaction(models.Model):
created_date = models.DateField('created_date')
price = models.IntegerField(default=0)
abc = models.IntegerField(default=0)
pqr = models.IntegerField(default=0)
ghi = models.IntegerField(default=0)
Then I take a user input
input.html
<form method="POST" action="search/" style="margin-left:5em;">
{% csrf_token %}
<input type="radio" name="account" value="price"> price<br>
<input type="radio" name="account" value="abc"> abc<br>
<input type="radio" name="account" value="pqr"> pqr<br>
<input type="radio" name="account" value="ghi"> ghi<br>
</form>
views. py
def search(request):
if request.method == 'POST':
search_id = request.POST.get("account", None)
selected_transactions = Transaction.objects.exclude(search_id=0)
return render(request, 'stats/account_details.html', {'selected_transactions': selected_transactions,
'search_id': search_id})
else:
return render(request, 'stats/index.html')
I have to display contents based on user input.
account_details.html
<table>
<tr>
<th>Transaction date</th>
<th>{{ search_id }}</th>
</tr>
{% for transaction in selected_transactions %}
<tr>
<td>{{ transaction.created_date }}</td>
<td>{{ transaction.{{ search_id }} }}</td>
</tr>
{% endfor %}
</table>
I have two issues here.
1.Transaction.objects.exclude(search_id=0) doesn't work. It does not take the value of variable search_id. How do I exclude dynamically those transactions where user input attribute=0?
2.{{ transaction.{{ search_id }} }} in account_details.html doesn't work as it is a syntax error. I need to display data varying on user input. How do I use two variables inside a single tag in my template?
I get that I can resolve both using if else statements, but I have a large no. of attributes. So, is there a shorter way to do it?
Any help is appreciated.
Issue 1: You are trying to use an attribute in a query set filter which is not present in your model. You might want to use any of your attributes of your model like price or any other attribute.
Issue 2: Code below:
<td>{{ transaction.created_date }}</td>
<td>{{ transaction.{{ search_id }} }}</td>
is not correct for various reasons. First thing that you are trying to access created_date attribute which is not present in your queryset attribute. Either you have to remove this attribute or add it into your model. Your second line is incorrect because its a syntax error. Below one might be helpful to you and its syntactically correct.
<td> {{ search_id }} </td>
Edit: You can put if else to compare which search_id is selected by the user and based on that corresponding data can be displayed.
{% if search_id == "abc" %}
{{ transaction.abc }}
{% elif search_id == "pqr" %}
{{ transaction.pqr }}
{% endif %}

How to get variable value from html into views.py in django

html code:
{% for data in top_100_active_webshells_tuple %}
<tr>
<td>{{ data.0 }}</td>
<td>{{ data.1 }}</td>
<td>{{ data.2 }}</td>
<td><form action="/my_image/" method="POST">
{% csrf_token %}
<input id ="my_input" type="submit" class="btn" name="{{ data.3 }}" value="image" style="background:white;color:black;border:3px solid grey"/>
</form>
</td>
</tr>
{% endfor %}
views.py function:
def my_image(request):
if "data.3" in request.GET:
address=request.GET["data.3"]
resp="address is "+address
return HttpResponse(resp)
else:
return HttpResponse("error here")
Question:
Question is that i can't get value stored in variable "data.3 "in the function named
def my_image(request)
And else statement is printed when i click input button,how to fix it and get variable value in views.py
Please reply as soon as possible.
You will get the value of data.3 and not data.3 as a key in the request data.
Also, you will receive the data in request.POST and not request.GET as form method is POST.
def my_image(request):
if <value_of_data.3> in request.POST:
address=request.POST[<value_of_data.3>]
resp="address is "+address
return HttpResponse(resp)
else:
return HttpResponse("error here")
But, as you are iterating and the value of data.3 might change in different requests, you won't be able to get your view to work correctly everytime as intended using the above logic.