0

I have no idea how to even look for this, here is a simplified example

I have a class:

class MyField():

    def __init__(self, model=None, source=None, id=None):
        self.source = source
        self.model = model
        self.id = id

    def somemethod(self):
        ...

That is used on this other class

class MyClass(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    somefield = db.Column(db.String(255))

    @property
    def someproperty(self):

        specs = MyField(
            source=self.somefield,
            model=self.__class__.__name__,
            id=self.id
        )

        return specs.somemethod()

By that is no ideal to me, I want to have something simpler to code for the second class, so making it look like this:

class MyClass(db.Model):
    somefield = db.Column(db.String(255))

    someproperty = MyField(source='somefield')

and have on the first class all the logic that handles that data. Here I have no idea on how to read the contents of 'somefield' and id, 'somefield' may vary and have another name, thats why I use it as an argument, and 'id' is always the same for every class

2
  • Are you looking for something built-in to Python or something that you might be able to add yourself? Commented Aug 8, 2014 at 22:42
  • someone below gave me the perfect solution, thanks a lot Commented Aug 9, 2014 at 0:38

1 Answer 1

1

All that @property does is return a custom descriptor whose __get__ method calls your function. So, you can just do that directly.

I can't test this, because I don't have sqlalchemy installed here, but something like this:

class FieldProperty(object):
    def __init__(self, field, source):
        self.field, self.source = field, source
    def __get__(self, obj, typ=None):
        if typ is None:
            typ = obj.__class__
        specs = self.field(
            source = getattr(obj, self.source),
            model = typ.__name__,
            id = obj.id)
        return specs.somemethod()

Now:

class MyClass(db.Model):
    somefield = db.Column(db.String(255))

    someproperty = FieldProperty(MyField, source='somefield')

Or, if you prefer, you can create a base class or mixin for all your fields that adds a class method that does this for you:

class BaseField(object):
    @classmethod
    def make_property(cls, source):
        return FieldProperty(cls, source)

And now:

class MyClass(db.Model):
    somefield = db.Column(db.String(255))

    someproperty = MyField.make_property('somefield')

Note the FieldProperty(object) above. Descriptors have to be new-style classes, and they only work in new-style classes. In Python 3.x, new-style classes is all there is, but if you're using 2.x, every time you define a class with no base class, you get a old-style class. This is just one of the many reasons you don't want an old-style class; they also handle some special methods wrong, break multiple inheritance, make you look like a retro hipster, and sneak into your room and steal money out of your wallet while you sleep.

Sign up to request clarification or add additional context in comments.

6 Comments

The first solution worked great, but I had to change class FieldProperty: to class FieldProperty(object):. Now I'm going to try the second one. Thanks a lot!
@guinunez: Ah, I assumed you were in Python 3, because you left the (object) off of MyField. In Python 2, never ever leave the (object) off, except in very rare cases where you know that some ancient library requires it. I'll edit my answer.
@guinunez: Anyway, it's definitely worth reading the Descriptor HOWTO I linked above. Guido's blog post The Inside Story on New-Style Classes and a blog post I can't find that I'm think was by Ned Batchelder may help if you can't wrap your head around it. Also lots of experimenting with stupid ideas to see if they work. And read the source the the property, classmethod, and staticmethod decorators.
didn't knew about that difference, what should I do to make it compatible for python 2 and 3?. I am working on a module inspired on django-imagekit but for flask and sqlalchemy
@guinunez: Just always use object when you have nothing else to inherit from, and it works properly with both Python 2 and 3. (I should have done it in my code instead of making the assumption you were using 3. And now I understand why Guido recommends that everyone should always inherit from object even in Python 3… it's bad to get people out of the habit until Python 2.7 goes away.)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.