palten08
palten08

Reputation: 43

Changes to model class's __init__ method don't seem to be taking effect

I have two particular model classes that are giving me errors during my testing, upon inspecting the methods for each I was pretty certain my issues were the result of typos on my part.

I've made the changes in both classes as needed, but re-running the tests produces the same error. I even tried dropping my schema and re-creating it with Flask-SQLAlchemy's create_all() method, but I still run into issues.

In the Metrics class, the variables in the __init__ method were wrong and were missing underscores (Ie: self.name instead of self._name). I addressed that by changing them to self._name and self._metric_type

In the HostMetricMapping class, I needed to add the host_id parameter to the __init__ method, since I had forgotten it the first time. So, I added it.

class Metrics(_database.Model):



    __tablename__ = 'Metrics'
    _ID = _database.Column(_database.Integer, primary_key=True)
    _name = _database.Column(_database.String(45), nullable=False)
    _metric_type = _database.Column(_database.String(45))
    _host_metric_mapping = _database.relationship('HostMetricMapping', backref='_parent_metric', lazy=True)


    def __init__(self, name, metric_type):
        self._name = name # This line used to say self.name, but was changed to self._name to match the column name
        self._metric_type = metric_type # This line used to say self.metric_type, but was changed to self._metric_type to match the column name


    def __repr__(self):
        return '{0}'.format(self._ID)



class HostMetricMapping(_database.Model):



    __tablename__ = 'HostMetricMapping'
    _ID = _database.Column(_database.Integer, primary_key=True)
    _host_id = _database.Column(_database.Integer, _database.ForeignKey('Hosts._ID'), nullable=False)
    _metric_id = _database.Column(_database.Integer, _database.ForeignKey('Metrics._ID'), nullable=False)
    _metric = _database.relationship('MetricData', backref='_metric_hmm', lazy=True)
    _threshold = _database.relationship('ThresholdMapping', backref='_threshold_hmm', lazy=True)


    def __init__(self, host_id, metric_id):
        self._host_id = host_id # This line and it's corresponding parameter were missing, and were added
        self._metric_id = metric_id


    def __repr__(self):
        return '{0}'.format(self._ID)

The issues I encounter are:

  1. When trying to instantiate an instance of Metrics and add it into the database, SQLAlchemy raises an IntegrityError because I have the _name column set to not null, and SQLAlchemy inherits the values for both _name and _metric_type as None or NULL, even though I instantiate it with values for both parameters.

  2. For HostMetricMapping, Python raises an exception because it still treats that class as only having the metric_id parameter, instead of also having the host_id parameter I've added.

Upvotes: 0

Views: 2189

Answers (1)

Stephen Fuhry
Stephen Fuhry

Reputation: 13009

A better way to override __init__ when using flask-sqlalchemy is to use reconstructor. Object initialization with sqlalchemy is a little tricky, and flask-sqlalchemy might be complicating it as well.. anyways, here's how we do it:

from sqlalchemy.orm import reconstructor

class MyModel(db.Model):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_on_load()

    @reconstructor
    def init_on_load(self):
        # put your init stuff here

Upvotes: 3

Related Questions