Combine Two Variable Filters Django - django

I have two filters in my code here, students filters everyone in that particular class and students_wr is another filter that quieres my table K8Recess which logs all the students in the school who got recess for that day. What I want to do is combine these filters.
So show everyone in my class who got recess for the day . How do i do that ? Here is my Code
def K8_Recess_Report(request, classid):
if request.method == "GET":
date = datetime.date.today()
class_name = TeacherClass.objects.get(id=classid)
getstudents = Student.objects.filter(class_name=classid)
students = getstudents.all().order_by('student_name')
students_wr = K8Recess.objects.filter(created_at__date = date )
my_class_id = request.session['my_class_id']
context = ({'students': students, 'class_name': class_name, 'my_class_id': my_class_id, 'date': date,})
return render(request, 'points/k8_recess_report.html', context)
class K8Points(models.Model):
date = models.DateField(default=datetime.date.today())
class_name = models.ForeignKey(TeacherClass, on_delete = models.PROTECT, default = "",)
student_name = models.ForeignKey(Student,on_delete = models.CASCADE, default ="" ,)
week_of = models.IntegerField(default=weeknumber)
day = models.CharField(max_length= 10, default = dayofweek)
TIME_FRAME_CHOICES = [
(None, 'PLEASE SELECT TIME FRAME'), # THIS IS OPTIONAL
(1, '(1.) 8:45AM - 9:00AM'),
(2, '(2.) 9:00AM - 9:30AM'),
(3, '(3.) 9:30AM - 10:00AM'),
(4, '(4.) REC. I 10:00AM -10:10AM'),
(5, '(5.) 10:10AM-10:40AM'),
(6, '(6.) 10:40AM-11:10AM'),
(7, '(7.) 11:10AM-11:40AM'),
(8, '(8.) LUNCH 11:40AM-12:00PM'),
(9, '(9.) REC. II 12:00PM-12:20PM'),
(10, '(10.) 12:20PM-12:50PM'),
(11,'(11.) 12:50PM-1:20PM'),
(12,'(12.) 1:20PM-1:50PM'),
(13,'(13.) 1:50PM-2:20PM'),
(14,'(14.) REC. III 2:20PM-2:30PM'),
]
time_frame = models.PositiveSmallIntegerField(choices=TIME_FRAME_CHOICES,)
behavior = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(1)
])
academic = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(0)
] )
created_at = models.DateTimeField(default=datetime.datetime.now())
class Meta:
verbose_name = "K8-Points"
def __str__(self):
return self.student_name
class K8Recess(models.Model):
student_ps = models.ForeignKey(Student,on_delete = models.CASCADE, default ="" ,)
created_at = models.DateTimeField(default=datetime.datetime.now())
morning_recess = models.BooleanField(blank= True, null = True)
lunch_recess = models.BooleanField(blank= True, null = True)
afternoon_recess = models.BooleanField(blank= True, null = True)

You can get this by:
K8Recess.objects.filter(student_ps__class_name=classid, created_at__date=date)

Related

Filter Foreign Key Drop Down Field Django

