Skip to content

Instantly share code, notes, and snippets.

@miguelgrinberg
Created October 7, 2017 21:56
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save miguelgrinberg/39503aabef376dbe215788770b5ae839 to your computer and use it in GitHub Desktop.
Save miguelgrinberg/39503aabef376dbe215788770b5ae839 to your computer and use it in GitHub Desktop.
#!/bin/env python
# -------------------------------------------------------------------------------
# This is a basic implementation of comments with a flat structure,
# as described in my article:
# https://blog.miguelgrinberg.com/post/implementing-user-comments-with-sqlalchemy
# -------------------------------------------------------------------------------
from datetime import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(140))
author = db.Column(db.String(32))
timestamp = db.Column(db.DateTime(), default=datetime.utcnow, index=True)
# create the database and insert a few comments
db.create_all()
c1 = Comment(text='hello1', author='bob')
c2 = Comment(text='hello2', author='alice')
c3 = Comment(text='hello3', author='bob')
c4 = Comment(text='hello4', author='alice')
db.session.add_all([c1, c2, c3, c4])
db.session.commit()
# display the comments
for comment in Comment.query.order_by(Comment.timestamp.asc()):
print('{}: {}'.format(comment.author, comment.text))
#!/bin/env python
# -------------------------------------------------------------------------------
# This is an implementation of comments with replies using an adjacency list,
# as described in my article:
# https://blog.miguelgrinberg.com/post/implementing-user-comments-with-sqlalchemy
# -------------------------------------------------------------------------------
from datetime import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(140))
author = db.Column(db.String(32))
timestamp = db.Column(db.DateTime(), default=datetime.utcnow, index=True)
parent_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
replies = db.relationship(
'Comment', backref=db.backref('parent', remote_side=[id]),
lazy='dynamic')
def add_reply(self, text):
return Comment(text=text, parent=self)
db.create_all()
c1 = Comment(text='hello1', author='alice')
c2 = Comment(text='hello2', author='bob')
c11 = Comment(text='reply11', author='bob', parent=c1)
c12 = Comment(text='reply12', author='susan', parent=c1)
c111 = Comment(text='reply111', author='susan', parent=c11)
c21 = Comment(text='reply21', author='alice', parent=c2)
db.session.add_all([c1, c2, c11, c12, c111, c21])
db.session.commit()
def display_comment(comment, level=0):
print('{}{}: {}'.format(' ' * level, comment.author, comment.text))
for reply in comment.replies:
display_comment(reply, level + 1)
for comment in Comment.query.filter_by(parent=None):
display_comment(comment)
#!/bin/env python
# -------------------------------------------------------------------------------
# This is an implementation of comments with replies using a comment path,
# as described in my article:
# https://blog.miguelgrinberg.com/post/implementing-user-comments-with-sqlalchemy
# -------------------------------------------------------------------------------
from datetime import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Comment(db.Model):
_N = 6
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(140))
author = db.Column(db.String(32))
timestamp = db.Column(db.DateTime(), default=datetime.utcnow, index=True)
path = db.Column(db.Text, index=True)
parent_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
replies = db.relationship(
'Comment', backref=db.backref('parent', remote_side=[id]),
lazy='dynamic')
def save(self):
db.session.add(self)
db.session.commit()
prefix = self.parent.path + '.' if self.parent else ''
self.path = prefix + '{:0{}d}'.format(self.id, self._N)
db.session.commit()
def level(self):
return len(self.path) // self._N - 1
db.create_all()
c1 = Comment(text='hello1', author='alice')
c2 = Comment(text='hello2', author='bob')
c11 = Comment(text='reply11', author='bob', parent=c1)
c12 = Comment(text='reply12', author='susan', parent=c1)
c111 = Comment(text='reply111', author='susan', parent=c11)
c21 = Comment(text='reply21', author='alice', parent=c2)
for comment in [c1, c2, c11, c12, c111, c21]:
comment.save()
for comment in Comment.query.order_by(Comment.path):
print('{}{}: {}'.format(' ' * comment.level(), comment.author, comment.text))
@miguelgrinberg
Copy link
Author

The code to print the comments in order is in the article, you just need to adapt the loop to Jinja.

@ondiekelijah
Copy link

Thanks, here's how I did it

        {% for comment in comments %}
        <div class="row">
            <!-- Begin comment indentation -->
            {% if comment.level() == 0 %}
            <div class="col-12 border-start border-primary">
                {% elif comment.level() == 1 %}
                <div class="col-11 offset-1 border-start border-secondary">
                    {% elif comment.level() == 2 %}
                    <div class="col-10 offset-2 border-start border-success">
                        {% elif comment.level() == 3 %}
                        <div class="col-9 offset-3 border-start border-info">
                            {% elif comment.level() == 4 %}
                            <div class="col-8 offset-4 border-start border-primary">
                                {% else %}
                                <div class="col-7 offset-5 border-start border-primary">
                                    {% endif %}
                                    <!-- End comment indentation -->
                                    <div>
                                        <p class="m-0 text-muted"><span class="text-primary">
                                                {{comment.author}}</span> <br>
                                            <span class="text-small">{{comment.timestamp}}</span>
                                        </p>
                                        <p class="m-0 text-muted">{{comment.text}}</p>
                                        <a class="" data-bs-toggle="collapse" href="#comment-{{comment.id}}" role="button" aria-expanded="false" aria-controls="collapseExample">
                                            <i class="bi bi-reply"></i>
                                        </a>
                                    </div>
                                    <div class="collapse w-50" id="comment-{{comment.id}}">
                                        <form action="{{url_for('reply_comment',post_id=post.id,comment_id=comment.id) }}" method="POST">
                                            {{ form2.csrf_token }}
                                            <div class="form-group mt-2">
                                                {{form2.author(class="form-control", placeholder="Name")}}
                                            </div>
                                            <div class="form-group mt-2">
                                                {{form2.reply(class="form-control" ,placeholder="Response")}}
                                            </div>
                                            <button type="submit" class="btn btn-primary mt-2 btn-sm">Post Reply</button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                            {% endfor %}

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