I'm new in Django Rest Framework. I have this model -
class Post(models.Model):
created = models.DateTimeField(auto_now_add=True)
description = models.CharField(verbose_name='description', db_index=True, max_length=64)
In this model, I want to add field "isActual", which value equal True or False.
His value must be False, if Post created more than 1 month (check field "created").
I don't know how to create it. Is it possible?
First, Create BooleanField() and
Check with current timezone like this Answer and try it.
Hope this helps!
You can annotate your queryset like:
from django.utils.timezone import
from dateutil.relativedelta import relativedelta
from django.db.models import BooleanField, Q, Expression
Post.objects.annotate(
is_actual=ExpressionWrapper(
Q(created__gte=now() - relativedelta(months=1)),
output_field=BooleanField()
)
)
The Post objects that arise from this, will carry an extra attribute is_actual that is True if the post is younger than one month, and False otherwise.
You need to install the python-dateutil package [PiPy] first in order to import the relativedelta [readthedocs.io], with:
pip install python-dateutil
Related
i'm trying to give condition to an annotate field to return a BooleanField
class Employee(models.Model):
date_of_expire = models.DateTimeField()
my views.py
from django.db.models import Case,When,BooleanField
def lists(request):
lists = Employee.objects.annotate(is_expire=Case(When(
date_of_expire__lte=timezone.now()
),output_field=BooleanField())).order_by('-date_of_expire')
#others
but it doesnt work , still return all existing data even some of object's date_of_expire is less than current time
is there something else i should try please ?
as Mr #willem Van Onsem mentioned a link in the comment
from django.db.models import BooleanField,ExpressionWrapper,Q
lists = Employee.objects.annotate(is_expire=ExpressionWrapper(Q(date_of_expire__lte=timezone.now()),output_field=BooleanField()).order_by('-date_of_expire')
ExpressionWrapper
I have a django model that has a date field and a separate time field. I am trying to use a filter to find a value on the latest record by date/time that is less than the current record's date time.
How do I use annotate/aggregate to combine the date and time fields into one and then do a filter on it?
models.py
class Note(models.model):
note_date = models.DateField(null=True)
note_time = models.TimeField(null=True)
note_value = models.PositiveIntegerField(null=True)
def get_last(n):
"""
n: Note
return: Return the note_value of the most recent Note prior to given Note.
"""
latest = Note.objects.filter(
note_date__lte=n.note_date
).order_by(
'-note_date', '-note_time'
).first()
return latest.note_value if latest else return 0
This will return any notes from a previous date, but if I have a two notes on the same date, one at 3pm and one at 1pm, and I send the 3pm note to the function, I want to get the value of the 1pm note. Is there a way to annotate the two fields into one for comparison, or do I have to perform a raw SQL query? Is there a way to convert the date and time component into one, similar to how you could use Concat for strings?
Note.objects.annotate(
my_dt=Concat('note_date', 'note_time')
).filter(
my_dt__lt=Concat(models.F('note_date'), models.F('note_time')
).first()
I am too late but here is what I did
from django.db.models import DateTimeField, ExpressionWrapper, F
notes = Note.objects.annotate(my_dt=ExpressionWrapper(F('note_date') + F('note_time'), output_field=DateTimeField()))
Now we have added a new field my_dt of datetime type and can add a filter further to do operations
Found an answer using models.Q here: filter combined date and time in django
Note.objects.filter(
models.Q(note_date__lt=n.note_date) | models.Q(
note_date=n.note_date,
note_time__lt=n.note_time
)
).first()
I guess I just wasn't searching by the right criteria.
Here is another Approach which is more authentic
from django.db.models import Value, DateTimeField
from django.db.models.functions import Cast, Concat
notes = Note.objects.annotate(my_dt=Cast(
Concat('note_date', Value(" "), 'note_time', output_field=DateTimeField()),
output_field=DateTimeField()
).filter(my_dt__lte=datetime.now())
Here is another solution following others.
def get_queryset(self):
from django.db import models
datetime_wrapper = models.ExpressionWrapper(models.F('note_date') + models.F('note_time'), output_field=models.DateTimeField())
return Note.objects.annotate(
note_datetime=datetime_wrapper
).filter(note_datetime__gt=timezone.now()).order_by('note_datetime')
Given that I have a django model that has a ForeignKey that is linked to itself.
class DjangoModel():
[...]
successor = models.ForeignKey('self', null=True)
I was able to write a custom django database function like this:
from django.db.models import BooleanField
from django.db.models import Func
class IsNull(Func):
"""
See docs: https://docs.djangoproject.com/en/1.8/ref/models/database-functions/
"""
template = '%(expressions)s IS NULL'
def __init__(self, *args, **kwargs):
kwargs['output_field'] = BooleanField()
super(IsNull, self).__init__(*args, **kwargs)
So I can do this:
queryset = DjangoModel.objects.all()
queryset = queryset.annotate(**{'is_latest': IsNull('successor')})
and if use queryset.values() .. I get
[{'pk': 1, is_latest': True}, {'pk': 2, 'is_latest': False}, ]
where is_latest == True when successor field is NULL for an object.
Now I want to do something similar, but have no idea where to start!
The bundled django.contrib.auth.models.User has a ManyToMany relations to django.contrib.auth.models.Group model
For my project, there are multiple user group types, e.g customer / marketing / finance etc
What I want to do.. is annotate a User queryset with is_FOO field where FOO is a group name. e.g is_customer or is_marketing
So if I use .values() on a queryset, I should get something like this:
[{'pk': 1, 'is_customer': True, 'is_marketing': False }, {'pk': 1, 'is_customer': True, 'is_marketing': True }]
The group name could be hardcoded, e.g
queryset.annotate(**{'is_customer': IsGroupMember('customer')})
I just need help with the IsGroupMember database function!
Is that even possible? Any hints or tips to get me started?
Any help will be genuinely appreciated. Many Thanks
I have 2 solutions for the problem :-)
Given that I'm using the django auth user model
from django.contrib.auth.models import User
and the group name I'm interested in:
CUSTOMER_GROUP_NAME = 'customer'
Solution 1 — as suggested by Todor Velichkov in django-users google group.
Slightly modified version of his answer below:
from django.db.models.expressions import RawSQL
def is_group_member(group_name):
return RawSQL("""EXISTS(
SELECT 1 FROM `auth_group`
WHERE `auth_group`.`name` = %s
AND `auth_group`.`id` IN (
SELECT `auth_user_groups`.`group_id`
FROM `auth_user_groups`
WHERE `auth_user_groups`.`user_id` = `auth_user`.`id`
)
)""", (group_name,), output_field=BooleanField())
qs1 = User.objects.all().annotate(is_customer=is_group_member(CUSTOMER_GROUP_NAME))
Link to original answer: https://groups.google.com/d/msg/django-users/BLCGZtUzEcY/w5w87frbBgAJ
I did some more research and learnt about django conditional expressions.
Docs: https://docs.djangoproject.com/en/1.9/ref/models/conditional-expressions/
Solution 2 — using django expressions :-)
from django.contrib.auth.models import User
from django.db.models import BooleanField
from django.db.models import When, Case, Value
query = When(groups__name__in=[CUSTOMER_GROUP_NAME, ], then=Value(1))
qs2 = User.objects.annotate(
is_customer=Case(query, default=Value(0), output_field=BooleanField()))
I think "Solution 2" is cleaner and easier to read. So I'll be using that :-)
I have a model:
class Document(models.Model):
expiry_date = models.DateField()
How can I build a query which fetches all documents and give them annotation whether the expiry date has passed or not?
I tried this:
today = timezone.now.date()
Document.objects.annotate(
expired=Value(
F('expiry_date')<today,
BooleanField()
)
)
But it raises an error: TypeError: unorderable types: F() < datetime.date()
How can I compare value from F() expression with the date?
Also, I'd like to avoid SQL and .extra()
There's no need to do that in the database. Put it in a model method:
class Document(models.Model):
expiry_date = models.DateField()
def expired(self):
return self.expiry_date < timezone.now.date()
You can use a conditional annotation.
Tested with Django 1.11.10.
from django.db.models import BooleanField, Case, When
from django.utils import timezone
Document.objects.annotate(
expired=Case(
When(expiry_date__lt=timezone.now(), then=True),
default=False,
output_field=BooleanField()
)
).order_by('expired')
This works for Django >= 2, didn't check for previous versions
from django.db import models
from django.db.models import ExpressionWrapper, Q
from django.db.models.functions import Now
Document.objects.annotate(
expired=ExpressionWrapper(Q(expiry_date__lt=Now()),
output_field=models.BooleanField())
)
source:
https://stackoverflow.com/a/57114224/11193405
I am fairly new to django and I am trying to constrain a django model field such that the age less than 25 years is shown as an error (using the datefield). So, I have the following model:
dob = models.DateField(blank=False, )
I am wondering how one can apply the above constraint in a django model.
Thanks.
I've just come across the same problem, and here is my solution for a custom field validator that checks for a minimum age value:
from django.utils.deconstruct import deconstructible
from django.utils.translation import ugettext_lazy as _
from django.core.validators import BaseValidator
from datetime import date
def calculate_age(born):
today = date.today()
return today.year - born.year - \
((today.month, today.day) < (born.month, born.day))
#deconstructible
class MinAgeValidator(BaseValidator):
message = _("Age must be at least %(limit_value)d.")
code = 'min_age'
def compare(self, a, b):
return calculate_age(a) < b
The calculate_age snippet is from this post.
Usage:
class MyModel(models.Model):
date_of_birth = models.DateField(validators=[MinAgeValidator(18)])
You need to create custom field validator.
Unfortunately you will need to hardcode the age value inside validator function, since it doesn't allow you to pass any arguments.
Then to calculate age use this snippet to correctly cover leap years.