SqlAlchemy TIMESTAMP on update extra

2024/10/12 4:34:40

I am using SqlAlchemy on python3.4.3 to manage a MySQL database. I was creating a table with:

from datetime import datetimefrom sqlalchemy import Column, text, create_engine
from sqlalchemy.types import TIMESTAMP
from sqlalchemy.dialects.mysql import BIGINT
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()
class MyClass(Base):__tablename__ = 'my_class'id = Column(BIGINT(unsigned=True), primary_key=True)created_at = Column(TIMESTAMP, default=datetime.utcnow, nullable=False)updated_at = Column(TIMESTAMP, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)param1 = Column(BIGINT(unsigned=True), server_default=text('0'), nullable=False)

when I create this table with:

engine = create_engine('{dialect}://{user}:{password}@{host}/{name}'.format(**utils.config['db']))
Base.metadata.create_all(engine)

I get:

mysql> describe my_class;
+----------------+---------------------+------+-----+---------------------+-----------------------------+
| Field          | Type                | Null | Key | Default             | Extra                       |
+----------------+---------------------+------+-----+---------------------+-----------------------------+
| id             | bigint(20) unsigned | NO   | PRI | NULL                | auto_increment              |
| created_at     | timestamp           | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |                           |
| updated_at     | timestamp           | NO   |     | 0000-00-00 00:00:00 |                             |
| param1         | bigint(20) unsigned | NO   |     | 0                   |                             |

Now the problem is that I do not want any on_update server default on my created_at attribute, its purpose is, in fact, being written only at the creation of the record, not on every update, as stated in the declaration of the class.

From a couple of tests I have made, I noticed that if I insert another attribute of type TIMESTAMP before created_at, then this attribute gets the on update CURRENT_TIMESTAMP extra, while created_at does not, as desired. This suggests that the first TIMESTAMP attribute SqlAlchemy finds in the declaration of a mapping gets the on update CURRENT_TIMESTAMP extra, though I don't see any reason for such behaviour.

I have also tried:

created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=None, nullable=False)

and

created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=text(''), nullable=False)

but the problem persists. Any suggestion?

Answer

Apparently the problem is not related with SqlAlchemy but with the underlying MySQL engine. The default behaviour is to set on update CURRENT_TIMESTAMP on the first TIMESTAMP column in a table.

This behaviour is described here. As far as I understand, a possible solution is to start MySQL with the --explicit_defaults_for_timestamp=FALSE flag. Another solution can be found here. I haven't tried either solution yet, I will update this answer as soon as I solve the problem.

EDIT: I tried the second method and it is not very handy but it works. In my case I created a set of the tables which do not have a created_at attribute and then I have altered all the remaining tables as described in the link above.

Something along the lines of:

_no_alter = set(['tables', 'which', 'do not', 'have', 'a created_at', 'column'])
Base.metadata.create_all(engine)
for table in Base.metadata.tables.keys():if table not in _no_alter:engine.execute(text('ALTER TABLE {} MODIFY created_at TIMESTAMP NOT NULL DEFAULT 0'.format(table)))

EDIT2: another (easier) way to accomplish this is by setting in SqlAlchemy a server_default value for the column:

created_at = Column(TIMESTAMP, default=datetime.utcnow, nullable=False, server_default=text('0'))
https://en.xdnf.cn/q/69691.html

Related Q&A

Is it possible to pass a dictionary with extraneous elements to a Django object.create method?

I am aware that when using MyModel.objects.create in Django, it is possible to pass in a dictionary with keys which correspond to the model fields in MyModel. This is explained in another question here…

When should I use varargs in designing a Python API?

Is there a good rule of thumb as to when you should prefer varargs function signatures in your API over passing an iterable to a function? ("varargs" being short for "variadic" or …

PyPDF2 wont extract all text from PDF

Im trying to extract text from a PDF (https://www.sec.gov/litigation/admin/2015/34-76574.pdf) using PyPDF2, and the only result Im getting is the following string:bHere is my code:import PyPDF2 import …

Python 3.4 decode bytes

I am trying to write a file in python, and I cant find a way to decode a byte object before writing the file, basically, I am trying to decode this bytes string:Les \xc3\x83\xc2\xa9vad\xc3\x83\xc2\xa9s…

No module named unusual_prefix_*

I tried to run the Python Operator Example in my Airflow installation. The installation has deployed webserver, scheduler and worker on the same machine and runs with no complaints for all non-PytohnOp…

Python: Variables are still accessible if defined in try or if? [duplicate]

This question already has answers here:Short description of the scoping rules(9 answers)Closed last year.Im a Python beginner and I am from C/C++ background. Im using Python 2.7.I read this article: A …

Networkx Traveling Salesman Problem (TSP)

I would like to know if there is a function in NetworkX to solve the TSP? I can not find it. Am I missing something? I know its an NP hard problem but there should be some approximate solutions right

Comparing dateutil.relativedelta

Im trying to do a > comparison between two relativedeltas: if(relativedelta(current_date, last_activity_date) > relativedelta(minutes=15)):Here is the output from the debugger window in Eclipse:O…

Python. Argparser. Removing not-needed arguments

I am parsing some command-line arguments, and most of them need to be passed to a method, but not all.parser = argparse.ArgumentParser() parser.add_argument("-d", "--dir", help = &q…

Where can I find some hello world-simple Beautiful Soup examples?

Id like to do a very simple replacement using Beautiful Soup. Lets say I want to visit all A tags in a page and append "?foo" to their href. Can someone post or link to an example of how to …