Search code examples
pythonoopflasksqlalchemyflask-sqlalchemy

Why add self instead of self.last_seen in sqlalchemy db (Flask)


In this code the last_seen field is being refreshed with the current time whenever the user uses the site. However, in the call to the db, he (Minuel Grindberg "Flask Web Development") adds self instead of self.last_seen, which confuses me. I understand what the basic principals of OOP are, and I (thought) understand what self is (reference to the object being created), but I do NOT understand why we don't add self.last_seen in the last line db.session.add(self)? Full code below. . .

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    password_hash = db.Column(db.String(128))
    confirmed = db.Column(db.Boolean, default=False)
    name = db.Column(db.String(64))
    location = db.Column(db.String(64))
    about_me = db.Column(db.Text())
    member_since = db.Column(db.DateTime(), default=datetime.utcnow)
    last_seen = db.Column(db.DateTime(), default=datetime.utcnow)

def ping(self):
    self.last_seen = datetime.utcnow()
    db.session.add(self)

Looks very simple and I'm sure it is, but obviously I'm missing something, or haven't learned something I should have. If i knew what to google for an answer, I would have certainly done so, but I'm not even sure what to search for other than the principals of Python OOP which I thought I already understood (I did review). Any help would be greatly appreciated because this is driving me crazy, lol.


Solution

  • He is adding the updated model to the DB. The model changed so db.session.add() will update the proper row behind the scene. I don't believe SQLAlchemy would allow you to add on the property of model because it wouldn't know which row to update

    Perhaps an example would make this clearer. Let's take the following model:

    class User(db.model):
        __tablename__ = 'User'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(25))
    

    Now there are 2 very important attributes on the model for inserting/updating it in the DB. The table name and the id. So to add that model to the DB with plain SQL we would need to do something like:

    INSERT INTO User (name) VALUES ('Some string');
    

    This is roughly what happens when you use db.session.add() on a new model. To update our model we would need to do something like:

    UPDATE User
    SET name='Some other String'
    WHERE id=1;
    

    Now if you were to only pass one attribute of a model to SQLAlchemy how would it be able to figure out what table you wanted to add to or which row was supposed to get changed? If you just passed self.name to db.session.add() the query would end up looking like this:

    UPDATE  # There is no way to know the table
    SET name='Some other String'
    WHERE  ; # There is no way to know which row needs to be changed
    

    SQLAlchemy would most likely throw an exception if you tried. As for why it can't deduce the model from self that is probably way outside the scope of an SO question.