Reputation: 21
In my Flask python application, I have several interconnected objects, each with it's own is_active
toggle to virtually delete the record. When that happens for one record, I want the logical delete to take with it whatever related objects it has. This is how I want to control whether content is published or not in the application.
Since there are other considerations that could factor in besides the relevant is_active
fields, I have a method defined in each of the models that looks something like:
def is_published(self):
"""
Considers all needed criteria for visibility on the website,
returning a boolean to reflect current publication status
"""
if self.is_active and self.member.active and self.published_on:
return True
return False
where member
is a relationship defined through a foreign key. So essentially, this record should only be visible if (a) it is active, (b) the member who owns it is active, and (c) it has a publication date defined, replacing the initial null value.
Later, when I want to query a list of all of these published records, I can do something like:
articles = ArticleModel.query\
.join(MemberModel, MemberModel.id==ArticleModel.member_id)\
.filter(ArticleModel.is_active==True)\
.filter(ArticleModel.published_on!=None)\
.filter(MemberModel.active==True)\
.order_by(desc(ArticleModel.modified_at))\
.all()
This works, but if I want to change the definition for "published" later, I have to find all of the instances of this criteria and make adjustments. I would much rather reference that model's method (or some other central place for that complex criteria).
I want to know if I can set up a query to do something like this:
articles = ArticleModel.query\
.join(MemberModel, MemberModel.id==ArticleModel.member_id)\
.filter(ArticleModel.is_published()==True)\
.order_by(desc(ArticleModel.modified_at))\
.all()
Python doesn't like that filter line, returning an error: TypeError: unbound method is_published() must be called with ArticleModel instance as first argument (got nothing instead)
.
Is there a way to set multiple filters in one place for a particular model and reference that in the query?
Upvotes: 0
Views: 681
Reputation: 1069
Have you tried using a hybrid property (docs and more docs)?
EDIT:
Below is a code example (not a very good use case, though). It adds self.title
as a fall back for self.short_title
.
class SomeModel(db.Model):
# init blabla
...
@hybrid_property
def short_title(self):
return self._short_title if self._short_title is not None else self.title
@short_title.expression
def short_title(self):
return db.case(
[(Category._short_title == None, Category.title)],
else_=Category._short_title
)
@short_title.setter
def short_title(self, short_title):
self._short_title = short_title
Upvotes: 1