Filter a Query Set - filter

The following view works great. I pass in student_id and I get a queryset of headers and attendance days related to that student_id. My challenge is that I cannot figure out how to filter my attendance_days queryset by a specific date or date range.
I have tried variations of:
attendance_days = student.zzabsentdetail_set.order_by('-absent_date').filter('absent_date' is between '2021-02-01' and '2021-02-26')
or
attendance_days = student.zzabsentdetail_set.order_by('-absent_date').filter('absent_date' > '2021-02-01')
I would like to filter my zzabsent_detail queryset by absent date on that line if possible.
Here is my view:
def absent_detail(request, student_id):
"""Show student & attendance info"""
student = Student.objects.get(id=student_id)
header = student.zzheader_set.order_by('id')
attendance_days = student.zzabsentdetail_set.order_by('-absent_date')
context = {'student': student, 'header': header, 'attendance_days':
attendance_days}
return render(request, 'learning_logs/absent_detail_99.html', context)

You can do this with a __range lookup [Django-doc]:
attendance_days = student.zzabsentdetail_set.filter(
absent_date__range=('2021-02-01', '2021-02-26')
).order_by('-absent_date')
here the two bounds are inclusive, so items on February 1st, or February 26th will be included as well.
or you can work with the __gt lookup [Django-doc] to express that the value should be greater than a given value:
attendance_days = student.zzabsentdetail_set.filter(
absent_date__gt='2021-02-01'
).order_by('-absent_date')
for the last 10 days, you can work with a date object instead of a string, so:
from datetime import timedelta
from django.utils.timezone import now
from_dt = now().date()-timedelta(days=10)
attendance_days = student.zzabsentdetail_set.filter(
absent_date__gt=from_dt
).order_by('-absent_date')

Related

how to extract the today's date out of the date column using SQL query?

