Skip to content

Instantly share code, notes, and snippets.

@tachyondecay
Last active March 19, 2024 19:08
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tachyondecay/e0fe90c074d6b6707d8f1b0b1dcc8e3a to your computer and use it in GitHub Desktop.
Save tachyondecay/e0fe90c074d6b6707d8f1b0b1dcc8e3a to your computer and use it in GitHub Desktop.
Tags in Flask via SQLalchemy and association proxies
from app import db
from sqlalchemy import desc, event, func, orm
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy_utils import ArrowType, auto_delete_orphans
from slugify import slugify_unicode
tags = db.Table('tag_associations',
db.Column('tag_id', db.Integer, db.ForeignKey('tags.id')),
db.Column('article_id', db.Integer, db.ForeignKey('articles.id')))
class Article(db.Model):
"""Blog posts."""
__tablename__ = 'articles'
_tags = db.relationship('Tag', secondary=tags, backref='articles')
tag_list = association_proxy('_tags', 'label')
@property
def tags(self):
"""Return list of tag objects associated with this article."""
tag_list = getattr(self, 'tag_list', [])
return tag_list if (tag_list != ['']) else []
@tags.setter
def tags(self, tag_list):
"""Set list of tag objects associated with this article."""
self._tags = [self._find_or_create_tag(t) for t in tag_list]
# Model continues
class Tag(db.Model):
"""Flexible categories for articles."""
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
handle = db.Column(db.String(100), unique=True)
label = db.Column(db.String(100))
def __init__(self, label):
"""Create a handle for a tag based on the supplied label."""
self.label = label
self.handle = self.slugify(label)
@classmethod
def frequency(cls):
"""Returns tuples of tags and their frequencies."""
return db.session.query(cls, func.count()) \
.outerjoin((tags, tags.c.tag_id == cls.id),
(Article, Article.id == tags.c.article_id)) \
.filter(Article.status == 'published') \
.group_by(cls.id) \
.order_by(func.lower(cls.label))
@classmethod
def slugify(cls, text):
"""Create a unique handle for this tag."""
return slugify_unicode(text, to_lower=True, max_length=100)
# Tags no longer associated with any article should be removed
auto_delete_orphans(Article._tags)
@tachyondecay
Copy link
Author

@marknagelberg
Copy link

Thanks for this, helped me out a lot!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment