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.
Related
I want my data to be displayed like this:
Date installment month amount total
January 1, 2021 January 30000 30000
February 1, 2021 February 40000 70000 (i.e sum of 30000 and 40000)
March 1, 2021 March 30000 100000 (i.e sum of 30000, 40000 and 30000)
.
.
and so on..
For this purpose I am using aggregate() in my InstallmentListView as given below:
views.py
class InstallmentListView(ListView):
model = Installment
template_name = 'client_management_system/installment_detail.html'
context_object_name = 'installments'
# This function is to show the installments of the client, the details of which we are seeing currently, and
# pk=self.kwargs['pk'] is to get the client id/pk from URL
def get_queryset(self):
user = get_object_or_404(Client, pk=self.kwargs['pk'])
return Installment.objects.filter(client=user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = get_object_or_404(Client, pk=self.kwargs['pk'])
queryset = Installment.objects.annotate(total=Window(expression=Sum('installment_amount'), order_by=F('installment_month').asc(), frame=RowRange(end=0)))
context['total'] = queryset
#register.filter
def get_item(total, key):
return total.get(key)
return context`
and my template file is given below:
template.html
<!DOCTYPE html>
{% extends "client_management_system/base.html" %}
{% block content %}
<body>
<legend class="border-bottom mb-4"><h5>Installment History</h5></legend>
<article class="media content-section">
<div>
<table id="installmentTable" style="width:100%">
<tr>
<th style="width:150px">Date</th>
<th style="width:250px">Installment Month</th>
<th style="width:170px">Amount</th>
<th style="width:100px">Balance</th>
</tr>
{% for installment in installments %}
<fieldset>
<tr>
<td>{{ installment.installment_date|date:"F d, Y" }}</td>
<td>{{ installment.installment_month }}</td>
<td>{{ installment.installment_amount }}</td>
<td>{{ total|get_item:'installment_amount__sum' }}</td>
</tr>
</fieldset>
{% endfor %}
</table>
</div>
</article>
</body>
{% endblock %}
But I am getting the following error:
ValueError: too many values to unpack (expected 2)
It looks like I am not implementing the Window function correctly. Does anyone has an idea how to resolve this?
You have written:
queryset = Installment.objects.annotate(total=Window(expression=Sum('installment_amount'), order_by=F('installment_month').asc(), frame=RowRange(end=0)))
context['total'] = queryset
As indicated by the variable name queryset is a QuerySet, i.e. a collection of Installment instances. Yet later you write total|get_item:'installment_amount__sum' which effectively translates to queryset.get('installment_amount__sum') which doesn't make sense and obviously gives you an error.
Instead you want to add this window expression to the queryset returned by get_queryset instead, also you want to use order_by on the installment_date ordering on a string month doesn't make much sense:
class InstallmentListView(ListView):
model = Installment
template_name = 'client_management_system/installment_detail.html'
context_object_name = 'installments'
# This function is to show the installments of the client, the details of which we are seeing currently, and
# pk=self.kwargs['pk'] is to get the client id/pk from URL
def get_queryset(self):
user = get_object_or_404(Client, pk=self.kwargs['pk'])
return Installment.objects.filter(client=user).annotate(
total=Window(
expression=Sum('installment_amount'),
order_by=F('installment_date').asc(),
frame=RowRange(end=0)
)
)
# Remove your `get_context_data`
Next in the template you can simply write:
{% for installment in installments %}
<fieldset>
<tr>
<td>{{ installment.installment_date|date:"F d, Y" }}</td>
<td>{{ installment.installment_month }}</td>
<td>{{ installment.installment_amount }}</td>
<td>{{ installment.total }}</td>
</tr>
</fieldset>
{% endfor %}
Note: Why do you even store installment_month you can get that from installment_date... Plus that custom template tag of yours was
unnecessary, dictionary lookups can be done in the template as simply
as {{ variable.key_name }}
I have two Django models that record time. Model one records time during the morning and Model two records time during the evening. I want to present both of these times along with the difference between the times within an HTML table but am confused about how to do it. I am new to Django and would really appreciate some advice.
This is what I have so far:
models.py:
class Alltime(models.Model):
id= models.ForeignKey(User, on_delete = models.CASCADE)
mtime = models.DateTimeField()
etime = models.DateTimeField()
views.py:
def panel(request):
time_data = User.objects.filter(pk__gt=1) #I need all data except for the default Super User account
get_time = Alltime.objects.all()
return render(request, 'users/interface.html', {'data': time_data, "get_time": get_time})
panel.html:
<form>
{% csrf_token %}
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for data in data %}
<tr>
<td>{{data.username}}</td>
{% endfor %}
{% if get_time %}
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
{% endfor %}
{% else %}
<td> Not available </td>
{% endif %}
</tr>
</table>
</form>
How can I get the difference between the times and place them within the HTML table?
If I understand correctly what you want to do, then you can/need to structure your data differently. An easy way is to prepare the data in your view:
def panel(request):
time_data = User.objects.filter(pk__gt=1)
time_table=[]
for user in time_data:
morning_time = Morning.objects.filter(user=user)
evening_time = Evening.objects.filter(user=user)
diff = morning_time - evening_time
time_table.append((user.name, morning_time, evening_time, diff))
return render(request, 'users/interface.html', {'data': time_table})
And in the template:
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for line in data %}
<tr>
<td>{{line.0}}</td>
<td>{{line.1}}</td>
<td>{{line.2}}</td>
<td>{{line.3}}</td>
</tr>
{% endfor %}
</table>
You need to add the handling of not existing data in the view code.
Some remarks:
The whole thing does not really make sense to me. I guess you will need to filter for dates too. But you should get the idea from this. And why is it in a form?
You can add a property to the Alltime model that returns the difference between the morning and evening time
#property
def diff(self):
return self.etime - self.mtime
Then in your template you can use this property
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
<td>{{m.diff}}</td>
{% endfor %}
I have written a nested loop and doing value comparison between data coming from outer loop with inner loop. Below is my template code :-
<tbody>
{% for col in filter2.qs %}
<tr>
{% for mso in filter1.qs %}
{{ col.box_id }} vs {{ mso.box_id }}
<br>
{% if mso.box_id == forloop.parentloop.col.box_id %}
<td>{{ mso.mso_id }}</td>
<td>{{ col.box_id }}</td>
<td>{{ col.channel_id }}</td>
{% endif %}
{% endfor %}
</tr>
{% empty %}
<tr>
<td colspan="5">No data</td>
</tr>
{% endfor %}
</tbody>
Problems are :
When i do print {{ col.box_id }} vs {{ mso.box_id }} i can see values
When i do print {{ col.box_id|length }} vs {{ mso.box_id|length }} i see length of outer loop value as 0.
If condition below the prints never runs hence no data is inserted in the table.
I am getting data for both the loops from views.py
def search(request):
user_list1 = VCB_Execution_Details.objects.all()
user_filter1 = ReportFilter_VCB_Execution_Details(request.GET, queryset=user_list1)
user_list2 = VCB_Details.objects.all()
user_filter2 = ReportFilter_VCB_Details(request.GET, queryset=user_list2)
print(user_filter2.qs)
print(type(user_filter1))
return render(request, 'user_list.html', {'filter1':user_filter2,'filter2': user_filter1})
filters.py
class ReportFilter_VCB_Execution_Details(django_filters.FilterSet):
class Meta:
model = VCB_Execution_Details
fields = ['box_id','channel_id']
class ReportFilter_VCB_Details(django_filters.FilterSet):
class Meta:
model = VCB_Details
fields = ['box_id','mso_id']
So Finally i got the answer, problem was the object type was VCB_Execution_Details vs str. I tried checking the data type in def search(request): by printing variable type for each data in queryset of user_list1 and user_list2
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 %}
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.