I assume I would need to change query in order to sort the data with today's date.
Please tell me how to change it though...
SQL QUERY in ToDoDao
#Query("SELECT * FROM todo_table WHERE date(date) = date('now')")
fun getTodayList(): Flow<List<ToDoTask>>
DATABASE
#Entity(tableName = DATABASE_TABLE)
data class ToDoTask(
#PrimaryKey(autoGenerate = true) val id: Int = 0,
#ColumnInfo(name = "title") val title: String,
#ColumnInfo(name = "description") val description: String,
#ColumnInfo(name = "priority") val priority: Priority,
#ColumnInfo(name = "date") val date: String,
#ColumnInfo(name = "favorite") var favorite: Boolean)
date val in ViewModel class
val date : MutableState<String> = mutableStateOf("")
datas inserted
enter image description here
I have tried the code below and I was able to activate the function as the query as I intented, so I think the query is the issue here.
#Query("SELECT * FROM todo_table WHERE date = '2023-2-14'")
fun getTodayList(): Flow<List<ToDoTask>>
The Issue
The issue is that the SQLite date function expects the date to be in an accepted format.
YYYY-M-DD is not such a format and will result in null rather than a date. YYYY-MM-DD is an accepted format (see https://www.sqlite.org/lang_datefunc.html#time_values). That is leading zeros are used to expand single digit numbers to 2 digit numbers for the month and day of month values.
The Fix (not recommended)
To fix the issue you have shown, you could use (see the However below):-
#Query("SELECT * FROM todo_table WHERE date(substr(date,1,5)||CASE WHEN substr(date,7,1) = '-' THEN '0' ELSE '' END ||substr(date,6)) = date('now');")
If the month was 2 numerics i.e. MM (e.g. 02 for February) then the above would not be necessary.
The CASE WHEN THEN ELSE END construct is similar to IF THEN ELSE END. see https://www.sqlite.org/lang_expr.html#the_case_expression. This is used to add the additional leading 0, when omitted, to the string used by the date function.
However, the above would not cater for days that have the leading 0 omitted for the first 9 days of the month. This due to the 4 permutations of the format (YYYY-MM-DD, YYYY-MM-D, YYYY-M-D and YYYY-M-DD) would be more complex e.g.
#Query("SELECT * FROM todo_table WHERE date(CASE WHEN length(date) = 8 THEN substr(date,1,5)||'0'||substr(date,6,1)||'-0'||substr(date,8) WHEN length(date) = 9 AND substr(date,7,1) = '-' THEN substr(date,1,5)||'0'||substr(date,6) WHEN length(date) = 9 AND substr(date,8,1) = '-' THEN substr(date,1,8)||'0'||substr(date,9) ELSE date END) = date('now');")
Recommended Fix
The recommended fix is to store values using one of the accepted formats rather than try to manipulate values to be an accepted date to then be worked upon using the date and time functions.

Django lte and gte queries producing empty queryset

I'm stumped. I have a Django query that should return results, but does not seem to.
I have a database with a model Postcodes with latitude and longitude data.
class Postcode(models.Model):
name = models.CharField(max_length=50)
postcode = models.CharField(max_length=7)
latitude = models.DecimalField(max_digits=8, decimal_places=5, blank=True, null=True)
longitude = models.DecimalField(max_digits=8, decimal_places=5, blank=True, null=True)
I want to find the postcodes with 100km of a given postcode, at:
{'latitude': 1.445671659052796, 'longitude': 1.6673342919117797}
and I find the latitude and longitude ranges to be:
longitude_max = 1.9703812919117922
longitude_min = -1.3642872919117792
latitude_max = 52.2326886590528
latitude_min = 49.3413453409472
I query the db like so:
return Postcode.objects.filter(latitude__range=(latitude_min, latitude_max), longitude__range=(longitude_min, longitude_max))
But I don't get anything back? I should at least get the result I extrapolated the ranges from!
If you are filtering with those parameters for that coordinate, the queryset will not contain that item. The latitude is outside of the range provided.

How to check if event's date is within a date range?

I have events (from an Event model) that have a starts_at: value in the form of a datetime. e.g.:
2016-02-18 11:00:00:00000
What I want to be able to do is check whether an event is starting this week.
I want to be able to make a list of events that are occuring this week (starting from the latest Monday).
#events = #calendar.events.where( ... )
I thought something along the lines of this:
start_week = Date.today.beginning_of_week(:monday).day()
end_week = Date.today.beginning_of_week(:monday).day()+6
range = start_week..end_week
#events = #calendar.events.where(starts_at: in range)
But it doesn't take into account the month or year. Also I'm not sure how to write the 'where' clause. How should I go about doing this? Thanks
Try this:
start_week = Date.today.beginning_of_week(:monday)
end_week = Date.today.beginning_of_week(:monday)+6
range = start_week..end_week
#events = #calendar.events.where(starts_at: range)
Assuming you want all the events from the current week, something like this should work:
#events = #calendar.events.where(starts_at: Time.zone.today.all_week)
all_week returns a Date range covering the current week.

Django rest framework serialize queryset of many models

I would like to combine 2 querysets from 2 differents models, then I need to order them by date and finally my goal is to serialize it.
So far I did that :
last_actions = serializers.SerializerMethodField()
def get_last_actions(self, obj):
prc = obj.product_request_configs.all().order_by('modified_date')[:5]
psc = obj.product_send_configs.all().order_by('modified_date')[:5]
result_list = sorted(
chain(prc, psc),
key=attrgetter('modified_date'),
reverse=True)
But I don't know how to call my two django rest serializers so that I can return the right data.
If I could make a database view it coult be simpler I think.
Serializers are designed for match one model relationship, so we need to create a custom Model for the logic you are trying to achieve:
class CustomModel(models.Model):
def dictfetchall(self, cursor):
"""Returns all rows from a cursor as a dict"""
desc = cursor.description
return [dict(zip([col[0] for col in desc], row))
for row in cursor.fetchall()]
def yourMethod(self):
cursor = connection.cursor()
cursor.execute("""
select field1, field2 from app_table
where field1=%s and field2=%s group by field1
""",
[value1, value2,]
)
return self.dictfetchall(cursor)
class Meta:
abstract = True
This will return a dictionary and then you can serialize that response with a seializer like:
class CustomModelSerializer(serializers.Serializer):
field1 = serializers.IntegerField()
field2 = serializers.CharField()
Please note that on SQL you can use as keyword to rename some fields, the current name of fields must match var names in your serializer.

Rails Auto-populate form field based off of date input

I have a Rails 3.2.18 app where in my form I have a field for age (int) and date of birth (datetime). I will be using a simple jQuery date picker to select the DOB.
Here's what I want to happen.
The first field is the DOB (Date of birth). I want to select that, and as soon as it's selected I'd like to calculate the age and automatically fill the age field based off of that selection.
I think I can do it somehow by creating a method on the model that calculates the age, but I'm not sure how to populate it in the age field. Perhaps some Javascript or something?
Any help would be greatly appreciated.
Below is a method I wrote for another app that calculates age based on DOB and can be used in a view:
def age(dob)
now = Time.zone.now.to_date
now.year - patient_dob.year - ((now.month > patient_dob.month || (now.month == patient_dob.month && now.day >= patient_dob.day)) ? 0 : 1)
end
What you are suggesting is not possible to do in Ruby. You can use JavaScript.
It's not possible to calculate the age, based on user input, without first traveling to the server, calculating the age, and then rendering the result to the client. The model has no knowledge of the date that the user puts in; this is, unless you submit the form, of course.
It's possible to submit the form via Ajax. For example, some sites let you fill in a zip code, and then they prefil the address for you. What is really happening is, behind the scenes, the browser is sending an ajax request to a server that returns an address.
In your case you shouldn't have to do that since calculating the age in JavaScript is very easy. It's also quicker to do it on the client since it saves you the round trip to the server.
Take a look at this answer which shows you how to calculate a persons age based on an input date.
If you are using Rails you will likely be using jQuery. In which case you can do something like this:
$('#date_input').on('change', function () {
date = $(this).val();
age = getAge(date);
$('#age_input').val(age);
});
# This is taken directly from this answer: https://stackoverflow.com/a/7091965/276959
function getAge(dateString) {
var today = new Date();
var birthDate = new Date(dateString);
var age = today.getFullYear() - birthDate.getFullYear();
var m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
Then, on the server you may want to recalculate the age before you save the data into the database. This is because nothing stops the user from submitting a false age directly. Either by filling it in, or by altering the DOM.
class Person
before_save :set_age
private
def set_age
self.age = # Calculate age here.
end
end
See this answer on how to calculate age using Ruby, which looks identical to the code you have in your question.
This is a more client side javascript way to achieve this with date accuracy using server.
In your rails view when parent page loads
<%= javascript_tag do%>
var currDate = new Date('<%= Date.today%>');
<%end%>
In your js file (i assumed date-picker to be the input selected using date picker.)
function calcAge(dateString) {
var birthDate = new Date(#('date_picker').val());
var age = currDate.getFullYear() - birthDate.getFullYear();
var m = currDate.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && currDate.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
Then just need to call calcAge on date selected event and the
return age;
can change to set value on an input field
$('#ageField').val(age);

Resources