Find class being queried on from custom Query class in SQLAlchemy? - python

I'm currently doing something like this in SQLA:
class Base(object):
query = DBSession.query_property()
#classmethod
def _get_fulltext_query(cls, terms):
# Search is a method which runs a fulltext search in Whoosh for objects of the given type, returning all ids which match the given terms
ids = search(terms, cls.__name__)
return cls.query.filter(cls.id.in_(ids))
I want to set up a custom query class and do something like:
class BaseQuery(Query):
def fulltext(self, terms):
# Need a way to find out what class we're querying so that I can run the fulltext search and return the proper query
class Base(object):
query = DBSession.query_property(BaseQuery)
It just seems cleaner to me. I also have other use cases for needing to know what class is being queried -- for instance, a series of Notification classes in which I need to know what notification type to return.
Is there any way to find out what class is being queried from inside BaseQuery.fulltext?

This should work:
class BaseQuery(Query):
def fulltext(self, terms):
# assuming query is always created with `cls.query` or `DBSession.query(cls)`
cls = self._entities[0].type
...

Related

How to get class values in static method

I want to get the field value like we use self in Django models.
class UserModel(Model):
id = IDField()
uid = TextField()
#classmethod
def get_user(cls):
return cls.uid
The class method, keep returning NONE instead of the string value of the uid field. Did I miss something?
This is from the Firestore Python wrapper https://octabyte.io/FireO/quick-start/
If you use #classmethod and cls you can only get empty values. It is because you have basic class schema from which you can create objects (aka instances of that class).
To get value of current objects it has to be from self, so standard method. Then you can get a value of this particular object instance.
I didn't even find mention of a #classmethod in the Firestore Python. Most likely you don't need that decorator for now.

Django - How to return all objects in a QuerySet in their subclass form, rather than their parent class form?

I have a class Set with a many-to-many relationship to Item. I have lots of 'set' objects all containing lots of 'items'.
However, the Item class has been subclassed to create Article, Podcast, Video, and Episode. Basically, everything on the database was originally an Item. If my_set is a Set instance, containing Items - how do I create a Queryset which returns those objects in their subclass form? Ie, rather than me getting a Queryset full of Item instances, I get a Queryset with Article, Episode, Video, Podcast instances.
How would I get `my_set.objects.all().as_subclass()' to work?
class Item(models.Model, AdminVideoMixin):
base_attributes = 'foo'
def as_episode(self):
return Episode.objects.get(slug=self.slug)
class Video(Item):
class specific fields
class Article(Item):
class specific fields
class Podcast(Item):
class specific fields
class Episode(Item):
class specific fields
class Set(Item):
front_page = models.BooleanField(max_length=300, blank=False, default=False, null=False)
items = models.ManyToManyField(Item, related_name='in_sets', through='SetMeta', max_length=5000,)
def get_absolute_url(self):
return reverse('foo')
def ordered(self):
return self.items.all().order_by('-itemOrder__order')
def episodes(self):
episode_list = []
for each_item in self.items.all():
episode_list.append(each_item.as_episode())
return episode_list
def __str__(self):
return self.title
As you can see I tried two methods - to write a model method on Item() which returns itself as an Episode - but this only worked for single instances rather than a Queryset. As such I wrote a method on Set which can perform that method on all items within the self, but this doesn't produce a Queryset, just a list, and it feels messy?
Update: have just skimmed the django-polymorphic documentation again, and it seems to be exactly what you want. So the rest of my answer is probably not very useful, unless you are prohibited from taking code out of django-packages
I don't think Django provides a way to express a queryset that returns objects of more than one model type. Querysets are supposed to map inro SQL queries, and I don't think SQL can return rows from more than one table mixed up. (I'm not an SQL expert, so I may be wrong). However, if you don't want a list, Python provides a means to take a queryset and apply a transformation to each Item instance it returns: a generator function. So, for example, you could code
def items_as_subclasses(qs):
for instance in qs:
try:
yield instance.video
continue
except Video.DoesNotExist:
pass
try:
yield instance.article
continue
except Article.DoesNotExist:
pass
try: ...
raise ProbableCodingError(
f"Item instance id={instance.id} does not have a known subclass"
)
and then write
for item_subclass_instance in items_as_subclasses(queryset):
# whatever
or indeed pass "items":items_as_subclasses( queryset) into a template rendering
context.
If there is a long list of possible subclasses it might be better to have a subclass_type field in the base class, and use that to go straight to the only valid subclass field.
There's a nullable OneToOne link from the base class to its particular subclass, so you can write querysets that interrogate subclasses.
Or you could investigate django-polymorphic, which I once skimmed, and which I vaguely remember is for this sort of usage.

How to write a common get_by_id() method for all kinds of models in Sqlalchemy?

I'm using pylons with sqlalchemy. I have several models, and found myself wrote such code again and again:
question = Session.query(Question).filter_by(id=question_id).one()
answer = Session.query(Answer).fileter_by(id=answer_id).one()
...
user = Session.query(User).filter_by(id=user_id).one()
Since the models are all extend class Base, is there any way to define a common get_by_id() method?
So I can use it as:
quesiton = Question.get_by_id(question_id)
answer = Answer.get_by_id(answer_id)
...
user = User.get_by_id(user_id)
If id is your primary key column, you just do:
session.query(Foo).get(id)
which has the advantage of not querying the database if that instance is already in the session.
Unfortunately, SQLAlchemy doesn't allow you to subclass Base without a corresponding table declaration. You could define a mixin class with get_by_id as a classmethod, but then you'd need to specify it for each class.
A quicker-and-dirtier solution is to just monkey-patch it into Base:
def get_by_id(cls, id, session=session):
return session.query(cls).filter_by(id=id).one()
Base.get_by_id = classmethod(get_by_id)
This assumes you've got a session object available at definition-time, otherwise you'll need to pass it as an argument each time.
class Base(object):
#classmethod
def get_by_id(cls, session, id):
q = session.query(cls).filter_by(id=id)
return q.one()
Question.get_by_id(Session, question_id)

Extending appengine's db.Property with caching

I'm looking to implement a property class for appengine, very similar to the existing db.ReferenceProperty. I am implementing my own version because I want some other default return values. My question is, how do I make the property remember its returned value, so that the datastore query is only performed the first time the property is fetched? What I had is below, and it does not work. I read that the Property classes do not belong to the instances, but to the model definition, so I guess that the return value is not cached for each instance, but overwritten on the model every time. Where should I store this _resolved variable?
class PageProperty(db.Property):
data_type = Page
def get_value_for_datastore(self, model_instance):
page = super(PageProperty, self).get_value_for_datastore(model_instance)
self._resolved = page
return page.key().name()
def make_value_from_datastore(self, value):
if not hasattr(self, '_resolved'):
self._resolved = Page.get_by_name(value)
return self._resolved
Edit
Alex' answer is certainly usable. But it seems that the built-in db.ReferenceProperty does store the _RESOLVED variable on the model instance. As evidenced by:
[...]
setattr(model_instance, self.__resolved_attr_name(), value)
[...]
def __resolved_attr_name(self):
return '_RESOLVED' + self._attr_name()
The get_value_for_datastore method is passed the model instance, but make_value_from_datastore is not, so how do they find the _RESOLVED property from that method?
Edit 2
From the code I gather that google is using the __get__() and __set__() methods, both of which do get the model instance as an argument. Are those usable in custom classes? What is the difference with get_value_for_datastore and its counterpart?
A PageProperty instance exists per-model, not per-entity (where an entity is an instance of the model class). So I think you need a dictionary that maps pagename -> Page entity, instead of a single attribute per PageProperty instance. E.g., maybe something like...:
class PageProperty(db.Property):
data_type = Page
def __init__(self, *a, **k):
super(PageProperty, self).__init__(*a, **k)
self._mycache = {}
def get_value_for_datastore(self, model_instance):
page = super(PageProperty, self).get_value_for_datastore(model_instance)
name = page.key().name()
self._mycache[name] = page
return name
def make_value_from_datastore(self, value):
if value not in self._mycache:
self._mycache[value] = Page.get_by_name(value)
return self._mycache[value]
If you only want to change some small part of the behaviour of ReferenceProperty, you may want to simply extend it, overriding its default_value method. You may find the source for ReferenceProperty to be instructive.

Django model class methods for predefined values

I'm working on some Django-code that has a model like this:
class Status(models.Model):
code = models.IntegerField()
text = models.CharField(maxlength=255)
There are about 10 pre-defined code/text-pairs that are stored in the database. Scattered around the codebase I see code like this:
status = Status.objects.get(code=0) # successful
status = Status.objects.get(code=1) # failed
I would rather have a method for each so that the code would look something like this instead:
status = Status.successful()
status = Status.failed()
etc...
Is this possible? I have looked in to the Manager-stuff but I haven't really found a way. Is it time to really RTFM?
In Java it would be a static method and in Ruby you would just define a method on self, but it's not that easy in Python, is it?
You should perhaps implement this by defining a custom manager for your class, and adding two manager methods on that manager (which I believe is the preferred way for adding table-level functionality for any model). However, another way of doing it is by throwing in two class methods on your class that query and return resulting objects, such as:
class Status(models.Model):
code = models.IntegerField()
text = models.CharField(maxlength=255)
#classmethod
def successful(cls):
return cls.objects.get(code=0)
#classmethod
def failed(cls):
return cls.objects.get(code=1)
Do note please that get() is likely to throw different exceptions, such as Status.DoesNotExist and MultipleObjectsReturned.
And for an example implementation of how to do the same thing using Django managers, you could do something like this:
class StatusManager(models.Manager):
def successful(self):
return self.get(code=1)
def failed(self):
return self.get(code=0)
class Status(models.Model):
code = models.IntegerField()
text = models.CharField(maxlength=255)
objects = StatusManager()
Where, you could do Status.objects.successful() and Status.objects.failed() to get what you desire.

Categories