Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#31471 closed Bug (worksforme)

update_or_create object returns either an unparsed field (like a str) or datetime for DateTimeField, depending on whether object is saved or not.

Reported by: Fonville Owned by:
Component: Database layer (models, ORM) Version: 3.0
Severity: Normal Keywords: datetime, OneToOne
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have a Telemetry class/model with a DateTimeField:

class Telemetry(models.Model):
    time_stamp = models.DateTimeField()

Whitin this class/model the time_stamp field is correctly treated as a Python datetime object

Telemetry has a OnetoOne relationship with another model:

class ExtraTelemetry(models.Model):
    telemetry = models.OneToOneField(Telemetry, on_delete=models.CASCADE, primary_key=True)

in this related ExtraTelemetery object I am fetching the value of the DateTimeField with:
self.telemetry.time_stamp

You'd expect this to be a Python datetime object too, but instead it returns a str object (e.g. "2020-04-15T17:03:05Z")
I am only able to use the field as datetime object by parsing it myself with dateutil.parser.parse(self.telemetry.time_stamp)

I think this is a bug, because it should be a datetime object and not a string, even when fetched through a relationship.
Django version is 3.0.5 with Python3.8.2 and SQLite

Change History (7)

comment:1 by Omkar Kulkarni, 5 years ago

Owner: changed from nobody to Omkar Kulkarni
Status: newassigned

comment:2 by Omkar Kulkarni, 5 years ago

Owner: Omkar Kulkarni removed
Status: assignednew

I was unable to reproduce this bug using Django 3.0.5, Python 3.8.0, and a SQLite database. My models and REPL output are shown below:
models.py

from django.db import models
class Test(models.Model):
    time_stamp = models.DateTimeField(auto_now=True)

class RelationTest(models.Model):
    test_field = models.OneToOneField(Test, on_delete=models.CASCADE, primary_key=True)

REPL:

$ ./manage.py shell
Python 3.8.0 (v3.8.0:fa919fdf25, Oct 14 2019, 10:23:27)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from app.models import *
>>> r = RelationTest.objects.get(test_field=1)
>>> r.test_field.time_stamp
datetime.datetime(2020, 4, 16, 19, 48, 44, 277170, tzinfo=<UTC>)

comment:3 by Omkar Kulkarni, 5 years ago

Resolution: worksforme
Status: newclosed

comment:4 by Fonville, 5 years ago

Thanks for testing in a simple test case, unfortunately I am still hitting the bug in the context of the app I am writing.
It is triggered during the running of a post_save receiver. I will investigate a bit more, what factor in the context is relevant and how to reproduce it!

comment:5 by Fonville, 5 years ago

Summary: DateTimeField is returned as str instead of as datetime object, when using reverse lookupupdate_or_create object returns either an unparsed field (like a str) or datetime for DateTimeField, depending on whether object is saved or not.

Ok, I found the culprit, I was entering the datetime as a str into the model with the DateTimeField using a update_or_create() method as a kwarg.

Depending on whether the update_or_create had triggered a save (and thus parsing) of the field, the field was either a string or a datetime.

I am not sure what your take is on things, but imho the nondeterministic behaviour of update_or_create() is in my opinion not expected by a developer.
I would expect even if the object is not updated in the database, the field to still be parsed into a datetime in the object returned by the update_or_create() method.

comment:6 by Tim Graham, 5 years ago

Component: UncategorizedDatabase layer (models, ORM)

While I haven't investigated the details here, I'm inclined to say that behavior probably won't change. See, for example, past tickets like #12401.

comment:7 by Fonville, 5 years ago

Thanks for your explanation with the past ticket.
Maybe it is good to document somewhere these kind of gotchas that (underwater) .save() can change the fieldtypes of the model object.

Note: See TracTickets for help on using tickets.
Back to Top