добавил краткое описание и форматирование в заголовок, описание и текст статьи

main
Сергей Ванюшкин 2023-09-22 14:31:42 +03:00
parent 23e8a2e492
commit 7c6fc02529
13 changed files with 237 additions and 10 deletions

View File

@ -1,8 +1,8 @@
"""initial_migration """initial_migration
Revision ID: af05a1cbd975 Revision ID: 8c415e462cb3
Revises: Revises:
Create Date: 2023-09-19 22:57:11.510132 Create Date: 2023-09-22 12:19:22.923813
""" """
import flask_security import flask_security
@ -10,7 +10,7 @@ import sqlalchemy as sa
from alembic import op from alembic import op
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = "af05a1cbd975" revision = "8c415e462cb3"
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -20,8 +20,8 @@ def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table( op.create_table(
"role", "role",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(length=80), nullable=False), sa.Column("name", sa.String(length=80), nullable=False),
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("description", sa.String(length=255), nullable=True), sa.Column("description", sa.String(length=255), nullable=True),
sa.Column("permissions", flask_security.datastore.AsaList(), nullable=True), sa.Column("permissions", flask_security.datastore.AsaList(), nullable=True),
sa.Column( sa.Column(
@ -78,8 +78,9 @@ def upgrade():
"post", "post",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("author", sa.Integer(), nullable=True), sa.Column("author", sa.Integer(), nullable=True),
sa.Column("slug", sa.String(length=30), nullable=False), sa.Column("slug", sa.String(length=100), nullable=False),
sa.Column("title", sa.String(length=50), nullable=False), sa.Column("title", sa.Text(), nullable=False),
sa.Column("description", sa.Text(), nullable=False),
sa.Column("published", sa.Boolean(), nullable=True), sa.Column("published", sa.Boolean(), nullable=True),
sa.Column("create_datetime", sa.DateTime(), nullable=True), sa.Column("create_datetime", sa.DateTime(), nullable=True),
sa.Column("update_datetime", sa.DateTime(), nullable=True), sa.Column("update_datetime", sa.DateTime(), nullable=True),

View File

@ -1,4 +1,4 @@
from flask import abort, redirect, request, url_for from flask import abort, g, redirect, request, url_for
from flask_admin.contrib import sqla from flask_admin.contrib import sqla
from flask_ckeditor import CKEditorField from flask_ckeditor import CKEditorField
from flask_security import current_user from flask_security import current_user
@ -72,6 +72,7 @@ class PostView(MyAdminView):
tags="Тэги", tags="Тэги",
slug="Слаг", slug="Слаг",
title="Заголовок", title="Заголовок",
description="Краткое описание статьи",
author="Автор", author="Автор",
published="Опубликовано", published="Опубликовано",
create_datetime="Дата создания", create_datetime="Дата создания",
@ -79,6 +80,10 @@ class PostView(MyAdminView):
text="Текст", text="Текст",
) )
form_overrides = dict(text=CKEditorField) form_overrides = dict(
title=CKEditorField,
description=CKEditorField,
text=CKEditorField,
)
create_template = "admin/edit.html" create_template = "admin/edit.html"
edit_template = "admin/edit.html" edit_template = "admin/edit.html"

View File

@ -76,6 +76,10 @@ def create_app(test_config=None):
app.register_blueprint(bp_cli) app.register_blueprint(bp_cli)
from pyproger.blog.blog import bp as bp_blog
app.register_blueprint(bp_blog)
@security.context_processor @security.context_processor
def security_context_processor(): def security_context_processor():
return dict( return dict(

View File

9
pyproger/blog/blog.py Normal file
View File

@ -0,0 +1,9 @@
from flask import Blueprint
bp = Blueprint(
"bp_blog",
__name__,
template_folder="templates/blog",
)
from . import urls

43
pyproger/blog/urls.py Normal file
View File

@ -0,0 +1,43 @@
import locale
from flask import render_template, render_template_string, request
from ..dbase.database import get_paginated_posts, get_post
from .blog import bp
locale.setlocale(locale.LC_ALL, "")
@bp.route("/", methods=["GET"], defaults={"page": 1})
@bp.route("/<int:page>", methods=["GET"])
def index(page=1):
per_page = 3
posts, total_pages = get_paginated_posts(page, per_page)
list_pages = [
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
]
return render_template(
"blog/index.html",
request=request,
posts=posts,
title="pyproger - разговоры про питон",
menu_title="pyproger",
page=page,
total_pages=total_pages,
list_pages=list_pages,
)
@bp.route("/post/")
@bp.route("/post/<path:slug>")
def post(slug=None):
if slug:
current_post = get_post(slug)
return render_template(
"blog/postview.html",
title=f"pyproger - {current_post.Post.title}",
menu_title="pyproger",
post=current_post,
)
else:
return render_template_string("noup")

View File

@ -0,0 +1,24 @@
from . import db
from .models import Post, User
def get_paginated_posts(page, per_page):
quer = (
db.session.query(Post, User)
.join(User, Post.author == User.id)
.order_by(Post.create_datetime.desc())
.paginate(page=page, per_page=per_page, error_out=False)
)
total_pages = quer.total // per_page + [0, 1][quer.total % per_page != 0]
return quer, total_pages
def get_post(slug):
post_query = (
db.session.query(Post, User)
.join(User, Post.author == User.id)
.filter(Post.slug == slug)
.first()
)
return post_query

View File

@ -1,5 +1,6 @@
import datetime import datetime
from flask_security import current_user
from flask_security.models import fsqla from flask_security.models import fsqla
from sqlalchemy import Boolean, Column, DateTime, Integer, String, Text from sqlalchemy import Boolean, Column, DateTime, Integer, String, Text
@ -69,8 +70,9 @@ class Post(db.Model):
autoincrement=True, autoincrement=True,
) )
author = Column(Integer, db.ForeignKey("user.id")) author = Column(Integer, db.ForeignKey("user.id"))
slug = Column(String(30), nullable=False) slug = Column(String(100), nullable=False)
title = Column(String(50), nullable=False) title = Column(Text, nullable=False)
description = Column(Text, nullable=False)
published = Column(Boolean, default=False) published = Column(Boolean, default=False)
tags = db.relationship("Tag", secondary=tag_post) tags = db.relationship("Tag", secondary=tag_post)
@ -82,5 +84,6 @@ class Post(db.Model):
update_datetime = Column( update_datetime = Column(
DateTime(), DateTime(),
nullable=True, nullable=True,
onupdate=datetime.datetime.utcnow(),
) )
text = Column(Text) text = Column(Text)

View File

@ -8,5 +8,7 @@ if you have set the configuration variables more than CKEDITOR_SERVE_LOCAL and C
or you need to config the CKEditor textarea, use the line below to register the configuration. or you need to config the CKEditor textarea, use the line below to register the configuration.
The name value should be the name of the CKEditor form field. The name value should be the name of the CKEditor form field.
#} #}
{{ ckeditor.config(name='Title') }}
{{ ckeditor.config(name='Text') }} {{ ckeditor.config(name='Text') }}
{% endblock %} {% endblock %}

View File

@ -0,0 +1,50 @@
<!doctype html>
<html lang="{{page_lang}}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
{% block title %}
{% endblock title %}
</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<body>
<div id="main-container" class="container-fluid">
<nav class="navbar p-2 navbar-expand-lg bg-dark border-bottom border-bottom-dark rounded-bottom-4"
data-bs-theme="dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for(".index")}}">
{% block menu_title %}
{% endblock menu_title %}</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Переключатель навигации">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
text
</ul>
</div>
</div>
</nav>
<div id="content-container" class="container-fluid">
{% block content %} {% endblock %}
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,58 @@
{% extends 'blog/base.html' %}
{% block title %}
{{title}}
{% endblock %}
{% block menu_title %}
{{ menu_title }}
{% endblock %}
{% block content %}
<div class="conteiner">
<br>
</div>
<div class="container px-4 px-lg-5">
<div class="list-group justify-content-center">
{% for p in posts %}
<a href="{{ url_for(".post", slug=p.Post.slug )}}" class="list-group-item list-group-item-action border-0">
<h5 class="post-title">{{ p.Post.title | safe }}</h5>
{{ p.Post.description | safe}}
</a>
<small>
Опубликовал
<a href="mailto:{{p.User.email}}">
{{ p.User.username}}
</a>
{{ p.Post.create_datetime.strftime('%d %B, %Y') }}
</small>
<hr class="my-4" />
{% endfor %}
</div>
<nav class="container">
<ul class="pagination justify-content-start"
{% if posts.has_prev %}
<li class="page-item"><a class="page-link" href="{{ url_for(".index", page=posts.prev_num)}}">&lt;&lt;</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" >&lt;&lt;</a></li>
{% endif %}
{% for i in list_pages %}
{% if i == page %}
<li class="page-item active"><a class="page-link" href="{{ url_for(".index", page=i)}}">{{ i }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="{{ url_for(".index", page=i)}}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<li class="page-item"><a class="page-link" href="{{ url_for(".index", page=posts.next_num)}}">&gt;&gt;</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" >&gt;&gt;</a></li>
{% endif %}
</nav>
{% endblock %}

View File

@ -0,0 +1,19 @@
{% extends 'blog/base.html' %}
{% block title %}
{{title}}
{% endblock %}
{% block menu_title %}
{{ menu_title }}
{% endblock %}
{% block content %}
<!-- Main Content-->
<div class="conteiner">
<br>
<h4>{{ post.Post.title | safe }}</h4>
{{ post.Post.text | safe }}
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
<html>
<body>
<div>
<a href="{{ url_for('admin.index') }}">админ панель</a>
</div>
</body>
</html>