from app import db class TagInformation(db.Model): """Detailed information about tags, by dot-string tag identifier.""" __tablename__ = 'tag_information' # The ID is the dot-string of the tag (eg. "calc.g35+e2") id = db.Column(db.String(64), primary_key=True) # List of uses. Note how we load tag information along individual tags, but # we don't load uses unless the field is accessed. uses = db.relationship('Tag', back_populates='tag', lazy='dynamic') # Pretty name pretty = db.Column(db.String(64)) # ... any other static information about tags def __init__(self, id): self.id = id def category(self): return self.id.split(".", 1)[0] @staticmethod def all_tags(): all_tags = {} for ti in TagInformation.query.all(): ctgy = ti.category() if ctgy not in all_tags: all_tags[ctgy] = [] all_tags[ctgy].append(ti) return all_tags class Tag(db.Model): """Association between a Post and a dot-string tag identifier.""" __tablename__ = 'tag' id = db.Column(db.Integer, primary_key=True) # Tagged post post_id = db.Column(db.Integer, db.ForeignKey('post.id'), index=True) post = db.relationship('Post', back_populates='tags', foreign_keys=post_id) # Tag name. Note how we always load the information along the tag, but not # the other way around. tag_id = db.Column(db.String(64), db.ForeignKey('tag_information.id'), index=True) tag = db.relationship('TagInformation', back_populates='uses', foreign_keys=tag_id, lazy='joined') def __init__(self, post, tag): self.post = post if isinstance(tag, str): tag = TagInformation.query.filter_by(id=tag).one() self.tag = tag