I have 3 tables Student, K8Points, and TeacherClass . The table students tracks all student data information and you can assign them to a classroom, points tracks the points they earned for the day, classroom table is where you create the classroom names. What i want to accomplish is when you are logged in to /k8_points_classroom/1? page, there is a drop down field of students. 1 at the end of the classroom is the classroom id. The field student_name should only show the kids in that particular class, how do i filter that field ? Right now it just pulls up every student in the database. Thanks for the help .
Model
class TeacherClass(models.Model):
class_name = models.CharField(max_length = 50, default= "")
teacher_name = models.ManyToManyField(User)
grade = models.CharField(max_length = 2, default= "")
class Meta:
verbose_name = "Teacher Class Room"
def __str__(self):
return self.class_name
class Student(models.Model):
studentpsid= models.CharField(primary_key = True , default = "", max_length = 50, unique = True)
student_name = models.CharField(max_length = 50)
student_grade = models.CharField(max_length = 2, default = "")
home_room = models.CharField(max_length = 3, default = "")
counseling_goal = models.TextField(max_length = 255)
class_name = models.ManyToManyField(TeacherClass)
image =models.ImageField(default ="default.png", upload_to='student_pics')
class K8Points(models.Model):
date = models.DateField(default=datetime.date.today)
class_name = models.ForeignKey(TeacherClass, on_delete = models.PROTECT, default = "",)
student_name = models.ForeignKey(Student,on_delete = models.CASCADE, default ="" ,)
week_of = models.IntegerField(default=weeknumber)
day = models.CharField(max_length= 10, default = dayofweek)
TIME_FRAME_CHOICES = [
(None, 'PLEASE SELECT TIME FRAME'),
(1, '(1.) 8:45AM - 9:00AM'),
(2, '(2.) 9:00AM - 9:30AM'),
(3, '(3.) 9:30AM - 10:00AM'),
(4, '(4.) REC. I 10:00AM -10:10AM'),
(5, '(5.) 10:10AM-10:40AM'),
(6, '(6.) 10:40AM-11:10AM'),
(7, '(7.) 11:10AM-11:40AM'),
(8, '(8.) LUNCH 11:40AM-12:00PM'),
(9, '(9.) REC. II 12:00PM-12:20PM'),
(10, '(10.) 12:20PM-12:50PM'),
(11,'(11.) 12:50PM-1:20PM'),
(12,'(12.) 1:20PM-1:50PM'),
(13,'(13.) 1:50PM-2:20PM'),
(14,'(14.) REC. III 2:20PM-2:30PM'),
]
time_frame = models.PositiveSmallIntegerField(choices=TIME_FRAME_CHOICES,)
behavior = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(1)
])
academic = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(0)
] )
created_at = models.DateTimeField(default = timezone.now)
class Meta:
verbose_name = "K8-Points"
def __str__(self):
return self.student_name
Form
def __init__(self, *args, **kwargs):
self.classid = kwargs.pop('classid', None)
super(K8Points_ClassroomForm,self).__init__(*args,**kwargs)
self.fields['date'].disabled = True
self.fields['day'].disabled = True
self.fields['week_of'].disabled = True
self.fields['class_name'].widget.attrs['readonly'] = True
getstudents = Student.objects.filter(class_name = self.classid).order_by('student_name')
self.fields['student_name'].queryset= getstudents.all().order_by('student_name')
View
#login_required
def K8_Points_Classroom(request, classid):
if request.method == "GET":
date = datetime.date.today()
students = Student.objects.filter(class_name=classid).order_by('student_name')
class_name = TeacherClass.objects.get(id=classid)
form = K8Points_ClassroomForm(classid = class_name.id)
request.session['my_class_id'] = classid
return render(request, 'points/k8_points_classroom.html', {'form': form, 'students': students, 'class_name': class_name, 'date': date , 'classid': classid})
You need to pass the class in as a parameter to the form in the view, then adjust the student_name field's queryset to filter down to that class' students.
class K8PointsClassroomForm(forms.ModelForm):
def __init__(self, *args, class_=None, **kwargs):
super (K8Points_ClassroomForm,self).__init__(*args,**kwargs )
self.fields['date'].disabled = True
self.fields['day'].disabled = True
self.fields['week_of'].disabled = True
# Limit the fields queryset to that of the class's students.
self.fields['student_name'].queryset = class_.student_set.all()
Edit:
Here's the view I was trying to explain:
#login_required
def K8_Points_Classroom(request, classid):
class_name = TeacherClass.objects.get(id=classid)
form = K8Points_ClassroomForm(class_=class_name)

Filter Creation Date By Time Range

