Django - Get objects which do NOT have any related objects - python

This may be a duplicate.
So I have:
class User(models.Model):
school = models.ForeignKey(School)
email = models.EmailField(max_length=254)
password = models.CharField(max_length=128)
firstname = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
middlenames = models.CharField(max_length=100, blank=True)
utype = models.CharField(max_length=1, choices=(('a','Administrator'),('t','Staff'),('s','Student')))
lastlogin = models.DateTimeField(null=True)
active = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
class Staff(User):
# Some methods
class Student(User):
form = models.CharField(max_length=20)
parentemail = models.EmailField(max_length=254)
parentphone = models.CharField(max_length=20)
class Placement(models.Model):
student = models.ForeignKey(Student)
email = models.EmailField(max_length=254)
name = models.CharField(max_length=100)
company = models.CharField(max_length=100)
position = models.CharField(max_length=50)
house = models.CharField(max_length=50)
street = models.CharField(max_length=50)
town = models.CharField(max_length=50)
county = models.CharField(max_length=50)
postcode = models.CharField(max_length=8)
phone = models.CharField(max_length=20)
length = models.IntegerField(null=True)
category = models.CharField(max_length=50)
date = models.DateField(null=True)
state = models.CharField(max_length=1, choices=(('A','In progress'),('B','Confirmed'),('C','Completed')))
created = models.DateTimeField(auto_now_add=True)
class Visit(models.Model):
placement = models.ForeignKey(Placement)
staff = models.ForeignKey(Staff)
date = models.DateField(null=True)
feedback = models.CharField(max_length=1000)
confirmed = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
And I want to retrieve all Placements which do not have any Visits (and the Student belongs to a particular School).
My views
def placements(request):
if request.session['utype'] == 't':
context['user'] = Staff.objects.get(pk=request.session['user'])
if request.method == 'POST':
placements = context['placements'] = Placement.objects.filter(student__school=school)
for choice in visits:
placement = Placement.objects.get(pk=choice)
visit = placement.NewVisit(user, placement.date, '', False)
visit.save()
return redirect('workxp:visits')
else:
context['placements'] = Placement.objects.filter(student__school=school, visit_set=None)
return render(request, 'workxp/staff/placements.html', context)
This is what I have so far from looking at other questions, but it doesn't seem to work...
no_visits = Placement.objects.filter(student__school=school_object, visit_set=None)
If I give a related name to the placement field in Visit, it works. Why not visit_set?

You need to use visit_set to reference the reverse relation since it's one to many
no_visits = Placement.objects.filter(student__school=school_object, visit_set=None)
or if you were to specify a nice related name...
class Visit(models.Model):
placement = models.ForeignKey(Placement, related_name='visits')
...
no_visits = Placement.objects.filter(student__school=school_object, visits=None)

Related

Django: How separate the data inside the model based on the user

