I have some date filtering in django that I just can't see what's wrong.
I have a model with this field:
date_of_birth = models.DateField(blank = True, null=True, auto_now=False, auto_now_add=False)
I then select all data
users = UserDetails.objects.all()
I have 2 rows in the database and two object returned
>>> users
[<UserDetails: UserDetails object>, <UserDetails: UserDetails object>]
>>> users[0]
<UserDetails: UserDetails object>
I can see each objects date_of_birth value
>>> users[0].date_of_birth
datetime.date(1971, 9, 28)
However any filter I try always fails?
>>> users = users.filter(date_of_birth__year >= 1970)
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'date_of_birth__year' is not defined
>>> users = users.filter(date_of_birth == datetime.date(1971, 9, 28))
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'date_of_birth' is not defined
>>> users = users.filter(date_of_birth == '1971-09-28')
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'date_of_birth' is not defined
Can anyone help explain what's wrong here?
I'm at a loss.
Thanks.
You don't filter using the comparison operators. What you're doing is actually passing a keyword argument to the filter method. To filter based on equality, simply do:
users = users.filter(date_of_birth=datetime.date(1971, 9, 28))
To filter using greater than or equals, use:
users = users.filter(date_of_birth__year__gte=1970)
That is, you append __gte to the keyword argument.
You can also filter on less than or equals (date_of_birth__year__lte), less than (date_of_birth__year__lt), or greater than (date_of_birth__year__gt).
Related
I have a date of birth (dob) DateField in my Django Model (Author). I tried to annotate age parameter. I searched for many possible ways to do it and each procedure generated some kind of error.
Here I tried in python console first to make sure that the expression would be a valid one:
>>> from datetime import datetime
>>> (datetime.now() - datetime(2000,1,1)).days #output: 7506
First Try:
>>> from django.db.models import F
>>> authors = Author.objects.annotate(age = (datetime.now()-F('dob')).days) #no-error here
>>> print(authors) # Exception thrown here
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 324, in __getitem__
qs._fetch_all()
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 1305, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 70, in __iter__
for row in compiler.results_iter(results):
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/sql/compiler.py", line 1100, in apply_converters
value = converter(value, expression, connection)
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/backends/sqlite3/operations.py", line 291, in convert_datefield_value
value = parse_date(value)
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/utils/dateparse.py", line 75, in parse_date
match = date_re.match(value)
TypeError: expected string or bytes-like object
Second time I used ExpressionWrapper to define that output type will be DateTimeField
>>> from django.db.models import DateTimeField, ExpressionWrapper
>>> authors = Author.objects.annotate(age = ExpressionWrapper(timezone.now() - F('dob'), output_field=DateTimeField()).days)
AttributeError: 'ExpressionWrapper' object has no attribute 'days'
I have also tried the RawSQL. I am using Sqlite database here. so date('now') would provide me current date.
>>> from django.db.models.expressions import RawSQL
>>> authors = Author.objects.annotate(age=RawSQL("date('now')-dob"))
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'params'
So is there any way, I could solve the issue?
You were almost there, the issue was the output_field value. It should be DurationField instead of DateTimeField
age_expr = ExpressionWrapper(timezone.now() - F('dob'), output_field=DateTimeField())
queryset = Author.objects.annotate(age=age_expr)
NOTE: You can't use .days along with ExpressionWrapper since the annotate operation performs in the DB level.
To calculate the age, you may need to use the .total_seconds() method
print(queryset[0].age.total_seconds() / 60 / 60 / 24 / 365.25)
Empty string or list params worked for the RawSQL command.
authors = Author.objects.annotate(age=RawSQL("date('now')-dob", params=""))
Trying to get the city from the zip code, so I installed the pyzipcode package. However, whenever I try to get the city I get the following error. The state, zipcode, lat/long work normally. I've tried numerous zipcodes and none of them seem to pull any city records.
from pyzipcode import ZipCodeDatabase
zcdb = ZipCodeDatabase()
zipc=zcdb['90210']
zipc.city
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'ZipCode' object has no attribute 'city'
The documentation for the package uses 'city' as an example: https://pypi.org/project/pyzipcode/.
I don't understand what I am doing wrong here. Here is my Django model:
class VMMigrationEvent(models.Model):
created = models.DateTimeField(auto_now_add=True) # DateTime because there may be multiple events in a day.
dc = models.TextField(max_length=150), # data center
destination_host = models.TextField(max_length=150), # host migrated to.
message = models.TextField(), # The message from virtual center.
updated = models.DateTimeField(auto_now=True) # DateTime because there may be multifple events in a day.
user = models.TextField(max_length=150), # The user logged into the virtual center that execute the migration.
vc = models.TextField(max_length=150), # virtual center
vm = models.ForeignKey(VirtualMachine) # The VirtualMachine record associated with this event.
And from the python console I do this:
>>> from cm.models import *
>>> dc='DCM01N-01'
>>> destination_host='auroravm2-1.example.com'
>>> message='my hovercraft is full of eels.'
>>> user='mister_gumby'
>>> vc='vca-001-s.example.com'
>>> vm='ads-108'
>>> vm_db_obj = VirtualMachine.objects.filter(name=vm).latest('create_date')
>>> vmme = VMMigrationEvent.objects.create(dc=dc,
... destination_host=destination_host,
... message=message, user=user, vc=vc, vm=vm_db_obj)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/apps/man/man/env/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/apps/man/man/env/lib/python2.7/site-packages/django/db/models/query.py", line 392, in create
obj = self.model(**kwargs)
File "/apps/man/man/env/lib/python2.7/site-packages/django/db/models/base.py", line 573, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'vc' is an invalid keyword argument for this function
Why is vc invalid? It is a field in my model?
You have commas after several of your field definitions: vc, but also dc, destination_host and user. This turns them into tuples, which can't be used as fields on the model.
Delete those commas
(Also, you probably meant CharField rather than TextField.)
I would like to do something slightly different than this.
Suppose I have something like this in my models.py:
class Hipster(models.Model):
name = CharField(max_length=50)
has_iphone = BooleanField(default=True)
class Party(models.Model):
participants = models.ManyToManyField(Hipster, related_name="participants")
And then do:
hip_parties = Party.objects.filter(participants__has_iphone__istrue__count=4)
How can I do that?
UPDATE:
>>> Question.objects.filter(options__is_correct=True).annotate(options__count=Count('options')).filter(options__count=0)
[]
>>> q = Question.objects.get(id=49835)
>>> q.options.all()[0].is_correct
False
>>> q.options.all()[1].is_correct
False
>>> q.options.all()[2].is_correct
False
>>> q.options.all()[3].is_correct
False
>>> q.options.all()[4].is_correct
False
>>> q.options.all()[5].is_correct
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/patrickbassut/Programming/logus/lib/python2.7/site-packages/django/db/models/query.py", line 177, in __getitem__
return list(qs)[0]
IndexError: list index out of range
You can use annotations for this.
from django.db.models import Count
Party.objects.filter(
participants__has_iphone=True
).annotate(iphone_count=Count('participants')).filter(
iphone_count=4
)
Here's one for my Django comrades.
I am trying to build an application in Django 1.6.5 and MySQL where some database fields are encrypted in order to respect the privacy of users. I have successfully installed django-extensions and successfully used the EncryptedCharField to do a simple save and data retrieval.
However, I am running into a problem when using EncryptedCharField for floats. Now, simple typecasting has been useful--this problem doesn't seem to be that problem. I'm trying to start with an encrypted field that is a value, change the value by adding/subtracting some number, then save the back to the database. I've managed to reduce and reproduce the error like this:
>>> user_id = 1
>>> account = AccountCash.objects.get( id = 1 )
>>> account.id
1L
>>> account.portfolio_id
1L
>>> account.account_name
u'My Cash'
>>> account.current_value
u'200'
>>> account.current_value = account.current_value - 10
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'unicode' and 'int'
Here, account_name and current_value are both EncryptedCharFields. We see that current_value is a unicode, so typecasting to a float should (I thought) resolve the issue, as it has for me in other places.
However, doing so leads to another problem in
>>> account.current_value = float(account.current_value) - 10
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/jasonnett/anaconda/envs/bb_env/lib/python2.7/site-packages/django/db/models/fields/subclassing.py", line 35, in __set__
obj.__dict__[self.field.name] = self.field.to_python(value)
File "/Users/jasonnett/anaconda/envs/bb_env/lib/python2.7/site-packages/django_extensions/db/fields/encrypted.py", line 69, in to_python
elif value and (value.startswith(self.prefix)):
AttributeError: 'float' object has no attribute 'startswith'
I haven't been able to figure out what is different about assigning a float value to the encrypted field here vs. where I originally set the value like this:
# Make the new account, passing in the portfolio it belongs to
new_account = AccountCash(
portfolio = portfolio,
account_name = newCashAccountForm.cleaned_data['account_name'],
starting_balance = newCashAccountForm.cleaned_data['starting_balance'],
current_value = newCashAccountForm.cleaned_data['starting_balance'],
)
new_account.save()