سؤال

I am trying to build a base model class with the most used couch-views on it (mainly those for CRUD).

I cannot just add the ViewFields to the base class, since the js string inside must be changed slightly per the model class name.
This is no problem to do inside the base class __init__ but for some reason, the ViewField then wont work.

When using a ViewField normally like so:

class MyModel(Document):
    only_carrots = ViewField("mymodel", js-string)

Then if we run:

mod = MyModel()
mod.only_carrots 

It will show:
<ViewDefinition '_design/mymodel/_view/only_carrots'>

But if the ViewField is added during the __init__, it looks like this:

<flaskext.couchdb.ViewField object at 0x10fe8f190>

The code running on the base model is this:

    for attr_name in dir(self):
        if not attr_name.startswith("_") and attr_name not in ["id", "rev"]:
            attr_val = getattr(self, attr_name)
            if isinstance(attr_val, CouchView):
                vd = ViewField(self.doc_type, attr_val.template.render(self.__dict__), name=attr_name, wrapper=self.__class__)
                setattr(self, attr_name, vd)

The CouchView class is my own. It is only used to store the info for the ViewField in a way that it is not detected by the code inside the metaclasses.

The Document class (of which my base model is a sub class) has a __metaclass__. This takes care of, at least, some part of the work to get the ViewField working, but I think I have that part covered in my own class.

The source for python-couchdb is found here:
https://code.google.com/p/couchdb-python/source/browse/#hg%2Fcouchdb

And for Flask-CouchDB:
https://bitbucket.org/leafstorm/flask-couchdb/src

So, how do I make ViewField work when it is added by __init__ and therefore not available to __new__ inside the metaclasses?

Many thanks for any help.

هل كانت مفيدة؟

المحلول

Well, I think I figured it out. Or at least, a workaround.

All ViewField does is to fire up ViewDefinition with the wrapper-param filled by the class it is bound to.

So, when doing all this at init time, just call ViewDefinition instead, like so:

    def __init__(self, *args, **kwargs):
    if not self.doc_type:
        self.doc_type = self.__class__.__name__
    for attr_name in dir(self):
        if not attr_name.startswith("_") and attr_name not in ["id", "rev"]:
            attr_val = getattr(self, attr_name)
            if isinstance(attr_val, CouchView):
                setattr(self, attr_name, ViewDefinition(self.doc_type, attr_name, attr_val.template.render(self.__dict__), wrapper=self))

Of course, now you must remember to instantiate your model classes before adding them to the manager (it comes with the flask extension):

user = User()
manager.add_document(user)

This bit me while testing. Gotta stop doing this when I'm this tired.
And for some reason you need to add _data = {} to your custom base class. I can't figure out why it is not getting set properly, but its an easy fix.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top