blog model and view and url and route
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import *
|
||||||
|
from unfold.admin import ModelAdmin
|
||||||
|
|
||||||
|
from import_export.admin import ImportExportModelAdmin
|
||||||
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(BlogModel)
|
||||||
|
class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
|
import_form_class = ImportForm
|
||||||
|
export_form_class = ExportForm
|
||||||
|
|
||||||
|
|
||||||
|
compressed_fields = True
|
||||||
|
warn_unsaved_form = True
|
||||||
|
|
||||||
|
formfield_overrides = {
|
||||||
|
models.TextField: {
|
||||||
|
"widget": WysiwygWidget,
|
||||||
|
},
|
||||||
|
ArrayField: {
|
||||||
|
"widget": ArrayWidget,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class BlogConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'blog'
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-01-29 12:17
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0004_alter_subcategorymodel_parent'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BlogModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=200)),
|
||||||
|
('slug', models.SlugField(blank=True, max_length=200, unique=True)),
|
||||||
|
('content', models.TextField()),
|
||||||
|
('summery', models.TextField()),
|
||||||
|
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('is_published', models.BooleanField(default=False)),
|
||||||
|
('cover_image', models.ImageField(upload_to='blog_covers/')),
|
||||||
|
('views', models.PositiveIntegerField(default=0)),
|
||||||
|
('meta_description', models.CharField(help_text='این فیلد را حتما پر کنید', max_length=300)),
|
||||||
|
('meta_keywords', models.CharField(help_text='این فیلد را حتما پر کنید', max_length=300)),
|
||||||
|
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blogs', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blogs', to='product.subcategorymodel')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
from django.db import models
|
||||||
|
from account.models import User
|
||||||
|
from django.utils.text import slugify
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from product.models import SubCategoryModel
|
||||||
|
|
||||||
|
class BlogModel(models.Model):
|
||||||
|
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blogs')
|
||||||
|
title = models.CharField(max_length=200)
|
||||||
|
slug = models.SlugField(max_length=200, unique=True, blank=True)
|
||||||
|
content = models.TextField()
|
||||||
|
summery = models.TextField()
|
||||||
|
category = models.ForeignKey(SubCategoryModel, on_delete=models.SET_NULL, null=True, related_name='blogs')
|
||||||
|
created_at = models.DateTimeField(default=now, editable=False)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
is_published = models.BooleanField(default=False)
|
||||||
|
cover_image = models.ImageField(upload_to='blog_covers/', blank=True)
|
||||||
|
views = models.PositiveIntegerField(default=0)
|
||||||
|
meta_description = models.CharField(max_length=300, help_text='این فیلد را حتما پر کنید')
|
||||||
|
meta_keywords = models.CharField(max_length=300, help_text='این فیلد را حتما پر کنید')
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.slug:
|
||||||
|
self.slug = slugify(self.title)
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# class Comment(models.Model):
|
||||||
|
# blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name='comments')
|
||||||
|
# user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
# content = models.TextField()
|
||||||
|
# created_at = models.DateTimeField(default=now)
|
||||||
|
|
||||||
|
# def __str__(self):
|
||||||
|
# return f'Comment by {self.user} on {self.blog}'
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from .models import BlogModel
|
||||||
|
|
||||||
|
class BlogSerilizer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = BlogModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class AllBlogSerilizer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = BlogModel
|
||||||
|
fields = "__all__"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('all', views.AllBlogView.as_view(), name='product-chat-view'),
|
||||||
|
path('<int:pk>', views.BlogView.as_view(), name='product-chat-view'),
|
||||||
|
]
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from rest_framework.views import APIView, Response
|
||||||
|
from rest_framework import status
|
||||||
|
from .models import BlogModel
|
||||||
|
from .serializers import AllBlogSerilizer, BlogSerilizer
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from utils.pagination import StructurePagination
|
||||||
|
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AllBlogView(APIView):
|
||||||
|
authentication_classes = []
|
||||||
|
serializer_class = AllBlogSerilizer
|
||||||
|
pagination_class = StructurePagination
|
||||||
|
@extend_schema(
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(
|
||||||
|
name="limit",
|
||||||
|
description="لیمیتش",
|
||||||
|
required=False,
|
||||||
|
type=OpenApiTypes.INT,
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="offset",
|
||||||
|
description="افستش",
|
||||||
|
required=False,
|
||||||
|
type=OpenApiTypes.INT,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
responses={
|
||||||
|
200: AllBlogSerilizer(many=True),
|
||||||
|
404: OpenApiTypes.OBJECT,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def get(self, request):
|
||||||
|
blogs = BlogModel.objects.filter(is_published=True)
|
||||||
|
paginator = self.pagination_class()
|
||||||
|
paginated_blogs = paginator.paginate_queryset(blogs, request)
|
||||||
|
blog_ser = self.serializer_class(instance=paginated_blogs, many=True, context={'request': request})
|
||||||
|
return paginator.get_paginated_response(blog_ser.data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BlogView(APIView):
|
||||||
|
authentication_classes = []
|
||||||
|
serializer_class = BlogSerilizer
|
||||||
|
def get(self, request, pk):
|
||||||
|
blog = get_object_or_404(BlogModel, pk=pk)
|
||||||
|
if blog.is_published:
|
||||||
|
blog_ser = self.serializer_class(instance=blog, context={'request': request})
|
||||||
|
return Response(blog_ser.data, status=status.HTTP_200_OK)
|
||||||
|
else:
|
||||||
|
return Response({'detail': 'object with the given id does not exiest or its not published yet'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
@@ -111,6 +111,7 @@ INSTALLED_APPS = [
|
|||||||
'chat',
|
'chat',
|
||||||
'order',
|
'order',
|
||||||
'home',
|
'home',
|
||||||
|
'blog',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ urlpatterns = [
|
|||||||
path('accounts/', include('account.urls')),
|
path('accounts/', include('account.urls')),
|
||||||
path('chat/', include('chat.urls')),
|
path('chat/', include('chat.urls')),
|
||||||
path('tickets/', include('ticket.urls')),
|
path('tickets/', include('ticket.urls')),
|
||||||
|
path('blogs/', include('blog.urls')),
|
||||||
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user