How do I get all column names for an existing model in SQLAlchemy that is defined using a Base class with some columns defined there already? I am looking for a #classmethod, not for an instance method.
The model is not yet bound to a table, I have no __table__ attribute of the model definition yet.
I can loop through the dict and look at the types but surely there is a better way? I cannot use inspect, I get the error: 'No inspection system is available for object of type <class 'sqlalchemy.orm.decl_api.DeclarativeMeta'>'
Related
I am using Datastax Cassandra python driver's Object Mapper for defining cassandra table columns at run time (requirements are like those).
Table and column name and column types are resolved at run time.
I am trying to define a cassandra cqlengine model at runtime using 'type' to define a class.
Looks like Model class defined in python driver has added a metaclass to Model
#six.add_metaclass(ModelMetaClass)
class Model(BaseModel):
...
Is there even a way to define Models using type?
I am seeing following error while defining a Model class
from cassandra.cqlengine.models import Model
from cassandra.cqlengine import columns as Columns
attributes_dict = {
'test_id': Columns.Text(primary_key=True)
'test_col1': Columns.Text()
}
RunTimeModel = type ('NewModelName', tuple(Model), attributes_dict)
Error:
RunTimeModel = type ('NewModelName', tuple(Model), attributes_dict)
TypeError: 'ModelMetaClass' object is not iterable
I'll stay away from the rest, but to answer the question about the error, I think you have a simple syntax error trying to construct a tuple from a non-sequence argument. Instead, you might use the tuple literal notation:
RunTimeModel = type ('NewModelName', (Model,), attributes_dict)
I am having trouble building a Flask-SQLAlchemy query with a like() method, which should build a query using the the SQL LIKE statement.
According the SQLAlchemy docs the like method can be called on a column like this:
select([sometable]).where(sometable.c.column.like("%foobar%"))
I have a ModelClass that subclasses the Flask-SQLAlchemy db.Model class. Defined like this:
class ModelClass(db.Model):
# Some other columns ...
field1 = db.Column(db.Integer(), db.ForeignKey('my_other_class.id'))
rel1 = db.relationship("MyOtherClass", foreign_keys=[field1])
I then have a loop where I am building up filters dynamically. Outside the loop I use these filters to filter a query. The inside of my loop, slightly modified, looks like this:
search_term = '%{}%'.format(search_string)
my_filter = getattr(ModelClass, field_string).like(search_term)
This raises an error at the line with the like method:
NotImplementedError: <function like_op at 0x101c06668>
It raises this error for any text string. The Python docs for a NotImplementedError say:
This exception is derived from RuntimeError. In user defined base
classes, abstract methods should raise this exception when they
require derived classes to override the method.
This isn't an AttributeError, so I think the like method exists, but something else is wrong and I'm not sure what.
Update
Now that I'm looking more closely at the model definition I think the problem might be that I'm doing this on a relationship and not a Column type.
I saw that type(getattr(ModelClass, field_string)) gives:
<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x102018090>
Since this is not a Column type I looked at the values for field_string and saw that one of the values being passed was actually rel1.
So I guess that's the "answer" but I'm still confused why calling .like() on rel1 didn't raise an AttributeError.
So I've confirmed the issue is that I was trying to apply the .like() method to a relationship attribute instead of a column.
I changed my code to call the child model class directly as opposed to trying to go across the relationship from the parent to access the child class columns. Something like this:
search_term = '%{}%'.format(search_string)
my_filter = getattr(ChildModelClass, field_string).like(search_term)
As #ACV said, calling methods such as like(), is_(), is_not(), etc. on relationship attributes raises NotImplementedError. So, to workaround this problem, I called the method directly on the real column attribute instead of the relationship. E.g. if I have the following two attributes in a Model:
user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), index=True)
user = db.relationship(
'User', backref=db.backref('readings', lazy='dynamic', cascade='all, delete-orphan'))
I did the following query to filter the instances whose attribute user IS NOT NULL. (Note that I'm using MyModel.user_id instead of MyModel.user to successfully run the query):
MyModel.query.filter(MyModel.user_id.is_not(None))
Answer
As Sergey pointed out, class Model(**kwargs) is invalid, and is a typo in Django documentation.
The "class" part comes from the markup they used when they wrote it.
So, what they actually meant in the Django documentation is:
Creating objects
To create a new instance of a model, just instantiate it like any
other Python class:
Model(**kwargs)
The keyword arguments are simply the names of the fields you’ve
defined on your model. Note that instantiating a model in no way
touches your database; for that, you need to save().
Original question
I found the following while reading the Django Docs about Model instances:
Creating objects
To create a new instance of a model, just instantiate it like any
other Python class:
class Model(**kwargs)
The keyword arguments are simply the names of the fields you’ve
defined on your model. Note that instantiating a model in no way
touches your database; for that, you need to save().
What is the difference between these two codes?
class Model(**kwargs)
new_model = Model(**kwargs)
I know the second one creates a new instance of the class Model, with kwargs.
Is the first one different from it? To me, it seems like it rather redefines the Model class.
class Model(**kwargs) is not a valid Python syntax, the latter would look like
class Model(SomeBaseClass):
pass
Judging by the formatting (the line looks like a subheading), this must be a mistake in the Django documentation.
If you look at the Sphinx source of the page, you'll see that the "class" thing is actually a part of Sphinx markup. What they meant is
To create a new instance of a model, just instantiate it like any
other Python class:
Model(**kwargs)
The keyword arguments are simply the names of the fields you've
defined on your model.
The first line defines a class.
The second line defines an instance of a class.
I'm working on a OpenERP environment, but maybe my issue can be answered from a pure python perspective. What I'm trying to do is define a class whose "_columns" variable can be set from a function that returns the respective dictionary. So basically:
class repos_report(osv.osv):
_name = "repos.report"
_description = "Reposition"
_auto = False
def _get_dyna_cols(self):
ret = {}
cr = self.cr
cr.execute('Select ... From ...')
pass #<- Fill dictionary
return ret
_columns = _get_dyna_cols()
def init(self, cr):
pass #Other stuff here too, but I need to set my _columns before as per openerp
repos_report()
I have tried many ways, but these code reflects my basic need. When I execute my module for installation I get the following error.
TypeError: _get_dyna_cols() takes exactly 1 argument (0 given)
When defining the the _get_dyna_cols function I'm required to have self as first parameter (even before executing). Also, I need a reference to openerp's 'cr' cursor in order to query data to fill my _columns dictionary. So, how can I call this function so that it can be assigned to _columns? What parameter could I pass to this function?
From an OpenERP perspective, I guess I made my need quite clear. So any other approach suggested is also welcome.
From an OpenERP perspective, the right solution depends on what you're actually trying to do, and that's not quite clear from your description.
Usually the _columns definition of a model must be static, since it will be introspected by the ORM and (among other things) will result in the creation of corresponding database columns. You could set the _columns in the __init__ method (not init1) of your model, but that would not make much sense because the result must not change over time, (and it will only get called once when the model registry is initialized anyway).
Now there are a few exceptions to the "static columns" rules:
Function Fields
When you simply want to dynamically handle read/write operations on a virtual column, you can simply use a column of the fields.function type. It needs to emulate one of the other field types, but can do anything it wants with the data dynamically. Typical examples will store the data in other (real) columns after some pre-processing. There are hundreds of example in the official OpenERP modules.
Dynamic columns set
When you are developing a wizard model (a subclass of TransientModel, formerly osv_memory), you don't usually care about the database storage, and simply want to obtain some input from the user and take corresponding actions.
It is not uncommon in that case to need a completely dynamic set of columns, where the number and types of the columns may change every time the model is used. This can be achieved by overriding a few key API methods to simulate dynamic columns`:
fields_view_get is the API method that is called by the clients to obtain the definition of a view (form/tree/...) for the model.
fields_get is included in the result of fields_view_get but may be called separately, and returns a dict with the columns definition of the model.
search, read, write and create are called by the client in order to access and update record data, and should gracefully accept or return values for the columns that were defined in the result of fields_get
By overriding properly these methods, you can completely implement dynamic columns, but you will need to preserve the API behavior, and handle the persistence of the data (if any) yourself, in real static columns or in other models.
There are a few examples of such dynamic columns sets in the official addons, for example in the survey module that needs to simulate survey forms based on the definition of the survey campaign.
1 The init() method is only called when the model's module is installed or updated, in order to setup/update the database backend for this model. It relies on the _columns to do this.
When you write _columns = _get_dyna_cols() in the class body, that function call is made right there, in the class body, as Python is still parsing the class itself. At that point, your _get_dyn_cols method is just a function object in the local (class body) namespace - and it is called.
The error message you get is due to the missing self parameter, which is inserted only when you access your function as a method - but this error message is not what is wrong here: what is wrong is that you are making an imediate function call and expecting an special behavior, like late execution.
The way in Python to achieve what you want - i.e. to have the method called authomatically when the attribute colluns is accessed is to use the "property" built-in.
In this case, do just this: _columns = property(_get_dyna_cols) -
This will create a class attribute named "columns" which through a mechanism called "descriptor protocol" will call the desired method whenever the attribute is accessed from an instance.
To leran more about the property builtin, check the docs: http://docs.python.org/library/functions.html#property
Been trying to figure this out for a couple of hours now and have gotten nowhere.
class other(models.Model):
user = models.ForeignKey(User)
others = other.objects.all()
o = others[0]
At this point the ORM has not asked for the o.user object, but if I do ANYTHING that touches that object, it loads it from the database.
type(o.user)
will cause a load from the database.
What I want to understand is HOW they do this magic. What is the pythonic pixie dust that causes it to happen. Yes, I have looked at the source, I'm stumped.
Django uses a metaclass (django.db.models.base.ModelBase) to customize the creation of model classes. For each object defined as a class attribute on the model (user is the one we care about here), Django first looks to see if it defines a contribute_to_class method. If the method is defined, Django calls it, allowing the object to customize the model class as it's being created. If the object doesn't define contribute_to_class, it is simply assigned to the class using setattr.
Since ForeignKey is a Django model field, it defines contribute_to_class. When the ModelBase metaclass calls ForeignKey.contribute_to_class, the value assigned to ModelClass.user is an instance of django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor.
ReverseSingleRelatedObjectDescriptor is an object that implements Python's descriptor protocol in order to customize what happens when an instance of the class is accessed as an attribute of another class. In this case, the descriptor is used to lazily load and return the related model instance from the database the first time it is accessed.
# make a user and an instance of our model
>>> user = User(username="example")
>>> my_instance = MyModel(user=user)
# user is a ReverseSingleRelatedObjectDescriptor
>>> MyModel.user
<django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor object>
# user hasn't been loaded, yet
>>> my_instance._user_cache
AttributeError: 'MyModel' object has no attribute '_user_cache'
# ReverseSingleRelatedObjectDescriptor.__get__ loads the user
>>> my_instance.user
<User: example>
# now the user is cached and won't be looked up again
>>> my_instance._user_cache
<User: example>
The ReverseSingleRelatedObjectDescriptor.__get__ method is called every time the user attribute is accessed on the model instance, but it's smart enough to only look up the related object once and then return a cached version on subsequent calls.
This will not explain how exactly Django goes about it, but what you are seeing is Lazy Loading in action. Lazy Loading is a well known design pattern to defer the initialization of objects right up until the point they are needed. In your case until either of o = others[0] or type(o.user) is executed. This Wikipedia article may give you some insights into the process.
Properties can be used to implement this behaviour. Basically, your class definition will generate a class similar to the following:
class other(models.Model):
def _get_user(self):
## o.users being accessed
return User.objects.get(other_id=self.id)
def _set_user(self, v):
## ...
user = property(_get_user, _set_user)
The query on User will not be performed until you access the .user of an 'other' instance.