I want to make an attendance system that prevents each user to see the attendance that some users have taken. But in my case, the attendance that the other users take can be shown by every user. How can I prevent this part? These are my codes: Models.py
class ClassAttendance(models.Model):
Faculty_Name = models.CharField(max_length=200, null=True, blank=True)
Student_ID = models.CharField(max_length=200, null=True, blank=True)
firstname = models.CharField(max_length=200, null=True, blank=True)
lastname = models.CharField(max_length=200, null=True, blank=True)
date = models.DateField(auto_now_add = True, null = True)
time = models.TimeField(auto_now_add=True, null = True)
college = models.CharField(max_length=200, null=True, blank=True)
course = models.CharField(max_length=200, null=True, blank=True)
year = models.CharField(max_length=200, null = True)
section = models.CharField(max_length=200, null = True)
subject = models.CharField(max_length=200, null = True)
status = models.CharField(max_length=200, null = True, default='Absent')
def __str__(self):
return str(self.Student_ID + "_" + str(self.lastname) + "_" + str(self.date)+ "_" + str(self.subject))
class Faculty(models.Model):
user = models.OneToOneField(User, null = True, blank = True, on_delete= models.CASCADE)
firstname = models.CharField(max_length=200, null=True, blank=True)
lastname = models.CharField(max_length=200, null=True, blank=True)
college = models.CharField(max_length=200, null=True, choices=COLLEGE)
course = models.CharField(max_length=200, null=True, choices=COURSE)
year = models.CharField(max_length=200, null=True, choices=YEAR)
section = models.CharField(max_length=200, null=True, choices=SECTION)
subject = models.CharField(max_length=200, null=True, choices=SUBJECT)
def str(self):
return str(self.firstname + " " + self.lastname)
class Meta:
verbose_name_plural = "Faculties"
views.py
#login_required(login_url = 'login')
def takeClassAttendance(request):
if request.method == 'POST':
details = {
'college':request.POST['college'],
'course':request.POST['course'],
'year': request.POST['year'],
'section':request.POST['section'],
'subject':request.POST['subject'],
'faculty':request.user.faculty
}
if ClassAttendance.objects.filter(date = str(date.today()), college = details['college'], course = details['course'], year = details['year'], section = details['section'],subject = details['subject']).count() != 0 :
messages.error(request, "Attendance already recorded.")
return redirect('home')
else:
students = Student.objects.filter(college = details['college'], course = details['course'], year = details['year'], section = details['section'])
names = Recognizer(details)
for student in students:
if str(student.student_id) in names:
classattendance = ClassAttendance(Faculty_Name = request.user.faculty,
Student_ID = str(student.student_id),
lastname = str(student.lastname),
firstname = str(student.firstname),
college = details['college'],
course = details['course'],
year = details['year'],
section = details['section'],
subject = details['subject'],
status = 'Present')
classattendance.save()
else:
classattendance = ClassAttendance(Faculty_Name = request.user.faculty,
Student_ID = str(student.student_id),
lastname = str(student.lastname),
firstname = str(student.firstname),
college = details['college'],
course = details['course'],
year = details['year'],
section = details['section'],
subject = details['subject'],)
classattendance.save()
classattendances = ClassAttendance.objects.filter(date = str(date.today()),college = details['college'], course = details['course'], year = details['year'], section = details['section'],subject = details['subject'])
context = {"attendances":classattendances, "ta":True}
messages.success(request, "Attendance taking success")
return render(request, 'attendance_sys/attendance.html', context)
context = {}
return render(request, 'attendance_sys/home.html', context)
def facultyProfile(request):
faculty = request.user.faculty
form = FacultyForm(instance = faculty)
context = {'form':form}
return render(request, 'attendance_sys/facultyForm.html', context)
I expected that after the users take attendance, they are the ones that can see that information
You can filter the returned objects by request.user.faculty.

Multiple For Loops Django

I have the following two models ASPBoookings and Athlete. The Athlete model is linked to the ASPBookings model by the foreign key named athlete.
I am trying to create a loop that will cycle through all of the bookings in the ASPBooking table and find out which is the most recent booking by each athlete (the table can contain multiple bookings each to the same or different athletes (athlete_id).
Once I have this information (booking_date and athlete_id), I then want to be able to automatically update the "Lastest ASP Session Field" in the Athlete Model.
This is what I have tried so far. I can cycle through the bookings in the ASPBookings table and retrieve and update the "Latest ASP Session Field" using the booking_date and athlete_id, but I cannot do this for multiple different athletes that are within the table. Currently the view just identifies the latest booking and the assigned athlete_id and then updates the field.
Thanks in advance for any help.
Below is the code:
ASPBookings Model
class ASPBookings(models.Model):
asp_booking_ref = models.CharField(max_length=10, default=1)
program_type = models.CharField(max_length=120, default='asp')
booking_date = models.DateField()
booking_time = models.CharField(max_length=10, choices=booking_times)
duration = models.CharField(max_length=10, choices=durations, default='0.5')
street = models.CharField(max_length=120)
suburb = models.CharField(max_length=120)
region = models.CharField(max_length=120, choices=regions, default='Metro')
post_code = models.CharField(max_length=40)
organisation_type = models.CharField(max_length=120,choices=organisation_types, default='Government School')
audience_number = models.CharField(max_length=10)
presentation_form = models.CharField(max_length=120, choices=presentation_form_options, default='Face to Face')
contact_name = models.CharField(max_length=80)
email = models.EmailField()
phone_number = models.CharField(max_length=120)
comments = models.TextField()
status = models.CharField(max_length=80, choices=statuses, default='TBC')
email_sent = models.BooleanField(default=False)
athlete = models.ForeignKey(Athlete, default= '1', on_delete=models.CASCADE)
def __str__(self):
return self.contact_name
# return URL after the POST has been submitted.
def get_absolute_url(self):
return reverse('vistours:success')
Athlete Model
class Athlete(models.Model):
athlete_ref = models.CharField(max_length=10, default=1)
athlete_name = models.CharField(max_length=80)
email = models.EmailField()
phone_number = models.CharField(max_length=120)
home = models.CharField(max_length=120)
education = models.CharField(max_length=120)
sport = models.CharField(max_length=120, choices=sports, default='1500m Runner')
notes = models.TextField(default='None')
gender = models.CharField(max_length=120, choices=genders, default='Not Specified')
para_athlete = models.BooleanField(blank=True)
working_with_children = models.BooleanField(blank=True)
expiry_date = models.DateField(blank=True, null=True)
available = models.BooleanField(blank=True)
available_from = models.DateField(blank=True, null=True)
bfbw = models.BooleanField(blank=True)
latest_bfbw_session = models.DateField(blank=True, null=True)
number_bfbw_sessions = models.CharField(blank=True, null=True, max_length=10)
asp = models.BooleanField(blank=True)
latest_asp_session = models.DateField(blank=True, null=True)
number_asp_sessions = models.CharField(blank=True, null=True, max_length=10)
tours = models.BooleanField(blank=True)
latest_tours_session = models.DateField(blank=True, null=True)
number_tours_sessions = models.CharField(blank=True, null=True, max_length=10)
def __str__(self):
return self.athlete_name
# return URL after the POST has been submitted.
def get_absolute_url(self):
return reverse('home')
View
# Complete first loop for inital values.
for date in asp_data:
if date.booking_date != None:
first_loop = date.booking_date
athl_id = date.athlete_id
break
# If next value is greater than inital value, replace current values.
for date in asp_data:
if date.booking_date != None:
if date.booking_date > first_loop:
first_loop = date.booking_date
athl_id = date.athlete_id
print(first_loop)
print(athl_id)
update_date = Athlete.objects.get(id=athl_id)
update_date.latest_asp_session = first_loop
update_date.save()
No need for loops. You can do this for all athletes in just one go using subqueries to leave all the heavy-lifting to your database:
from django.db.models import F, OuterRef, Subquery
bookings = ASPBookings.objects.filter(
athlete=OuterRef('pk')
).order_by('-booking_date')
Athlete.objects.annotate(
latest_asp_booking_date=Subquery(
bookings.values('booking_date')[:1]
)
).update(
latest_asp_session=F('latest_asp_booking_date')
)

Need help in adding Foreign key using django models

Okay so I don't know how to frame this.
I have two models Employee and Customer. I am storing the Employee as foreign key in Customer model under emp_id. The epm_id stores the primary key of the employee who admits the customer. I am not sure how to do this in django.
Here are my models:
class Customer(models.Model):
firstname = models.CharField(max_length=15)
lastname = models.CharField(max_length=15)
age = models.IntegerField()
sex = models.CharField(max_length=10)
phoneno = models.IntegerField()
emailid = models.CharField(max_length=25)
address = models.CharField(max_length=50)
children = models.IntegerField()
adults = models.IntegerField()
roomtype = models.CharField(max_length=10)
aadharno = models.CharField(max_length=15)
daysstayed = models.IntegerField()
date_visited = models.DateTimeField(default=timezone.now)
emp_id = models.ForeignKey(Employee,on_delete=models.SET_NULL,blank=True,null=True)
class Employee(models.Model):
firstname = models.CharField(max_length=15)
lastname = models.CharField(max_length=15)
age = models.IntegerField()
sex = models.CharField(max_length=10)
phoneno = models.IntegerField()
emailid = models.CharField(max_length=25)
address = models.CharField(max_length=50)
salary = models.IntegerField()
designation = models.CharField(max_length=10)
password = models.CharField(max_length=10)
aadharno = models.CharField(max_length=15)
datejoined = models.DateField(default=timezone.now)
I need some help here.
The best way I could suggest is that you create the models as follows:
models.py
from django.db import models
from django.contrib.auth.models import User
SEX = [
('male', 'Male'),
('female', 'Female'),
('not_to_say', 'Rather not to say')
]
class BaseModel(models.Model):
age = models.IntegerField()
sex = models.CharField(max_length=20, choices=SEX)
phone = models.CharField(max_length=10)
address = models.CharField(max_length=50)
aadhar_no = models.CharField(max_length=15)
class Employee(BaseModel):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='employee_user')
salary = models.IntegerField()
designation = models.CharField(max_length=10)
class Customer(BaseModel):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='customer_user')
childrens = models.IntegerField()
adults = models.IntegerField()
room_type = models.CharField(max_length=10)
days_stayed = models.IntegerField()
date_visited = models.DateTimeField(default=timezone.now)
employee = models.ForeignKey(Employee, on_delete=models.SET_NULL, relted_name='serving_employee')
You can access password, date_joined, first_name, last_name & email of employee from Employee.user, and first_name, last_name & email of customer from Customer.user.
I hope this solves your problem.

given a clinic_id, how do I get the mods belonging the profile of the user

