I am working on a Django project with 2 Models; Customer and Deposit and I want to display a list of Customers with their names, deposited dated, account number, and Total Deposited within the year so how do I do it the right way.
See what I have tried but Couldn't get the Customers' name in my Django Templates.
Models:
class Customer(models.Model):
surname = models.CharField(max_length=10, null=True)
othernames = models.CharField(max_length=20, null=True)
account_number = models.CharField(max_length=10, null=True)
address = models.CharField(max_length=50, null=True)
phone = models.CharField(max_length=11, null=True)
date = models.DateTimeField(auto_now_add=True, null=True)
#Get the url path of the view
def get_absolute_url(self):
return reverse('customer_create', args=[self.id])
#Making Sure Django Display the name of our Models as it is without Pluralizing
class Meta:
verbose_name_plural = 'Customer'
#
def __str__(self):
return f'{self.surname} {self.othernames} - {self.account_number}'
class Deposit(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True)
acct = models.CharField(max_length=6, null=True)
staff = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
deposit_amount = models.PositiveIntegerField(null=True)
date = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self):
return reverse('create_account', args=[self.id])
def __str__(self):
return f'{self.customer} Deposited {self.deposit_amount} by {self.staff.username}'
here is my view code:
def customer_list(request):
#Get Current Date
current_date = datetime.now().date()
#Get Current Month Name from Calendar
current_month_name = calendar.month_name[date.today().month]
group_deposits = Deposit.objects.filter(date__year=current_date.year).order_by('acct')
grouped_customer_deposit = group_deposits.values('acct').annotate(total `=Sum('deposit_amount')).order_by()`
context = { 'customers':grouped_customer_deposit,}
Here is how I tried to display the result in Django Template:
{% for deposit in customers %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ deposit.acct }}</td>
<td>{{ deposit.customer.surname }}</td>
<td>{{ deposit.total }}</td>
<td>{{ customer.deposit.date }}</td>
<th scope="row"><a class="btn btn-info btn-sm" href=" ">Deposit</a></th>
</tr>
{% endfor %}
Someone should graciously help with the most efficient way of getting the Total Deposit for each customer with their names, account number, and date deposited. Thank in anticipation for your kind answers.
As you are using the values method:
grouped_customer_deposit = group_deposits.values('acct').annotate(total `=Sum('deposit_amount')).order_by()`
Django will return a queryset that returns dictionaries rather than model instances. See Django Queryset API reference for more details.
This means that you cannot reference your model relationships as you are trying to do here:
<td>{{ deposit.customer.surname }}</td>
as that information will not be in the dictionary passed to the template (you can do a print of grouped_customer_deposit in your view, or display it in your template -- {{ customers }} -- to see what I mean).
Ergo, if you remove your call to values() then your template will receive model instances which should solve your problem, and make your template work as-is.
grouped_customer_deposit = group_deposits.annotate(total `=Sum('deposit_amount')).order_by()`
(Although your syntax for your annotate is not correct, so I'm assuming that was a mistake when you pasted your code here.)
Related
Please i would like anyone to help me out, tryna grouping this student result from the lecturer session so that lecturer can view each student based on the course student submitted i have successfully get a list but the list are not grouped by the student ids
here is the view for lecturer request
class LecturerListOfStudentResult(View):
def get(self, request, *args, **kwargs):
lecturer = Lecturers.objects.get(admin=request.user.id)
result = LecturerCourse.objects.filter(lecturer=lecturer)
context = {
'question':result,
}
return render(request, 'superadmin/lecturer/list-result-
student.html', context)
Here is the list of all submitted student result view
class ListAllSubmittedAnswerByCourseRegister(View):
def get(self, request, *args, **kwargs):
lecturer = Lecturers.objects.get(admin=request.user.id)
result = StudentSubmittedAnswer.objects.filter(lecturer=lecturer,
student=int(kwargs['id']))
context = {'question':result}
return render(request, 'superadmin/lecturer/list-all-result-
student.html', context)
here is the detailview for the list which i only get the count record
class LecturerListOfStudentResultDetail(View):
def get(self, request, *args, **kwargs):
student = Students.objects.get(admin=int(kwargs['id']))
result = StudentSubmittedAnswer.objects.filter(student=student)
skipped = StudentSubmittedAnswer.objects.filter(student=student,
right_answer='Not Submitted').count()
attempted = StudentSubmittedAnswer.objects.filter
(student=student).exclude(right_answer='Not Submitted').count()
rightAns=0
percentage=0
for row in result:
if row.question.right_opt == row.right_answer:
rightAns+=1
if len(result) > 0:
percentage=(rightAns*100)/result.count()
return render(request, 'superadmin/lecturer/view-result-
detail.html', {'result': result,'total_skipped':
skipped,'attempted': attempted, 'rightAns': rightAns,
'percentage':percentage})
Here is my url.py
path('lecturer/course/registration',
LecturerCourseRegistration.as_view(), name="lecturer-course-
registration"),
path('list/lecturer/course/registration',
ListLecturerCourseRegistration.as_view(), name="list-lecturer-
course-registration"),
path('list/submitted/course/answer/student/<int:id>/',
ListAllSubmittedAnswerByCourseRegister.as_view(), name="list-all-
submitted-course-question-by-student"),
here is the list of student html
{% for r in question %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ r.course.name }}</td>
<td>{{ r.created_at }}</td>
<td><a href="{% url 'emisapp:list-all-submitted-course-
question-by-student' r.lecturer.admin.id %}">View</a></td>
{% endfor %}
Here is the html view for looping all the exam submitted for each student
{% for row in result %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ row.course.name }}</td>
<td>{{ row.question.question }}</td>
<td>{{ row.question.right_opt }}</td>
{% if row.question.right_opt == row.right_answer %}
<td class="bg-success text-white">{{ row.right_answer }}</td>
{% else %}
<td class="bg-danger text-white">{{ row.right_answer }}</td>
{% endif %}
</tr>
{% endfor %}
Models.py
class StudentSubmittedAnswer(models.Model):
id = models.AutoField(primary_key=True)
course = models.ForeignKey(Courses)
lecturer = models.ForeignKey(Lecturers)
question = models.ForeignKey(QuizQuestion)
student = models.ForeignKey(Students)
right_answer = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True, null=True)
Here is my added Models.py
class StudentSubmittedAnswer(models.Model):
id = models.AutoField(primary_key=True)
lecturercourse = models.ForeignKey(LecturerCourse, null=True,
related_name='studentsubmittedanswer', on_delete=models.CASCADE)
lecturer = models.ForeignKey(Lecturers, null=True,
related_name='studentsubmittedanswer', on_delete=models.CASCADE)
question = models.ForeignKey(QuizQuestion,
related_name='studentsubmittedanswer', on_delete=models.CASCADE)
student = models.ForeignKey(Students,
related_name='studentsubmittedanswer', null=True,
on_delete=models.CASCADE)
right_answer = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True, null=True)
class Faculty(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
slug = models.SlugField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
objects = models.Manager()
class Department(models.Model):
id = models.AutoField(primary_key=True)
faculty = models.ForeignKey(Faculty, default=None)
name = models.CharField(max_length=255)
slug = models.SlugField(null=True)
short_desc = models.TextField(null=True, blank=True)
class Courses(models.Model):
id = models.AutoField(primary_key=True)
faculty = models.ManyToManyField(Faculty, related_name='courses')
department = models.ManyToManyField(Department)
name = models.CharField(max_length=255)
slug = models.SlugField()
short_desc = models.TextField(blank=True, null=True)
long_desc = models.TextField(blank=True, null=True)
class StudentFaculty(models.Model):
id = models.AutoField(primary_key=True)
student = models.ForeignKey(Students, null=True)
studentfaculty = models.ForeignKey('Faculty')
slug = models.SlugField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class StudentDepartment(models.Model):
id = models.AutoField(primary_key=True)
student = models.ForeignKey(Students)
studentfaculty = models.ForeignKey(StudentFaculty)
studentdepartment = models.ForeignKey(Department)
slug = models.SlugField(null=True)
class StudentCourses(models.Model):
id = models.AutoField(primary_key=True)
student = models.ForeignKey(Students)
studentfaculty = models.ForeignKey(StudentFaculty)
studentdepartment = models.ForeignKey('StudentDepartment')
studentcourse = models.ForeignKey(Courses)
class QuizQuestion(models.Model):
id = models.AutoField(primary_key=True)
lecturer = models.ForeignKey(Lecturers)
faculty = models.ForeignKey(LecturerFaculty, null=True)
lecturerdepartment = models.ForeignKey(LecturerDepartment, null=True)
lecturercourse = models.ForeignKey(LecturerCourse)
session = models.ForeignKey(SessionYearModel)
semester = models.ForeignKey(Semester, null=True)
mark = models.IntegerField(null=True)
examtype = models.ForeignKey('ExamType', related_name='quizzes')
question = models.TextField()
opt_1 = models.CharField(max_length=255)
opt_2 = models.CharField(max_length=255)
opt_3 = models.CharField(max_length=255)
opt_4 = models.CharField(max_length=255)
class LecturerFaculty(models.Model):
id = models.AutoField(primary_key=True)
lecturer = models.ForeignKey('Lecturers',
related_name='lecturerfaculty', null=True, on_delete=models.CASCADE)
faculty = models.ForeignKey('Faculty')
slug = models.SlugField(null=True)
class LecturerDepartment(models.Model):
id = models.AutoField(primary_key=True)
lecturer = models.ForeignKey('Lecturers')
lecturerfaculty = models.ForeignKey('LecturerFaculty')
lecturerdepartment = models.ForeignKey('Department')
class LecturerCourse(models.Model):
id = models.AutoField(primary_key=True)
lecturer = models.ForeignKey('Lecturers')
faculty = models.ForeignKey('Faculty')
lecturerdepartment = models.ForeignKey('LecturerDepartment')
lecturercourse = models.ForeignKey('Courses')
slug = models.SlugField(null=True)
class Lecturers(models.Model):
id = models.AutoField(primary_key=True)
admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
profile_pic = models.ImageField(default='default.jpg')
middle_name = models.CharField(max_length=255)
You can use values and annotate to group by student Ids.
class ListAllSubmittedAnswerByCourseRegister(View):
def get(self, request, *args, **kwargs):
lecturer = Lecturers.objects.get(admin=request.user.id)
=> result = StudentSubmittedAnswer.objects.values('student','lecturer').annotate(answers_count=Count('answers')).filter(lecturer=lecturer,
student=int(kwargs['id'])).order_by()
context = {'question':result}
return render(request, 'superadmin/lecturer/list-all-result-
student.html', context)
I assumed the name of the fields in the model student answers lecturer
Refrence
Django documentation: values(), annotate(), and Count
Django documentation: Aggregation, and in particular the section entitled Interaction with default ordering or order_by()
https://docs.djangoproject.com/en/4.0/topics/db/aggregation/#order-of-annotate-and-values-clauses
I have gathered data from two tables that is Orders and Purchases (joined) and saved that in dictionary, when I'm printing the qty on the console its giving me the value but when I'm trying to print the values on template it not showing up however columns from the orders table like first name last name status address is shown on the template but qty and product from the purchases table is not showing up on the template but can be easily printed on console
can somebody help???
Models.py
Dispatcher = models.ForeignKey(Dispatchers , null=True, on_delete=models.SET_NULL )
Firstname = models.CharField(max_length=200 , null=True)
Lastname = models.CharField(max_length=200 , null=True)
Email = models.CharField(max_length=200 , null=True)
Address = models.CharField(max_length=200 , null=True)
Country = models.CharField(max_length=200 , null=True)
State = models.CharField(max_length=200 , null=True)
status = models.CharField(max_length=200 , null=True)
def __str__(self):
return self.Lastname
class purchases(models.Model):
orders_id = models.ForeignKey(Orders , null=True, on_delete=models.SET_NULL )
product = models.CharField(max_length=200 , null=True)
qty = models.CharField(max_length=200 , null=True)
price = models.CharField(max_length=200 , null=True)
def __str__(self):
return self.product
views.py file
dispatcherOrders = {}
orders = request.user.dispatchers.orders_set.all()
for order in orders:
dispatcherOrders[order] = purchases.objects.get(orders_id = order.id)
print(dispatcherOrders[order].qty)
return render(request , 'dispatcherOrders.html',{'dispatcherOrders' : dispatcherOrders})
dispatcherOrders.html
{%for Orders in dispatcherOrders%}
<tr>
<th scope="row">1</th>
<td>{{Orders.Firstname}}</td>
<td>{{Orders.Lastname}}</td>
<td>{{Orders.Address}}</td>
<td>{{Orders.product}}</td>
<td>{{Orders.qty}}</td>
<td>{{Orders.status}}</td>
</tr>
{% endfor %}
In your code, dispatcherOrders dictionary keys are orders and dictionary values are purchases:
dispatcherOrders[order] = purchases.objects.get(orders_id = order.id)
yet you are iterating only on dictionary keys, the orders:
{%for Orders in dispatcherOrders%}
To get the info from purchases, iterate the dictionary items too.
So your template code should be similar to
{%for Orders, Purchase in dispatcherOrders.items %}
<tr>
<th scope="row">1</th>
<td>{{Orders.Firstname}}</td>
<td>{{Orders.Lastname}}</td>
<td>{{Orders.Address}}</td>
<td>{{Purchase.product}}</td>
<td>{{Purchase.qty}}</td>
<td>{{Purchase.status}}</td>
</tr>
{% endfor %}
Here's how .items work: https://stackoverflow.com/a/6285769/3694363
I am struggling to get current remaining stock in my inventory application.
I have written code to calculate remaining quantity but it calculates based on purchased quantity only. I want to add total sold quantity and find the difference between purchased and total sold quantity.
How do I calculate total sold quantity and calculate the remaining stock.
models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=100)
price = models.DecimalField(max_digits=6, decimal_places=2)
quantity = models.IntegerField(null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.name
class Stock(models.Model):
sold_quantity = models.IntegerField(null=True, blank=True, default=0)
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.product.name
#property
def get_difference(self):
total = self.product.quantity-self.sold_quantity
return total
Views.py
def add_sales(request):
form = AddSalesForm()
if request.method == 'POST':
form = AddSalesForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.product.quantity -= instance.sold_quantity
instance.save()
return redirect('stock_details')
contex = {'form': form}
return render(request, 'stockmgmt/add_sales.html', contex)
templates
{% extends 'stockmgmt/base.html' %}
{% block content %}
<form method="GET">
Add Sales
<p>
<table class="table table-bordered">
<tr>
<th>Item</th>
<th>Category</th>
<th>Purchased Qty</th>
<th>Sold Qty</th>
<th>Remaining Qty</th>
<th>Price</th>
<th>Action</th>
</tr>
{% for item in stocks %}
<tr>
<td>{{item.product.name}}</td>
<td>{{item.product.category}}</td>
<td>{{item.product.quantity}}</td>
<td>{{item.sold_quantity}}</td>
<td>{{item.get_difference}}</td>
<td>{{item.product.price}}</td>
<td>Delete
Edit
</td>
</tr>
{% endfor %}
</table>
</form>
{% endblock %}
you need to update the existing stock after each order
for ex.
opening stock = 100
current stock = 100
after first order of 10 qty
opening stock = 100
current stock = current stock - order qty = 100 - 10 = 90
after second order of 5 qty
opening stock = 100
current stock = current stock - order qty = 90 - 5 = 85
if i purchase or add new stock the current stock will be updated
after adding 50 qty
current stock = current stock + purchase qty = 85 + 50 = 135
you can have a log table (Model) for income and outgoing of stock for tracking
hope you understand the concept i'm trying to explain
I am trying to get details of two querysets and display on my datatable. I can display details of first queryset but not of the second which is also dependent on the first queryset.
My views.py function;
def truck_list(request):
q_data = quar_contacts.objects.all().filter(.....)
hot_details = []
for d in q_data:
h_details = truck_contacts.objects.filter(p_contacts=d.id)
hot_details.append(h_details)
my_list_data = zip(q_data, hot_details)
data = {'quar_data': my_list_data}
return render(request, 'syst/truck_list.html', data)
I can print out details of the zip list as a tuple i.e data = tuple(my_list_data) and see the data.
Then my truck_list template on the datatable body section :
<tbody>
{% for q_data, hot_details in quar_data %}
<tr>
<td>{{ q_data.last_name }}</td>
<td>{{ q_data.first_name }}</td>
<td>{{ q_data.age }}</td>
<td>{{ q_data.sex }}</td>
<td>{{ q_data.phone_number }}</td>
<td>{{ hot_details.hotel_name}}</td>
<td>{{ hot_details.date_check_in }}</td>
<td>{{ hot_details.created_by }}</td>
</tr>
{% endfor %}
</tbody>
How can i get the hot_details (hotel_name and date_checked_in) displayed on my datatable. How can I loop for each contact what hotel details are there.
Is there an easier way of achieving this?
My Models:
class quar_contacts(models.Model):
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=50)
dob = models.DateField(default=date.today)
passport_number = models.CharField(max_length=50, blank=True)
created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='quar_updated_by')
class truck_contacts(models.Model):
patient_contacts = models.ForeignKey(quar_contacts, on_delete=models.DO_NOTHING, related_name='truck_contact')
vehicle_registration = models.CharField(max_length=50, blank=True)
company_name = models.CharField(max_length=50, blank=True)
hotel = models.CharField(max_length=50, blank=True)
hotel_town = models.CharField(max_length=50, blank=True)
date_check_in = models.DateField(default=date.today)
date_check_out = models.DateField(default=date.today)
Also, how do you get the 'created_by' value which is a foreign key of the Users table?
You can use annotate to add additional fields to each object from quar_contacts queryset. I don't know your db schema, but if "quar contact" has a foreign key to "truck contact" it can be something like that:
from django.db.models import F
q_data = quar_contacts.objects.all().filter(.....).annotate(
hotel_name=F("your_relation_name__hotel_name"),
date_check_in=F("your_relation_name__date_check_in"),
)
Then you can access hotel_name and date_check_in just like other fields from this objects.
Please let me know if it's helpful. If you have different relation between those models I'll update my answer.
Using "annotate" I have managed to to add the fields the other way. getting 'truck_contacts' queryset then look for the parent field values 'quar_contacts'. Thanks to #rafaljusiak idea above.
all_data = truck_contacts.objects.all().annotate(
first_name=F("patient_contacts__first_name"),
last_name=F("patient_contacts__last_name"),
sex=F("patient_contacts__sex"),
age=F("patient_contacts__dob"),
passport_number=F("patient_contacts__passport_number"),
phone_number=F("patient_contacts__phone_number"),
created_by=F("patient_contacts__created_by"),
)
But am still struggling how to display 'created by' being a foreign key of Users table
Im trying to join two tables together before being sent to a view, using _set in a view causes 100s of queries which is highly inefficient.
example structure sites.models.py
class SiteData(models.Model):
location = models.CharField(max_length=50)
site_type = models.ForeignKey(SiteTypes, verbose_name="Site Type", \
on_delete=models.PROTECT)
bgp_as = models.CharField(max_length=6, verbose_name="BGP AS Number")
opening_date = models.DateField(verbose_name="Site opening date")
last_hw_refresh_date = models.DateField(verbose_name="Date of latest hardware refresh", \
blank=True, null=True)
is_live = models.BooleanField(default=False, verbose_name="Is this a live site?")
example structure config.models.py
class SiteSubnets(models.Model):
site_data = models.ForeignKey(SiteData, verbose_name="Location", \
on_delete=models.PROTECT, blank=True, null=True)
subnet = models.GenericIPAddressField(protocol='IPv4', \
verbose_name="Subnet", blank=True, null=True)
subnet_type = models.ForeignKey(SubnetTypes, verbose_name="Subnet Type")
vlan_id = models.IntegerField(verbose_name="Vlan ID", blank=True, null=True)
peer_desc = models.IntegerField(verbose_name="Peer description", blank=True, null=True)
site_ip = models.BooleanField(default=False, verbose_name="Is this a site supernet IP?")
class Meta:
verbose_name = "Site Subnets"
verbose_name_plural = "Site Subnets"
Queries:
site_subnets = SiteSubnets.objects.only('subnet').filter(site_ip=True)
site_data = SiteData.objects.only('location','is_live','bgp_as','postcode','opening_date','live_link_type')
Desired Outcome example:
Location | Subnet | BGP AS
---------------------------------
London | 10.10.10.0 | 65001
Manchester | 10.10.20.0 | 65002
...
I cant do a select_related without having the SitesSubnet table as the main table, as when I do it on site data, I get
django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'site_subnets'. Choices are: site_type
If I use the SiteSubnet as the main table, if a Site does not have a SiteSubnet.site_up I wont get the Site info. displayed
does anyone know a way around this that will display all the data and not run n+1 queries?
EDIT:
prefetch also fails with the below error:
AttributeError: Cannot find 'site_subnets_set' on SiteData object, 'site_subnets_set' is an invalid parameter to prefetch_related()
I would be sending the data to a template to be accessed in a loop i.e
<table>
<tr>
<td>Location</td>
<td>Subnet</td>
<td>BGP AS</td>
<tr>
{%for site in sitedata %}
<tr>
<td>{{ site.location }}</td>
<td>{{ site.subnet }}</td>
<td>{{ site.bg_as }}</td>
<tr>
{% endfor %}
Thanks
You can use prefetch_related to prefetch sitesubnets for the sitedata queryset.
SiteData.objects.prefetch_related('sitesubnets_set')