Upcoming birthdays with MongoEngine - python

Any idea how can I find the next upcoming birthdays considering this code (based on Python/Mongoengine)
class User(mongoengine.Document):
(...)
birthday = DateTimeField()
I know how to do it in plain SQL, but I have no idea how to do this query with this language.

There could be some benefit to save something like:
class User(mongoengine.Document):
birthdate = DateTimeField()
birth_month = IntegerField()
birth_day = IntegerField()
then to query, everyone with bithrdays this month or next month
current_month = datetime.now().month
current_day = datetime.now().day
next_month = (datetime.date.today() +
dateutil.relativedelta.relativedelta(months=1)).month
User.object.filter(Q(birth_month=current_month, birth_day__gte=current_day) |
Q(birth_month=next_month)).order_by('birthday')
The above should get all the users who have birthday from today until next the end of next month. Started to write a solution but failed!, this problem seems deceptively hard, hopefully someone has a lot cleaner solution

Related

how to get year from datefield at django?

i want to get year from birthday.
so i use self.birthday.year
but it make error.
how do i fix it?
best regards.
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_("Name of User"), blank=True, max_length=255) #이름
gender = models.CharField(max_length=1, choices=CHOICES_GENDER) # 성
birthday = models.DateField(null=True) #생일
def calculate_age(self):
import datetime
return int((datetime.date.year - self.birthday.year) +1)
age = property(calculate_age) #나이
Try this solution,
from datetime import date
class User(AbstractUser):
name = models.CharField(_("Name of User"), blank=True, max_length=255)
gender = models.CharField(max_length=1, choices=CHOICES_GENDER)
birthday = models.DateField(null=True)
#property
def calculate_age(self):
if self.birthday:
today = date.today()
return today.year - self.birthday.year - ((today.month, today.day) < (self.birthday.month, self.birthday.day))
return 0 # when "self.birthday" is "NULL"
The problem is that datetime.date.year does not exists. You can fetch the year of a date (or datetime) object with .year, and you can thus for example use today() or now().
Semantically the function is incorrect as well. If I am born in 1984, then I am not per se 35 years old: that depends on whether the current year is before or after the day of birth (for example February 9th).
Finally there can be an error if the self.birthday value is None. In that case you probably want to return None as well.
So a potential solution for this is:
from datetime import date
class User(AbstractUser):
# ...
def calculate_age(self):
bd = self.birthday
if bd:
td = date.today()
return td.year - bd.year - ((td.month, td.day) < (bd.month, bd.day))
We thus first calculate today(), and then we return the current year minus the year of the birthday and minus one if today is still before the birthday this year.
In case the user did not specify his/her birthday, then the calculate_age(..) will return None (a value that can be interpreted as "unknown").
An issue that still remains (and is harder to fix) are timezones: since today in Australia is another today than in the United States, it is possible that - depending on where the server and users are located - the age of a user is one too high the day before his/her birthday, or one too low one day on his/her birthday. This is a harder problem to solve, since we have no information here where the user is located.

Django exclude on multiple fields in subquery

Given some code like this:
# coding: utf-8
import datetime
from django.db import models
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
class Premium(models.Model):
"""Access to Premium Features™®."""
end = models.DateField()
user = models.ForeignKey(User)
site = models.ForeignKey(Site)
def get_ending_premiums():
"""Get a queryset of all Premiums for which a user has none following."""
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
future_premiums = Premium.objects.filter(end__gt=tomorrow).values('user', 'site')
return Premium.objects.filter(end=tomorrow).exclude(
# Would love if something like this actually worked...
user_and_site__in=future_premiums,
)
How can I complete get_ending_premiums()? One of the key things is I want Premiums only when there isn't another one that ends later, but on a per-site basis. So if a user has another Premium on groceries.com, the one about to end tomorrow doesn't get returned, but if they don't have another Premium on officesupplies.com, that one does get returned.
(Note the line with with the comments before it doesn’t actually work... that’s the part I need to complete.)
I can work out how to do this outside the ORM but I’d really prefer an ORM solution, as we’re planning on switching database vendors in a few months, so I’m trying to avoid raw SQL as much as possible.
Here’s a test for the behavior I’d like to get:
class PremiumTest(TestCase):
def test_gets_ending_premiums(self):
today = date(2020, 6, 5)
tomorrow = today + timedelta(days=1)
next_year = today + timedelta(days=366)
groceries = Site.objects.create(domain='groceries.com')
catvids = Site.objects.create(domain='catvids.com')
dave = User.objects.create_user('dave')
sally = User.objects.create_user('sally')
Premium.objects.create(user=dave, site=groceries, end=tomorrow)
Premium.objects.create(user=dave, site=groceries, end=next_year)
Premium.objects.create(user=dave, site=catvids, end=tomorrow)
Premium.objects.create(user=sally, site=groceries, end=tomorrow)
Premium.objects.create(user=sally, site=catvids, end=tomorrow)
Premium.objects.create(user=sally, site=catvids, end=next_year)
ending_premiums = get_ending_premiums(today)
ending = set((p.user, p.site) for p in ending_premiums)
self.assertNotIn((dave, groceries), ending)
self.assertIn((dave, catvids), ending)
self.assertIn((sally, groceries), ending)
self.assertNotIn((sally, catvids), ending)
self.assertEqual(2, len(ending_premiums))
I've come up with this... It's got some raw SQL but it still returns a QuerySet with normal QuerySet methods (although it uses the apparently deprecated QuerySet.extra() method)
def get_ending_premiums(day=None):
"""Get a queryset of Premiums for which a user has none following."""
if day is None:
day = date.today()
tomorrow = day + timedelta(days=1)
ending_premiums = Premium.objects.filter(
end=tomorrow,
).extra(
where=['NOT EXISTS (SELECT NULL FROM premium_premium child where premium_premium.site_id = site_id AND premium_premium.user_id = user_id AND end > %s )'],
params=[tomorrow],
)
return ending_premiums
Still wondering if there isn’t a better way...

