Вынес статику html из футера в конфиг, Вынес меню и приватные линки в апп.конфиг. Поправил отображение title в постах для отображения без тэгов разметки
parent
19dec390c3
commit
dfea8eff48
|
@ -0,0 +1,36 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: ea0fde3014d7
|
||||||
|
Revises: 5e6d181b4b74
|
||||||
|
Create Date: 2023-10-07 14:32:08.410786
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ea0fde3014d7'
|
||||||
|
down_revision = '5e6d181b4b74'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('site_headers',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=20), nullable=True),
|
||||||
|
sa.Column('description', sa.Text(), nullable=True),
|
||||||
|
sa.Column('content', sa.Text(), nullable=True),
|
||||||
|
sa.Column('enabled', sa.Boolean(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('site_headers')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -99,3 +99,16 @@ class PageView(MyAdminView):
|
||||||
form_overrides = dict(text=CKEditorField)
|
form_overrides = dict(text=CKEditorField)
|
||||||
create_template = "admin/edit.html"
|
create_template = "admin/edit.html"
|
||||||
edit_template = "admin/edit.html"
|
edit_template = "admin/edit.html"
|
||||||
|
|
||||||
|
|
||||||
|
class HeadersView(MyAdminView):
|
||||||
|
column_labels = dict(
|
||||||
|
name="Название",
|
||||||
|
description="Описание содержимого",
|
||||||
|
content="Содержимое включаемое в header",
|
||||||
|
enabled="Включить код в страницы сайта",
|
||||||
|
)
|
||||||
|
column_list = (
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
)
|
||||||
|
|
|
@ -8,7 +8,8 @@ from flask_migrate import Migrate
|
||||||
from flask_security.core import Security
|
from flask_security.core import Security
|
||||||
|
|
||||||
from pyproger.dbase import Role, User, db, user_datastore
|
from pyproger.dbase import Role, User, db, user_datastore
|
||||||
from pyproger.dbase.models import Page, Post, Tag
|
from pyproger.dbase.database import get_headers, get_menu_items
|
||||||
|
from pyproger.dbase.models import Page, Post, SiteHeaders, Tag
|
||||||
|
|
||||||
|
|
||||||
def create_app(test_config=None):
|
def create_app(test_config=None):
|
||||||
|
@ -21,11 +22,7 @@ def create_app(test_config=None):
|
||||||
load_dotenv(dotenv_path)
|
load_dotenv(dotenv_path)
|
||||||
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
|
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
|
||||||
app.config["SECURITY_PASSWORD_SALT"] = os.getenv("SECURITY_PASSWORD_SALT")
|
app.config["SECURITY_PASSWORD_SALT"] = os.getenv("SECURITY_PASSWORD_SALT")
|
||||||
if os.getenv("SQLALCHEMY_DATABASE_URI") is not None:
|
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("SQLALCHEMY_DATABASE_URI")
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv(
|
|
||||||
"SQLALCHEMY_DATABASE_URI"
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
app.config.from_mapping(test_config)
|
app.config.from_mapping(test_config)
|
||||||
|
|
||||||
|
@ -50,8 +47,8 @@ def create_app(test_config=None):
|
||||||
|
|
||||||
admin.init_app(app)
|
admin.init_app(app)
|
||||||
|
|
||||||
from pyproger.admin.views import (PageView, PostView, RoleView, TagView,
|
from pyproger.admin.views import (HeadersView, PageView, PostView,
|
||||||
UserView)
|
RoleView, TagView, UserView)
|
||||||
|
|
||||||
admin.add_view(
|
admin.add_view(
|
||||||
RoleView(
|
RoleView(
|
||||||
|
@ -89,8 +86,16 @@ def create_app(test_config=None):
|
||||||
PageView(
|
PageView(
|
||||||
Page,
|
Page,
|
||||||
db.session,
|
db.session,
|
||||||
category=" Страницы",
|
category="Страницы",
|
||||||
name="Страницы блога",
|
name="Статические страницы блога",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
admin.add_view(
|
||||||
|
HeadersView(
|
||||||
|
SiteHeaders,
|
||||||
|
db.session,
|
||||||
|
category="Страницы",
|
||||||
|
name="Включаемые в html заголовки",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -104,6 +109,12 @@ def create_app(test_config=None):
|
||||||
app.register_blueprint(bp_errors)
|
app.register_blueprint(bp_errors)
|
||||||
app.register_blueprint(bp_robots)
|
app.register_blueprint(bp_robots)
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
site_headers = get_headers()
|
||||||
|
app.config["SITE_HEADERS"] = site_headers
|
||||||
|
menu_items = get_menu_items()
|
||||||
|
app.config["MENU_ITEMS"] = menu_items
|
||||||
|
|
||||||
@security.context_processor
|
@security.context_processor
|
||||||
def security_context_processor():
|
def security_context_processor():
|
||||||
return dict(
|
return dict(
|
||||||
|
|
|
@ -1,23 +1,11 @@
|
||||||
import locale
|
import locale
|
||||||
|
import re
|
||||||
|
|
||||||
from flask import (
|
from flask import (abort, current_app, redirect, render_template, request,
|
||||||
abort,
|
session, url_for)
|
||||||
current_app,
|
|
||||||
redirect,
|
|
||||||
render_template,
|
|
||||||
request,
|
|
||||||
session,
|
|
||||||
url_for,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ..dbase.database import (
|
from ..dbase.database import (get_all_posts_by_tag, get_page,
|
||||||
get_all_posts_by_tag,
|
get_paginated_posts, get_post, get_tags)
|
||||||
get_menu_items,
|
|
||||||
get_page,
|
|
||||||
get_paginated_posts,
|
|
||||||
get_post,
|
|
||||||
get_tags,
|
|
||||||
)
|
|
||||||
from .blog import bp
|
from .blog import bp
|
||||||
|
|
||||||
locale.setlocale(locale.LC_ALL, "")
|
locale.setlocale(locale.LC_ALL, "")
|
||||||
|
@ -33,37 +21,46 @@ def index(page=1):
|
||||||
list_pages = [
|
list_pages = [
|
||||||
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
|
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
|
||||||
]
|
]
|
||||||
menu_items = get_menu_items()
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"blog/index.html",
|
"blog/index.html",
|
||||||
title="pyproger - разговоры про питон",
|
title=f'{current_app.config.get("BRAND")} - разговоры про питон',
|
||||||
menu_title="pyproger",
|
headers=current_app.config.get("SITE_HEADERS"),
|
||||||
menu_items=menu_items,
|
menu_title=current_app.config.get("BRAND"),
|
||||||
|
menu_items=current_app.config.get("MENU_ITEMS"),
|
||||||
posts=posts,
|
posts=posts,
|
||||||
page=page,
|
page=page,
|
||||||
total_pages=total_pages,
|
total_pages=total_pages,
|
||||||
list_pages=list_pages,
|
list_pages=list_pages,
|
||||||
|
mylinks=current_app.config.get("MYLINKS"),
|
||||||
|
copyright=current_app.config.get("COPYRIGHT"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/post/")
|
@bp.route("/post/")
|
||||||
@bp.route("/post/<path:slug>")
|
@bp.route("/post/<path:slug>")
|
||||||
def post(slug=None):
|
def post(slug=None):
|
||||||
back_url = session.get("back_url")
|
|
||||||
if slug is not None:
|
if slug is not None:
|
||||||
current_post = get_post(slug)
|
current_post = get_post(slug)
|
||||||
|
|
||||||
if current_post is None:
|
if current_post is None:
|
||||||
return abort(404)
|
return abort(404)
|
||||||
menu_items = get_menu_items()
|
|
||||||
|
TAG_RE = re.compile(r"<[^>]+>")
|
||||||
|
|
||||||
|
def remove_tags(text):
|
||||||
|
return TAG_RE.sub("", text)
|
||||||
|
|
||||||
|
title = remove_tags(current_post.Post.title)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"blog/postview.html",
|
"blog/postview.html",
|
||||||
title=f"pyproger - {current_post.Post.title}",
|
title=f'{current_app.config.get("BRAND")} - {title}',
|
||||||
menu_title="pyproger",
|
headers=current_app.config.get("SITE_HEADERS"),
|
||||||
menu_items=menu_items,
|
menu_title=current_app.config.get("BRAND"),
|
||||||
|
menu_items=current_app.config.get("MENU_ITEMS"),
|
||||||
post=current_post,
|
post=current_post,
|
||||||
back_url=back_url,
|
mylinks=current_app.config.get("MYLINKS"),
|
||||||
|
copyright=current_app.config.get("COPYRIGHT"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
@ -72,13 +69,15 @@ def post(slug=None):
|
||||||
@bp.route("/tags/")
|
@bp.route("/tags/")
|
||||||
def get_all_tags():
|
def get_all_tags():
|
||||||
tags = get_tags()
|
tags = get_tags()
|
||||||
menu_items = get_menu_items()
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"blog/tags.html",
|
"blog/tags.html",
|
||||||
title="pyproger - поиск по тэгу",
|
title=f'{current_app.config.get("BRAND")} - поиск по тэгу',
|
||||||
menu_title="pyproger",
|
headers=current_app.config.get("SITE_HEADERS"),
|
||||||
|
menu_title=current_app.config.get("BRAND"),
|
||||||
tags=tags,
|
tags=tags,
|
||||||
menu_items=menu_items,
|
menu_items=current_app.config.get("MENU_ITEMS"),
|
||||||
|
mylinks=current_app.config.get("MYLINKS"),
|
||||||
|
copyright=current_app.config.get("COPYRIGHT"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,25 +88,29 @@ def get_posts_by_tag(page=1, tag=None):
|
||||||
tag = request.args.get("tag")
|
tag = request.args.get("tag")
|
||||||
if tag is None:
|
if tag is None:
|
||||||
return redirect(url_for(".get_all_tags"))
|
return redirect(url_for(".get_all_tags"))
|
||||||
per_page = current_app.config.get("POSTS_ON_PAGE")
|
|
||||||
|
|
||||||
posts, total_pages = get_all_posts_by_tag(tag, page, per_page)
|
per_page = current_app.config.get("POSTS_ON_PAGE")
|
||||||
|
posts, total = get_all_posts_by_tag(tag, page, per_page)
|
||||||
|
total_pages = total // per_page + [0, 1][total % per_page != 0]
|
||||||
|
|
||||||
if posts is None:
|
if posts is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
list_pages = [
|
list_pages = [
|
||||||
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
|
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
|
||||||
]
|
]
|
||||||
menu_items = get_menu_items()
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"blog/index.html",
|
"blog/index.html",
|
||||||
title=f"pyproger - посты по {tag}",
|
title=f'{current_app.config.get("BRAND")} - посты по {tag}',
|
||||||
menu_title="pyproger",
|
headers=current_app.config.get("SITE_HEADERS"),
|
||||||
menu_items=menu_items,
|
menu_title=current_app.config.get("BRAND"),
|
||||||
|
menu_items=current_app.config.get("MENU_ITEMS"),
|
||||||
posts=posts,
|
posts=posts,
|
||||||
page=page,
|
page=page,
|
||||||
total_pages=total_pages,
|
total_pages=total_pages,
|
||||||
list_pages=list_pages,
|
list_pages=list_pages,
|
||||||
|
mylinks=current_app.config.get("MYLINKS"),
|
||||||
|
copyright=current_app.config.get("COPYRIGHT"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,11 +119,13 @@ def page(slug=None):
|
||||||
page = get_page(slug)
|
page = get_page(slug)
|
||||||
if page is None:
|
if page is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
menu_items = get_menu_items()
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"blog/page.html",
|
"blog/page.html",
|
||||||
title=f"pyproger - {page.name}",
|
title=f'{current_app.config.get("BRAND")} - {page.name}',
|
||||||
menu_title="pyproger",
|
headers=current_app.config.get("SITE_HEADERS"),
|
||||||
menu_items=menu_items,
|
menu_title=current_app.config.get("BRAND"),
|
||||||
|
menu_items=current_app.config.get("MENU_ITEMS"),
|
||||||
content_body=page.text,
|
content_body=page.text,
|
||||||
|
mylinks=current_app.config.get("MYLINKS"),
|
||||||
|
copyright=current_app.config.get("COPYRIGHT"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,14 +1,28 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# Настройки блога
|
||||||
|
BRAND = "pyproger"
|
||||||
|
COPYRIGHT = {
|
||||||
|
"year": "2023",
|
||||||
|
"name": "Сергей Вaнюшкин",
|
||||||
|
"link": "https://pi3c.ru",
|
||||||
|
"city": "г.Нарьян-Мар, Ненецкий А.О.",
|
||||||
|
}
|
||||||
|
MYLINKS = (
|
||||||
|
{"icon": "fab fa-telegram", "link": "https://t.me/pi3c_nao"},
|
||||||
|
{"icon": "fab fa-vk", "link": "https://m.vk.com/pi3c_nao"},
|
||||||
|
{"icon": "fab fa-yandex", "link": "mailto:pi3c@yandex.ru"},
|
||||||
|
{"icon": "fab fa-github", "link": "https://github.com/pi3c"},
|
||||||
|
{"icon": "fa fa-gitea", "link": "https://git.pi3c.ru"},
|
||||||
|
)
|
||||||
|
POSTS_ON_PAGE = 6
|
||||||
|
|
||||||
# Тема оформления админ панели
|
# Тема оформления админ панели
|
||||||
FLASK_ADMIN_SWATCH = "slate"
|
FLASK_ADMIN_SWATCH = "slate"
|
||||||
|
|
||||||
# Тестовый ключ
|
# Тестовый ключ
|
||||||
SECRET_KEY = "Test_secret_key"
|
SECRET_KEY = "Test_secret_key"
|
||||||
|
|
||||||
# Настройки подключения к бд
|
|
||||||
SQLALCHEMY_DATABASE_URI = "sqlite:///sqlite.db"
|
|
||||||
# For debug - show every DB query
|
|
||||||
SQLALCHEMY_ECHO = False
|
SQLALCHEMY_ECHO = False
|
||||||
|
|
||||||
# Настройки Flask-Security
|
# Настройки Flask-Security
|
||||||
|
@ -44,6 +58,3 @@ CKEDITOR_PKG_TYPE = "full"
|
||||||
CKEDITOR_SERVE_LOCAL = True
|
CKEDITOR_SERVE_LOCAL = True
|
||||||
CKEDITOR_ENABLE_CODESNIPPET = True
|
CKEDITOR_ENABLE_CODESNIPPET = True
|
||||||
CKEDITOR_CODE_THEME = "monokai_sublime"
|
CKEDITOR_CODE_THEME = "monokai_sublime"
|
||||||
|
|
||||||
# Настройки блога
|
|
||||||
POSTS_ON_PAGE = 6
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
from datetime import datetime, timezone
|
|
||||||
|
|
||||||
from sqlalchemy import func
|
|
||||||
|
|
||||||
from . import db
|
from . import db
|
||||||
from .models import Page, Post, Tag, User
|
from .models import Page, Post, SiteHeaders, Tag, User
|
||||||
|
|
||||||
|
|
||||||
def get_paginated_posts(page, per_page):
|
def get_paginated_posts(page, per_page):
|
||||||
|
@ -13,11 +9,7 @@ def get_paginated_posts(page, per_page):
|
||||||
.order_by(Post.create_datetime.desc())
|
.order_by(Post.create_datetime.desc())
|
||||||
.paginate(page=page, per_page=per_page, error_out=True)
|
.paginate(page=page, per_page=per_page, error_out=True)
|
||||||
)
|
)
|
||||||
total_pages = (
|
return all_post_query, all_post_query.total
|
||||||
all_post_query.total // per_page + [0, 1][all_post_query.total % per_page != 0]
|
|
||||||
)
|
|
||||||
|
|
||||||
return all_post_query, total_pages
|
|
||||||
|
|
||||||
|
|
||||||
def get_post(slug):
|
def get_post(slug):
|
||||||
|
@ -71,3 +63,12 @@ def get_posts_for_sitemap():
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
return posts
|
return posts
|
||||||
|
|
||||||
|
|
||||||
|
def get_headers():
|
||||||
|
headers = (
|
||||||
|
db.session.query(SiteHeaders.content)
|
||||||
|
.filter(SiteHeaders.enabled.is_(True))
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
return headers
|
||||||
|
|
|
@ -107,3 +107,18 @@ class Page(db.Model):
|
||||||
default=func.now(),
|
default=func.now(),
|
||||||
onupdate=func.now(),
|
onupdate=func.now(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SiteHeaders(db.Model):
|
||||||
|
__tablename__ = "site_headers"
|
||||||
|
id = Column(
|
||||||
|
Integer,
|
||||||
|
primary_key=True,
|
||||||
|
nullable=False,
|
||||||
|
unique=True,
|
||||||
|
autoincrement=True,
|
||||||
|
)
|
||||||
|
name = Column(String(20))
|
||||||
|
description = Column(Text)
|
||||||
|
content = Column(Text)
|
||||||
|
enabled = Column(Boolean, default=False)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="{{page_lang}}">
|
<html lang="ru">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
<title>
|
<title>{% block title %}{% endblock title %}</title>
|
||||||
{% block title %}
|
{% for h in headers %}
|
||||||
{% endblock title %}
|
{{h.content | safe}}
|
||||||
</title>
|
{% endfor %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
|
@ -67,40 +67,13 @@
|
||||||
<div class="container p-2">
|
<div class="container p-2">
|
||||||
<!-- Section: Social media -->
|
<!-- Section: Social media -->
|
||||||
<section class="mb-2">
|
<section class="mb-2">
|
||||||
<!-- Telegram -->
|
{% for l in mylinks %}
|
||||||
<a class="btn btn-outline-light btn-floating m-2"
|
<a class="btn btn-outline-light btn-floating m-2"
|
||||||
href="https://t.me/pi3c_nao"
|
href="{{ l.link }}"
|
||||||
role="button"
|
role="button"
|
||||||
><i class="fab fa-telegram"></i
|
><i class="{{ l.icon }}"></i
|
||||||
></a>
|
|
||||||
|
|
||||||
<!-- VK -->
|
|
||||||
<a class="btn btn-outline-light btn-floating m-2"
|
|
||||||
href="https://m.vk.com/pi3c_nao"
|
|
||||||
role="button"
|
|
||||||
><i class="fab fa-vk"></i
|
|
||||||
></a>
|
|
||||||
|
|
||||||
<!-- Yandex -->
|
|
||||||
<a class="btn btn-outline-light btn-floating m-2"
|
|
||||||
href="mailto:pi3c@yandex.ru"
|
|
||||||
role="button"
|
|
||||||
><i class="fab fa-yandex"></i
|
|
||||||
></a>
|
|
||||||
|
|
||||||
<!-- Github -->
|
|
||||||
<a class="btn btn-outline-light btn-floating m-2"
|
|
||||||
href="https://github.com/pi3c"
|
|
||||||
role="button"
|
|
||||||
><i class="fab fa-github"></i
|
|
||||||
></a>
|
|
||||||
|
|
||||||
<!-- Gitea -->
|
|
||||||
<a class="btn btn-outline-light btn-floating m-2"
|
|
||||||
href="https://git.pi3c.ru"
|
|
||||||
role="button"
|
|
||||||
><i class="fa fa-gitea"></i
|
|
||||||
></a>
|
></a>
|
||||||
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
<!-- Section: Social media -->
|
<!-- Section: Social media -->
|
||||||
|
|
||||||
|
@ -168,10 +141,10 @@
|
||||||
|
|
||||||
<!-- Copyright -->
|
<!-- Copyright -->
|
||||||
<small class="text-center text-body">
|
<small class="text-center text-body">
|
||||||
© 2023
|
© {{ copyright.year}}
|
||||||
<a class="link-offset-2 link-underline link-underline-opacity-0 text-white" href="https://pi3c.ru/">Сергей Ванюшкин</a>
|
<a class="link-offset-2 link-underline link-underline-opacity-0 text-white" href="{{ copyright.link }}">{{ copyright.name}}</a>
|
||||||
<br>
|
<br>
|
||||||
г.Нарьян-Мар Ненецкий А.О
|
{{copyright.city}}
|
||||||
</small>
|
</small>
|
||||||
<!-- Copyright -->
|
<!-- Copyright -->
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends 'blog/base.html' %}
|
{% extends 'blog/base.html' %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{title}}
|
{{ title }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block menu_title %}
|
{% block menu_title %}
|
||||||
|
|
Loading…
Reference in New Issue