Add support for pinned pages
This commit is contained in:
parent
89f29e649a
commit
731a443209
10 changed files with 110 additions and 8 deletions
|
@ -4,5 +4,4 @@ Simple blog management system.
|
||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
4. Find a nice way to display metadata (author, dates, etc)
|
4. Find a nice way to display metadata (author, dates, etc)
|
||||||
5. Allow adding pages (pinned articles ?)
|
|
||||||
6. Add syntax coloration to code blocks
|
6. Add syntax coloration to code blocks
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.contrib.admin import register
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from .models import Article, User
|
from .models import Article, Page, User
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|
||||||
|
@ -67,3 +67,22 @@ class ArticleAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
css = {"all": ("admin_articles.css",)}
|
css = {"all": ("admin_articles.css",)}
|
||||||
|
|
||||||
|
|
||||||
|
@register(Page)
|
||||||
|
class PageAdmin(ArticleAdmin):
|
||||||
|
list_display = ["position"] + ArticleAdmin.list_display
|
||||||
|
fieldsets = [
|
||||||
|
(
|
||||||
|
"Metadata",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
("title", "slug", "position"),
|
||||||
|
("author", "status"),
|
||||||
|
("published_at", "created_at", "updated_at"),
|
||||||
|
"views_count",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
("Content", {"fields": ("content",)}),
|
||||||
|
]
|
||||||
|
|
5
articles/context_processors.py
Normal file
5
articles/context_processors.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from articles.models import Article, Page
|
||||||
|
|
||||||
|
|
||||||
|
def pages(request):
|
||||||
|
return {"pages": Page.objects.filter(status=Article.PUBLISHED)}
|
31
articles/migrations/0006_page.py
Normal file
31
articles/migrations/0006_page.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 3.1 on 2020-08-17 07:00
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("articles", "0005_article_slug"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Page",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"article_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="articles.article",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
bases=("articles.article",),
|
||||||
|
),
|
||||||
|
]
|
19
articles/migrations/0007_auto_20200817_0941.py
Normal file
19
articles/migrations/0007_auto_20200817_0941.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.1 on 2020-08-17 07:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("articles", "0006_page"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="page", options={"ordering": ["position", "-published_at"]},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="page", name="position", field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
|
@ -13,6 +13,11 @@ class User(AbstractUser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleManager(models.Manager):
|
||||||
|
def get_queryset(self):
|
||||||
|
return super().get_queryset().filter(page__isnull=True)
|
||||||
|
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
DRAFT = "draft"
|
DRAFT = "draft"
|
||||||
PUBLISHED = "published"
|
PUBLISHED = "published"
|
||||||
|
@ -30,6 +35,9 @@ class Article(models.Model):
|
||||||
views_count = models.IntegerField(default=0)
|
views_count = models.IntegerField(default=0)
|
||||||
slug = models.SlugField(unique=True)
|
slug = models.SlugField(unique=True)
|
||||||
|
|
||||||
|
objects = ArticleManager()
|
||||||
|
with_pages = models.Manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ["-published_at"]
|
ordering = ["-published_at"]
|
||||||
|
|
||||||
|
@ -67,7 +75,15 @@ class Article(models.Model):
|
||||||
self.status = self.DRAFT
|
self.status = self.DRAFT
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def save(self, *args, **kwargs): # new
|
def save(self, *args, **kwargs):
|
||||||
if not self.slug:
|
if not self.slug:
|
||||||
self.slug = slugify(self.title)
|
self.slug = slugify(self.title)
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Page(Article):
|
||||||
|
objects = models.Manager()
|
||||||
|
position = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["position", "-published_at"]
|
||||||
|
|
|
@ -11,7 +11,15 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a href="{% url 'articles-list' %}">Gab's Notes</a>
|
<a href="{% url 'articles-list' %}">Gab's Notes</a>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|
|
||||||
<a href="{% url 'drafts-list' %}">View drafts</a>
|
<a href="{% url 'drafts-list' %}">View drafts</a>
|
||||||
|
<a href="{% url 'admin:index' %}">Admin</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if pages %}
|
||||||
|
|
|
||||||
|
{% for page in pages %}
|
||||||
|
<a href="{% url 'article-detail' slug=page.slug %}">{{ page.title }}</a>
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
|
@ -23,19 +23,18 @@ class DraftsListView(generic.ListView, LoginRequiredMixin):
|
||||||
model = Article
|
model = Article
|
||||||
paginate_by = 15
|
paginate_by = 15
|
||||||
context_object_name = "articles"
|
context_object_name = "articles"
|
||||||
|
queryset = Article.with_pages.filter(status=Article.DRAFT)
|
||||||
|
|
||||||
def get_context_data(self, *, object_list=None, **kwargs):
|
def get_context_data(self, *, object_list=None, **kwargs):
|
||||||
context = super().get_context_data(object_list=object_list, **kwargs)
|
context = super().get_context_data(object_list=object_list, **kwargs)
|
||||||
context["title"] = "Drafts"
|
context["title"] = "Drafts"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return super().get_queryset().filter(status=Article.DRAFT)
|
|
||||||
|
|
||||||
|
|
||||||
class ArticleDetailView(generic.DetailView):
|
class ArticleDetailView(generic.DetailView):
|
||||||
model = Article
|
model = Article
|
||||||
context_object_name = "article"
|
context_object_name = "article"
|
||||||
|
queryset = Article.with_pages.all()
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
|
|
|
@ -71,6 +71,7 @@ TEMPLATES = [
|
||||||
"django.template.context_processors.request",
|
"django.template.context_processors.request",
|
||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"articles.context_processors.pages",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,10 +7,10 @@ def main():
|
||||||
writefreely_c = writefreely.cursor()
|
writefreely_c = writefreely.cursor()
|
||||||
db_c = db.cursor()
|
db_c = db.cursor()
|
||||||
writefreely_c.execute(
|
writefreely_c.execute(
|
||||||
"SELECT slug, created, updated, view_count, title, content FROM posts;"
|
"SELECT slug, created, updated, view_count, title, content, pinned_position FROM posts;"
|
||||||
)
|
)
|
||||||
for line in writefreely_c.fetchall():
|
for line in writefreely_c.fetchall():
|
||||||
db_c.execute(
|
ret = db_c.execute(
|
||||||
"INSERT INTO articles_article(title, content, status, published_at, created_at, updated_at, author_id, views_count, slug) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);",
|
"INSERT INTO articles_article(title, content, status, published_at, created_at, updated_at, author_id, views_count, slug) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);",
|
||||||
(
|
(
|
||||||
line[4],
|
line[4],
|
||||||
|
@ -24,6 +24,11 @@ def main():
|
||||||
line[0],
|
line[0],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
if line[6] is not None:
|
||||||
|
db_c.execute(
|
||||||
|
"INSERT INTO articles_page(article_ptr_id) VALUES (?);",
|
||||||
|
(ret.lastrowid,),
|
||||||
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue