Django manipulate / modify date in template - django

Is it possible to make an input that changes the date.today for the whole template ?
my template
{% for Ansicht in Ansicht.lehrertabelle_set.all %}
<tbody>
<tr>
<th scope="row"></th>
<td>{{Ansicht.Pflichtstunden_normal}}</td>
<td>{{Ansicht.Status_normal}}</td>
{% if Ansicht.Prognose_FK %}
<td>{{Ansicht.Prognose_FK.Status}}</td>
<td>{{Ansicht.Prognose_FK.Stunden}}</td>
{% else %}
<td>{{Ansicht.Prognose_FK.Status_2}}</td>
<td>{{Ansicht.Prognose_FK.Stunden_2}}</td>
{% endif %}
{% endfor %}
the filter then would show
those
<td>{{Ansicht.Prognose_FK.Status_2}}</td>
<td>{{Ansicht.Prognose_FK.Stunden_2}}</td>
instead of the first ones when the date is modified, I tried to use javascript but I guess it dont work bc of python objects
my model is
class PrognoseTabelle(models.Model):
Benutzer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
Lehrer_FK = models.ForeignKey('LehrerTabelle', on_delete=models.SET_NULL, related_name='LehrerNName', null=True, blank=True)
#######Status 1######
von_Datum = models.DateField(null=True, blank=True)
Status = models.CharField(max_length=20, null=True, blank=True)
Stunden = models.CharField(max_length=20, null=True, blank=True)
bis_Datum = models.DateField(null=True, blank=True)
#######Status 2######
von_Datum_2 = models.DateField(null=True, blank=True)
Status_2 = models.CharField(max_length=20, null=True, blank=True)
Stunden_2 = models.CharField(max_length=20, null=True, blank=True)
bis_Datum_2 = models.DateField(null=True, blank=True)
#######Status 3######

It is impossible to influence the rendered HTML from only server-side code, after it has been rendered and displayed by the user. If I understand you correctly, your intended user interaction with this view/menu looks kind of like this:
User action: The user opens the menu.
Program action: Among other things, a date-input is displayed.
User action: The user inputs a date using the date-input.
Program action: The displayed content changes.
Given, that you cannot influence the rendered HTML with only server-side code in step 4., you have two possibilities to achieve this:
display new rendered HTML
use client-side code (for example JavaScript)
I'm going to explain the first possibility here:
It's probably the easiest to use a django form to render the input.
forms.py:
from django import forms
from django.utils.timezone import localdate
class PrognoseFilterForm(forms.Form):
"""Form for filtering the Prognose table."""
datum = forms.DateField()
somewhere in views.py:
def prognose_tabelle_view(request, *args, **kwargs):
form = PrognoseFilterForm(request.GET, initial={'date': timezone.localdate()})
datum = timezone.localdate()
if form.is_bound() and form.is_valid():
datum = form.cleaned_data['datum']
prognose_query = Ansicht.lehrertabelle_set.all()
prognoseansichten_bis_einschliesslich_datum = prognose_query.filter(
Prognose_FK__von_Datum__lte=datum
)
prognoseansichten_ab_datum = prognose_query.filter(
Prognose_FK__von_Datum__gt=datum
)
return render(
request,
'your_app/prognose_tabelle.html',
context={
'filter_form': form,
'prognosen_bis_datum': prognoseansichten_bis_einschliesslich_datum,
'prognosen_ab_datum': prognoseansichten_ab_datum,
}
)
prognose_tabelle.html:
<form action="{% url '<name of the view according to urls.py>' %}" method="get">
{{ filter_form.as_p }}
<input type="submit">Filtern</input>
</form>
<table>
<tbody>
{% for Ansicht in prognosen_bis_datum %}
<tr>
<th scope="row"></th>
<td>{{Ansicht.Pflichtstunden_normal}}</td>
<td>{{Ansicht.Status_normal}}</td>
<td>{{Ansicht.Prognose_FK.Status}}</td>
<td>{{Ansicht.Prognose_FK.Stunden}}</td>
</tr>
{% endfor %}
{% for Ansicht in prognosen_ab_datum %}
<tr>
<th scope="row"></th>
<td>{{Ansicht.Pflichtstunden_normal}}</td>
<td>{{Ansicht.Status_normal}}</td>
<td>{{Ansicht.Prognose_FK.Status_2}}</td>
<td>{{Ansicht.Prognose_FK.Stunden_2}}</td>
</tr>
{% endfor %}
</tbody>
</table>
When a user clicks the button labelled with "Filtern", the form data is sent to the view via an HTTP-Get-Request in its GET-Parameters. The server then responds with a new HTML page, which the browser then displays to the user.

Related

Django initial loading of page taking too long

Hi I am a beginner at Django and I am working on a project that lists 100 companies in each page along with there contacts and also the amount of items sold. Here is an example:
As you can see the initial loading time of the page is very high. But when I refresh the page it refreshes very fast because I am using caching.
Here are some of my other files:
models.py
from __future__ import unicode_literals
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=150)
bic = models.CharField(max_length=150, blank=True)
def get_order_count(self):
orders = self.orders.count()
return orders
def get_order_sum(self):
orders = Order.objects.filter(company=self)
total_sum = sum([x.total for x in orders])
return total_sum
class Meta:
ordering = ['-id']
class Contact(models.Model):
company = models.ForeignKey(
Company, related_name="contacts", on_delete=models.PROTECT)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150, blank=True)
email = models.EmailField()
def get_order_count(self):
orders = self.orders.count()
return orders
class Order(models.Model):
order_number = models.CharField(max_length=150)
company = models.ForeignKey(Company, related_name="orders", on_delete=models.CASCADE)
contact = models.ForeignKey(Contact, related_name="orders", on_delete=models.SET_NULL, blank=True, null=True)
total = models.DecimalField(max_digits=18, decimal_places=9)
order_date = models.DateTimeField(null=True, blank=True)
added_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
def __str__(self):
return "%s" % self.order_number
views.py
from django.shortcuts import render
# Create your views here.
from django.views.generic import ListView
from mailer.models import Company, Contact, Order
class IndexView(ListView):
template_name = "mailer/index.html"
model = Company
paginate_by = 100
The html
<div class="container">
<table class="table table-borderless">
{% if is_paginated %}
<tr><td>
{% if page_obj.has_previous %}
«
{% endif %}
</td>
<td></td>
<td></td>
<td>
{% if page_obj.has_next %}
»
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<th>Name</th>
<th>Order Count</th>
<th>Order Sum</th>
<th>Select</th>
</tr>
{% for company in company_list %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.get_order_count }}</td>
<td>{{ company.get_order_sum|floatformat:2 }}</td>
<td><input type="checkbox" name="select{{company.pk}}" id=""></td>
</tr>
{% for contact in company.contacts.all %}
<tr>
<td> </td>
<td>{{ contact.first_name }} {{ contact.last_name }}</td>
<td>Orders: {{ contact.get_order_count }}</td>
<td></td>
</tr>
{% endfor %}
{% endfor %}
</table>
</div>
Is there any way in which I can reduce the initial load time. Please show me an efficient way to solve this problem.
Each {{company.get_order_count}} will hit the DB. Admittedly with a very simple query, but even so, it will slow things down.
You want to annotate the objects with this count. Use
from django.db.models import Count
class IndexView(ListView):
template_name = "mailer/index.html"
model = Company
paginate_by = 100
def get_queryset(self):
return super().get_queryset().annotate( num_orders=Count('orders') )
and replace {{ company.get_order_count }} with {{ company.num_orders }}. This will turn N+1 DB queries into one DB query.
That's the easy one. There's a similar problem with get_order_sum which can almost certainly be solved with another annotation involving the django.db.Sum. Sorry but its late and my stomach is growling and I don't have any confidence that I would get that one right straight off the top of my head.
The cheat sheet on annotation is here. You might also need to look at aggregation.
Oh, and install Django_debug-toolbar in your developer environment. Every time in future it gets slow, you can just click there to see what SQL was executed and how long it took.

How to upload files based on primary key of foreignkey?

