Flask-SQLALchemy i have a model with columns:
class MyModel(db.Model):
def my_method1(self, arg1):
pass
a = Column(String(), primary_key=True)
Now i have a function which accepts Columns as argument to retrieve some information from them:
def get_column_info(column):
if column.primary_key:
return True
else:
return False
Note that this is just an example, the get_column_info does much more than that in reality.
Now i want to be able to access the originating model in my get_column_info function. That is i want to be able to call my_method1()
from within get_column_info.
Is there a way i can retrieve the originating model from a column instance?
There is no proper out of the box method for doing this. Column object has table attribute which returns __table__ attribute of the model but you can't get actual model from it. However (as this answer suggested) you can use get_class_by_table method in sqlalchemy_utils plugin:
from sqlalchemy_utils.functions import get_class_by_table
def get_model(column):
return get_class_by_table(db.Model, column.__table__)
Related
What is the right way to lookup a table and use its last value as a value in a new model instance? Something like this:
class MyClass(models.Model):
id = models.AutoField(primary_key=True)
obj = MyClass.objects.latest('id')
my_field = models.IntegerField(default=(obj+1))
I need a db column, which keeps track of the primary_key, but is independent of it and can also be modified. Also I need to use its value as default when creating new instances of the Model.
you can use custom constructor as described in the docs:
https://docs.djangoproject.com/en/2.2/ref/models/instances/
you will need to define the obj field either as integer(to store the id of the previous record) or as a foreign key(if you want to reference the previous db record). In the second case you will need to pass the name of the model to the ForeignKeyField constructor as string('MyClass') and not directly(MyClass).
I have an ndb.Model class and inside it there is a particular attribute that calls a certain function as validator:
class Article(ndb.Model):
itemList = ndb.StringProperty()
...
penInspc = ndb.IntegerProperty(default=0, indexed=True, validator=minPen)
I want the function minPen() to print the ID of the instance of class Article. How do I do that?
Just use a hook before put. This is as effective as a validator but also won’t mess up your queries in case you don’t have old data that do not respect the new validator rules.
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))
A form generates a list of all available foreign key elements. They are displayed depending on the __str__ function defined in the model.
I don't know how to search for this, but need to change this without touching the model.
My model connects with the User model. This model shows the username, but i would like to call the _get_full_name function to get a better list.
class Trainer(models.Model):
user=models.OneToOneField(User)
Is it possible to define it inside the definition of the Foreignkey or inside the model which connects (in my example the Trainer model)?
This should work:
def user_new_unicode(self):
return self.get_full_name()
User.__unicode__ = user_new_unicode #or User.__str__ = user_new_unicode
Of course it should be placed in your class.
Assuming i have a class that is called Customer that is defined in sqlalchemy to represent the customer table. I want to write a search method so that ...
results = Customer.search(query)
will return the results based on the method. Do I want to do this as a #classmethod?
#classmethod
def search(cls,query):
#do some stuff
return results
Can i use cls in place of DBSession.query?
DBSession.query(Customer).filter(...)
cls.query(Customer).filter(...)
To use
cls.query
you have to assign a query_property to your model classes!
You probably want to use this in other model classes as well, so you might want to do that in your model Base class somewhere in your model/__init__.py:
Base.query = Session.query_property()
Then you can simply write:
cls.query.filter(...)
Note that you don't specify the Object to query for anymore, that is automatically done by using the query_property mechanism.
I just recently wrote some similar code, following this reference.
class Users(Base):
__tablename__ = 'users'
#classmethod
def by_id(cls, userid):
return Session.query(Users).filter(Users.id==userid).first()
So the answer to your first question appears to be "yes". Not sure about the second, as I didn't substitute cls for DBSession.