I have a django model like this
class AthleteSubscription(models.Model):
user = models.ForeignKey(User, related_name="user_subscription", default='')
subscription_start = models.DateField(default=datetime.date.today)
subscription_end = models.DateField(default=datetime.date.today() + timedelta(30))
Where subscription_start is start date of subscription and subscription_end is the end date of subscription. Subscription is of 30 days. I want to get those records in which current date (date today) lies between subscription_start and subscription_end. How can I do this with django ORM.
qv = AthleteSubscription.objects.filter(subscription_start__gte=some_date, subscription_end__lte=some_date)
Related
I want to bring users who have not updated their salary information in the last 1 year. BUT WITH ORM not For Loop.
from simple_history.models import HistoricalRecords
class User(AbstractUser):
...
salary_expectation = models.IntegerField()
history = HistoricalRecords(cascade_delete_history=True)
################################################################
User.objects.filter(# MAGIC ) # Get users who have NOT updated their salary information in the last year
I can see that this is a package which has its documentation in querying its entries, see below:
https://django-simple-history.readthedocs.io/en/latest/querying_history.html
nevertheless you can do that intuitively following Django's normal behavior and a couple of SQL knowledge, I'd expect that history field's table most likely has a one-to-many relationship with the users table, so what I'd do is first open the database, find the column that shows the date of change, write down its name and then write this ORM query below
sub_query = ~Q(history__history_date__lte= "Replace with end of date", history__history_date__gte= "Replace with beginning of date", salary_expectation__isnull=False)
users = User.objects.filter(sub_query)
dont forget to import Q
from django.db.models import Q
You do not need to check HistoricalRecords class for this information.
Add created_at and updated_at (date_time_fields) fields to your User model
class User(...):
...
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Queryset Code
from django.db.models.functions import Now, ExtractDay
from django.contrib.auth import get_user_model
User = get_user_model()
users = User.objects.annotate(
# Calculate duration between now and last update date saved
duration=models.ExpressionWrapper(
Now() - models.F("updated_at"),
output_field=models.DurationField()
),
# Extract the amount of days in the duration
days=ExtractDay('duration'),
# Check if the number of days between the 2 fields exceeds 1 year (365.25 Days)
last_update_beyond_a_year=models.Case(
models.When(
models.Q(days__gte=365.25),
then=True
),
default=False,
output_field=models.BooleanField()
)
# Then filter
).filter(last_update_beyond_a_year=True)
and Voila !
models.py
class Dibbs_Fields(models.Model):
hash = models.CharField(max_length=16)
nsn = models.CharField(max_length=32)
nomenclature = models.TextField()
technical_documents = models.TextField()
return_by = models.DateField()
How to filter this class in django views according to the date return_by ? I don't want to show the data that is expired i.e. if the return_by date is earlier than today's date, then it should not show.
You can do this:
from datetime import date
def func(request):
today = date.today()
data = Dibbs_Fields.objects.filter(
return_by__lt=today)
The code simply returns data are earlier than today's date.
EDIT
return_by__lt # less than
return_by__gt # greater than
return_by__gte # greater than or equal to
return_by__lte # less than or equal to
I am new with Django and coding. After doing Local Library and Polls tutorial on MDN and Django respectively.
I am now working on travel itinerary app. Where I want that my model should be able to take start date as enter by user and based on number of nights selected by user should auto fill the end date.
Example:
Start Date: 09-July-21
No. of Nights: 05
End Date: 14-July-21
Code for models.py is as follows, I will be using Postgresql DB for this project
class Packages(models.Model):
title_package = models.CharField(max_length=300)
no_of_nights = models.SmallIntegerField()
summary = models.TextField(max_length=3000)
start_date = models.DateField(help_text='should not allow client to book in past')
end_date = models.DateField(help_text='based on start date selection and no. of nights client is staying.')
You can count end date on view form_valid as follows:
def form_valid(self, form):
instance = form.save(commit=False)
start_date = form.cleaned_data.get('start_date')
no_of_nights = form.cleaned_data.get('no_of_nights')
instance.end_date = start_date + timedelta(days=no_of_nights)
instance.save()
Extending from the question here, where queryset is filtered using input from the user, I wanted to know if it was possible to filter queryset depending on present month and week. Eg each month should start on the 1st and each week on a monday and the queryset should be filtered for all the tests that have taken place in the present month and week.
models.py
class City(models.Model):
city_name=models.CharField(max_length=100,default='',blank=False)
class Person(models.Model):
title = models.CharField(max_length=3,default="mr",blank=False)
name = models.CharField(max_length=50,default='',blank=False)
address = models.CharField(max_length=200,default='',blank=False)
city = models.ForeignKey(City)
class Test(models.Model):
person = models.ForeignKey(Person)
date = models.DateTimeField(auto_now_add=True)
test_name = models.CharField(max_length=200,default='',blank=False)
subject = models.CharField(max_length=100,default='')
views.py
def personlist(request, id):
data = requests.get('http://127.0.0.1:8000/app/cities/' + id + '/persons/').json()
context = RequestContext(request, {
'persons': data['results'],'count': data['count'],
})
return render_to_response('template.html', context)
And the related json
According to this question - one way could be to use
startdate = date.today()
enddate = startdate + timedelta(days=6)
Sample.objects.filter(date__range=[startdate, enddate])
But wouldn't date.today() keep changing everyday and thus everyday a new week will start and thus, a new queryset?Similarly with month. Is there a way to get querysets filtered by present week and month. With each starting from every monday and every 1st respectively?
You can use the __month and __year lookups to limit the queryset to this month's objects.
from datetime import date
today = date.today()
this_month_qs = Sample.objects.filter(
date__month=today.month,
date_year=today.year,
)
To find this weeks objects, you first need to find the date of this Monday. You can do this by finding today's day of the week (Monday = 0, Sunday = 6) using a date's weekday() method, and subtracting that many days from today. It's easy to calculate the last day of the week by adding 6 days, and then you can use __range to find this week's objects.
from datetime import date, timedelta
today = date.today()
# Use today.isoweekday() if you want the week
# to start on Sunday instead of Monday
first_day_of_week = date.today() - timedelta(today.weekday())
end_date = first_day_of_week + timedelta(days=6)
this_week_qs = Sample.objects.filter(date__range=[startdate, enddate])
Lets say I have a sale model:
class Sale(models.Model):
total = models.DecimalField(max_digits=8, decimal_places=2, default=0)
sale_date = models.DateTimeField(auto_now_add=True)
Now, with each sale sale_date get its value saved in UTC, so if I try to group and sum all the sales by day:
report = Sale.objects.extra({'day':"date(sale_date)"}).values('day').annotate(day_total=Sum('total'))
I get all wrong becouse I expect each day in a different timezone (UTC-6).
Is there a way to get the correct sums in a specific tiemezone? Im working with MySQL.
Ah, this was a good challenge. I was able to test from PostGres, and I can confirm it is working. The MySQL code should be pretty close. However, there is a note on the CONVERT_TZ documentation:
To use named time zones such as MET or Europe/Moscow, the time zone tables must be properly set up. See Section 10.6, “MySQL Server Time Zone Support”, for instructions.
MySQL (using CONVERT_TZ(dt, from_tz, to_tz))
from_tz = 'UTC'
to_tz = 'Australia/ACT'
report = Sale.objects.extra(
{
'day': "date(CONVERT_TZ(sale_date, '{from_tz}', '{to_tz}'))".format(
from_tz=from_tz,
to_tz=to_tz
)
}
).values(
'day'
).annotate(
day_total=Sum('total')
)
PostGres: (using AT TIME ZONE)
time_zone = 'Australia/ACT'
report = Sale.objects.extra(
{'day': "date(sale_date) AT TIME ZONE '{0}'".format(time_zone)}
).values(
'day'
).annotate(
day_total=Sum('total')
)