stefanofontanelli / ColanderAlchemy

ColanderAlchemy helps you autogenerating Colander schemas based on SQLAlchemy mapped objects.
Other
65 stars 32 forks source link

Why can't columns' names be overridden ? #95

Closed olemoign closed 3 years ago

olemoign commented 8 years ago

In my model, I hide the users' passwords from the views by using an attribute _password and an hybrid property:

class User(Model):
    _password = Column('password', Unicode, nullable=False)

    @hybrid_property
    def password(self):
        return None

    @password.setter
    def password(self, value):
        self._password = hashpw(value.encode('utf-8'), gensalt()).decode('ascii')

So I have the problem that I'm now asking for _password, where I actually want users to send me password. This could easily be solved by overriding the name but Colanderalchemy refuses: ValueError: _password: argument name cannot be overridden via info kwarg. (schema.py, line 417). You may have a very valid reason to do that, but it's documented neither in the code nor in the main docs. Could you tell me why I can't do that ? Thank you !

tisdall commented 8 years ago

It's been a while since I looked at the code... Can you provide the code you use to invoke ColanderAlchemy to make your schema? The error you quoted seems to indicate you tried overriding the field twice (if I'm remembering correctly).

olemoign commented 8 years ago

Sure.

from bcrypt import hashpw, gensalt
from colanderalchemy import setup_schema
from sqlalchemy import Column, DateTime, func, Integer, Unicode
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)

    login = Column(Unicode, nullable=False, unique=True)
    _password = Column('password', Unicode, nullable=False, info={'colanderalchemy': {'name': 'password'}})

    first_name = Column(Unicode, nullable=False)
    last_name = Column(Unicode, nullable=False)

    creation_date = Column(DateTime, default=func.now())

    @hybrid_property
    def password(self):
        return None

    @password.setter
    def password(self, value):
        self._password = hashpw(value.encode('utf-8'), gensalt()).decode('ascii')

    def check_password(self, value):
        return hashpw(value.encode('utf-8'), self._password.encode('ascii')) == self._password.encode('ascii')

setup_schema(None, User)
tisdall commented 8 years ago

I see what you're talking about now... Yeah, I didn't write that code, so I'm not sure the exact reason behind but can only guess. I suspect it's just to avoid dealing with naming conflicts (you could have two Columns that map to the same name).

The best thing to do is probably remove the override and just manually modify the schema afterwards.

Feel free to submit a PR with tests and documentation if you'd like to change the functionality to allow overriding name. We could probably deal with naming collisions by throwing an exception in those cases. There may be other reasons the exclusion was put in, but I can't think of them at the moment.

tisdall commented 8 years ago

Looking at the history, it seems it goes back to the beginning... @stefanofontanelli, did you want to comment on this?