Im trying to filter my first two IF statement to only show the created_at records from 8 am to 10 am for todays current date, right now it just does the date, i need change date= date to created_at = '' however that would be done in a range. Here is my views.py. How do i add this to my IF statement ? Thanks
views.py
def Student_Progress(request, studentpsid):
if request.method == "GET":
date = datetime.date.today()
# Calculates Points on Student Progress Page
academic = K8Points.objects.values_list('academic', flat=True).filter(
student_name_id=studentpsid).filter(date=date)
behavior = K8Points.objects.values_list('behavior', flat=True).filter(
student_name_id=studentpsid).filter(date=date)
my_class_id = request.session['my_class_id']
academic_total = 0
behav_total = 0
for score in academic:
academic_total += int(score)
for score in behavior:
behav_total += int(score)
grand_total = academic_total + behav_total
counseling = Student.objects.values_list(
'counseling_goal', flat=True).get(studentpsid=studentpsid)
studentid = Student.objects.get(studentpsid=studentpsid)
k8obj = K8Points.objects.filter(
student_name_id=studentpsid, date=date).order_by('time_frame')
# Checks To See If a Student Gets Morning Recess
if grand_total >= 20 and K8Points.objects.filter(time_frame=1).filter(date=date) and K8Points.objects.filter(time_frame=2).filter(date=date) and K8Points.objects.filter(time_frame=3).filter(date=date):
morning_recess = "YES"
context = ({'studentid': studentid, 'date': date, 'counseling': counseling, 'grand_total': grand_total, 'academic_total': academic_total,
'behav_total': behav_total, 'k8obj': k8obj, 'my_class_id': my_class_id, 'morning_recess': morning_recess})
return render(request, 'points/student_progress.html', context)
if grand_total <= 20 and K8Points.objects.filter(time_frame=1) and K8Points.objects.filter(time_frame=2) and K8Points.objects.filter(time_frame=3).filter(date=date):
morning_recess = "NO"
context = ({'studentid': studentid, 'date': date, 'counseling': counseling, 'grand_total': grand_total, 'academic_total': academic_total,
'behav_total': behav_total, 'k8obj': k8obj, 'my_class_id': my_class_id, 'morning_recess': morning_recess})
return render(request, 'points/student_progress.html', context)
else:
context = ({'studentid': studentid, 'date': date, 'counseling': counseling, 'grand_total': grand_total, 'academic_total': academic_total,
'behav_total': behav_total, 'k8obj': k8obj, 'my_class_id': my_class_id, })
return render(request, 'points/student_progress.html', context)
models.py
class K8Points(models.Model):
date = models.DateField(default=datetime.date.today())
class_name = models.ForeignKey(TeacherClass, on_delete = models.PROTECT, default = "",)
student_name = models.ForeignKey(Student,on_delete = models.CASCADE, default ="" ,)
week_of = models.IntegerField(default=weeknumber)
day = models.CharField(max_length= 10, default = dayofweek)
TIME_FRAME_CHOICES = [
(None, 'PLEASE SELECT TIME FRAME'), # THIS IS OPTIONAL
(1, '(1.) 8:45AM - 9:00AM'),
(2, '(2.) 9:00AM - 9:30AM'),
(3, '(3.) 9:30AM - 10:00AM'),
(4, '(4.) REC. I 10:00AM -10:10AM'),
(5, '(5.) 10:10AM-10:40AM'),
(6, '(6.) 10:40AM-11:10AM'),
(7, '(7.) 11:10AM-11:40AM'),
(8, '(8.) REC II LUNCH 11:40AM-12:20PM'),
(9, '(9.) 12:20PM-12:50PM'),
(10,'(10.) 12:50PM-1:20PM'),
(11,'(11.) 1:20PM-1:50PM'),
(12,'(12.) 1:50PM-2:20PM'),
(13,'(13.) REC. III 2:20PM-2:30PM'),
]
time_frame = models.PositiveSmallIntegerField(choices=TIME_FRAME_CHOICES,)
behavior = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(1)
])
academic = models.IntegerField(default="", validators=[
MaxValueValidator(5),
MinValueValidator(0)
] )
total = models.IntegerField(default=0 )
morning_recess= models.CharField(max_length= 3, blank = True ,default = "" )
created_at = models.DateTimeField(auto_now_add=True)
for today day filter
today_date = datetime.datetime.now().date()
.filter(your_datetime_field__date = today_date)
for hour filter
.filter(your_datetime_field__hour__lte = 10).filter(your_datetime_field__hour__gte = 8)
Keep in mind that 10:59:59 will be in results of this query too.
If you need only 8:00:00 - 9:59:59 use lt instead of lte

