Przy tworzeniu stron internetowych większość z developerów napotka problem stworzenia systemu komentarzy.
Podstawowymi wymogami są:- komentować można nie tylko artykul/wpis na blogu, lecz takze sam komentarz
- kazdy komentarz mozna skomentować dowolną ilość razy
- brak ograniczeniu w zaglebieniu komentarzy
- funkcja zwijania/rozwijania komentarzy
- podstawowe informacje o komentarzu - wiek, nazwa uzytkownika
Technologie użyte w tym przykladzie to:
- Python
- Pyramid framework
- SQLAlchemy
- MySQL database
- Mako templating system
Docelowo powinno ono wygladac jak na Reddit.com:
Najpierw podstawa - baza danych. Zakladamy ze komentowane beda posty na Blogu - taki jak ten, który czytasz.
class Articles(Base):
"""This table represents list of added news"""
__tablename__ = 'articles'
id = Column(Integer, primary_key=True, index=True)
title = Column(String, nullable=False, index=True)
content = Column(UnicodeText, nullable=False)
description = Column(UnicodeText(length=250), nullable=False)
url = Column(UnicodeText, nullable=False)
image = Column(UnicodeText, nullable=True)
author_id = Column(Integer, ForeignKey(Users.id), nullable=False)
added_dt = Column(DateTime, nullable=False, default=datetime.now())
modified_dt = Column(DateTime, nullable=False, default=datetime.now())
visits = Column(Integer, nullable=False, default=0)
comments = relationship('Comments', cascade="delete", single_parent=True, lazy='subquery')
author = relationship(Users, single_parent=True, lazy='subquery')
Do tej pory chyba wszystko jest jasne. Wazna jest relacja comments do tabeli Comments zawierajacej komentarze.
Potrzebna nam również definicja klasy komentarzy:
class Comments(Base):
"""This table represents list of added comments"""
__tablename__ = 'comments'
id = Column(Integer, primary_key=True, index=True)
article_id = Column(Integer, ForeignKey(Articles.id), nullable=False)
author_id = Column(Integer, ForeignKey(Users.id), nullable=False)
content = Column(UnicodeText, nullable=False)
added_dt = Column(DateTime, nullable=False, default=datetime.now())
parent_id = Column(Integer, ForeignKey('comments.id'), nullable=True)
author = relationship(Users, single_parent=True, lazy='subquery')
children = relationship("Comments",
# cascade deletions
cascade="all, delete-orphan",
# many to one + adjacency list - remote_side
# is required to reference the 'remote'
# column in the join condition.
backref=backref("parent", remote_side=id),
# children will be represented as a dictionary
# on the "name" attribute.
collection_class=attribute_mapped_collection('id'),
)
Tutaj najwazniejszymi rzeczami sa:
- relacja children - jest to relacja komentarzy do komentarzy-dzieci, polaczona poprzez atrybut ID. Dzieki niej komentarze polaczone sa poprzez relacje ID-PARENT_ID.
Kwestia bazy danych jest zalatwiona. Teraz czas na controller - a mianowicie funkcje widoku:
@view_config(route_name='article_view', request_method='GET', renderer='project:templates/articles/view.mako')
def view(self):
try:
#TUTAJ POBIERAMY ARTYKUL Z BAZY DANYCH
article = DBSession.query(Articles).get(self.article_id)
#FUNKCJA POBIERAJACA WSZYSTKIE KOMENTARZE DLA ARTYKULU
comments = blogfacade.get_comments_for_article(self.article_id, self.page, self.comments_page_size)
return dict(status=True, article=article, comments=comments, user=user)
except Exception, ex:
h.exc_wrap(ex)
return dict(status=False, message=ex)
Pora na template Mako. Proponuje stworzyc osobny plik szablonu generujacy drzewo komentarzy:
<%def name="build_comment(c)"> <header class="uk-comment"> <div class="uk-comment-meta"> % if c.children: <a class="collapse">[ - ]</a> <a class="unroll uk-hidden">[ + ]</a> % endif <span class="uk-text-bold">${c.author.username}</span> | ${c.added_dt} <button type="submit" class="comment-reply-button">${_("reply")}</button> </div> <div class="uk-comment-body"> ${c.content} </div> <form action="${request.route_url('comment_reply', article_id=article.id, parent_id=c.id)}" method="post" class="uk-position-relative comment-reply uk-display-block uk-hidden" accept-charset="utf-8" enctype="multipart/form-data"> <textarea name="content" cols="50" rows="2" placeholder="${_("Reply this comment")}" required></textarea> <input type="hidden" name="csrf_token" value="${request.session.get_csrf_token()}"> <input class="uk-position-top comment-reply-button" type="submit" value="${_("Save")}"> </form> # TUTAJ GLOWNA CZESC - REKURSYWNE WYWOLANIE FUNKCJI GENERUJACEJ POTOMNE KOMENTARZE (CHILDY) % if hasattr(c, 'children') and len(c.children): % for child in c.children: ${build_comment(child)} % endfor % endif </header></%def>
Mamy już gotowa funkcje tworzaca drzewo komentarzy, wystarczy ja uzyc w jakims szablonie:
<article class="uk-article"> # TUTAJ TRESC ARTYKULU <span>${c.content}</span> % if comments: # IMPORTUJEMY FUNKCJE TWORZACA DRZEWO KOMENTARZY <%namespace name="comment_tree" file="comment_tree.mako"/> <ul class="uk-comment-list"> # I DLA KAZDEGO KOMENTARZA JA ODPALAMY (rekursywnie bedzie sie ona wywolywac, az "DO SPODU" % for c in comments: ${comment_tree.build_comment(c)} % endfor </ul> % endif</article>
GOTOWE. Mam nadzieje, ze ten artykul pomoze Wam w tworzeniu stron internetowych.