Sorting queryset with date

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])

Change query in Django based on day of week

First of all thank you for looking at my question.
I am looking for a way to store the day of week in a model, I have established that having a boolean for each day of the week in the model is likely the most simple approach. I had looked at using bitflags but was unsure again how to query this.
My model looks like the following
class CallForwardingRule(models.Model):
forward_to = models.CharField(max_length=255,null=False,blank=False)
start_time = models.TimeField(default=time(0,0))
end_time = models.TimeField(default=time(0,0))
active = models.BooleanField(default=True)
monday = models.BooleanField(default=False)
tuesday = models.BooleanField(default=False)
wednesday = models.BooleanField(default=False)
thursday = models.BooleanField(default=False)
friday = models.BooleanField(default=False)
saturday = models.BooleanField(default=False)
sunday = models.BooleanField(default=False)
My query is then like the following
CallForwardingRule.objects.filter(start_time__lte=time,end_time__gte=time)
What I need to do is alter the query depending on the current day, if the day is monday the query should look for a rule where boolean value monday=True
I hope I have been clear in my question, I am quite new to Django and Python.
Kind Regards
You can use a custom manager. Say
class TodayManager(models.Manager):
def get_queryset(self, *args, **kwargs):
today = self.weekday_as_string()
return super(TodayManager, self).get_queryset(*args, **kwargs).filter(
**{today: true})
def weekday_as_string(self):
# TODO
class CallForwardingRule(models.Model):
# your fields
of_today = TodayManager()
And query like this:
CallForwardingRule.of_today.filter(
start_time__lte=time,end_time__gte=time)
Read more about object managers here https://docs.djangoproject.com/en/1.8/topics/db/managers/
NOTE: If you don't intend for the user to be able to mix days in the same model instance, you should use an integer field with choices instead, as suggested in the comments.
You should either use an integer or a charfield for your dayofweek. Each of them may be used with choices (https://docs.djangoproject.com/en/1.8/ref/models/fields/#choices) which allows you to make it easier to translate the code of the day to its name.
Then, you just have to filter your queryset with this field.

How to create selection tabs for date and time field in Django?

Have looked through DateField, TimeField, DateTimeField related documents but I cannot seem to find what I need. I simply want to have a selection of month, day, year, hour, minute, (AM/PM) type option. I have tried using 'choice=', but do not get the nice behavior I am looking for.
** TL;DR: I simply want a way of putting in the date and time without having to type it in. I would like a nice drop down menu **
class Event(models.Model):
event_name = models.CharField(max_length = 50)
date_time = models.DateTimeField()
date = models.DateField()
location = models.CharField(max_length = 30)
address = models.CharField(max_length = 30)
city = models.CharField(max_length = 30)
zip_code = models.CharField(max_length = 30)
state = models.CharField(max_length = 30)
description = models.TextField()
def __unicode__(self):
return self.event_name
class EventForm(ModelForm):
class Meta:
model = Event
This is what I currently have. I have removed the choices part and I even tried making my own model object dedicated to date and time, but that did not go well
I tried it using this ...
DATE_CHOICES = (('Jan', "January"),
('Feb', "Feburary"),
('Mar', 'March'),
('Apr','April'),
('May ','May'),
('June','June'),
('July','July'),
('Aug','August'),
('Sept','Septemeber'),
('Oct','October'),
('Nov','November'),
('Dec','December')
)
class DateTime(models.Model):
month = models.CharField(max_length = 5, choices=DATE_CHOICES)
But I am not getting the correct behavior as I want.
You might be interested in using jquery date picker or jquery datetime picker.
http://jqueryui.com/datepicker/
http://trentrichardson.com/examples/timepicker/
On both sites there are exampels so you can see it in action :)
You definitely want to use this snippet. Unless you're a django ninja and want to roll up your own multi widget, which is what you will need to transform a set of select inputs into one datetime value.
This widget is the closest you will get to do it, without using any js plugins.
Your can use datepicker plagin as Erfin mentioned (I recommend it too and also datepicker for bootstrap) for date and masked input for time or just simple selects. Anyway you should send a request with datetime information. What to do in django:
If you use datepicker plugin for date and masked input for time
Let's assume that your request is POST. Your date will be a string with format you specify in javascript. It looks like "31.01.2013". And time will be like "22:30".
def write_datetime(request):
event = Event.objects.get(id=int(request.POST.get('id')))
from datetime.datetime import strptime
date = request.POST.get('date')
time = request.POST.get('time')
date_time = date + " " + time
event.date_time = strptime(date_time, "%d.%m.%y %H:%M"
event.save()
If you use just selects
In this case, it's simplier to make a datetime string from request parameters and repeat the preveous example.
def def write_datetime(request):
year = request.POST.get('year')
month = request.POST.get('month')
# etc
date_time = "%s.%s.%s %s:%s" % (day, month, year, hours, minutes)
# etc

Categories

Resources