Created
November 4, 2016 12:00
-
-
Save pilosus/e369d11a08079c557a1eb9dbe657a0f2 to your computer and use it in GitHub Desktop.
Comment SQLAlchemy model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Comment(db.Model): | |
"""Comment is a message under a post. | |
Comment that has a parent treated as a reply. Comment with replies | |
(children) represents n-ary tree. | |
""" | |
__tablename__ = 'comments' | |
id = db.Column(db.Integer, primary_key=True) | |
parent_id = db.Column(db.Integer, db.ForeignKey('comments.id')) | |
body = db.Column(db.Text) | |
body_html = db.Column(db.Text) | |
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) | |
disabled = db.Column(db.Boolean) | |
screened = db.Column(db.Boolean) | |
read = db.Column(db.Boolean) | |
author_id = db.Column(db.Integer, db.ForeignKey('users.id')) | |
recipient_id = db.Column(db.Integer, db.ForeignKey('users.id')) | |
post_id = db.Column(db.Integer, db.ForeignKey('posts.id')) | |
replies = db.relationship('Comment', | |
backref=db.backref('parent', remote_side=[id]), | |
cascade='all, delete-orphan') | |
@staticmethod | |
def dfs(comment, fun): | |
"""Traversal of the comment n-ary tree using Depth-First Search algorithm. | |
Function passed as a parameter used to process a node while | |
traversing the tree: print it, remove, etc. | |
>>> Comment.dfs(Comment.query.first(), print) | |
>>> descendants = [] | |
>>> Comment.dfs(Comment.query.first(), lambda x: descendants.append(x)) | |
""" | |
# comment has no replies | |
if not comment.replies: | |
return | |
else: | |
for r in comment.replies: | |
# do something with a comment here | |
fun(r) | |
# recurr | |
Comment.dfs(r, fun) | |
@staticmethod | |
def bfs(comment, fun): | |
"""Traversal of the comment n-ary tree using Breadth-First Search. | |
>>> Comment.bfs(Comment.query.first(), print) | |
""" | |
cur_level = [comment] | |
while cur_level: | |
next_level = [] | |
for c in cur_level: | |
# do not touch original comment to comply with dfs version | |
if not c == comment: | |
# do something with a comment | |
fun(c) | |
if c.replies: | |
next_level.extend(c.replies) | |
# level change | |
cur_level = next_level | |
@staticmethod | |
def on_changed_body(target, value, oldvalue, initiator): | |
allowed_tags = current_app.config['PILI_ALLOWED_COMMENT_TAGS'] | |
target.body_html = bleach.linkify(bleach.clean( | |
markdown(value, output_format='html'), | |
tags=allowed_tags, strip=True)) | |
def to_json(self): | |
json_comment = { | |
'url': url_for('api.get_comment', id=self.id, _external=True), | |
'post': url_for('api.get_post', id=self.post_id, _external=True), | |
'body': self.body, | |
'body_html': self.body_html, | |
'timestamp': self.timestamp, | |
'author': url_for('api.get_user', id=self.author_id, | |
_external=True), | |
} | |
return json_comment | |
@staticmethod | |
def from_json(json_comment): | |
body = json_comment.get('body') | |
if body is None or body == '': | |
raise ValidationError('comment does not have a body') | |
return Comment(body=body) | |
def __repr__(self): | |
return '<Comment %r>' % self.id | |
db.event.listen(Comment.body, 'set', Comment.on_changed_body) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What the
remote_side=[id]
mean? I read the docs, but still can't figure it out. The docs said it makes the relationship to become a many-to-one pattern. However, I think the relationship between comment and replies was one(comment)-to-many(replies).