Skip to content
Open

Blog #12

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,14 @@ dmypy.json

# vscode
.vscode/

# asset/media/static
asset/
media/
static/


# pytest cache
.pytest_cache/
htmlcov/
.coveragerc
15 changes: 15 additions & 0 deletions BaseDRF/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.db import models
from django.utils.translation import gettext_lazy as _


class TimestampModel(models.Model):
created_at = models.DateTimeField(
_("created at"),
auto_now_add=True
)
updated_at = models.DateTimeField(
_("updated at"),
auto_now=True
)
class Meta:
abstract = True
34 changes: 33 additions & 1 deletion BaseDRF/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
Expand All @@ -37,8 +38,15 @@
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"rest_framework_simplejwt",
"django_filters",
"user",
"mptt",
"blog",
"imagekit",
"ckeditor",
"ckeditor_uploader",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -120,6 +128,26 @@
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "asset")
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)

# Media
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"


REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
# 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}

IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND = "path.to.MyImageCacheBackend"

SITE_PROTOCOL = "http"

CKEDITOR_BASEPATH = "/static/ckeditor/ckeditor/"
CKEDITOR_UPLOAD_PATH = "uploads/"


AUTH_USER_MODEL = "user.User"
Expand All @@ -128,9 +156,13 @@
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
]
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
],
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

OTP_EXPIRE_TIME = 60

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

34 changes: 28 additions & 6 deletions BaseDRF/urls.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from rest_framework_simplejwt.views import (
TokenRefreshView,
)
from user.views import MyTokenObtainPairView

urlpatterns = [
path("admin/", admin.site.urls),
path("auth/", include("auth_user.urls")),
path("api/token/", MyTokenObtainPairView.as_view(), name="token_obtain_pair"),
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
]
from django.views.decorators.csrf import csrf_exempt
from blog.views import MyImageUploadView

from rest_framework import routers

router = routers.DefaultRouter()


urlpatterns = (
[
path("admin/", admin.site.urls),
path("auth/", include("auth_user.urls")),
path("blog/", include("blog.urls")),
path("api-auth/", include("rest_framework.urls")),
path("api/token/", MyTokenObtainPairView.as_view(), name="token_obtain_pair"),
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path(
"ckeditor/upload/",
csrf_exempt(MyImageUploadView.as_view()),
name="ckeditor_upload",
),
path("ckeditor/", include("ckeditor_uploader.urls")),
]
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
)
Empty file added blog/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions blog/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.contrib import admin
from .models import PostComment, Post, BlogCategory
from mptt.admin import MPTTModelAdmin


@admin.register(BlogCategory)
class BlogCategoryAdmin(MPTTModelAdmin):
mptt_level_indent = 20
list_display = ("id", "name", "parent")
list_display_link = "id"
list_editable = ("parent", "name")
sortable = "-id"


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = (
"id",
"title",
"author",
"is_published",
"category",
)
list_editable = ("title", "author", "is_published", "category")


@admin.register(PostComment)
class PostCommentAdmin(MPTTModelAdmin):
mptt_level_indent = 20
list_display = ("id", "author", "post", "is_published", "parent")
list_editable = ("author", "post", "is_published", "parent")
sortable = "-id"
5 changes: 5 additions & 0 deletions blog/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class BlogConfig(AppConfig):
name = 'blog'
45 changes: 45 additions & 0 deletions blog/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import django_filters
from .models import PostComment, Post, BlogCategory
from django_filters import rest_framework as filters


class PostFilter(filters.FilterSet):
category_name = django_filters.CharFilter(
lookup_expr="contains", field_name="category__name", label="category name"
)
author_username = django_filters.CharFilter(
lookup_expr="contains", field_name="author__username", label="author username"
)

class Meta:
model = Post
fields = [
"title",
"slug",
"author",
"author_username",
"category",
"category_name",
"is_published",
]


class PostCommentFilter(filters.FilterSet):
author_username = django_filters.CharFilter(
lookup_expr="contains", field_name="author__username", label="author username"
)
post_author = django_filters.CharFilter(
lookup_expr="contains", field_name="post__author", label="post author"
)
post_is_published = django_filters.BooleanFilter(
field_name="post__is_published", label="post is published"
)
post_category_name = django_filters.CharFilter(
lookup_expr="contains",
field_name="post__category__name",
label="post category name",
)

class Meta:
model = PostComment
fields = "__all__"
72 changes: 72 additions & 0 deletions blog/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Generated by Django 3.1 on 2021-10-15 13:15

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import mptt.fields
import tinymce.models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=500, unique=True)),
('lft', models.PositiveIntegerField(editable=False)),
('rght', models.PositiveIntegerField(editable=False)),
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
('level', models.PositiveIntegerField(editable=False)),
('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='blog.category')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Post',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='updated at')),
('title', models.CharField(max_length=1000, unique=True, verbose_name='title of post')),
('slug', models.SlugField(blank=True, max_length=1000, null=True, unique=True, verbose_name='slug of post')),
('image', models.ImageField(blank='True', null='True', upload_to='PostImages/', verbose_name='title image')),
('content', tinymce.models.HTMLField(blank=True, null=True, verbose_name='content of post, use one just h1 for header in content')),
('is_published', models.BooleanField(verbose_name='can publish post?')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author')),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='category of post')),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='PostComment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='updated at')),
('content', models.TextField(verbose_name='text of post')),
('is_published', models.BooleanField(default=True, verbose_name='can publish comment?')),
('lft', models.PositiveIntegerField(editable=False)),
('rght', models.PositiveIntegerField(editable=False)),
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
('level', models.PositiveIntegerField(editable=False)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author')),
('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='blog.postcomment')),
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.post', verbose_name='post')),
],
options={
'abstract': False,
},
),
]
17 changes: 17 additions & 0 deletions blog/migrations/0002_auto_20211112_1455.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.1 on 2021-11-12 14:55

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('blog', '0001_initial'),
]

operations = [
migrations.RenameModel(
old_name='Category',
new_name='BlogCategory',
),
]
19 changes: 19 additions & 0 deletions blog/migrations/0003_post_content_b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 3.1 on 2021-11-12 16:23

import ckeditor.fields
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('blog', '0002_auto_20211112_1455'),
]

operations = [
migrations.AddField(
model_name='post',
name='content_b',
field=ckeditor.fields.RichTextField(blank=True, null=True),
),
]
19 changes: 19 additions & 0 deletions blog/migrations/0004_auto_20211112_1625.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 3.1 on 2021-11-12 16:25

import ckeditor_uploader.fields
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('blog', '0003_post_content_b'),
]

operations = [
migrations.AlterField(
model_name='post',
name='content_b',
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True),
),
]
17 changes: 17 additions & 0 deletions blog/migrations/0005_remove_post_content_b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.1 on 2021-11-17 10:32

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('blog', '0004_auto_20211112_1625'),
]

operations = [
migrations.RemoveField(
model_name='post',
name='content_b',
),
]
19 changes: 19 additions & 0 deletions blog/migrations/0006_auto_20211117_1041.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 3.1 on 2021-11-17 10:41

import ckeditor_uploader.fields
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('blog', '0005_remove_post_content_b'),
]

operations = [
migrations.AlterField(
model_name='post',
name='content',
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='content of post, use one just h1 for header in content'),
),
]
Empty file added blog/migrations/__init__.py
Empty file.
Loading