Skip to content

Instantly share code, notes, and snippets.

@Azarakhsh
Created March 11, 2018 07:20
Show Gist options
  • Save Azarakhsh/c34a5090d5fae62550d2a95ae0e92da9 to your computer and use it in GitHub Desktop.
Save Azarakhsh/c34a5090d5fae62550d2a95ae0e92da9 to your computer and use it in GitHub Desktop.
Extends dlango_jalali to supports database Extract functions
# Adding support for Extracting date components for Jalali Date models
from django_jalali.db.models import jDateField, jDateTimeField
from django.db.models import (
DateField, IntegerField,
Transform,
)
from django.db.models.functions.datetime import TimezoneMixin
class jExtract(TimezoneMixin, Transform):
lookup_name = None
output_field = IntegerField()
def __init__(self, expression, lookup_name=None, tzinfo=None, **extra):
if self.lookup_name is None:
self.lookup_name = lookup_name
if self.lookup_name is None:
raise ValueError('lookup_name must be provided')
self.tzinfo = tzinfo
super().__init__(expression, **extra)
def as_sql(self, compiler, connection):
sql, params = compiler.compile(self.lhs)
lhs_output_field = self.lhs.output_field
if isinstance(lhs_output_field, jDateTimeField):
tzname = self.get_tzname()
sql = connection.ops.datetime_extract_sql(self.lookup_name, sql, tzname)
elif isinstance(lhs_output_field, jDateField):
sql = connection.ops.date_extract_sql(self.lookup_name, sql)
else:
# resolve_expression has already validated the output_field so this
# assert should never be hit.
assert False, "Tried to jExtract from an invalid type."
return sql, params
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
copy = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
field = copy.lhs.output_field
if not isinstance(field, (jDateField, jDateTimeField)):
raise ValueError(
'jExtract input expression must be jDateField, jDateTimeField.'
)
# Passing dates to functions expecting datetimes is most likely a mistake.
if type(field) == jDateField and copy.lookup_name in ('hour', 'minute', 'second'):
raise ValueError(
"Cannot extract time component '%s' from jDateField '%s'. " % (copy.lookup_name, field.name)
)
return copy
class jExtractYear(jExtract):
lookup_name = 'year'
class jExtractMonth(jExtract):
lookup_name = 'month'
class jExtractDay(jExtract):
lookup_name = 'day'
class jExtractWeek(jExtract):
"""
Return 1-52 or 53, based on ISO-8601, i.e., Monday is the first of the
week.
"""
lookup_name = 'week'
class jExtractWeekDay(jExtract):
"""
Return Sunday=1 through Saturday=7.
To replicate this in Python: (mydatetime.isoweekday() % 7) + 1
"""
lookup_name = 'week_day'
class jExtractQuarter(jExtract):
lookup_name = 'quarter'
DateField.register_lookup(jExtractYear)
DateField.register_lookup(jExtractMonth)
DateField.register_lookup(jExtractDay)
DateField.register_lookup(jExtractWeekDay)
DateField.register_lookup(jExtractWeek)
DateField.register_lookup(jExtractQuarter)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment