I would like to store entity used in my code and avoid multiple occurrences. Thus, my idea was to use an __init__
method for collecting the main data for my class, and then use a kind of __post_init__
method for computing an id from my class object. Here is the code:
class Worker(Base):
__tablename__='worker'
id = Column(Integer,primary_key=True)
profile=Column(String(100),nullable=False)
useragent=Column(String(100),nullable=False)
def __init__(self,useragent,profile):
""" specify the main information"""
print('init')
self.profile= profile
self.useragent=useragent
def __post_init__(self):
""" compute an id based on self, the worker"""
self.id=id(self)
print('dans post init')
With this example, the __init__
method can be used, but it doesn't run the __post_init__
method like we could expect with dataclass, for example.
How could I run this method just after the execution of the __init__
method ?
The __post_init__
method is specific to the dataclasses
library, because the __init__
method on dataclass
classes is generated and overriding it would entirely defeat the purpose of generating it in the first place.
SQLAlchemy, on the other hand, provides an __init__
implementation on the base model class (generated for you with declarative_base()
). You can safely re-use that method yourself after setting up default values, via super().__init__()
. Take into account that the SQLAlchemy
-provided __init__
method only takes keyword arguments:
def __init__(self, useragent, profile):
"""specify the main information"""
id = generate_new_id(self)
super().__init__(id=id, useragent=useragent, profile=profile)
If you need to wait for the other columns to be given updated values first (because perhaps they define Python functions as a default
), then you can also run functions after calling super().__init__()
, and just assign to self
:
def __init__(self, useragent, profile):
"""specify the main information"""
super().__init__(useragent=useragent, profile=profile)
self.id = generate_new_id(self)
Note: you do not want to use the built-in id()
function to generate ids for SQL-inserted data, the values that the function returns are not guaranteed to be unique. They are only unique for the set of all active Python objects only, and only in the current process. The next time you run Python, or when objects are deleted from memory, values can and will be reused, and you can't control what values it'll generate next time, or in a different process altogether.
If you were looking to only ever create rows with unique combinations of the useragent
and profile
columns, then you need to define a UniqueConstraint
in the table arguments. Don't try to detect uniqueness at the Python level, as you can't guarantee that another process will not make the same check at the same time. The database is in a much better position to determine if you have duplicate values, without risking race conditions:
class Worker(Base):
__tablename__='worker'
id = Column(Integer, primary_key=True, autoincrement=True)
profile = Column(String(100), nullable=False)
useragent = Column(String(100), nullable=False)
__table_args__ = (
UniqueConstraint("profile", "useragent"),
)
or you could use a composite primary key based on the two columns; primary keys (composite or otherwise) must always be unique:
class Worker(Base):
__tablename__='worker'
profile = Column(String(100), primary_key=True, nullable=False)
useragent = Column(String(100), primary_key=True, nullable=False)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With