I am really stuck here and I am considering changing my models and starting fresh
I have these models
class CustomUser(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
password2 = models.CharField(max_length=128)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
active = models.BooleanField(default=True) # Able to login
practitioner = models.BooleanField(default=False) # has access to a clinc
admin = models.BooleanField(default=False) # superuser
staff = models.BooleanField(default=False) # staff
timestamp = models.DateTimeField(auto_now_add=True)
class Modalities(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User,
related_name='prof_user',
on_delete=models.CASCADE)
bio = models.TextField(max_length=5000)
mods = models.ManyToManyField(Modalities)
phone = PhoneNumberField()
clinics = models.ManyToManyField(Clinic)
personnummer = models.CharField(max_length=12)
street = models.CharField(max_length=50)
city = models.CharField(max_length=50)
consent = models.BooleanField()
class Clinic(models.Model):
practitioner = models.OneToOneField(User,
related_name='prac_user',
on_delete=models.CASCADE)
lat = models.FloatField(null=True, blank=True)
lng = models.FloatField(null=True, blank=True)
name = models.CharField(max_length=128, )
phone = PhoneNumberField()
description = models.TextField(max_length=5000)
street = models.CharField(max_length=128, )
city = models.CharField(max_length=128, )
From my view I am trying to get the mods from the Profile model, starting with the clinic_id
something like
clinic = Clinic.objects.filter(pk=clinic_id)
profile = get_object_or_404(Profile, user=request.user)
mods = profile.mods
I have tried so many things over the last few hours and I just can't figure this out.
Do I need to change my models or am I going about accessing this wrong?
profile = Profile.objects.filter(user=Clinic.objects.get(pk=clinic_id).practitioner)
mods = profile[0].mods.all() if profile else []
clinic = Clinic.objects.get(clinic_id)
profile = get_object_or_404(Profile, user=request.user)
mods = profile.mods.filter(name__startswith=clinic.pk)
but not that if the clinic_id is 1
the mods starting with 10,11,111 etc will also be selected unless you have a particular way of entering modality name.
I believe your view needs to look something like:
clinic = clinic.objects.get(pk=clinic_id)
profile = profile.objects.get(clinic.practitioner)
mods = mods.objects.filter(pk__in=profile.mods.values_list('pk'))

Filtering two models

I have a problem with following thing: using models described below, I need to search for a car, that has more than x km of mileage and latest visit has date of more than year ago. Of course one car can have more than one visit.
class Car(models.Model):
...
id = models.CharField(max_length=10, primary_key=True, db_index=True)
mileage = models.PositiveIntegerField(db_index=True)
class Visit(models.Model):
...
id = models.ForeignKey(Car, db_column='id', db_index=False)
date = models.DateField(db_index=True)
In views.py I have code like this
def search_car(request):
time_threshold = datetime.now() - timedelta(days=365)
cars = Car.objects.filter(mileage__gte=500000,
id=Visit.objects.filter(data__lt=time_threshold.date()))
return render(request, 'myapp/search_car.html', {'cars': cars})
Unfortunately, it doesn't work. Any ideas?
EDIT Exact code:
models.py
class Samochod(models.Model):
marka = models.CharField(max_length=30)
model = models.CharField(max_length=30)
nr_rejestracyjny = models.CharField(max_length=10, primary_key=True, db_index=True)
nr_VIN = models.CharField(max_length=17, unique=True, validators=[validators.MinLengthValidator(17)])
przebieg = models.PositiveIntegerField(db_index=True)
id_uzytkownika = models.ForeignKey(User, db_column='id_uzytkownika', db_index=True)
class Wizyta(models.Model):
id_wizyty = models.IntegerField(primary_key=True, db_index=True)
data = models.DateField(db_index=True)
status = models.CharField(max_length=6, choices=STAN_CHOICE, db_index=True)
id_uzytkownika = models.ForeignKey(User, db_column='id_uzytkownika', db_index=True)
nr_rejestracyjny = models.ForeignKey(Samochod, db_column='nr_rejestracyjny', db_index=False)
przebieg_w_momencie_wizyty = models.PositiveIntegerField()
opis = models.CharField(max_length=200)
id_czesci = models.ForeignKey(Czesci, db_column='id_czesci')
cena = models.PositiveIntegerField()
czas_pracownikow = models.PositiveIntegerField(validators=[validators.MaxValueValidator(1000)])
id_sprzetu = models.ForeignKey(Sprzet, db_column='id_sprzetu', db_index=True)
views.py
def search_car(request):
time_threshold = datetime.now() - timedelta(days=365)
samochody = Samochod.objects.distinct().filter(przebieg__gte=500000).exclude(wizyta__date__gte=time_threshold)
return render(request, 'warsztat_app/search_car.html', {'samochody': samochody})
cars = Car.objects.distinct().filter(mileage__gte=500000) \
.exclude(visit__date__gte=time_threshold)
For your real models code should look like this:
samochody = Samochod.objects.distinct().filter(przebieg__gte=500000) \
.exclude(wizyta__data__gte=time_threshold)

Categories