Django, Unable to view certain database information - django

I've been working on a project and I've been stuck for over a week and haven't been able to find the solution to this problem.
I'm creating a school management app. I've successfully allowed the teachers to create a schedule, allowed the students to view it and select it as part of their class. The problem I'm running into is that the teacher is not able to see the students information after they've chosen a class.
For models I have:
class Student(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
englishName = models.CharField(max_length=200)
studentName = models.CharField(max_length=200)
studentId = models.CharField(max_length=200)
birthday = models.DateField()
gender = models.CharField(max_length=6)
gradeLevel = models.CharField(max_length=8)
since = models.DateField()
duration = models.CharField(max_length=3)
contactNumber = models.CharField(max_length=13, default=00000000)
email = models.EmailField(max_length=200, default='address#email.com')
def __str__(self):
return self.studentName
def index(request):
data=Student
context = {'form': data}
return render(request, 'student-information.html', context)
class Schedule(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date = models.DateField(null = True, blank = True)
time = models.TimeField(null = True, blank = True)
duration = models.TextField(null = True, blank = True)
capacity = models.PositiveSmallIntegerField(default=1)
student = models.ForeignKey(Student, null = True, on_delete=models.CASCADE)
def __datetime__(self):
return self.date + '' + self.student
def index(request):
data = Schedule
context = {'form': data}
return render(request, 'set-schedule.html', context)
For my views file I have:
#login_required
#allowed_users(allowed_roles=['teacher'])
def dailySchedule(request):
today = datetime.now().date()
schedules = Schedule.objects.filter(date=today)
students = []
for schedule in schedules:
students.append(schedule.student)
context = {'today': datetime.now().date(), 'schedules': schedules, 'students': students}
return render(request, 'eslbeeph/daily-schedule.html', context)
and for the html file I have:
{% extends 'main.html' %}
{% block content %}
<div class="container-fluid">
<div class="daily-schedule-title">
<h3 class="daily-schedule-header">Schedule</h3>
</div>
<!--Information to be obtained by from the database.-->
<div class="daily-schedule-table">
<table class="daily-schedule">
<tr>
<th>Date</th>
<th colspan="6">{{ today|date:"F d, Y" }}</th>
</tr>
<tr>
<th>Start Time</th>
<th>Account</th>
<th>Duration</th>
<th>Student ID</th>
<th>Student Name</th>
<th>Class Status</th>
<th>Student Profile</th>
</tr>
{% for schedule in schedules %}
<tr>
<td>{{ schedule.time|date:"H:i" }}</td>
{% for student in students %}
<td>{{ schedule.student.user.username }}</td>
<td>{{ schedule.duration }}</td>
<td>{{ schedule.student.studentId }}</td>
<td>{{ schedule.student.englishName }}</td>
{% endfor %}
<td>{ status }</td>
<td></td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock content %}
Now, There's a lot more code to the project but these are the areas I think are causing the problem. I've tried a number of different things to get this to work, but nothing's worked.
If anyone can see where I'm going wrong or what I need to do let me know. I appreciate any help anyone can give me.
What I've been trying to do is get the a table to show up with the schedule time, the user name of the student who selected the schedule, the number of minutes the teacher stated the class would be, the students id number, and the students english name. The class status and the button for the students profile I plan to handle later.
Right now the time and the class length show up fine. But no matter what I do I cannot get the students user name, english name, and ID to populate at all.
Any tips, examples, or guesses as to why this is happening would be appreciated.
EDIT
After doing a bit more work I found that the Student model is not connecting to the Schedule model. So, the problem is different from what I originally suspected. It's not that the student information isn't being shown. It's that the schedule a student selects isn't recognizing the student has selected it.

Related

Django: Accessing full User information via ManyToMany field

everyone- I'm new to Django and working on my first big project and I'm having trouble with accessing default Django User model information via a ManyToMany relationship. I've spent a great deal of time searching and can't crack it.
models.py
class Event(models.Model):
event_name = models.CharField(max_length=200, null=True, unique=True)
#etc...
class School(models.Model):
user = models.ManyToManyField(User)
event = models.ForeignKey(Event, null=True, on_delete=models.PROTECT)
#etc...
My url contains the id of the Event, so...
views.py
def schools(request, pk):
event = Event.objects.get(id=pk)
school = School.objects.filter(event=event)
return render(request, 'accounts/schools.html', {'event':event, 'school':school})
template
{% for school in school %}
<tr>
<td>{{school.name}}</td>
<td>{{school.user.all}}</td>
{% endfor %}
On my template, I'm able to use {{school.user.all}} to get me a Queryset displayed with the username of each User, but I want the first_name and last_name and can't see to figure out how to get that..
Thank you for any suggestions. I greatly appreciate your time!
You should include both schools and users to your context.
You can do this with a dictionary. Add each school as a key, and users of each school as its values. Then you can pass this dictionary to your template.
View function:
def schools(request):
school_dict = dict()
schools = School.objects.all()
for school in schools:
school_dict[school] = school.user.all()
return render(request, 'accounts/schools.html', {'schools': school_dict})
And in your template:
{% for school, users in schools.items %}
<h3>{{ school.title }}</h3>
<table>
{% for user in users %}
<tr>
<td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
I was able to add this to my school model to get what I wanted:
def director(self):
test = ",".join([str(p) for p in self.user.all()])
user = User.objects.get(username=test)
return user.first_name + " " + user.last_name
HOWEVER: if there is more than one user associated with "School" it displays blank

How to get two models data in for loop with filter: Django

I do have two model as below, like patient details model and patient visit model. I want to list the visits of all patients (if exist). in views.py I am passing both models data by get all. how to filter and show it in the template by using for loop. I am using two for loop it shows total number of patient multiply total number of visit which is wrong..
class patientprofile(models.Model):
pat_Fname = models.CharField(max_length=100)
pat_Lname = models.CharField(max_length=100, blank=True)
def IntegerField(self):
return self.id
class visits(models.Model):
pat_ID = models.ForeignKey(patientprofile, on_delete=models.CASCADE)
visit_date = models.DateField(blank=False, null=False)
visit_time = models.TimeField(blank=False, null=False)
views.py
#login_requireddef visitslist(request):
patpro=patientprofile.objects.all()
vis=visits.objects.all()
return render(request, 'pmp/visitslist.html', {'vis':vis, 'patpro':patpro})
Template as below
{% for a in vis %}
<tr>
<td>
{{ a.visit_time }}
</td>
<td>{{ a.visit_date }}</td>
<td>{{ patpro.id }}</td>
<td>{{ patpro.pat_Fname }}</td>
</td>
</tr>
{% endfor %}
You can easily transform it into a dict object using values() function in queryset object.
for example:
merged_tables_dict = visits.objects.values('visit_date', 'visit_time', 'pat_ID__pat_Fname', 'pat_ID__pat_Lname')
That will return a list of objects with all data in values params
You can read more about it Django Docs values

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 can I capture the name or reg_no of the book in this list?

I'm working on a library system. I am unable to get the registration number of a book/books to be returned back to library...
My intention is to click on Return which captures the book name for return processing.. With what I have, when I print(book) it returns None meaning nothing has been taken from the click
My models
class Books(models.Model):
DEPARTMENT = (
('COM', 'Computer'),
('ELX', 'Electronics'),
('CIV', 'Civil'),
('BBS', 'Business'),
('MSC', 'Miscellaneous'),
)
reg_no = models.CharField(max_length=20, blank=True)
book_name = models.CharField(max_length=200)
no_of_books = models.IntegerField()
book_detail = models.TextField(default='text')
department = models.CharField(max_length=3, choices=DEPARTMENT)
def Claimbook(self):
if self.no_of_books>1:
self.no_of_books=self.no_of_books-1
self.save()
else:
print("not enough books to Claim")
def Addbook(self):
self.no_of_books=self.no_of_books+1
self.save()
def __str__(self):
return self.book_name
class Return(models.Model):
return_date = models.DateField(default=datetime.date.today)
borrowed_item = models.ForeignKey(Issue,on_delete=models.CASCADE)
def new_issue(request):
if request.method == 'POST':
i_form = IssueForm(request.POST)
if i_form.is_valid():
name = i_form.cleaned_data['borrower_id']
book = i_form.cleaned_data['book_id']
i_form.save(commit=True)
books = Books.objects.get(book_name=book)#Get a book names as selected in the dropdown
semest = Student.objects.get(name=name).semester#Get a student with a semester as selected in the dropdown
departm = Student.objects.get(name=name).depart
Books.Claimbook(books)
return redirect('new_issue')
else:
i_form = IssueForm()
semest = None
departm = None
sem_book = Semester.objects.filter(sem=semest, depart=departm)
return render(request, 'libman/new_issue.html', {'i_form': i_form, 'sem_book': sem_book})
The return view
def return_book(request):
book = request.GET.get('book_pk')
print(book)
books = Books.objects.get(id=book)
#b_id = r_form.cleaned_data['borrower_id']
Books.Addbook(books)
Issue.objects.filter(borrower_id=1, id=book).delete()
return render(request,'libman/view_issue.html',{'issue':issue})
The template that displays the borrowed books with a link to return beside each book.
{% if issue %}
<table class="layout">
<thead>
<th>Reg No.</th>
<th>Student Name</th>
<th>Book Name</th>
<th>Issue Date</th>
<th>Action</th>
</thead>
{% for borrow in issue %}
<tr>
<td>{{ borrow.borrower_id.student_id }}</td>
<td>{{ borrow.borrower_id }}</td>
<td>{{ borrow.book_id }}</td>
<td>{{ borrow.issue_date }}</td>
<td name='book_pk'>Return </td>
</tr>
{% endfor %}
</table>
{% else %}
<p> There are no books registered. </p>
{% endif %}
Issue model
class Issue(models.Model):
borrower_id = models.ForeignKey(Student,on_delete=models.CASCADE)
book_id = models.ForeignKey(Books,on_delete=models.CASCADE)
issue_date = models.DateField(default=datetime.date.today)
def __str__(self):
return str(self.book_id)
if i understood correctly - I believe you need to pass the borrow.book_id to the return view. so the return view knows which book you want return
in your template add the variable book_pk as follows
<td name='book_pk'>Return </td>
also you need to update your urls.py file to accept the new variable something like this
urlpatterns = [
path('returnbook/<book_pk>/', return_book),
]
but the above will need to also update your view function to handle the new passed argument and fetch the object etc..
def return_book(request,book_pk):
Or
you can add a form with a submit button
<form action="{% url 'return_book' %}">
<label for="book_id">Borrowed Book_id</label>
<input type="text" id="book_id" name="book_pk" value="{{ borrow.book_id }}" disabled><br><br>
<input type="submit" value="Submit">
</form>
it should work with your current code i think

Django: Two questions on extending ListView with get_context_data

I tried something similar to this. I have three models:
class PartBase(models.Model):
name = models.CharField('Name', max_length=120)
price = models.DecimalField("Price per part", decimal_places=2, max_digits=6)
class Sett(models.Model):
name = models.CharField('Name', max_length=120)
class PartRelation(models.Model):
part = models.ForeignKey(PartBase, on_delete=models.CASCADE)
qty = models.PositiveIntegerField("Quantity")
sett = models.ForeignKey(Sett, related_name='setts', on_delete=models.SET_NULL, null=True)
def get_position_price(self):
return self.qty * self.part.price
now I want to add the price of all the items in a Sett in a row in my HTML.
{% extends 'base.html' %}
{% block title %}
Add Set
{% endblock title %}
{% block content %}
<table class="table">
<tr>
<th>Set Name</th>
<th>Total price</th>
</tr>
{% for set in setts %}
<tr>
<td>{{ set.name }}</td>
<td>{{ set.test }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
I wanted to override the get_context_data method somehow like this:
class SetListView(ListView):
model = Sett
context_object_name = "setts"
def get_context_data(self,**kwargs):
context = super(SetListView, self).get_context_data(**kwargs)
context['test'] = "price"
return context
But I only get an empty field in the template (which I assumed would have the word "price".
I can access the price in the shell via
for s in Sett.objects.all():
pr = PartRelation.objects.filter(sett=s)
price = 0
for p in pr:
price += p.get_position_price()
But how would I put the code from the shell in the get_context_data() function, so that for every row I get the corresponding total price?
This did the trick:
class SetListView(ListView):
model = Sett
context_object_name = "setts"
def get_context_data(self, **kwargs):
context = super(SetListView, self).get_context_data(**kwargs)
for s in context["setts"]:
pr = PartRelation.objects.filter(sett=s)
s.total_price = 0
for p in pr:
s.total_price += p.get_position_price()
return context
I would gladly get feedback if that is a good approach (and why not/how to do better).