Model's fields being cleared after ModelForm.save() called

I'm having an issue where I instantiate a ModelForm-based form with a pre-existing instance of the model in the GET portion of my view function. This model already has several fields filled in; the ModelForm is used to collect other fields in the model. The pre-existing fields are excluded in the ModelForm's definition.
The problem is, during POST processing, after successful validation of the ModelForm, I'm calling ModelForm.save(commit=False)...and the model returned (which should be the same one I passed in as 'instance' in the GET handling, remember) has somehow lost all the fields that were previously set. The fields actually set by the form are fine; but it's no longer the original instance of my model.
This is not the behavior I expected; and in fact I've used this partial-model-in-modelform previously, and it works other places. What am I missing here??
Hopefully some code'll make all this clear...
So here's the Model:
class Order(models.Model):
STATUS = (
('Created', -1),
('Pending', 0),
('Charged', 1),
('Credited', 2),
)
SHIPPING_STATUS = (
('Cancelled', 0),
('Ready for pickup', 1),
('Shipped', 2),
('OTC', 3),
)
orderID = models.IntegerField(max_length=15, null=True, blank=True)
store = models.ForeignKey(Store)
paymentInstrument = models.ForeignKey(PaymentInstrument, null=True, blank=True)
shippingMethod = models.ForeignKey(ShippingMethod, null=True, blank=True)
last_modified = models.DateTimeField(null=True, blank=True)
date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
total = models.FloatField(default=0.0, blank=True)
shippingCharge = models.FloatField(default=0.0, blank=True)
tax = models.FloatField(default=0.0, blank=True)
status = models.CharField(max_length=50, choices=STATUS, default = 'Created')
shippingStatus = models.CharField(max_length=50, choices=SHIPPING_STATUS, default = '1')
errstr = models.CharField(max_length=100, null=True, blank=True)
# billing info
billingFirstname = models.CharField(max_length = 50, blank = True)
billingLastname = models.CharField(max_length = 50, blank = True)
billingStreet_line1 = models.CharField(max_length = 100, blank = True)
billingStreet_line2 = models.CharField(max_length = 100, blank = True)
billingZipcode = models.CharField(max_length = 5, blank = True)
billingCity = models.CharField(max_length = 100, blank = True)
billingState = models.CharField(max_length = 100, blank = True)
billingCountry = models.CharField(max_length = 100, blank = True)
email = models.EmailField(max_length=100, blank = True)
phone = models.CharField(max_length=20, default='', null=True, blank=True)
shipToBillingAddress = models.BooleanField(default=False)
# shipping info
shippingFirstname = models.CharField(max_length = 50, blank = True)
shippingLastname = models.CharField(max_length = 50, blank = True)
shippingStreet_line1 = models.CharField(max_length = 100, blank = True)
shippingStreet_line2 = models.CharField(max_length = 100, blank = True)
shippingZipcode = models.CharField(max_length = 5, blank = True)
shippingCity = models.CharField(max_length = 100, blank = True)
shippingState = models.CharField(max_length = 100, blank = True)
shippingCountry = models.CharField(max_length = 100, blank = True)
Here's the ModelForm definition:
class OrderForm(ModelForm):
class Meta:
model = Order
exclude = ('orderID',
'store',
'shippingMethod',
'shippingStatus',
'paymentInstrument',
'last_modified',
'date',
'total',
'payportCharge',
'errstr',
'status', )
widgets = {
'billingCountry': Select(choices = COUNTRIES, attrs = {'size': "1"}),
'shippingCountry': Select(choices = COUNTRIES, attrs = {'size': "1"}),
'billingState': Select(choices = STATES, attrs = {'size': "1"}),
'shippingState': Select(choices = STATES, attrs = {'size': "1"}),
}
And here is the view function:
def checkout(request):
theDict = {}
store = request.session['currentStore']
cart = request.session.get('cart', False)
order = request.session['currentOrder'] # some fields already set
if not cart: # ...then we don't belong on this page.
return HttpResponseRedirect('/%s' % store.urlPrefix)
if request.method == 'GET':
form = OrderForm(instance=order, prefix='orderForm')
else: # request.method == 'POST':
logging.info("Processing POST data...")
form = OrderForm(request.POST, prefix='orderForm')
if form.is_valid():
### AT THIS POINT, ORDER FIELDS ARE STILL GOOD (I.E. FILLED IN)
order = form.save(commit=False)
### AFTER THE SAVE, WE'VE LOST PRE-EXISTING FIELDS; ONLY ONES SET ARE
### THOSE FILLED IN BY THE FORM.
chargeDict = store.calculateCharge(order, cart)
request.session['currentOrder'] = order
return HttpResponseRedirect('/%s/payment' % store.urlPrefix)
else:
logging.info("Form is NOT valid; errors:")
logging.info(form._errors)
messages.error(request, form._errors)
theDict['form'] = form
theDict['productMenu'] = buildCategoryList(store)
t = loader.get_template('checkout.html')
c = RequestContext(request, theDict)
return HttpResponse(t.render(c))
Any/all help appreciated...
When you instantiate the form during the POST, the instance of the model you're editing is None, because you're not passing it in, and you're not persisting the form instance from the GET. Django won't do anything on its own to persist data between requests for you.
Try:
...
form = OrderForm(request.POST or None, instance=order, prefix='orderForm')
if request.method == 'POST':
logging.info("Processing POST data...")
if form.is_valid():
...
Now the instance will be populated for GET and POST, but the data from request.POST is optional for the form if it's None. It also saves you from having to instantiate the form in two places depending on request.method

