Django - F('datetimefield') + relativedelta(months=1) fails

2.4k views Asked by At

I am trying to update a self datetime field of a model using F() object in django.

HeatWatchList.objects.filter(
    user=request.user,
    next_date_to__lt=datetime.combine(datetime.now().date(), time.min)
).update(
    next_date_from = F('next_date_from') + relativedelta(months=1),
    next_date_to = F('next_date_to') + relativedelta(months=1)
)

But when doing this i got AttributeError: relativedelta object has no attribute translate.

Here is the traceback i got when executing the code maybe it has an issue using the F() object when adding value with a datetime type relativedelta.

Traceback (most recent call last):
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\core\handlers\exception.py", line 39, in inner
    response = get_response(request)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\views\decorators\csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\rest_framework\viewsets.py", line 83, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\rest_framework\views.py", line 477, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\rest_framework\views.py", line 437, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\rest_framework\views.py", line 474, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\farm_management\heat\views.py", line 192, in update_watchlist
    next_date_to = F('next_date_to') + relativedelta(months=1)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\models\query.py", line 637, in update
    rows = query.get_compiler(self.db).execute_sql(CURSOR)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\models\sql\compiler.py", line 1148, in execute_sql
    cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\models\sql\compiler.py", line 835, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\backends\utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\backends\utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\django\db\backends\mysql\base.py", line 110, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\cursors.py", line 164, in execute
    query = self.mogrify(query, args)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\cursors.py", line 143, in mogrify
    query = query % self._escape_args(args, conn)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\cursors.py", line 118, in _escape_args
    return tuple(conn.literal(arg) for arg in args)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\cursors.py", line 118, in <genexpr>
    return tuple(conn.literal(arg) for arg in args)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\connections.py", line 800, in literal
    return self.escape(obj, self.encoders)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\connections.py", line 793, in escape
    return escape_item(obj, self.charset, mapping=mapping)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\converters.py", line 27, in escape_item
    val = encoder(val, mapping)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\converters.py", line 110, in escape_unicode
    return u"'%s'" % _escape_unicode(value)
  File "C:\Users\Web\Desktop\PyDev\Envs\djangular\lib\site-packages\pymysql\converters.py", line 73, in _escape_unicode
    return value.translate(_escape_table)
AttributeError: 'relativedelta' object has no attribute 'translate'
1

There are 1 answers

6
neverwalkaloner On BEST ANSWER

Seems like pymysql's converters does not support relativedelta objects. One possible solution is to iterate over objects and update it (inefficient):

objects_list = HeatWatchList.objects.filter(
user=request.user,
next_date_to__lt=datetime.combine(datetime.now().date(), time.min)
)

for obj in object_list:
    obj.next_date_from = onj.next_date_from + relativedelta(months=1)
    obj.next_date_to = onj.next_date_to + relativedelta(months=1)
    objsave()  

Or better use datetime.timedelta instead of relativedelta if it possible:

HeatWatchList.objects.filter(
user=request.user,
next_date_to__lt=datetime.combine(datetime.now().date(), time.min)
).update(
next_date_from = F('next_date_from') + timedelta(days=31),
next_date_to = F('next_date_to') + timedelta(days=31)
)