diff --git a/backend/app/article/__init__.py b/backend/app/article/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/article/admin.py b/backend/app/article/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/backend/app/article/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/app/article/apps.py b/backend/app/article/apps.py new file mode 100644 index 0000000..8295b57 --- /dev/null +++ b/backend/app/article/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ArticleConfig(AppConfig): + name = 'article' diff --git a/backend/app/article/migrations/__init__.py b/backend/app/article/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/article/models.py b/backend/app/article/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/backend/app/article/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/backend/app/article/tests.py b/backend/app/article/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/backend/app/article/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/app/article/views.py b/backend/app/article/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/backend/app/article/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/backend/app/base/__init__.py b/backend/app/base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/base/admin.py b/backend/app/base/admin.py new file mode 100644 index 0000000..1bf5592 --- /dev/null +++ b/backend/app/base/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from .models import SiteInfo +# Register your models here. +admin.site.register(SiteInfo) \ No newline at end of file diff --git a/backend/app/base/apps.py b/backend/app/base/apps.py new file mode 100644 index 0000000..ef566bd --- /dev/null +++ b/backend/app/base/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class BaseConfig(AppConfig): + name = 'app.base' diff --git a/backend/app/base/filters.py b/backend/app/base/filters.py new file mode 100644 index 0000000..c0b5d71 --- /dev/null +++ b/backend/app/base/filters.py @@ -0,0 +1,13 @@ +import django_filters +from .models import SiteInfo + + +class SiteInfoFilter(django_filters.rest_framework.FilterSet): + """ + to check Website Live Status + """ + class Meta: + model = SiteInfo + fields = ['is_live'] + + diff --git a/backend/app/base/migrations/0001_initial.py b/backend/app/base/migrations/0001_initial.py new file mode 100644 index 0000000..29201aa --- /dev/null +++ b/backend/app/base/migrations/0001_initial.py @@ -0,0 +1,108 @@ +# Generated by Django 3.0.5 on 2020-04-18 18:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('root', '0002_auto_20200418_1841'), + ] + + operations = [ + migrations.CreateModel( + name='BloggerInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=20)), + ('desc', models.CharField(default='', max_length=300)), + ('avatar', models.ImageField(blank=True, null=True, upload_to='base/avatar/image/%y/%m')), + ('background', models.ImageField(blank=True, null=True, upload_to='base/background/image/%y/%m')), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='NavigationLink', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('desc', models.CharField(max_length=100)), + ('image', models.ImageField(blank=True, null=True, upload_to='base/friendlink/image/%y/%m')), + ('url', models.CharField(max_length=200)), + ('target', models.CharField(blank=True, choices=[('_blank', 'Next Page'), ('_self', 'in same Frame'), ('_parent', 'parent'), ('_top', 'top')], max_length=10, null=True)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='SiteInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=20)), + ('desc', models.CharField(default='', max_length=150)), + ('keywords', models.CharField(default='', max_length=300)), + ('icon', models.ImageField(blank=True, null=True, upload_to='base/site/image/%y/%m')), + ('background', models.ImageField(blank=True, null=True, upload_to='base/site/image/%y/%m')), + ('api_base_url', models.URLField(max_length=30)), + ('copyright', models.CharField(default='', max_length=100)), + ('copyright_desc', models.CharField(default='', max_length=300)), + ('icp', models.CharField(default='', max_length=20)), + ('is_live', models.BooleanField(default=False)), + ('is_force_refresh', models.BooleanField(default=False)), + ('force_refresh_time', models.DateTimeField(blank=True, null=True)), + ('access_password', models.CharField(blank=True, max_length=20, null=True)), + ('access_password_encrypt', models.CharField(blank=True, max_length=100, null=True)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='SiteInfoNavigation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=20)), + ('index', models.IntegerField(default=0)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('navigation', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='base.NavigationLink')), + ('site', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='base.SiteInfo')), + ], + ), + migrations.AddField( + model_name='siteinfo', + name='navigations', + field=models.ManyToManyField(through='base.SiteInfoNavigation', to='base.NavigationLink'), + ), + migrations.CreateModel( + name='BloggerSocial', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=20)), + ('index', models.IntegerField(default=0)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('blogger', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='base.BloggerInfo')), + ('social', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='root.Social')), + ], + ), + migrations.CreateModel( + name='BloggerMaster', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', max_length=20)), + ('index', models.IntegerField(default=0)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('blogger', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='base.BloggerInfo')), + ('master', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='root.Master')), + ], + ), + migrations.AddField( + model_name='bloggerinfo', + name='masters', + field=models.ManyToManyField(through='base.BloggerMaster', to='root.Master'), + ), + migrations.AddField( + model_name='bloggerinfo', + name='socials', + field=models.ManyToManyField(through='base.BloggerSocial', to='root.Social'), + ), + ] diff --git a/backend/app/base/migrations/__init__.py b/backend/app/base/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/base/models.py b/backend/app/base/models.py new file mode 100644 index 0000000..f988a86 --- /dev/null +++ b/backend/app/base/models.py @@ -0,0 +1,134 @@ +from django.db import models + +# Create your models here. +import hashlib +from django.db import models +from app.root.models import Social, Master + + +class NavigationLink(models.Model): + TARGET_TYPE = ( + ("_blank", "Next Page"), + ("_self","in same Frame"), + ("_parent", "parent"), + ("_top", "top") + ) + name = models.CharField(max_length=30) + desc = models.CharField(max_length=100) + image = models.ImageField(upload_to="base/friendlink/image/%y/%m", null=True, blank=True) + url = models.CharField(max_length=200,) + target = models.CharField(max_length=10, choices=TARGET_TYPE, null=True, blank=True) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(NavigationLink, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.name + + +class SiteInfo(models.Model): + + """ + Config For Website + """ + name = models.CharField(default="", max_length=20) + desc = models.CharField(default="", max_length=150) + keywords = models.CharField(default="", max_length=300) + icon = models.ImageField(upload_to="base/site/image/%y/%m", null=True, blank=True) + background = models.ImageField(upload_to="base/site/image/%y/%m", null=True, blank=True) + api_base_url = models.URLField(max_length=30, null=False, blank=False,) + navigations = models.ManyToManyField(NavigationLink, through="SiteInfoNavigation", through_fields=( + 'site', 'navigation')) + copyright = models.CharField(default="", max_length=100,) + copyright_desc = models.CharField(default="", max_length=300) + icp = models.CharField(default="", max_length=20) + is_live = models.BooleanField(default=False) + is_force_refresh = models.BooleanField(default=False) + force_refresh_time = models.DateTimeField(null=True, blank=True,) + access_password = models.CharField(max_length=20, null=True, blank=True) + access_password_encrypt = models.CharField(max_length=100, null=True, blank=True) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def __str__(self): + return self.name + + def save(self, *args, **kwargs): + if self.access_password: + md5 = hashlib.md5() + md5.update(self.access_password.encode('utf8')) + self.access_password_encrypt = md5.hexdigest() + else: + self.access_password_encrypt = '' + super(SiteInfo, self).save(*args, **kwargs) + + class Meta: + pass + + + +class BloggerInfo(models.Model): + name = models.CharField(default="", max_length=20) + desc = models.CharField(default="", max_length=300,) + avatar = models.ImageField(upload_to="base/avatar/image/%y/%m", null=True, blank=True,) + background = models.ImageField(upload_to="base/background/image/%y/%m", null=True, blank=True) + socials = models.ManyToManyField(Social, through='BloggerSocial', through_fields=('blogger', 'social')) + masters = models.ManyToManyField(Master, through='BloggerMaster', through_fields=('blogger', 'master')) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(BloggerInfo, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.name + + +class BloggerSocial(models.Model): + name = models.CharField(default="", max_length=20) + blogger = models.ForeignKey(BloggerInfo ,on_delete=models.DO_NOTHING) + social = models.ForeignKey(Social,on_delete=models.CASCADE) + index = models.IntegerField(default=0) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + class Meta: + pass + + def __str__(self): + return self.name + + +class BloggerMaster(models.Model): + name = models.CharField(default="", max_length=20) + blogger = models.ForeignKey(BloggerInfo,on_delete=models.DO_NOTHING) + master = models.ForeignKey(Master,on_delete=models.DO_NOTHING) + index = models.IntegerField(default=0) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + class Meta: + pass + + def __str__(self): + return self.name + + +class SiteInfoNavigation(models.Model): + name = models.CharField(default="", max_length=20) + site = models.ForeignKey(SiteInfo,on_delete=models.DO_NOTHING) + navigation = models.ForeignKey(NavigationLink,on_delete=models.DO_NOTHING) + index = models.IntegerField(default=0) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + class Meta: + pass + + def __str__(self): + return self.name + + + diff --git a/backend/app/base/serializer.py b/backend/app/base/serializer.py new file mode 100644 index 0000000..6e186c9 --- /dev/null +++ b/backend/app/base/serializer.py @@ -0,0 +1,50 @@ +from rest_framework import serializers +from .models import SiteInfo, BloggerInfo, NavigationLink +from app.root.serializer import MasterSerializer, SocialSerializer +from django.conf import settings + + +class NavigationLinkSerializer(serializers.ModelSerializer): + class Meta: + model = NavigationLink + fields = "__all__" + + +class SiteInfoSerializer(serializers.ModelSerializer): + navigations = NavigationLinkSerializer(many=True) + icon = serializers.SerializerMethodField() + background = serializers.SerializerMethodField() + + def get_icon(self, site_info): + if site_info.icon: + return "{0}/{1}".format(settings.MEDIA_URL_PREFIX, site_info.icon) + + def get_background(self, blogger_info): + if blogger_info.background: + return "{0}/{1}".format(settings.MEDIA_URL_PREFIX, blogger_info.background) + + class Meta: + model = SiteInfo + fields = ( + 'name', 'desc', 'keywords', 'icon', 'background', 'api_base_url', 'is_live', + 'is_force_refresh', 'force_refresh_time', 'navigations', 'copyright', 'copyright_desc', + 'icp') + + +class BloggerInfoSerializer(serializers.ModelSerializer): + socials = SocialSerializer(many=True) + masters = MasterSerializer(many=True) + avatar = serializers.SerializerMethodField() + background = serializers.SerializerMethodField() + + def get_avatar(self, blogger_info): + if blogger_info.avatar: + return "{0}/{1}".format(settings.MEDIA_URL_PREFIX, blogger_info.avatar) + + def get_background(self, blogger_info): + if blogger_info.background: + return "{0}/{1}".format(settings.MEDIA_URL_PREFIX, blogger_info.background) + + class Meta: + model = BloggerInfo + fields = "__all__" diff --git a/backend/app/base/tests.py b/backend/app/base/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/base/utils.py b/backend/app/base/utils.py new file mode 100644 index 0000000..eb98bfe --- /dev/null +++ b/backend/app/base/utils.py @@ -0,0 +1,19 @@ +from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination + + +class CustomePageNumberPagination(PageNumberPagination): + page_size = 10 + page_size_query_param = 'page_size' + page_query_param = 'page' + max_page_size = 100 + +class CustomeLimitOffsetPagination(LimitOffsetPagination): + default_limit = 50 + limit_query_param = 'limit' + offset_query_param = 'offset' + max_limit = 100 + min_limit = 1 + min_offset = 0 + + +ALLOWED_PROTOCOLS = ['http', 'https', 'mailto'] \ No newline at end of file diff --git a/backend/app/base/views.py b/backend/app/base/views.py new file mode 100644 index 0000000..c8065e0 --- /dev/null +++ b/backend/app/base/views.py @@ -0,0 +1,31 @@ +from django.shortcuts import render + +# Create your views here. +# _*_ coding: utf-8 _*_ + + +from rest_framework import viewsets, filters +from django_filters.rest_framework import DjangoFilterBackend + +from .models import SiteInfo, BloggerInfo +from .serializer import BloggerInfoSerializer, SiteInfoSerializer +from .filters import SiteInfoFilter + + +class SiteInfoViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + """ + queryset = SiteInfo.objects.all() + serializer_class = SiteInfoSerializer + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + filter_class = SiteInfoFilter +# + +class BloggerInfoViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + """ + queryset = BloggerInfo.objects.all() + serializer_class = BloggerInfoSerializer + diff --git a/backend/app/root/admin.py b/backend/app/root/admin.py index 8c38f3f..95c5bbe 100644 --- a/backend/app/root/admin.py +++ b/backend/app/root/admin.py @@ -1,3 +1,18 @@ from django.contrib import admin # Register your models here. + +from .models import Category, Tag, License, PostBaseInfo, Banner, \ + Camera, Picture, Social, Master, PostTag + +# admin.site.r +admin.site.register(Category) +admin.site.register(Tag) +admin.site.register(License) +admin.site.register(PostBaseInfo) +admin.site.register(Banner) +admin.site.register(Camera) +admin.site.register(Picture) +admin.site.register(Social) +admin.site.register(Master) +admin.site.register(PostTag) diff --git a/backend/app/root/apps.py b/backend/app/root/apps.py index 4ff1019..9a92220 100644 --- a/backend/app/root/apps.py +++ b/backend/app/root/apps.py @@ -2,4 +2,5 @@ class RootConfig(AppConfig): - name = 'root' + name = 'app.root' + verbose_name = "Root App" \ No newline at end of file diff --git a/backend/app/root/filters.py b/backend/app/root/filters.py new file mode 100644 index 0000000..b345294 --- /dev/null +++ b/backend/app/root/filters.py @@ -0,0 +1,57 @@ +from django.db.models import Q +import django_filters +from .models import Category, Banner, PostBaseInfo + + +class CategoryFilter(django_filters.rest_framework.FilterSet): + """ + Category Filter + """ + level_min = django_filters.NumberFilter(field_name='category_level', lookup_expr='gte') + level_max = django_filters.NumberFilter(field_name='category_level', lookup_expr='lte') + + top_category = django_filters.NumberFilter(method='top_category_filter') + + def top_category_filter(self, queryset, name, value): + return queryset.filter(Q(id=value) | Q(parent_category_id=value) | Q( + parent_category__parent_category_id=value)) + + class Meta: + model = Category + fields = ['id', 'level_min', 'level_max', 'is_tab'] + + +class BannerFilter(django_filters.rest_framework.FilterSet): + """ + Banner Filter + """ + level_min = django_filters.NumberFilter(field_name='category_level', lookup_expr='gte') + level_max = django_filters.NumberFilter(field_name='category_level', lookup_expr='lte') + + top_category = django_filters.NumberFilter(method='top_category_filter') + + def top_category_filter(self, queryset, name, value): + return queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q( + category__parent_category__parent_category_id=value)) + + class Meta: + model = Banner + fields = ['title', 'url', 'index'] + + +class PostBaseInfoFilter(django_filters.rest_framework.FilterSet): + """ + Base Post Currently filtering on Time Created + """ + time_min = django_filters.DateFilter(field_name='add_time', lookup_expr='gte') + time_max = django_filters.DateFilter(field_name='add_time', lookup_expr='lte') + + top_category = django_filters.NumberFilter(method='top_category_filter') + + def top_category_filter(self, queryset, name, value): + return queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q( + category__parent_category__parent_category_id=value)) + + class Meta: + model = PostBaseInfo + fields = ['time_min', 'time_max', 'is_hot', 'is_recommend', 'post_type'] diff --git a/backend/app/root/migrations/0001_initial.py b/backend/app/root/migrations/0001_initial.py new file mode 100644 index 0000000..463ef05 --- /dev/null +++ b/backend/app/root/migrations/0001_initial.py @@ -0,0 +1,158 @@ +# Generated by Django 3.0.5 on 2020-04-18 17:30 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Camera', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('device', models.CharField(max_length=30)), + ('version', models.CharField(max_length=200)), + ('environment', models.CharField(max_length=200)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(default='', help_text='Root Category Name', max_length=30, verbose_name='Category Name')), + ('category_type', models.CharField(choices=[('articles', 'Articles'), ('articles/category', 'Article Classification')], help_text='Used to configure route ', max_length=30, verbose_name='Category Type ')), + ('desc', models.TextField(blank=True, help_text='category description', null=True, verbose_name='decription')), + ('image', models.ImageField(blank=True, help_text='图片', null=True, upload_to='comment/category/image/%Y/%m')), + ('category_level', models.CharField(choices=[('1', 'level1'), ('2', 'level2'), ('3', 'level3')], help_text='level', max_length=20, verbose_name='类目级别')), + ('is_active', models.BooleanField(default=True, help_text='Active', verbose_name='Active Status')), + ('is_tab', models.BooleanField(default=True, help_text='Tab', verbose_name='Tab Status')), + ('index', models.IntegerField(default=0, help_text='.', verbose_name='indexing')), + ('add_time', models.DateTimeField(auto_now_add=True, help_text='When was added', verbose_name='Add Time')), + ('parent_category', models.ForeignKey(blank=True, help_text='parent category', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sub_category', to='root.Category', verbose_name='parent')), + ], + options={ + 'verbose_name': 'Classfication', + 'verbose_name_plural': 'Classficationlist', + }, + ), + migrations.CreateModel( + name='License', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('en_name', models.CharField(blank=True, max_length=30, null=True)), + ('desc', models.CharField(blank=True, max_length=255, null=True)), + ('en_desc', models.CharField(blank=True, max_length=255, null=True)), + ('link', models.URLField(blank=True, null=True)), + ('color', models.CharField(choices=[('#878D99', '灰色'), ('#409EFF', '蓝色'), ('#67C23A', '绿色'), ('#EB9E05', '黄色'), ('#FA5555', '红色')], default='blue', max_length=20)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='Master', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('desc', models.CharField(blank=True, max_length=100, null=True)), + ('image', models.ImageField(blank=True, null=True, upload_to='comment/master/image/%y/%m')), + ('url', models.URLField()), + ('experience', models.FloatField(default=0)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='PostBaseInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100)), + ('desc', models.CharField(blank=True, max_length=255, null=True)), + ('author', models.CharField(blank=True, max_length=20, null=True)), + ('post_type', models.CharField(blank=True, choices=[('article', 'article')], max_length=20, null=True)), + ('click_num', models.IntegerField(default=0)), + ('like_num', models.IntegerField(default=0)), + ('comment_num', models.IntegerField(default=0)), + ('front_image', models.ImageField(blank=True, null=True, upload_to='post/image/%y/%m')), + ('front_image_type', models.CharField(choices=[('0', 'small'), ('1', 'medium'), ('2', 'collection')], default='0', max_length=20)), + ('is_hot', models.BooleanField(default=False)), + ('is_recommend', models.BooleanField(default=False)), + ('is_banner', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('is_commentable', models.BooleanField(default=True)), + ('browse_password', models.CharField(blank=True, max_length=20, null=True)), + ('browse_password_encrypt', models.CharField(blank=True, max_length=100, null=True)), + ('index', models.IntegerField(default=0)), + ('add_time', models.DateTimeField(blank=True, null=True)), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='root.Category')), + ('license', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='root.License')), + ], + ), + migrations.CreateModel( + name='Social', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('desc', models.CharField(max_length=100)), + ('image', models.ImageField(blank=True, null=True, upload_to='comment/social/image/%y/%m')), + ('url', models.URLField()), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ], + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('description', models.TextField(max_length=30)), + ('color', models.CharField(default='blue', max_length=20)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='root.Category')), + ], + ), + migrations.CreateModel( + name='PostTag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='root.PostBaseInfo')), + ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='root.Tag')), + ], + ), + migrations.AddField( + model_name='postbaseinfo', + name='tags', + field=models.ManyToManyField(through='root.PostTag', to='root.Tag'), + ), + migrations.CreateModel( + name='Picture', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100)), + ('en_title', models.CharField(blank=True, max_length=100, null=True)), + ('desc', models.CharField(blank=True, max_length=255, null=True)), + ('en_desc', models.CharField(blank=True, max_length=255, null=True)), + ('image', models.ImageField(blank=True, null=True, upload_to='comment/picture/image/%Y/%m')), + ('link', models.URLField(blank=True, null=True)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('camera', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='root.Camera')), + ], + ), + migrations.CreateModel( + name='Banner', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100)), + ('image', models.ImageField(blank=True, null=True, upload_to='comment/banner/image/%y/%m')), + ('url', models.URLField()), + ('index', models.IntegerField(default=0)), + ('add_time', models.DateTimeField(auto_now_add=True, null=True)), + ('category', models.ForeignKey(default='1', on_delete=django.db.models.deletion.CASCADE, to='root.Category')), + ], + ), + ] diff --git a/backend/app/root/migrations/0002_auto_20200418_1841.py b/backend/app/root/migrations/0002_auto_20200418_1841.py new file mode 100644 index 0000000..ac6d520 --- /dev/null +++ b/backend/app/root/migrations/0002_auto_20200418_1841.py @@ -0,0 +1,34 @@ +# Generated by Django 3.0.5 on 2020-04-18 18:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('root', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='license', + name='en_desc', + ), + migrations.RemoveField( + model_name='license', + name='en_name', + ), + migrations.RemoveField( + model_name='picture', + name='en_desc', + ), + migrations.RemoveField( + model_name='picture', + name='en_title', + ), + migrations.AlterField( + model_name='category', + name='category_level', + field=models.CharField(choices=[('1', 'level1'), ('2', 'level2'), ('3', 'level3')], help_text='level', max_length=20), + ), + ] diff --git a/backend/app/root/models.py b/backend/app/root/models.py index 71a8362..ba06b1a 100644 --- a/backend/app/root/models.py +++ b/backend/app/root/models.py @@ -1,3 +1,286 @@ +import hashlib + from django.db import models +from django.conf import settings + +__author__ = 'Akash Singh' +__date__ = '2020-APR-18' + +CATEGORY_LEVEL = ( + ("1", "level1"), + ("2", "level2"), + ("3", "level3") +) +CATEGORY_TYPE = ( + ("articles", "Articles"), + ("articles/category", "Article Classification"), +) + + +class Category(models.Model): + """ + Model for Category Of Blog App + + FIELD OPTIONS DESCRIPTION + Null If True, Django will store empty values as NULL in the database. Default is False. + Blank If True, the field is allowed to be blank. Default is False. + db_column The name of the database column to use for this field. If this isn’t given, Django will use the field’s name. + Default The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created. + help_text Extra “help” text to be displayed with the form widget. It’s useful for documentation even if your field isn’t used on a form. + primary_key If True, this field is the primary key for the model. + editable If False, the field will not be displayed in the admin or any other ModelForm. They are also skipped during model validation. Default is True. + error_messages The error_messages argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override. + help_text Extra “help” text to be displayed with the form widget. It’s useful for documentation even if your field isn’t used on a form. + verbose_name A human-readable name for the field. If the verbose name isn’t given, Django will automatically create it using the field’s attribute name, converting underscores to spaces. + validators A list of validators to run for this field. See the validators documentation for more information. + Unique If True, this field must be unique throughout the table. + + """ + CATEGORY_LEVEL = ( + ("1", "level1"), + ("2", "level2"), + ("3", "level3") + ) + CATEGORY_TYPE = ( + ("articles", "Articles"), + ("articles/category", "Article Classification"), + ) + name = models.CharField(max_length=30, default="", verbose_name="Category Name", help_text="Root Category Name") + category_type = models.CharField(max_length=30, choices=CATEGORY_TYPE, verbose_name="Category Type ",help_text="Used to configure route ") + desc = models.TextField(null=True, blank=True, verbose_name="decription", help_text="category description") + image = models.ImageField(upload_to="comment/category/image/%Y/%m", null=True, blank=True, help_text="图片") + category_level = models.CharField(max_length=20, choices=CATEGORY_LEVEL, help_text="level") + parent_category = models.ForeignKey("self", null=True, blank=True, verbose_name="parent", help_text="parent category",related_name="sub_category", on_delete=models.CASCADE) + + is_active = models.BooleanField(default=True, verbose_name="Active Status", help_text="Active") + is_tab = models.BooleanField(default=True, verbose_name="Tab Status", help_text="Tab") + index = models.IntegerField(default=0, verbose_name="indexing", help_text=".") + add_time = models.DateTimeField(auto_now_add=True, verbose_name="Add Time", help_text="When was added") + + class Meta: + verbose_name = "Classfication" + verbose_name_plural = verbose_name + 'list' + + def save(self, *args, **kwargs): + super(Category,self).save(*args, **kwargs) + + def __str__(self): + return '{0} - {1} - {2}'.format(self.name, self.get_category_type_display(), self.get_category_level_display()) + + +class Tag(models.Model): + """ + Tag That Category Post COmprises of + """ + name = models.CharField(max_length=30, null=False, blank=False, ) + description = models.TextField(max_length=30) + category = models.ForeignKey(Category, null=True, blank=True,on_delete=models.CASCADE) + color = models.CharField(max_length=20, default="blue", ) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + if not self.description: + self.description = self.name + super(Tag, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.name + + +class License(models.Model): + """ + Lisence + """ + COLOR_TYPE = ( + ("#878D99", "灰色"), + ("#409EFF", "蓝色"), + ("#67C23A", "绿色"), + ("#EB9E05", "黄色"), + ("#FA5555", "红色") + ) + name = models.CharField(max_length=30, null=False, blank=False, ) + desc = models.CharField(max_length=255, null=True, blank=True,) + link = models.URLField(null=True, blank=True, ) + color = models.CharField(max_length=20, default="blue", choices=COLOR_TYPE) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(License, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.name + + +class Camera(models.Model): + """ + Camera + """ + device = models.CharField(max_length=30 ) + version = models.CharField(max_length=200 ) + environment = models.CharField(max_length=200 ) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + class Meta: + pass + + def __str__(self): + return self.device + + +class Picture(models.Model): + """ + Picture + """ + title = models.CharField(max_length=100, null=False, blank=False, ) + desc = models.CharField(max_length=255, null=True, blank=True, ) + image = models.ImageField(upload_to="comment/picture/image/%Y/%m", null=True, blank=True) + camera = models.ForeignKey(Camera, null=True, blank=True,on_delete=models.CASCADE) + link = models.URLField(null=True, blank=True,) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(Picture, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.title + + +class PostBaseInfo(models.Model): + """ + Post + """ + POST_TYPE = ( + ("article", "article"), + ) + FRONT_IMAGE_TYPE = ( + ("0", "small"), + ("1", 'medium'), + ("2", "collection") + ) + title = models.CharField(max_length=100, null=False, blank=False) + desc = models.CharField(max_length=255, null=True, blank=True) + author = models.CharField(max_length=20, null=True, blank=True) + category = models.ForeignKey(Category, null=False, blank=False,on_delete=models.DO_NOTHING ) + tags = models.ManyToManyField(Tag, through="PostTag", through_fields=('post', 'tag')) + post_type = models.CharField(max_length=20, choices=POST_TYPE, null=True, blank=True) + click_num = models.IntegerField(default=0) + like_num = models.IntegerField(default=0 ) + comment_num = models.IntegerField(default=0 ) + front_image = models.ImageField(upload_to="post/image/%y/%m", null=True, blank=True) + front_image_type = models.CharField(max_length=20, default="0", choices=FRONT_IMAGE_TYPE) + license = models.ForeignKey(License, null=True, blank=True,on_delete=models.CASCADE) + is_hot = models.BooleanField(default=False) + is_recommend = models.BooleanField(default=False ) + is_banner = models.BooleanField(default=False) + is_active = models.BooleanField(default=True) + is_commentable = models.BooleanField(default=True) + browse_password = models.CharField(max_length=20, null=True, blank=True) + browse_password_encrypt = models.CharField(max_length=100, null=True, blank=True) + index = models.IntegerField(default=0) + add_time = models.DateTimeField(null=True, blank=True) + + def save(self, *args, **kwargs): + + if self.browse_password and len(self.browse_password) > 0: + md5 = hashlib.md5() + md5.update(self.browse_password.encode('utf8')) + self.browse_password_encrypt = md5.hexdigest() + else: + self.browse_password_encrypt = None + super(PostBaseInfo, self).save(*args, **kwargs) + + # Will Make It Get From Enviroment + def get_absolute_url(self): + return '{0}/{1}/{2}'.format(settings.SITE_BASE_URL, self.post_type, self.id) + + class Meta: + pass + + def __str__(self): + return self.title + + +class PostTag(models.Model): + """ + Post tags + """ + post = models.ForeignKey(PostBaseInfo, null=False, blank=False,on_delete=models.CASCADE) + tag = models.ForeignKey(Tag, null=False, blank=False,on_delete=models.CASCADE) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + class Meta: + pass + + def __str__(self): + return self.tag.name + + +class Banner(models.Model): + """ + Banner for The Blog Special + """ + title = models.CharField(max_length=100) + image = models.ImageField(upload_to="comment/banner/image/%y/%m", null=True, blank=True, ) + url = models.URLField(max_length=200,) + category = models.ForeignKey(Category, default='1', null=False, blank=False,on_delete=models.CASCADE) + index = models.IntegerField(default=0, ) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(Banner, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.title + + +class Social(models.Model): + """ + Social Media Handle of Blogyy + """ + name = models.CharField(max_length=30, ) + desc = models.CharField(max_length=100, ) + image = models.ImageField(upload_to="comment/social/image/%y/%m", null=True, blank=True) + url = models.URLField(max_length=200) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(Social, self).save(*args, **kwargs) + + class Meta: + pass + + def __str__(self): + return self.name + + +class Master(models.Model): + """¡ + Main Model + """ + name = models.CharField(max_length=30) + desc = models.CharField(max_length=100, null=True, blank=True, ) + image = models.ImageField(upload_to="comment/master/image/%y/%m", null=True, blank=True) + url = models.URLField(max_length=200 ) + experience = models.FloatField(default=0) + add_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) + + def save(self, *args, **kwargs): + super(Master, self).save(*args, **kwargs) + + class Meta: + pass -# Create your models here. + def __str__(self): + return self.name diff --git a/backend/app/root/serializer.py b/backend/app/root/serializer.py new file mode 100644 index 0000000..5abaea1 --- /dev/null +++ b/backend/app/root/serializer.py @@ -0,0 +1,137 @@ +from rest_framework import serializers + +from .models import Category, Tag, License, PostBaseInfo, Banner, \ + Camera, Picture, Social, Master, PostTag + +from blogyy.settings import MEDIA_URL_PREFIX + + +class OrderCategoryListSerializer(serializers.ListSerializer): + + def to_representation(self, data): + data = data.filter(is_active=True).order_by('index') + return super(OrderCategoryListSerializer, self).to_representation(data) + + +class CategorySerializer3(serializers.ModelSerializer): + + class Meta: + list_serializer_class = OrderCategoryListSerializer + model = Category + fields = "__all__" + + +class CategorySerializer2(serializers.ModelSerializer): + sub_category = CategorySerializer3(many=True) + + class Meta: + list_serializer_class = OrderCategoryListSerializer + model = Category + fields = "__all__" + + +class CategorySerializer(serializers.ModelSerializer): + sub_category = CategorySerializer2(many=True) + + class Meta: + model = Category + fields = "__all__" + + +class SingleLevelCategorySerializer(serializers.ModelSerializer): + + class Meta: + model = Category + fields = "__all__" + + +class TagSerializer(serializers.ModelSerializer): + related_post_num = serializers.SerializerMethodField() + + def get_related_post_num(self, tag): + return len(PostTag.objects.filter(tag__id=tag.id)) + + class Meta: + model = Tag + fields = ('name', 'color', 'related_post_num') + + +class LicenseSerializer(serializers.ModelSerializer): + + class Meta: + model = License + fields = "__all__" + + +class CameraSerializer(serializers.ModelSerializer): + + class Meta: + model = Camera + fields = "__all__" + + +class PictureSerializer(serializers.ModelSerializer): + camera = CameraSerializer() + + class Meta: + model = Picture + fields = "__all__" + + +class PostBaseInfoSerializer(serializers.ModelSerializer): + tags = TagSerializer(many=True) + front_image = serializers.SerializerMethodField() + need_auth = serializers.SerializerMethodField() + + def get_front_image(self, article): + if article.front_image: + return "{0}/{1}".format(MEDIA_URL_PREFIX, article.front_image) + + def get_need_auth(self, article): + if article.browse_password_encrypt: + return True + else: + return False + + class Meta: + model = PostBaseInfo + fields = ( + 'id', 'title', 'desc', 'tags', 'like_num', 'comment_num', 'click_num', 'front_image', 'front_image_type', + 'is_hot', + 'is_recommend', 'is_banner', 'is_commentable', + 'post_type', 'need_auth', 'add_time') + + +class BannerSerializer(serializers.ModelSerializer): + + class Meta: + model = Banner + fields = "__all__" + + +class SocialSerializer(serializers.ModelSerializer): + image = serializers.SerializerMethodField() + + def get_image(self, social): + if social.image: + return "{0}/{1}".format(MEDIA_URL_PREFIX, social.image) + + class Meta: + model = Social + fields = ('id', 'name', 'image', 'url', 'desc') + + +class MasterSerializer(serializers.ModelSerializer): + + class Meta: + model = Master + fields = "__all__" + + +class PostLikeSerializer(serializers.Serializer): + post_id = serializers.IntegerField(required=True, label='post') + + +class VerifyPostAuthSerializer(serializers.Serializer): + post_id = serializers.CharField(max_length=11, min_length=1, required=True, label='postid') + browse_auth = serializers.CharField(max_length=64, min_length=6, required=True, label='brouseauth') diff --git a/backend/app/root/views.py b/backend/app/root/views.py index 91ea44a..bcb349c 100644 --- a/backend/app/root/views.py +++ b/backend/app/root/views.py @@ -1,3 +1,155 @@ -from django.shortcuts import render +from rest_framework import mixins, status +from rest_framework.response import Response -# Create your views here. +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework import viewsets, filters + +from .models import Category, Tag, Banner, PostBaseInfo +from .serializer import CategorySerializer, SingleLevelCategorySerializer, TagSerializer, BannerSerializer, PostBaseInfoSerializer, PostLikeSerializer, VerifyPostAuthSerializer +from .filters import CategoryFilter, BannerFilter, PostBaseInfoFilter +from app.base.utils import CustomeLimitOffsetPagination, CustomePageNumberPagination + + +class CategoryListViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + Category + """ + queryset = Category.objects.filter(is_active=True) + pagination_class = CustomePageNumberPagination + serializer_class = CategorySerializer + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + filter_class = CategoryFilter + search_fields = ('name', 'category_type', 'desc') + ordering_fields = ('category_level', 'index') + ordering = ('index',) + + +class SingleLevelCategoryListViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + One Level Category + """ + queryset = Category.objects.filter(is_active=True) + pagination_class = CustomePageNumberPagination + serializer_class = SingleLevelCategorySerializer + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + filter_class = CategoryFilter + search_fields = ('name', 'category_type', 'desc') + ordering_fields = ('category_level', 'index') + ordering = ('index',) + + +class TagListViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + Tag List + """ + queryset = Tag.objects.all() + serializer_class = TagSerializer + search_fields = ('name', 'subname') + ordering_fields = ('name', 'subname') + + +class BannerListViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + Banner list + """ + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + filter_class = BannerFilter + queryset = Banner.objects.all().order_by("-index") + serializer_class = BannerSerializer + + +class PostBaseInfoListViewset(viewsets.ReadOnlyModelViewSet): + """ + List: + Post Base Info + """ + queryset = PostBaseInfo.objects.filter(is_active=True) + pagination_class = CustomeLimitOffsetPagination + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + filter_class = PostBaseInfoFilter + search_fields = ('title', 'subtitle', 'abstract', 'desc') + ordering_fields = ('id', 'click_num', 'like_num', 'comment_num', 'add_time') + serializer_class = PostBaseInfoSerializer + + +class PostLikeViewset(mixins.CreateModelMixin, viewsets.GenericViewSet): + """ + PostLike + """ + serializer_class = PostLikeSerializer + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) # status 400 + + post_id = serializer.validated_data["post_id"] + + post = PostBaseInfo.objects.filter(id=post_id)[0] + + if post is not None: + post.like_num += 1 + post.save() + context = { + "post": post_id + } + return Response(context, status.HTTP_201_CREATED) + else: + context = { + "error": '500 Something Went Wrong' + } + return Response(context, status=status.HTTP_400_BAD_REQUEST) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + +class VerifyPostAuthViewset(mixins.CreateModelMixin, viewsets.GenericViewSet): + """ + Verify Post Auth + """ + serializer_class = VerifyPostAuthSerializer + + def create(self, request, *args, **kwargs): + """ + """ + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) # status 400 + + post_id = serializer.validated_data['post_id'] + browse_auth = serializer.validated_data['browse_auth'] + + if post_id is None: + context = { + "error": 'No Post Id' + } + return Response(context, status=status.HTTP_400_BAD_REQUEST) + + if browse_auth is None: + context = { + "error": 'Auth Failed' + } + return Response(context, status=status.HTTP_400_BAD_REQUEST) + + posts = PostBaseInfo.objects.filter(id=post_id) + + if len(posts): + if posts[0].browse_password_encrypt == browse_auth: + context = { + 'post_id': posts[0].id + } + return Response(context, status.HTTP_202_ACCEPTED) + else: + context = { + 'error': 'Invalid' + } + return Response(context, status=status.HTTP_403_FORBIDDEN) + else: + context = { + 'error': 'No Post', + 'post_id': post_id + } + return Response(context, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/backend/base/site/image/20/04/e42b779c-0777-4ac6-8a4f-5fb0eeac2a79.png b/backend/base/site/image/20/04/e42b779c-0777-4ac6-8a4f-5fb0eeac2a79.png new file mode 100644 index 0000000..ea189d6 Binary files /dev/null and b/backend/base/site/image/20/04/e42b779c-0777-4ac6-8a4f-5fb0eeac2a79.png differ diff --git a/backend/base/site/image/20/04/profile.jpeg b/backend/base/site/image/20/04/profile.jpeg new file mode 100644 index 0000000..57b6a92 Binary files /dev/null and b/backend/base/site/image/20/04/profile.jpeg differ diff --git a/backend/blogyy/settings.py b/backend/blogyy/settings.py index b447147..d569cca 100644 --- a/backend/blogyy/settings.py +++ b/backend/blogyy/settings.py @@ -39,6 +39,19 @@ 'django.contrib.staticfiles', ] +PERSONAL_APPS = [ + + 'app.root.apps.RootConfig', + 'app.base.apps.BaseConfig', +] +EXTRA_APPS = [ + +'rest_framework', + 'django_filters', +'rest_framework_swagger' +] +INSTALLED_APPS += PERSONAL_APPS +EXTRA_APPS + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -67,6 +80,25 @@ }, ] +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + ), + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework.renderers.JSONRenderer', + 'rest_framework.renderers.BrowsableAPIRenderer', + ), + 'DEFAULT_THROTTLE_CLASSES': ( + 'rest_framework.throttling.AnonRateThrottle', + 'rest_framework.throttling.UserRateThrottle' + ), + 'DEFAULT_THROTTLE_RATES': { + 'anon': '100000/day', + 'user': '100000/day' + }, + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', + 'UPLOADED_FILES_USE_URL': False +} + WSGI_APPLICATION = 'blogyy.wsgi.application' @@ -113,8 +145,11 @@ USE_TZ = True +SITE_BASE_URL ='http://127.0.0.1:8000/ç' + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ STATIC_URL = '/static/' +MEDIA_URL_PREFIX = '/static/' diff --git a/backend/blogyy/urls.py b/backend/blogyy/urls.py index 22eac97..1b0ebfe 100644 --- a/backend/blogyy/urls.py +++ b/backend/blogyy/urls.py @@ -13,9 +13,38 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.conf.urls import url from django.contrib import admin -from django.urls import path +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from rest_framework.authtoken import views +from rest_framework_swagger.views import get_swagger_view + +from app.base.views import SiteInfoViewset, BloggerInfoViewset +from app.root.views import CategoryListViewset, SingleLevelCategoryListViewset, TagListViewset, \ + BannerListViewset, PostBaseInfoListViewset, PostLikeViewset, VerifyPostAuthViewset + +router = DefaultRouter() + +# basename is available form drf version 3 + + +router.register(r'categorys', CategoryListViewset, basename='categorys') +router.register(r'category', SingleLevelCategoryListViewset, basename='category') +router.register(r'tags', TagListViewset, basename='tags') +router.register(r'banners', BannerListViewset, basename='banners') +router.register(r'siteInfo', SiteInfoViewset, basename="siteInfo") +router.register(r'blogger', BloggerInfoViewset, basename="blogger") +router.register(r'postBaseInfos', PostBaseInfoListViewset, basename="postBaseInfos") +router.register(r'verifyPostAuth', VerifyPostAuthViewset, basename="verifyPostAuth") +router.register(r'likePost', PostLikeViewset, basename="likePost") + + + +schema_view = get_swagger_view(title='Bloggy API') urlpatterns = [ + url(r'^$', schema_view), path('admin/', admin.site.urls), + url(r'^api/', include(router.urls)), ] diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index e69de29..60590c2 100644 Binary files a/backend/db.sqlite3 and b/backend/db.sqlite3 differ diff --git a/backend/requirement.txt b/backend/requirement.txt index 0788226..e708d02 100644 --- a/backend/requirement.txt +++ b/backend/requirement.txt @@ -1,5 +1,21 @@ asgiref==3.2.7 +certifi==2020.4.5.1 +chardet==3.0.4 +coreapi==2.3.3 +coreschema==0.0.4 Django==3.0.5 +django-filter==2.2.0 +django-rest-swagger==2.2.0 djangorestframework==3.11.0 +idna==2.9 +itypes==1.1.0 +Jinja2==2.11.2 +MarkupSafe==1.1.1 +openapi-codec==1.3.2 +Pillow==7.1.1 pytz==2019.3 +requests==2.23.0 +simplejson==3.17.0 sqlparse==0.3.1 +uritemplate==3.0.1 +urllib3==1.25.9