diff --git a/blog_project/blog/blog.db b/blog_project/blog/blog.db index f63ad1b..ca922d3 100644 Binary files a/blog_project/blog/blog.db and b/blog_project/blog/blog.db differ diff --git a/blog_project/blog/forms.py b/blog_project/blog/forms.py index 76ff115..a6e91eb 100644 --- a/blog_project/blog/forms.py +++ b/blog_project/blog/forms.py @@ -39,15 +39,17 @@ class LoginForm(FlaskForm): class UpdateProfileForm(FlaskForm): - username = StringField('user name', validators=[DataRequired(), Length(min=4, max=25)]) + username = StringField('user name', validators=[ + DataRequired(), Length(min=4, max=25)]) password = PasswordField('password', validators=[DataRequired()]) class PostForm(FlaskForm): title = StringField('title', validators=[DataRequired()]) content = TextAreaField('content', validators=[DataRequired()]) + tags = StringField('tags', validators=[DataRequired()]) + class SearchForm(FlaskForm): query = StringField('Post Title', validators=[DataRequired()]) - submit = SubmitField('Search') - \ No newline at end of file + submit = SubmitField('Search') diff --git a/blog_project/blog/models.py b/blog_project/blog/models.py index 35bb197..55f211b 100644 --- a/blog_project/blog/models.py +++ b/blog_project/blog/models.py @@ -8,6 +8,13 @@ def load_user(user_id): return User.query.get(int(user_id)) +post_tags = db.Table('post_tags', + db.Column('post_id', db.Integer, + db.ForeignKey('post.id')), + db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')) + ) + + class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(30), unique=True, nullable=False) @@ -25,6 +32,16 @@ class Post(db.Model): date = db.Column(db.DateTime, nullable=False, default=datetime.now) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) - + tags = db.relationship('Tag', secondary=post_tags, + backref=db.backref('posts', lazy='dynamic')) + + def __repr__(self): + return f'{self.__class__.__name__}({self.id}, {self.title})' + + +class Tag(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(30), unique=True, nullable=False) + def __repr__(self): - return f'{self.__class__.__name__}({self.id}, {self.title})' \ No newline at end of file + return f'{self.__class__.__name__}({self.id}, {self.name})' diff --git a/blog_project/blog/routes.py b/blog_project/blog/routes.py index 4a5c43c..64cdef5 100644 --- a/blog_project/blog/routes.py +++ b/blog_project/blog/routes.py @@ -1,7 +1,7 @@ from flask import render_template, redirect, url_for, flash, request, abort from . import app, db, bcrypt -from .forms import RegistrationForm, LoginForm, UpdateProfileForm, PostForm , SearchForm -from .models import User, Post +from .forms import RegistrationForm, LoginForm, UpdateProfileForm, PostForm, SearchForm +from .models import User, Post, Tag from flask_login import login_user, current_user, logout_user, login_required @@ -78,6 +78,7 @@ def profile(): return render_template('profile.html', form=form) + @app.route('/post/new', methods=['GET', 'POST']) @login_required def new_post(): @@ -88,6 +89,12 @@ def new_post(): content=form.title.data, author=current_user ) + tags_list = [tag.strip() for tag in form.tags.data.split(',')] + for tag_name in tags_list: + tag = Tag.query.filter_by(name=tag_name).first() + if not tag: + tag = Tag(name=tag_name) + post.tags.append(tag) db.session.add(post) db.session.commit() flash('post created') @@ -111,31 +118,48 @@ def delete(post_id): @login_required def update(post_id): post = Post.query.get_or_404(post_id) - + if post.author != current_user: abort(403) form = PostForm() - + if form.validate_on_submit(): post.title = form.title.data post.content = form.content.data + post.tags.clear() + + tags_list = [tag.strip() for tag in form.tags.data.split(',')] + for tag_name in tags_list: + tag = Tag.query.filter_by(name=tag_name).first() + if not tag: + tag = Tag(name=tag_name) + post.tags.append(tag) db.session.commit() flash('post updated', 'success') return redirect(url_for('detail', post_id=post.id)) elif request.method == 'GET': form.title.data = post.title form.content.data = post.content + form.tags.data = ','.join([tag.name for tag in post.tags]) return render_template('update.html', form=form) -@app.route('/post/search' , methods=['GET', 'POST']) + +@app.route('/post/search', methods=['GET', 'POST']) def search(): - form = SearchForm() + form = SearchForm() if form.validate_on_submit(): - posts = Post.query.filter(Post.title.like(f"%{form.query.data}%")).all() + posts = Post.query.filter( + Post.title.like(f"%{form.query.data}%")).all() if posts: - return render_template('search.html', posts=posts , form=form) + return render_template('search.html', posts=posts, form=form) else: - flash('No such post has been found!','danger') - return render_template('search.html',form=form) - return render_template('search.html', form=form) \ No newline at end of file + flash('No such post has been found!', 'danger') + return render_template('search.html', form=form) + return render_template('search.html', form=form) + + +@app.route('/tag/') +def tag_posts(tag_name): + tag = Tag.query.filter_by(name=tag_name).first_or_404() + return render_template('tag_posts.html', posts=tag.posts, tag_name=tag_name) diff --git a/blog_project/blog/templates/detail.html b/blog_project/blog/templates/detail.html index 9e7fa45..ce47d19 100644 --- a/blog_project/blog/templates/detail.html +++ b/blog_project/blog/templates/detail.html @@ -1,9 +1,15 @@ {% extends 'base.html' %} {% block content %} -

{{ post.title }}

- {{ post.author.username }} - {{ post.date.strftime('%Y-%m-%d') }} -
-

{{ post.content|safe }}

+

{{ post.title }}

+{{ post.author.username }} +{{ post.date.strftime('%Y-%m-%d') }} +
+ {% for tag in post.tags %} + {{ tag.name + }} + {% endfor %} +
+
+

{{ post.content|safe }}

{% endblock content %} \ No newline at end of file diff --git a/blog_project/blog/templates/home.html b/blog_project/blog/templates/home.html index c1997ce..6b7a873 100644 --- a/blog_project/blog/templates/home.html +++ b/blog_project/blog/templates/home.html @@ -1,18 +1,24 @@ {% extends 'base.html' %} {% block content %} -

Home Page {{ current_user.username }}

+

Home Page {{ current_user.username }}

-
- {% for post in posts %} -
-
{{ post.title }}
- Show - {% if post.author == current_user %} - Delete - Update - {% endif %} -
- {% endfor %} +
+ {% for post in posts %} +
+
{{ post.title }}
+
+ {% for tag in post.tags %} + {{ tag.name + }} + {% endfor %} +
+ Show + {% if post.author == current_user %} + Delete + Update + {% endif %}
-{% endblock %} + {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/blog_project/blog/templates/new_post.html b/blog_project/blog/templates/new_post.html index 5cf5700..51afe3a 100644 --- a/blog_project/blog/templates/new_post.html +++ b/blog_project/blog/templates/new_post.html @@ -1,15 +1,18 @@ {% extends 'base.html' %} {% block content %} -
- {{ form.csrf_token }} + + {{ form.csrf_token }} - {{ form.title.label}} - {{ form.title}} + {{ form.title.label}} + {{ form.title}} - {{ form.content.label }} - {{ form.content }} + {{ form.content.label }} + {{ form.content }} - -
+ {{form.tags.label}} + {{form.tags}} + + + {% endblock content %} \ No newline at end of file diff --git a/blog_project/blog/templates/tag_posts.html b/blog_project/blog/templates/tag_posts.html new file mode 100644 index 0000000..6e7a6c9 --- /dev/null +++ b/blog_project/blog/templates/tag_posts.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} + +{% block content %} +

Posts tagged with "{{ tag_name }}"

+ +
+ {% for post in posts %} +
+
{{ post.title }}
+ Show + {% if post.author == current_user %} + Delete + Update + {% endif %} +
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/blog_project/blog/templates/update.html b/blog_project/blog/templates/update.html index 5cf5700..51afe3a 100644 --- a/blog_project/blog/templates/update.html +++ b/blog_project/blog/templates/update.html @@ -1,15 +1,18 @@ {% extends 'base.html' %} {% block content %} -
- {{ form.csrf_token }} + + {{ form.csrf_token }} - {{ form.title.label}} - {{ form.title}} + {{ form.title.label}} + {{ form.title}} - {{ form.content.label }} - {{ form.content }} + {{ form.content.label }} + {{ form.content }} - -
+ {{form.tags.label}} + {{form.tags}} + + + {% endblock content %} \ No newline at end of file