I want to simply get objects which contract_time set to "0000-00-00" I've tried:
users = MonitoringUsers.objects.filter(contract_time = "0000-00-00")
But it throws Validation Error: year is out of range
I connect to the different system, I cannot change how this objects are stored.
Python can't convert this string to correct date
object so you have to use queryset's extra
method:
users = MonitoringUsers.objects.extra(where=["contract_time='0000-00-00'"])
To prevent errors while loading such records you have to defer
this field:
users = MonitoringUsers.objects.defer('contract_time').all()
You can iterate this queryset as usual but if you will try to access user.contract_time
for "0000-00-00" record you will get the same ValueError
. To solve this issue add a simple property to MonitoringUsers
:
class MonitoringUsers(models.Model):
...
@property
def contract_time_or_none(self):
try:
return self.contract_time
except ValueError:
return None
Your template in this case will look like:
<ul>
{% for user in users %}
<li>
{{ user }} -
{{ user.contract_time_or_none|default:"END of contract" }}
</li>
{% endif %}
</ul>
But you should understand that loading of deferred field means additional db hit for each instance of MonitoringUsers
. If you want to avoid this then you have to convert date-to-string at SQL level. I don't know which SQL server you use so here is example for SQLite:
users = MonitoringUsers.objects.defer('contract_time').extra(
select={'contract_time_str':
'CASE WHEN contract_time="0000-00-00" '
'THEN "END of contract" '
'ELSE strftime("%Y-%m-%d", contract_time) '
'END'})
With this solution you can output contract_time_str
as is:
<ul>
{% for user in users %}
<li>
{{ user }} - {{ user.contract_time_str }}
</li>
{% endif %}
</ul>
Of course in this scenario there will be no additional queries to database.
We used to have a table in MySQL with 0000-00-00
in date fields. Our work around wasn't quite as complicated as @catavaran's answer.
Like in the question, we got a ValidationError
when trying MonitoringUsers.objects.filter(contract_time="0000-00-00")
.
So to filter these users, we could use extra()
as @catavaran suggests.
When accessing contract_time
for a record with 0000-00-00
, we found that the Django ORM returned None
>>> users = MonitoringUsers.objects.extra(where=["contract_time='0000-00-00'"])
>>> for user in users:
... print repr(user.contract_time)
None
Therefore, in the template, we could simply use:
{{ user.contract_time|default:"END of contract" }}
and we didn't have to do a defer()
or add a select
argument to extra.
This is simply what we found. Different MySQL versions/configurations may vary. Eventually, we were able to convert all the 0000-00-00
s to nulls.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.