django queryset filter datetimefield - python

I am strungling to use the django queryset API reference with filters based on the DateTimeField.
I have prepared the following model, in my models.py:
class KleedkamerIndeling(models.Model):
gametimedate = models.DateTimeField(auto_now=False, auto_now_add=False) # date and time of game
hometeam = models.CharField(max_length=25, blank=True) # name of home playing team team
homedressroom = models.CharField(max_length=25, blank=True) # dressing room of home playing team
awayteam = models.CharField(max_length=25, blank=True) # name of visiting team team
awaydressroom = models.CharField(max_length=25, blank=True) # dressing room of visiting team team
pitch = models.CharField(max_length=25, blank=True) # name / number of playing pitch
referee = models.CharField(max_length=25, blank=True) # name of referee
refdressroom = models.CharField(max_length=25, blank=True) # name/number of referee dressroom
timestamp = models.DateField(auto_now_add=True, auto_now=False)
indelings_datum = models.DateField() # need to change to datum added later
def __unicode__(self):
return smart_unicode(self.hometeam)
I want to access the database based on the present date. Should be something like:
queryset = KleedkamerIndeling.objects.all().filter(gametimedate=date.today())
This worked before when I used a 'datefield' but I decided to go to a datetimefield because I also need the starting time of the game played.
I have seached the web and stackoverflow and found the following older topic, How can I filter a date of a DateTimeField in Django? but I stungle on the implemenation.
I want to create a queryset that obtains all the 'KleedkamerIndeling' that are available for today's date. Subsequently I want to check if there are more then 10 objects in the list. If that's the case than I want to further narrow it down based on the current time, also via a filter on the datetimefield. Lastly I want to sort the object list such that it is sorted on time.
I know that my problem has to do which the caracteristics of the datetimefield van I appreciate a couple lines of code to help me move foreward. I have been trying to find the right query in the python manage.py shell all afternoon....
My model most work because the queryset = KleedkamerIndeling.objects.all() seems to work and I am able to set up seperate list for each object called 'game0 through game10 from the queryset list.
I have a further issue on the datetimefield format:
I have defined a 'KleedkamerIndeling' that describes a game that starts at 13:00. I have used the objects in the queryset list to define 10 different 'game'objects. i.e. game0 = [queryset[0].hometeam etc... though game10 if applicable. The gametime field is displayed in the template via a filter like: {{game0.0|date:"H"}}:{{game0.0|date:"i"}}. I still end up with the ':' in the case of no game0 object. I plan to solve this via a if else script in the template or in the view, or is there a better way to fix this?

Since you are using a datetime field you want to make your query’s using datetime objects. so first order the queryset from earliest to latest then filter out the events tat arn't occurring today.
from datetime import datetime, timedelta, time
today = datetime.now().date()
tomorrow = today + timedelta(1)
today_start = datetime.combine(today, time())
today_end = datetime.combine(tomorrow, time())
queryset = KleedkamerIndeling.objects.order_by('-gametimedate').filter(gametimedate__gte=today_start).filter(gametimedate__lt=today_end)
After that we can check if there are more then 10 objects, filter by the current time, and limit the queryset to 10 objects.
if queryset.count() > 10:
queryset = KleedkamerIndeling.objects.filter(gametimedate__gte=datetime.now())[:10]

Related

How to define and render Django formset for registeting hours spent on a project each day during a month?

I building a Django site where users can register their time spent working on a particular project (Time Report). In the future Time reports will be subject to approval process and possibly sources for calculating invoices to clients, but right now I struggle in setting it up in Django.
I want Time Reports to hold multiple project lines and each project line should have as many input fields as many days is in a particular month . This will allow user to register number of hours spent each day on all projects they work on. In addition each project can be presented in more than line (so user can register different tasks within the project separately, e.g. hours spent on project planning vs time spent on development).
Projects are defined separately (separate model).
I believe that I need following models to support the requirements:
from django.db import models
class TimeReport(models.Model):
employee = models.ForeignKey('employees.Employee', on_delete=models.CASCADE)
start_date = models.DateField() #to calculate Time Report month
status = models.CharField(max_length=20, default='draft')
class ProjectLine(models.Model):
time_report = models.ForeignKey('TimeReport', on_delete=models.CASCADE)
project = models.ForeignKey('projects.Project', on_delete=models.CASCADE)
comment = models.TextField(blank=True, null=True)
class ProjectLineDay(models.Model):
project_line = models.ForeignKey(ProjectLine, on_delete=models.CASCADE)
date = models.DateField()
hours = models.DecimalField(max_digits=2, decimal_places=0)
I want to achieve something like this (excel example):
Example of expected form in excel
I figured out that I’ll need to use Django formsets but I have no experience with those and so far I don’t know how to start.
I've tried creating Django form with dynamiccaly calculated number of days (e.g. for current month) but failed with connecting it with View logic:
(I'm using django-autocomplete-light for autocomplete select)
class ProjectLineForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['project'] = forms.ModelChoiceField(queryset=Project.objects.all(), widget=autocomplete.ModelSelect2(url='projects:project-autocomplete'))
today = datetime.date.today()
days_in_month = calendar.monthrange(today.year, today.month)[1]
for day in range(1, days_in_month+1):
self.fields[f'day_{day}'] = forms.IntegerField(label=False, widget=forms.NumberInput(), required=False)
self.fields['comment'] = forms.CharField(required=False)
ProjectLineFormset = formset_factory(ProjectLineForm, extra=1, can_delete=True, min_num=1)
I'm using Crispy Forms for form formating, so I'm also trying to figure out how to display it in like a grid.

Truly dynamic DateField values in Django

Some of my app models define date ranges (e.g. of contracts), where the current instance has no fixed end date (i.e. it should always evaluate to today). Setting the default parameter on the end field –
class Contract(models.Model):
building = models.ForeignKey(Building, on_delete=models.CASCADE)
service = models.ForeignKey(Service, on_delete=models.CASCADE)
begin = models.DateField()
end = models.DateField(default=datetime.date.today)
– will populate the field with a fixed value. A property to work around the problem –
class Contract(models.Model):
building = models.ForeignKey(Building, on_delete=models.CASCADE)
service = models.ForeignKey(Service, on_delete=models.CASCADE)
begin = models.DateField()
end = models.DateField(blank=True)
#property
def get_end(self):
if not self.end:
return datetime.date.today()
return self.end
– does not work with querysets. Is there any way to implement a truly dynamic value on the database level using Django's ORM?
The best options available for a sudo-dynamic DateField are auto_now and auto_now_add as mentioned in the comments. The former updates the DateField on each .save() call and the latter does it at creation (Django doc).
The other option, as mentioned by Adrian, is to set the end as Null and use a conditional query for your claen() function. You can do that either by introducing an if statement or by using Case() and When(). You can check this Django doc or see this answer for more information.
Update: In your case something like this should work:
today = datetime.today()
conflicts = Contract.objects.filter(building=building, begin__lte=Case(
... When(end=Null, then=today), default=end), end__gte=begin)
There are also other options for having a dynamic date in your model but not as a DateField, which I assume is not what you are looking for nor anything near a 'clean code'.

Automate update of models based on conditions

I have a model
class Session(models.Model):
name = models.CharField(max_length=12)
active = models.BooleanField(default=False)
date = models.DateField()
startTime = models.TimeField()
The active field is set based on the date and start time.
For eg -
Suppose during the creation of an object, the date is for tomorrow, and let there be any time, I want to know the process and not the code on how and what to study to make this object active on that particular date and time.
BY default the active field is False, or should I change the way I'm thinking to implement it?
Thanks
I would advise to use a DateTimeField for the start timestamp, and make active a property, so:
from django.utils import timezone
class Session(models.Model):
name = models.CharField(max_length=12)
start = models.DateTimeField()
#property
def active(self):
return timezone.now() >= self.start
This will thus not store the active field in the database, but simply determine the value when needed.

How to retrieve random records of Django ORM on a weekly basis

I am new to Django and I'd need some help for a project I have.
I am currently building the API using Django-Rest-Framework and
I would like to have a view which returns a weekly list of exercises.
I am not sure how i could make it so the queried objects change weekly...
atm I've created a custom Manager which retrieves a random amount of exercises from the exercise db
Models.py
class ExerciseManager(models.Manager):
def random(self, amount=20):
random_exercises = []
exercises = Exercise.objects.all()
for i in range(amount):
random_exercises.append(random.choice(exercises))
return random_exercises
class Exercise(models.Model):
name = models.CharField(max_length=100, unique=True)
objects = ExerciseManager()
def __str__(self):
return f"{self.name}"
views.py
#api_view(['GET'])
def exercise_list(request):
exercises = Exercise.objects.random()
serializer = ExerciseSerializer(exercises, many=True)
return Response(serializer.data)
I would add a created field to Exercise created = models.DateTimeField(auto_now_add=True) and then change Exercise.objects.all() to Exercise.objects.filter(created__gte=datetime.date.today - datetime.timedelta(days=7) This way you are only querying Exercise objects created in the last 7 days.
As i understand it, you want the list of exercise to be random, but stay the same for the entire week.
To me, the best way would be to create a WeeklyExercise model with a M2M on Exercise and a created_at = models.DateTimeField(auto_now_add=True) field.
With a periodic script (probably using Celery) you would create a new entry in WeeklyExercise each week.
To populate this row you can do
weekly_exercise = WeeklyExercise.objects.create()
weekly_exercise.exercises.set(*list(Exercise.objects.order_by("?")[:EXERCISE_PER_WEEK]))
To retrieve the exercises for the week you can do WeeklyExercise.objects.order_by("-created_at").first().exercises.all()
If you do not need an history of previous exercices being the weekly exercises, you could just add a is_weekly_exercise = models.BooleanField(default=False) to your Exercise model.
Your Celery script would only be
Exercise.objects.filter(is_weekly_exercise=True).update(is_weekly_exercise=False)
Exercise.objects.order_by("?")[:EXERCISE_PER_WEEK].update(is_weekly_exercise=True)

Tricky logic to calculate unique recent visitors in a Django app

I have a live web-based chat app made in Django. Users can form groups where other users can congregate, leave messages (called replies) and photos. The url every user visits to access a group is:
url(r'^group/(?P<pk>\d+)/reply/$', auth(GroupView.as_view()), name="group_reply"),
where pk is group.pk.
My question is: how can I get a list (or set) of all distinct users who accessed a certain group's URL in the last 5 mins? Essentially, I'm trying to calculate the number of unique recent visitors for each group. I can't seem to wrap my head around how to do this, though I guess sessions information could help? (I'm using django user_sessions in this project, which
"makes session objects a first class citizen like other ORM objects"
).
In case required, the model behind a group is:
class Group(models.Model):
topic = models.TextField(validators=[MaxLengthValidator(200)], null=True)
rules = models.TextField(validators=[MaxLengthValidator(500)], null=True)
owner = models.ForeignKey(User)
private = models.CharField(max_length=50, default=0)
category = models.CharField(choices=TYPE, default=1, max_length=25)
created_at = models.DateTimeField(auto_now_add=True)
And the model behind posting a reply in each group is:
class Reply(models.Model):
text = models.TextField(validators=[MaxLengthValidator(500)])
which_group = models.ForeignKey(Group)
writer = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to=upload_pic_to_location, null=True, blank=True )
And User is a vanilla django.contrib.auth user.
You don't have anything that is collecting the data you need. If you want to record visits to a page, you will need to build a model to do that; a simple one with FKs to User (for the visitor) and Group (for the group being visited), plus a timestamp, should be enough. Then your GroupView can make an entry in that table every time a user visits.

Categories