How do I get the top-ranked products within a category?

Given a product (product_name is a parameter in the view), I am trying to return the 5 top-ranked products within that category (as defined by the method "get_avg_rating") as a list that I can loop through in a template. Any advice on how to do this?
class Productbackup(models.Model):
website = models.CharField('Product name', max_length = 200)
url_friendly = models.CharField('URL friendly', max_length = 200)
website_url = models.URLField('Product URL')
description= models.CharField('Description', max_length = 2000)
category = models.ForeignKey(Categories)
#category = models.ManyToManyField(Categories)
image_hero = models.URLField('Hero image url')
image_second = models.URLField('Second image url')
image_third = models.URLField('Third image url')
created_on = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.website
def get_avg_rating(self):
reviews = Reviewbackup.objects.filter(product=self)
count = len(reviews)
sum = 0.0
for rvw in reviews:
sum += rvw.rating
return (sum/count)
def get_num_reviews(self):
reviews = Reviewbackup.objects.filter(product=self)
count = len(reviews)
return count
RATING_OPTIONS = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(5, '5'),
(6, '6'),
(7, '7'),
(8, '8'),
(9, '9'),
(10, '10'),
)
class Reviewbackup(models.Model):
review = models.CharField('Review', max_length = 2000)
created_on = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
user = models.CharField('Username', max_length = 200)
rating = models.IntegerField(max_length=2, choices=RATING_OPTIONS)
product = models.ForeignKey(Productbackup)
def __unicode__(self):
return self.review
class Categories(models.Model):
category = models.CharField('Category_second', max_length = 200)
url_friendly = models.CharField('url_friendly', max_length = 200)
def __unicode__(self):
return unicode(self.category)
def view_reviews(request, product_name):
product = get_object_or_404(Productbackup, url_friendly=product_name)
product_id = product.id
#get reviews for the this product
reviews = Reviewbackup.objects.filter(product_id=product_id).order_by("-created_on")
#similar products in category comparison
prod_category = Productbackup.objects.filter(category=product.category)
#top_ranked = Productbackup.objects.order_by('get_avg_rating')[0:5]
#recently added
recent_added = Productbackup.objects.order_by('-created_on')[0:5]
return render_to_response('reserve/templates/view_reviews.html', {'prod_category': prod_category, 'product':product, 'reviews':reviews, 'recent_added':recent_added},
context_instance=RequestContext(request))
You can use annotate for that
from django.db.models import Sum, Avg
def get_top_products(amount=5):
try:
Productbackup.objects.annotate(review_amount=Sum("reviewbackup__product")).\
order_by("review_amount")[:amount]
except Productbackup.DoesNotExist:
return None
This is just a basic example, which can be extended to your needs
Try to implement that:
Create a dictionary. It will have the Product as the key and the rating as the value.
Loop through your items (Product.objects)
In that loop, put each item in the dictionary
Out of that loop, sort the dictionary by value.
(See Sort a Python dictionary by value)
Get the last items of the dictionary (dictionary[-5]).
Note that you will have to handle items with ex-aequo ratings. Indeed, if 10 items have the same score, then your Top 5 doesn't mean anything using the above method.
This would result in a code similar to this:
items_with_rating = {}
for product in Product.objects:
items_with_rating[product] = product.get_avg_rating()
items_sorted_by_rating = sorted(items_with_rating.iteritems(), key=operator.itemgetter(1))
top5_items = items_sorted_by_rating[-5]
Maybe something like this could work?
products = [[prod, prod.get_avg_rating()] for prod in Productbackup.objects()]
top_5_items = sorted(products, key=lambda x: x[1], reverse=True)[:5]

