Doodle-like functionality in a Django model? - django

I want to allow the user to provide his availability for any of three timeslots on any of the 7 days of the week.
The brute-force way to do this would be to simply provide 21 checkboxes, so
MONDAY_AM = models.BooleanField()
MONDAY_NOON = models.BooleanField()
...
SUNDAY_PM = models.BooleanField()
However this seems silly. What if I want to recall all the mondays, or all the evenings? It just doesn't seem like it would scale well.
I would like a more sophisticated approach, ideally one that would allow me to register these models to Django's admin so that I could see each user's availability in a table form, such as
|Mo Tu We Th Fr Sa Su
AM | x x
NOON | x x x x
PM | x x x
Any help would be much appreciated (and yes, thus far Doodle vastly outstrips the functionality of my thing, but 1. it's a learning project, 2. i plan to take it in a different direction)
edit: BTW, coming from Python and Qt and whatnot, my initial approach was nested for loops and dictionary, but South and Django seemed not to like that. I need to think more "database-like", so don't be afraid to submit something that's almost trivial. It's probably what I need, really.

In past I was also required this feature. In which Teacher has to define its availability timing in any of the day, so I came up with this model:
class Availability(models.Model):
WEEKDAY_CHOICES = (
(0, 'Monday'),
(1, 'Tuesday'),
(2, 'Wednesday'),
(3, 'Thursday'),
(4, 'Friday'),
(5, 'Saturday'),
(6, 'Sunday'),
)
id = models.AutoField(primary_key=True)
teacher = models.ForeignKey(Teacher)
weekday = models.PositiveSmallIntegerField(choices=WEEKDAY_CHOICES)
start_time = models.TimeField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
class Meta:
db_table = 'availability'
unique_together = ("teacher", "weekday")
I hope this will help you to get somewhere.

Related

How could you make this really reaaally complicated raw SQL query with django's ORM?

Good day, everyone. Hope you're doing well. I'm a Django newbie, trying to learn the basics of RESTful development while helping in a small app project. Currently, there's a really difficult query that I must do to create a calculated field that updates my student's status accordingly to the time interval the classes are in. First, let me explain the models:
class StudentReport(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE,)
upload = models.ForeignKey(Upload, on_delete=models.CASCADE, related_name='reports', blank=True, null=True,)
exams_date = models.DateTimeField(null=True, blank=True)
#Other fields that don't matter
class ExamCycle(models.Model):
student = models.ForeignKey(student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE,)
#Other fields that don't matter
class RecommendedClasses(models.Model):
report = models.ForeignKey(Report, on_delete=models.CASCADE,)
range_start = models.DateField(null=True)
range_end = models.DateField(null=True)
# Other fields that don't matter
class StudentStatus(models.TextChoices):
enrolled = 'enrolled' #started class
anxious_for_exams = 'anxious_for_exams'
sticked_with_it = 'sticked_with_it' #already passed one cycle
So this app will help the management of a Cram school. We first do an initial report of the student and its best/worst subjects in StudentReport. Then a RecommendedClasses object is created that tells him which clases he should enroll in. Finally, we have a cycle of exams (let's say 4 times a year). After he completes each exam, another report is created and he can be recommended a new class or to move on the next level of its previous class.
I'll use the choices in StudentStatus to calculate an annotated field that I will call status on my RecommendedClasses report model. I'm having issues with the sticked_with_it status because it's a query that it's done after one cycle is completed and two reports have been made (Two because this query must be done in StudentStatus, after 2nd Report is created). A 'sticked_with_it' student has a report created after exams_date where RecommendedClasses was created and the future exams_date time value falls within the 30 days before range_start and 60 days after the range_end values of the recommendation (Don't question this, it's just the way the higherups want the status)
I have already come up with two ways to do it, but one is with a RAW SQL query and the other is waaay to complicated and slow. Here it is:
SELECT rec.id AS rec_id FROM
school_recommendedclasses rec LEFT JOIN
school_report original_report
ON rec.report_id = original_report.id
AND rec.teacher_id = original_report.teacher_id
JOIN reports_report2 future_report
ON future_report.exams_date > original_report.exams_date
AND future_report.student_id = original_report.student_id
AND future_report.`exams_date` > (rec.`range_start` - INTERVAL 30 DAY)
AND future_report.`exams_date` <
(rec.`range_end` + INTERVAL 60 DAY)
AND original_report.student_id = future_report.student_id
How can I transfer this to a proper DJANGO ORM that is not so painfully unoptimized? I'll show you the other way in the comments.
FWIW, I find this easier to read, but there's very little wrong with your query.
Transforming this to your ORM should be straightforward, and any further optimisations are down to indexes...
SELECT r.id rec_id
FROM reports_recommendation r
JOIN reports_report2 o
ON o.id = r.report_id
AND o.provider_id = r.provider_id
JOIN reports_report2 f
ON f.initial_exam_date > o.initial_exam_date
AND f.patient_id = o.patient_id
AND f.initial_exam_date > r.range_start - INTERVAL 30 DAY
AND f.initial_exam_date < r.range_end + INTERVAL 60 DAY
AND f.provider_id = o.provider_id

How to get time slot in django for doctor appointment

I have two models Schedule and Appointment.
How can I get the duration of doctor in a different time slots for 15 minutes. I am getting blank in this
models.
class Schedule(models.Model):
doctor=models.ForeignKey(Doctor)
open=models.TimeField()
close=models.TimeField()
class Appointment(models.Model):
patient=models.ForeignKey(Patient)
doctor=models.ForeignKey(Doctor)
date=models.DateField()
time_slot=models.TimeField()
Based on the discussion we had in the comments, I will not provide you the exact code(as you have not done anything yet). But I will explain you different approaches(I can think right now) you can take.
Scheduler approach
First you can convert the timeslot into numbers, like 10:00 becomes 1, 10:15 becomes 1 and so on until the end time and every-time till the end of time(i.e 6pm in your case), store this as array in the timeslot field. Now every-time someone books a slot, just remove the number from the timeslot. Now if someone tires to book the same time slot you see that this number is not available and you don't let them book it or, every-time the page is reloaded you deactivate the slot for the user. The problem is that everyday you have to restore the array(timeslot) to blank before 10:00.(You might need a scheduler like django-beats).
More Generic way
Here what you do is in the table Appointment, make timeslot a number (it is just a number not array, but numbers follow the same pattern like above 10:00 becomes 1, 10:15 becomes 1 etc). Now everytime you load you page for the first time you query that give me all the appointments with this doctor for the day, initially it will be empty, hence you show all the available time slots. Once some user/patient books a timeslot you just need to create a entry in the Appointment with the patient, doctor, date, timeslot(you can hard code the appointment number on the frontend. like 10 bootstrap cards which show the 15 min timeslot and have different numbers, as you already know timeslot numbers i.e 10:00-> 1, you will receive the timeslot in backend and reserve the slot for the patient.) Now query all the time slots doctor have for the day and don't show the ones which are already booked(appointment table will tell you that).
These are two ways I can think right now, I will add more as I get to realise.
This should give you a direction for now at least.
Ask for details in comments, I will update the answer accordingly.
Here is the solution for that problem.
from django.db import models
class Appointment(models.Model):
"""Contains info about appointment"""
class Meta:
unique_together = ('doctor', 'date', 'timeslot')
TIMESLOT_LIST = (
(0, '09:00 – 09:30'),
(1, '10:00 – 10:30'),
(2, '11:00 – 11:30'),
(3, '12:00 – 12:30'),
(4, '13:00 – 13:30'),
(5, '14:00 – 14:30'),
(6, '15:00 – 15:30'),
(7, '16:00 – 16:30'),
(8, '17:00 – 17:30'),
)
doctor = models.ForeignKey('Doctor',on_delete = models.CASCADE)
date = models.DateField(help_text="YYYY-MM-DD")
timeslot = models.IntegerField(choices=TIMESLOT_LIST)
patient_name = models.CharField(max_length=60)
def __str__(self):
return '{} {} {}. Patient: {}'.format(self.date, self.time, self.doctor, self.patient_name)
#property
def time(self):
return self.TIMESLOT_LIST[self.timeslot][1]
class Doctor(models.Model):
"""Stores info about doctor"""
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
middle_name = models.CharField(max_length=20)
specialty = models.CharField(max_length=20)
def __str__(self):
return '{} {}'.format(self.specialty, self.short_name)
#property
def short_name(self):
return '{} {}.{}.'.format(self.last_name.title(), self.first_name[0].upper(), self.middle_name[0].upper())
To get the whole source code go to Click here!

How to query database with conditional expression in Django?

I have three models: Business, Offers and OfferPlan:
Business:
class Business(models.Model):
name_of_business = models.CharField(max_length=255)
Offers:
class Offers(models.Model):
business = models.ForeignKey(Business, related_name="business_offer",
on_delete=models.CASCADE)
title = models.CharField(max_length=255)
subtext = models.CharField(max_length=255)
OfferPlan:
class OfferPlan(models.Model):
WEEKDAYS = [
(1, _("Monday")),
(2, _("Tuesday")),
(3, _("Wednesday")),
(4, _("Thursday")),
(5, _("Friday")),
(6, _("Saturday")),
(7, _("Sunday")),
]
offer = models.ForeignKey(Offers, related_name="business_offer_plan",
on_delete=models.CASCADE)
weekday = models.IntegerField(
choices=WEEKDAYS,
)
from_hour = models.TimeField()
to_hour = models.TimeField()
I have a ListView which search for businesses open based on different params such as city, category etc. I also want to now search by weekday, say which business is open on Monday will be displayed and which are not wont be displayed on that day. Weekday information is stored in OfferPlan and there could be multiple timings for the offers that day in OfferPlan table, but I want to query (filter, exclude) the businesses who has even a single entry on that weekday number.
Here is my ListView:
class SearchListView(ListView):
template_name = 'search/search.html'
model = Business
def get_queryset(self):
# queryset = Business.objects.filter(business_address__city=AppLocations.objects.first().city)
if 'city' in self.request.GET:
queryset = Business.objects.filter(business_address__city=self.request.GET.get('city'))
if 'category' in self.request.GET:
queryset = queryset.filter(category__code=self.request.GET.get('category'))
# if 'date' not in self.request.GET:
# queryset = B
raise
return queryset
How could this be possible? Also looked into https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/ but not able to figure out.
Thanks
Update 1
After researching more in the web, I figured out this is how it could be achieved, but need to know for sure from other Django enthusiasts here that it is right.
queryset.filter(business_offer__business_offer_plan__weekday=1).annotate(count_entry=Count('business_offer__business_offer_plan__weekday')).filter(count_entry__gt=1)
Solution
Jefferson's solution was tagged as right answer as it provided more insights, about which query is fast and what wrong was with my previous update, so here is the proper solution to which we both agreed:
queryset.filter(business_offer__business_offer_plan__weekday=1).annotate(count_entry=Count('business_offer__business_offer_plan__weekday')).filter(count_entry__gte=1)
def get_query(weekday):
businesses = Business.objects.filter(business_offer__in=Offers.objects.filter(
business_offer_plan__in=OfferPlan.objects.filter(weekday=weekday))).distinct()
return businesses
There's a heavy query, but it works.
There's no conditional expression here - and your annotation is much too complicated. You just need an additional filter.
queryset.filter(business_offer__business_offer_plan__weekday=self.request.GET['weekday'])

django days-of-week representation in model

I have this "Jobs Server" model that i'm building. I want to include a field that will save which days of the week this job will run on. Ultimately in the UI, i would like the user to be able to have a series of check boxes(one for each day) that they can select. What would be the best way to represent this "days-of-week" data in my mode?
class Job(models.Model):
name = models.CharField(max_length=32, unique=True)
package = models.ForeignKey(Package)
binary = models.ForeignKey(Binary)
host = models.ForeignKey(Host)
colo = models.ForeignKey(Location)
group = models.ForeignKey(Group)
type = models.ForeignKey(Type)
start = models.TimeField()
end = models.TimeField()
days = ?
You may want to create DayOfTheWeek field type, which you can improve in various ways.
This code cause to translate automatically into the local language using the multilingual tools.
#myFields.py
from django.utils.translation import ugettext as _
DAY_OF_THE_WEEK = {
'1' : _(u'Monday'),
'2' : _(u'Tuesday'),
'3' : _(u'Wednesday'),
'4' : _(u'Thursday'),
'5' : _(u'Friday'),
'6' : _(u'Saturday'),
'7' : _(u'Sunday'),
}
class DayOfTheWeekField(models.CharField):
def __init__(self, *args, **kwargs):
kwargs['choices']=tuple(sorted(DAY_OF_THE_WEEK.items()))
kwargs['max_length']=1
super(DayOfTheWeekField,self).__init__(*args, **kwargs)
#models.py
import myFields
(..)
dayOfTheWeek = myFields.DayOfTheWeekField()
(..)
Something like this would work.
#models.py
DAYS_OF_WEEK = (
(0, 'Monday'),
(1, 'Tuesday'),
(2, 'Wednesday'),
(3, 'Thursday'),
(4, 'Friday'),
(5, 'Saturday'),
(6, 'Sunday'),
)
days = models.CharField(max_length=1, choices=DAYS_OF_WEEK
#forms.py
widgets = { 'days': forms.CheckboxSelectMultiple }
Or to save multiple days
#models.py
class Days(models.Model):
day = models.CharField(max_length=8)
days = models.ManyToManyField(Days)
#forms.py
widgets = { 'days': forms.CheckboxSelectMultiple }
If you want a checkbox for each one, then the easiest thing to do is to create BooleanFields for each of them. If you want to store it as a more complex value (eg. comma separated list or something), create your own widget and play with javascript, then you could go that route.
Just implemented django-weekday-field. Works great!
Hopefully this helps other people who stumble upon this question
EDIT: updated link to pypi since the bitbucket repo was deleted.
It hasn't been updated since 2014 but looking at the code is a great way to get started on answering this question

Django ratings system

I'm working on a project that needs a ratings system where they can rate the quality of the houses. They'd be doing it from the admin panel, so it's not something that a visitor would rate.
For example, for each listing, they can rate it from 1-5 stars:
Location:
Room:
Dining options:
Community:
Overall:
In my models.py file, I have this setup:
Class Listing (models.Model):
...
RATING_CHOICES = (
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
)
location_rating = models.DecimalField(choices = RATING_CHOICES, max_digits=3, decimal_places=2)
room_rating = models.DecimalField(choices = RATING_CHOICES, max_digits=3, decimal_places=2)
dining_options_rating = models.DecimalField(choices = RATING_CHOICES, max_digits=3, decimal_places=2)
community_rating = models.DecimalField(choices = RATING_CHOICES, max_digits=3, decimal_places=2)
recreation_rooms_rating = models.DecimalField(choices = RATING_CHOICES, max_digits=3, decimal_places=2)
def __unicode__(self):
return self.name
def get_avg_rating(self):
avg_rating = (self.location_rating + self.room_rating + self.recreation_rooms_rating + self.dining_options_rating + self.community_rating) / 5
return avg_rating
I'd plan to display the ratings with a little CSS. Just putting room_rating or avg_rating in a template tag doesn't work, so I'm assuming I'd have to add some lines of code to views.py. I've checked the Django docs, but I'm still not sure how to go about this.
This seems like something that should be easy to do, but I'm not really sure where to start.
A potential problem with the direction you taking is that you're only storing one set of ratings for each Listing. If user B wants to rate a Listing, he'll have to overwrite User A's ratings. Instead of putting the ratings inside the Listing, you'll need to break out your ratings into a separate Ratings table, and use a ManytoMany relationship between your Listings and Ratings. That way, you can have multiple users rate a particular listing, and then you can calculate and show the averages for each listing. See this discussion for reference.
It might be better to use an existing ratings app than starting from scratch. They already have documentation so you can get them up and running quickly, and they handle the database design for you.
Django Ratings
Django Valuate