Karen:

Thank you so much for your reply.

On Sep 23, 7:01 am, Karen Tracey <[email protected]> wrote:
> What you haven't shared is the code for DateTimeFieldInTZ.  It's going to be
> rather hard to figure out what is going wrong without seeing that code.
...
> If you show us what is in the DateTimeFieldInTZ implementation it's much
> more likely that someone will be able to help.

Ah, right you are.  Here's the custom field in question.

=====  datetimefieldintz.py:
# classes used by this class
from django.db import models
from django.conf import settings
# from django.db.backends.util import typecast_timestamp
import datetime
from dateutil.tz import tzutc, tzstr, tzlocal

_utc = tzutc()

class DateTimeFieldInTZ(models.DateTimeField):
        """DateTimeFieldInTZ: replacement for models.DateTimeField, but
stores UTC and returns tzinfo

        Use this class exactly as you would Django's models.DateTimeField.
However, instead of returning
        naive datetime values, it returns datetime values with time zone info
(the tzinfo attribute) set, based on
        Django's settings.TIME_ZONE value. You can set settings.TIME_ZONE to
None, and DateTimeField will return naive
        datetime values.

        If you store a value then read it back, you should get a datetime
value equal to the same UTC time as
        the original, but perhaps with a different timezone.

        Also it stores all datetime values in the  database in UTC,
converting as necessary from whatever tzinfo
        is in the datetime values it receives.  It treats incoming naive
datetimes as being in the
        settings.TIME_ZONE (or if that is None, in the Django server's time
zone).

        The approach is to store all datetimes in backend database as naive
datetimes, but with time converted to UTC.
        Django's settings.TIME_ZONE value becomes a sitewide timezone
directive; all timestamps returned from the
        database are labelled with this time zone. When a site doesn't care
about time zones, it's OK to set the
        settings.TIME_ZONE value to None. In this case, the class uses the
timezone of the server hosting Django
        as the starting point for conversion to UTC.

        Here is some background to this approach.  Some databases (e.g.
MySQL) do not have a mechanism for storing
        the timezone info in a timestamp value. Others (e.g. Postgres) have a
database setting for timezone.  Only
        naive datetimes will work in all these backends. However, we want to
have time zones in datetime values
        in the application code. We need some indication of what time zone to
fill in; the settings.TIME_ZONE value
        is a handy indicator.
        """

        def __init__(self, *args, **kwargs):
                super(DateTimeFieldInTZ, self).__init__(*args, **kwargs)
                # store tzinfo structs from the runtime environment, for later
reference
                self._server_tz = tzlocal()
                self._settings_tz = None
                if settings.TIME_ZONE:
                        self._settings_tz = tzstr(settings.TIME_ZONE)

        def to_python(self, value, *args, **kwargs):
                """DateTimeFieldInTZ.to_python(value): convert value to a Python
datetime with the proper time zone

                value: a datetime value as returned by the database, in 
database-
specific format
                return a datetime value which is in the settings.tz time zone.
                """
                # don't impose tzinfo on datetime.date types
                skip_tz =  isinstance(value, datetime.date)

                # let the superclass do the hard work
                utc_dt = super(DateTimeFieldInTZ, self).__init__(value, *args,
**kwargs)

                # if we don't need to impose a time zone, return
                if utc_dt is None or skip_tz:
                        return utc_dt

                # impose the timezone
                assert isinstance(utc_dt, datetime)
                utc_dt = utc_dt.replace(tzinfo=_utc)

                # now convert utc_dt to target timezone and store as dt
                if self._settings_tz == _utc:
                    dt = utc_dt
                elif self._settings_tz:
                    # Cast it to the specified timezone
                    dt = utc_dt.astimezone(self._settings_tz)
                else:
                    # Cast to server local time then make it naive
                    dt = utc_dt.astimezone(self._server_tz).replace(tzinfo=None)
                return dt


        def get_db_prep_value(self, value, *args, **kwargs):
                """DateTimeFieldInTZ.get_db_prep_value(value): Casts dates into 
the
format expected by the backend

                """
                print " @@@ get_db_prep_value( %s(%s) ) begins. " % 
(type(value),
value)

                # convert value which are datetime to be in UTC, and then make 
them
naiive
                if False and isinstance(value, datetime.datetime):
                        if value.tzinfo is None:
                                # Treat as settings or server local time, and 
cast to UTC
                                if self._settings_tz is not None:
                                        value = 
value.replace(tzinfo=self._settings_tz)
                                else:
                                        value = 
value.replace(tzinfo=self._server_tz)
                        # value now has a timezone. Move value to UTC if not 
there already
                        if value.tzinfo != _utc:
                                value = value.astimezone(_utc)
                        # value is now in UTC. Make it naive, for backend's 
benefit
                        value = value.replace(tzinfo=None)


                # let the superclass do the hard work
                r = super(DateTimeFieldInTZ, self).get_db_prep_value(value, 
*args,
**kwargs)
                print " @@@ get_db_prep_value( %s ) got %s back from superclass 
" %
(value, r)
                return r


        def value_to_string(self, obj, *args, **kwargs):
                """DateTimeFieldInTZ.value_to_string: returns same string as for
standard DateTimeField, but with timezone

                Timezone is represented as a UTC offset in minutes, of form 
"+0000"
or "-0000".
                Naive datetime values get no UTC offset.
                """
                value = Field._get_val_from_obj(obj)
                s = super(DateTimeFieldInTZ, self).value_to_string(obj, *args,
**kwargs)

                # Improve s if we can
                if False and s and isinstance(value, datetime.datetime) and
value.tzinfo is not None:
                        s += unicode(value.strftime(" %z"))

                return s

#       def formfield(self, **kwargs):
#               pass   # same as superclass

        def __unicode__(self):
                """DateTimeFieldInTZ.__unicode__(): returns a Unicode string 
with
the value of the datetime
                """
                return unicode(repr(self))
=====

I wrote this class while going over the definition of
models.DateTimeField in django/db/models/fields/__init__.py:526-583.

One interesting observation about the diagnostic print statement in
get_db_prep_value(). It prints out,
 @@@ get_db_prep_value( <type 'datetime.datetime'>(2009-06-30
23:59:45+00:00) ) begins.
 @@@ get_db_prep_value( 2009-06-30 23:59:45+00:00 ) got None back from
superclass
Making it look like models.DateTimeField.get_db_prep_value() is
choking on <type 'datetime.datetime'>(2009-06-30 23:59:45+00:00) (with
a utc tzinfo).

Here's the entire stack trace of the failure resulting from my S1.save
():

=====
======================================================================
ERROR: test_partial_readwrite (twang.workshop.tests.PartialTwStatus)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jdlh/workspace/Twanguages/src/twang/workshop/tests.py",
line 85, in test_partial_readwrite
    S1.save()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/base.py", line 410, in
save
    self.save_base(force_insert=force_insert,
force_update=force_update)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/base.py", line 495, in
save_base
    result = manager._insert(values, return_id=update_pk)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/manager.py", line 177, in
_insert
    return insert_query(self.model, values, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/query.py", line 1087, in
insert_query
    return query.execute_sql(return_id)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/sql/subqueries.py", line
320, in execute_sql
    cursor = super(InsertQuery, self).execute_sql(None)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/models/sql/query.py", line 2369,
in execute_sql
    cursor.execute(sql, params)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/db/backends/sqlite3/base.py", line
193, in execute
    return Database.Cursor.execute(self, query, params)
IntegrityError: workshop_twstatus.created_at may not be NULL
=====

Here's the entire traceback of the first failure in the Django built-
in tests:

=====
======================================================================
FAIL: Doctest: django.contrib.auth.tests.__test__.BASIC_TESTS
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/test/_doctest.py", line 2180, in
runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for
django.contrib.auth.tests.__test__.BASIC_TESTS
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/
lib/python2.6/site-packages/django/contrib/auth/tests/__init__.py",
line unknown line number, in BASIC_TESTS

----------------------------------------------------------------------
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/
python2.6/site-packages/django/contrib/auth/tests/__init__.py",
line ?, in django.contrib.auth.tests.__test__.BASIC_TESTS
Failed example:
    call_command("createsuperuser", interactive=False, username="joe",
email="[email protected]")
Exception raised:
    Traceback (most recent call last):
      File "/opt/local/Library/Frameworks/Python.framework/Versions/
2.6/lib/python2.6/site-packages/django/test/_doctest.py", line 1267,
in __run
        compileflags, 1) in test.globs
      File "<doctest django.contrib.auth.tests.__test__.BASIC_TESTS[27]
>", line 1, in <module>
        call_command("createsuperuser", interactive=False,
username="joe", email="[email protected]")
      File "/opt/local/Library/Frameworks/Python.framework/Versions/
2.6/lib/python2.6/site-packages/django/core/management/__init__.py",
line 166, in call_command
        return klass.execute(*args, **defaults)
      File "/opt/local/Library/Frameworks/Python.framework/Versions/
2.6/lib/python2.6/site-packages/django/core/management/base.py", line
221, in execute
        self.validate()
      File "/opt/local/Library/Frameworks/Python.framework/Versions/
2.6/lib/python2.6/site-packages/django/core/management/base.py", line
249, in validate
        num_errors = get_validation_errors(s, app)
      File "/opt/local/Library/Frameworks/Python.framework/Versions/
2.6/lib/python2.6/site-packages/django/core/management/validation.py",
line 38, in get_validation_errors
        if f.name.endswith('_'):
    AttributeError: 'NoneType' object has no attribute 'endswith'
----------------------------------------------------------------------
=====

Diagnosis is made a little harder, because my Eclipse + PyDev setup
cannot step all the way through to these errors. I get a different
failure in the debugger, and it happens in the midst of stepping to
the next line, so I don't see the point of error.

Thanks for any light anyone can shed! I appreciate the help.

— Jim DeLaHunt, Vancouver, Canada.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to