How do I fix an issue with django's modelform saving?

I'd like to be able to save data submitted by the form based on an argument passed via the url that references the product (instead of having the user to specify the product through a dropdown). Any thoughts on how I can accomplish this?
url(r'^products/(?P<product_id>\d+)/reviews/$', 'view_reviews'),
url(r'^products/(?P<product_id>\d+)/add_review/$', 'add_review'),
def add_review(request, product_id):
p = get_object_or_404(Productbackup, pk=product_id)
if request.method == 'POST':
form = ReviewbackupForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('reserve.views.view_reviews', kwargs={'product_id':p.id}))
else:
form = ReviewbackupForm()
variables = RequestContext(request, {'form': form, 'product_id': product_id})
return render_to_response('reserve/templates/create_review.html', variables)
RATING_OPTIONS = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(5, '5'),
(6, '6'),
(7, '7'),
(8, '8'),
(9, '9'),
(10, '10'),
)
class Reviewbackup(models.Model):
review = models.CharField('Review', max_length = 2000)
date = models.DateField('date')
created_on = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
user = models.CharField('Username', max_length = 200)
rating = models.IntegerField(max_length=2, choices=RATING_OPTIONS)
product = models.ForeignKey(Productbackup)
def __unicode__(self):
return self.review
class ReviewbackupForm(ModelForm):
class Meta:
model = Reviewbackup
fields = ('review', 'rating', 'user', 'date')
widgets = {
'review': Textarea(attrs={'cols': 80, 'rows': 7}),
}
class Productbackup(models.Model):
website = models.CharField('Product name', max_length = 200)
website_url = models.URLField('Product URL')
category = models.ForeignKey(Categories)
created_on = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.website
You can make use of form.save(commit=False), and set other attributes of your model in the instance and save it again.
In your view, when you save the form:
if form.is_valid():
review = form.save(commit=False)
review.product = p
review.save()