Basically I am trying to create an app which can allow user to upload lessons material such as documents on their specific posts. However, I am unsure of how I should display the documents uploaded based on the primary key of the posts. As of now, my posts are displaying all the documents that are being uploaded by the particular user.
This is my 'Post' model
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg', upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(default = 0)
def __str__(self):
return self.title
This is my 'Lesson' model
class Lesson(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="lesson/pdf")
date_posted = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lesson_upload', kwargs={'pk': self.pk})
This is my Class-based listview that is supposed to display the uploaded lessons based on the posts:
class LessonListView(ListView):
model = Lesson
template_name = 'store/uploaded_lesson.html'
context_object_name = 'lesson'
def get_queryset(self):
self.post = get_object_or_404(post, name=self.kwargs['post'])
return Lesson.objects.filter(post=self.post)
{% extends "store/base.html" %}
{% block content %}
<div id="main">
<table class="table mb-0">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Download</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for lesson in lesson %}
<tr>
<td>
{% if lesson.file %}
<img src="{{ lesson.file.url }}" style="width:100px;">
{% else %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
You will need another model for the material they are uploading. Something like:
class UploadedPostMaterial(models.Model):
content= models.TextField()
date_uploaded = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
This model will contain the uploaded data and tie it to a post. Now when you display all or specific Posts in your app, you can select the related content for each post and display the uploaded content.

Django -Help displaying content in nested for loop

I have a Requisition which may have multiple lines. So to implement this I included a unique_together constraint on two fields on the RequisitionLine model which one of the fields is a FK to Requisition . So naturally to pull all the lines of a requisition I would query the RequisitionLine table where the FK = the id of the Requisition model, then iterate over all the sequences to grab all the lines.
My goal is to display the header number with the lines of that requisition under the header in the template but am struggling to accomplish this. I have tried to iterate over the queryset but the code i am posting below is my most recent attempt trying pass lists to the template which is also not working. Right now each header is showing all the lines. Any help would be appreciated.
Models.py
class Requisition(models.Model):
username = models.ForeignKey(
'users.CustomUser', on_delete=models.CASCADE, related_name='req_user')
signature = models.CharField(max_length=10, blank=True, null=True)
class RequisitionLine(models.Model):
parent_req = models.ForeignKey('Requisition', on_delete=models.CASCADE, related_name='par_req_line' )
sequence = models.PositiveIntegerField()
item_code = models.ForeignKey(
'items.ItemMaster', on_delete=models.CASCADE, related_name='req_item', blank=True, null=True)
description = models.CharField(max_length=50, blank=True)
extra_information = models.TextField(blank=True)
quantity = models.PositiveIntegerField(blank=True, default=0,null=True)
price = models.DecimalField(max_digits=19, decimal_places=2, blank=True, default=0.00,null=True)
purchase_order = models.CharField(max_length=9, blank=True,null=True)
po_line = models.PositiveSmallIntegerField(blank=True,null=True)
req_delivery_date = models.DateField(blank=True,null=True)
act_delivar_date = models.DateField(blank=True, null=True)
status = models.ForeignKey('RequisitionStatus', related_name='req_status', on_delete=models.CASCADE, blank=True, null=True)
assistance = models.ForeignKey('users.UserRoles', related_name='req_assist', blank=True, null=True, on_delete=models.CASCADE, limit_choices_to= ~Q(role='Requestor'))
catagory = models.ForeignKey('items.ItemCatagory', on_delete=models.CASCADE, related_name='line_cat', blank=True, null=True)
notes = models.TextField(blank=True)
class Meta:
unique_together = ('parent_req','sequence')
Views.py
def pending_action(request):
user = CustomUser.objects.get(username=request.user)
user_req_headers = Requisition.objects.filter(username=user)
complete_status = RequisitionStatus.objects.get(status='Completed')
req_line_list = []
for req_header in user_req_headers:
req_lines = RequisitionLine.objects.filter(Q(parent_req = req_header) & ~Q(status=complete_status))
req_line_list.append(req_lines)
return render(request, 'req/pending_action.html', {'user_req_headers':user_req_headers,'req_line_list':req_line_list})
pending_action.html
{% for header in user_req_headers %}
<h3>{{header}}</h3>
{% for req_line in req_line_list %}
{% for req in req_line %}
<table>
{% if forloop.first %}
<tr>
<th>description</th>
<th>catagory</th>
</tr>
{% endif %}
<tr>
<!-- FOR LOOP HERE TO ITERATE OF LIST OF QUERYSETS-->
<td>{{ req }}</td>
</tr>
</table>
{% endfor %}
{% endfor %}
{% endfor %}
I solved this problem by creating a queryset of the header and using a reverse relationship to capture the lines associated with each header
<table class="table">
{% for req_header in req_header_list %}
<tr>
<ul>{{ req_header }}
{% for line in req_header.par_req_line.all %}
<li>{{line}}</li>
{% endfor %}
</ul>
</tr>
{% endfor %}
</table>

How to get a value from related object in a django template

I'm quite new with python and django and I apologize if the topic was already covered, but I coudln't find an answer to my question.
I have theese classes in my models.py
class Category(models.Model):
category_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.category_type
class Area(models.Model):
area_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.area_type
class Topic(models.Model):
topic_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.topic_type
class Tag(models.Model):
tag_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.tag_type
class GenericRecord(models.Model):
document_title = models.CharField(max_length=500)
category = models.ForeignKey("Category")
area = models.ForeignKey("Area")
topic = models.ForeignKey("Topic")
tag = models.ForeignKey("Tag")
note = models.TextField(null=True, blank=True)
link = models.TextField(null=True, blank=True)
file_upload = models.FileField(upload_to='GenericRecord/', null=True, blank=True)
class Meta:
abstract = True
class Document(GenericRecord):
code = models.CharField(max_length=500, null=True, blank=True)
reference = models.CharField(max_length=500)
issue_date = models.DateField(auto_now=False, auto_now_add=False)
validation_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
def get_admin_url(self):
return reverse("admin:%s_%s_change" % (self._meta.app_label, self._meta.model_name), args=(self.id,))
def __unicode__(self):
if self.code:
return "%s-%s" % (self.code, self.document_title)
else:
return "--%s" % self.document_title
And this piece of code in views.py
def documents_list(request):
# Generate counts of some of the main objects
num_docs=Document.objects.all().count()
docs=Document.objects.all()
num_articles=Article.objects.all().count()
articles=Article.objects.all()
template='documents_management.html'
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
# Render the HTML template documents_management.html with the data in the context variable
return render(request,template, context={'docs':docs, 'num_docs':num_docs,'docs':docs, 'num_articles':num_articles, 'articles':articles})
In the template I'm trying to get a table with all the values, but for the related objects I get the primary key (of course).
Here is the code in my template:
<table class="w3-table-all">
{% for object in docs %}
{%if forloop.first %}
<tr>
{% for field, value in object.fields.iteritems %}
<th>{{ field }}</th>
{% endfor %}
</tr>
{%endif%}
{% endfor %}
{% for object in docs %}
{% for field, value in object.fields.iteritems %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
What I see in my browser
My question is, how can I get the object Category, Area etc... in order to get the category_type, area_type etc. value?
Thanks!
Here is an great example from the docs: https://docs.djangoproject.com/en/1.11/intro/tutorial03/#use-the-template-system
What you are searching for is the question.choice_set.all part.
UPDATE due to a hint of bad style
As mentioned by daniel you should ditch the Field.to_value_string method.
Since I am not a fan of implicit code I always recommend to code templates as explicit as possible, here would by my version of your template
<table class="w3-table-all">
{% for doc in docs %}
{% if forloop.first %}
<tr>
<th>Document Title</th>
<th>Category Type</th>
<th>Area Type</th>
<th>...</th>
</tr>
{% else %}
<tr>
<td>{{ doc.document_title }}</td>
<td>{{ doc.category.category_type }}</td>
<td>{{ doc.area.area_type }}</td>
<td>...</td>
</tr>
{% endif %}
{% endfor %}
</table>
What I changed:
only one for loop, you started with the if forloop.first you might also finish with the else case
refactored object to doc because objects is used often within django for model managers
add the fields explicit doc.area.area_type, this will prevent a new field in the model to also appear in the template but here I recommend an explicit over an implicit coding style
Also you can remove this from document_list:
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
The problem is in your use of Field.value_to_string. As the docstring on that method shows, this is for serialization, not for displaying values.
A much simpler and more effective way of doing this would be to use getattr, which gets the actual value; the template will then take care of converting those to a string, which in the case of the foreign keys will call the __unicode__ method of the related objects.
object.fields = dict((field.name, getattr(obj, field.name)) for field in object._meta.fields)

Filtering date within daterange and show data of one template to another template in django

I have created many sitting dates by using following Sitting model:
class Sitting(models.Model):
sit_date = models.DateField(blank=False,unique=True)
cut_off_date = models.DateField(null=True, blank=True)
ballot_date = models.DateField(null=True, blank=True)
sess_no = models.ForeignKey(Session,
on_delete=models.CASCADE)
genre = TreeForeignKey('Genre', null=True, blank=True, db_index=True, unique=True)
Output of sitting template as following format:
I also designed another model named Circular:
class Circular(models.Model):
cir_no = models.IntegerField(blank=False)
sit_start_date = models.DateField(blank=False)
sit_end_date = models.DateField(blank=False)
sess_no = models.ForeignKey(Session,
on_delete=models.CASCADE)
parl_no = models.ForeignKey(Parliament,
on_delete=models.CASCADE)
class Meta:
unique_together = ('cir_no', 'sess_no',)
Using Circular model I will create different circulars. Suppose I will create Circular no-1 for the period of 31 August to 30 September 2016. In this case When I will view circular no-1 it will only shows those sittings that are between above mentioned dates inclusive. And this circular will also contain the above mentioned Ministry/Division table. Should I include the sitting template in the circular template?
How can I do that. Any help will be much appreciated.
Edit:
Here is sitting_list.html template:
{% block content %}
<table cellpadding="10">
<tr>
<th>Sitting Day & Date</th>
<th>Ministry/Division</th>
</tr>
{% for sitting in sittings %}
<tr>
<td> {{ sitting.sit_date|date:"l, d F, Y" }}</td>
<td>
{% for genre in sitting.genre.get_descendants %}
{{ genre }},
{% endfor %}
<p>(Ballot: {{ sitting.ballot_date}})</p>
</td>
</tr>
{% endfor %}
</table>
{% endblock content %}
I'm not sure if i completely understand you right. But one way to get sittings for the period of a circular (without an explicit model relation) could look as this:
class Circular(models.Model):
# ...
sit_start_date = models.DateField(blank=False)
sit_end_date = models.DateField(blank=False)
# ...
#property
def sittings(self):
qs = Sitting.objects.filter(sit_date__gte=self.sit_start_date, sit_date__lte=self.sit_end_date)
return qs
Then you can use this propperty on a 'circular' instance:
c = Circular.objects.get(pk=1)
c.sittings