diff --git a/.travis.yml b/.travis.yml index 3f06c6e..c6c191d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,6 @@ services: env: global: - DJANGO_SETTINGS_MODULE="travis_test.travis_settings" - matrix: - - DJANGO="Django==1.8" - - DJANGO="Django==1.9" - - DJANGO="Django==1.10" - - DJANGO="Django==1.11" branches: only: - master diff --git a/DjangoBlog/settings.py b/DjangoBlog/settings.py index 1b55ec1..26cc311 100644 --- a/DjangoBlog/settings.py +++ b/DjangoBlog/settings.py @@ -49,7 +49,7 @@ INSTALLED_APPS = [ 'compressor' ] -MIDDLEWARE_CLASSES = [ +MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.gzip.GZipMiddleware', diff --git a/DjangoBlog/sitemap.py b/DjangoBlog/sitemap.py index 18e11ed..72fcd04 100644 --- a/DjangoBlog/sitemap.py +++ b/DjangoBlog/sitemap.py @@ -17,7 +17,7 @@ from django.contrib.sitemaps import Sitemap from blog.models import Article, Category, Tag from accounts.models import BlogUser from django.contrib.sitemaps import GenericSitemap -from django.core.urlresolvers import reverse +from django.urls import reverse class StaticViewSitemap(Sitemap): diff --git a/DjangoBlog/tests.py b/DjangoBlog/tests.py index d95b8bf..fcde227 100644 --- a/DjangoBlog/tests.py +++ b/DjangoBlog/tests.py @@ -17,7 +17,7 @@ from django.test import Client, RequestFactory, TestCase from blog.models import Article, Category, Tag from django.contrib.auth import get_user_model from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse +from django.urls import reverse import datetime from DjangoBlog.utils import * diff --git a/DjangoBlog/urls.py b/DjangoBlog/urls.py index 8ed7d7f..eaca1b6 100644 --- a/DjangoBlog/urls.py +++ b/DjangoBlog/urls.py @@ -36,14 +36,14 @@ handler500 = 'blog.views.server_error_view' urlpatterns = [ url(r'^admin/', admin.site.urls), - url(r'', include('blog.urls', namespace='blog', app_name='blog')), + url(r'', include('blog.urls', namespace='blog')), - url(r'', include('comments.urls', namespace='comment', app_name='comments')), - url(r'', include('accounts.urls', namespace='account', app_name='accounts')), - url(r'', include('oauth.urls', namespace='oauth', app_name='oauth')), + url(r'', include('comments.urls', namespace='comment')), + url(r'', include('accounts.urls', namespace='account')), + url(r'', include('oauth.urls', namespace='oauth')), url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'), url(r'^feed/$', DjangoBlogFeed()), url(r'^search', include('haystack.urls'), name='search'), - url(r'', include('servermanager.urls', namespace='servermanager', app_name='servermanagers')) + url(r'', include('servermanager.urls', namespace='servermanager')) ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/README.md b/README.md index 6f13d82..9912930 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # DjangoBlog -基于`python3.5`和`Django1.10`的博客。 +基于`python3.5`和`Django2.0`的博客。 -[![Build Status](https://travis-ci.org/liangliangyy/DjangoBlog.svg?branch=master)](https://travis-ci.org/liangliangyy/DjangoBlog) [![Coverage Status](https://coveralls.io/repos/github/liangliangyy/DjangoBlog/badge.svg?branch=master)](https://coveralls.io/github/liangliangyy/DjangoBlog?branch=master) [![Requirements Status](https://requires.io/github/liangliangyy/DjangoBlog/requirements.svg?branch=master)](https://requires.io/github/liangliangyy/DjangoBlog/requirements/?branch=master) [![license](https://img.shields.io/github/license/liangliangyy/djangoblog.svg)]() [![GitHub release](https://img.shields.io/github/release/liangliangyy/djangoblog.svg)]() [![python3.5](https://img.shields.io/badge/python-3.5-brightgreen.svg)]() [![django1.10](https://img.shields.io/badge/django-1.10-brightgreen.svg)]() +[![Build Status](https://travis-ci.org/liangliangyy/DjangoBlog.svg?branch=master)](https://travis-ci.org/liangliangyy/DjangoBlog) [![Coverage Status](https://coveralls.io/repos/github/liangliangyy/DjangoBlog/badge.svg?branch=master)](https://coveralls.io/github/liangliangyy/DjangoBlog?branch=master) [![Requirements Status](https://requires.io/github/liangliangyy/DjangoBlog/requirements.svg?branch=master)](https://requires.io/github/liangliangyy/DjangoBlog/requirements/?branch=master) [![license](https://img.shields.io/github/license/liangliangyy/djangoblog.svg)]() [![GitHub release](https://img.shields.io/github/release/liangliangyy/djangoblog.svg)]() [![python3.5](https://img.shields.io/badge/python-3.5-brightgreen.svg)]() [![django1.10](https://img.shields.io/badge/django-2.0-brightgreen.svg)]() ## 主要功能: - 文章,页面,分类目录,标签的添加,删除,编辑等。文章及页面支持`Markdown`,支持代码高亮。 @@ -14,7 +14,6 @@ - 简单的SEO功能,新建文章等会自动通知Google和百度。 - 集成了简单的图床功能。 - 集成`django-compressor`,自动压缩`css`,`js`。 -- 基于`python3`,支持`Django`多版本。`Django`的1.8,1.9,1.10,1.11均测试通过。 - 网站异常邮件提醒,若有未捕捉到的异常会自动发送提醒邮件。 - 集成了微信公众号功能,现在可以使用微信公众号来管理你的vps了。 ## 安装 diff --git a/accounts/models.py b/accounts/models.py index d396bd3..5bf882f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,6 +1,6 @@ from django.db import models from django.contrib.auth.models import AbstractUser, BaseUserManager -from django.core.urlresolvers import reverse +from django.urls import reverse from django.contrib.sites.models import Site from django.utils.timezone import now @@ -9,6 +9,7 @@ from django.utils.timezone import now class BlogUser(AbstractUser): nickname = models.CharField('昵称', max_length=50, blank=True) + nickname = models.CharField('昵称', max_length=100, blank=True) mugshot = models.ImageField('头像', upload_to='upload/mugshots', blank=True) created_time = models.DateTimeField('创建时间', default=now) last_mod_time = models.DateTimeField('修改时间', default=now) diff --git a/accounts/tests.py b/accounts/tests.py index 2784463..db743e6 100644 --- a/accounts/tests.py +++ b/accounts/tests.py @@ -4,7 +4,7 @@ from django.contrib.auth import get_user_model from django.contrib.sites.models import Site import datetime from accounts.models import BlogUser -from django.core.urlresolvers import reverse +from django.urls import reverse # Create your tests here. diff --git a/accounts/urls.py b/accounts/urls.py index dfd248d..a648a76 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -19,6 +19,8 @@ from django.contrib.auth import views as auth_view from . import views from .forms import LoginForm +app_name="accounts" + urlpatterns = [ url(r'^login/$', views.LoginView.as_view(success_url='/'), name='login', kwargs={'authentication_form': LoginForm}), url(r'^register/$', views.RegisterView.as_view(success_url="/"), name='register'), diff --git a/accounts/views.py b/accounts/views.py index e092ae6..1e8548a 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -6,7 +6,7 @@ from django.contrib.auth import authenticate, login, logout from django.views.generic import FormView, RedirectView from django.contrib.auth import get_user_model from django.http import HttpResponseRedirect -from django.core.urlresolvers import reverse +from django.urls import reverse from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.contrib.auth import REDIRECT_FIELD_NAME from django.views.decorators.csrf import csrf_protect diff --git a/blog/middleware.py b/blog/middleware.py index 69e4243..00e0445 100644 --- a/blog/middleware.py +++ b/blog/middleware.py @@ -19,33 +19,17 @@ from DjangoBlog.utils import cache class OnlineMiddleware(object): - def process_request(self, request): - self.start_time = time.time() + def __init__(self, get_response=None): + self.get_response = get_response + super().__init__() - def process_view(self, request, view_func, view_args, view_kwargs): - """ - 处理当前在线人数 - """ + def __call__(self, request): + start_time = time.time() + response = self.get_response(request) http_user_agent = request.META.get('HTTP_USER_AGENT', []) if 'Spider' in http_user_agent or 'spider' in http_user_agent: - return + return response - online_ips = cache.get("online_ips", []) - if online_ips: - online_ips = cache.get_many(online_ips).keys() - online_ips = list(online_ips) - ip = get_real_ip(request) - - cache.set(ip, 0, 5 * 60) - - if ip not in online_ips: - online_ips.append(ip) - s = type(online_ips) - cache.set("online_ips", online_ips) - - def process_response(self, request, response): - cast_time = 0.921 - if self.__dict__ and 'start_time' in self.__dict__: - cast_time = time.time() - self.start_time + cast_time = time.time() - start_time response.content = response.content.replace(b'', str.encode(str(cast_time)[:5])) return response diff --git a/blog/models.py b/blog/models.py index ead1e76..6999645 100644 --- a/blog/models.py +++ b/blog/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.core.urlresolvers import reverse +from django.urls import reverse from django.conf import settings from uuslug import slugify @@ -125,7 +125,7 @@ class Article(BaseModel): class Category(BaseModel): """文章分类""" name = models.CharField('分类名', max_length=30, unique=True) - parent_category = models.ForeignKey('self', verbose_name="父级分类", blank=True, null=True) + parent_category = models.ForeignKey('self', verbose_name="父级分类", blank=True, null=True, on_delete=models.CASCADE) class Meta: ordering = ['name'] diff --git a/blog/templatetags/blog_tags.py b/blog/templatetags/blog_tags.py index 1e71c23..5605b1b 100644 --- a/blog/templatetags/blog_tags.py +++ b/blog/templatetags/blog_tags.py @@ -18,7 +18,7 @@ from django.conf import settings from django.template.defaultfilters import stringfilter from django.utils.safestring import mark_safe import random -from django.core.urlresolvers import reverse +from django.urls import reverse from blog.models import Article, Category, Tag, Links, SideBar from django.utils.encoding import force_text from django.shortcuts import get_object_or_404 @@ -266,7 +266,7 @@ def gravatar(email, size=40): return mark_safe('' % (url, size, size)) -@register.assignment_tag +@register.simple_tag def query(qs, **kwargs): """ template tag which allows queryset filtering. Usage: {% query books author=author as mybooks %} @@ -275,3 +275,5 @@ def query(qs, **kwargs): {% endfor %} """ return qs.filter(**kwargs) + + diff --git a/blog/urls.py b/blog/urls.py index 870e293..b68ce77 100644 --- a/blog/urls.py +++ b/blog/urls.py @@ -13,38 +13,32 @@ @time: 2016/11/2 下午7:15 """ -from django.conf.urls import url +from django.urls import path from django.views.decorators.cache import cache_page from . import views from haystack.forms import ModelSearchForm from haystack.query import SearchQuerySet from haystack.views import SearchView +app_name = "blog" urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^page/(?P\d+)$', views.IndexView.as_view(), name='index_page'), + path(r'', views.IndexView.as_view(), name='index'), + path(r'page//', views.IndexView.as_view(), name='index_page'), - url(r'^article/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+).html$', - views.ArticleDetailView.as_view(), - name='detailbyid'), + path(r'article////.html', + views.ArticleDetailView.as_view(), + name='detailbyid'), - url(r'^blogpage/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)-(?P[\w-]+).html$', - views.ArticleDetailView.as_view(), - name='pagedetail'), + path(r'category/.html', views.CategoryDetailView.as_view(), name='category_detail'), + path(r'category//.html', views.CategoryDetailView.as_view(), + name='category_detail_page'), - url(r'^category/(?P[\w-]+).html$', views.CategoryDetailView.as_view(), name='category_detail'), - url(r'^category/(?P[\w-]+)/(?P\d+).html$', views.CategoryDetailView.as_view(), - name='category_detail_page'), - # url(r'^category/(?P[\w-]+)/(?P\d+).html$', views.CategoryDetailView.as_view(), - # name='category_detail'), + path(r'author/.html', views.AuthorDetailView.as_view(), name='author_detail'), + path(r'author//).html', views.AuthorDetailView.as_view(), + name='author_detail_page'), - url(r'^author/(?P\w+).html$', views.AuthorDetailView.as_view(), name='author_detail'), - url(r'^author/(?P\w+)/(?P\d+).html$', views.AuthorDetailView.as_view(), - name='author_detail_page'), - - url(r'^tag/(?P[\w-]+).html$', views.TagDetailView.as_view(), name='tag_detail'), - url(r'^tag/(?P[\w-]+)/(?P\d+).html$', views.TagDetailView.as_view(), name='tag_detail_page'), - - url(r'^upload', views.fileupload, name='upload'), - url(r'^refresh', views.refresh_memcache, name='refresh') + path(r'tag/.html', views.TagDetailView.as_view(), name='tag_detail'), + path(r'tag//).html', views.TagDetailView.as_view(), name='tag_detail_page'), + path(r'upload', views.fileupload, name='upload'), + path(r'refresh', views.refresh_memcache, name='refresh') ] diff --git a/blog/views.py b/blog/views.py index 8009067..51b3076 100644 --- a/blog/views.py +++ b/blog/views.py @@ -218,11 +218,11 @@ def fileupload(request): isimage = len([i for i in imgextensions if fname.find(i) >= 0]) > 0 basepath = r'/var/www/resource/{type}/{timestr}'.format( - type='files' if not isimage else'image', timestr=timestr) + type='files' if not isimage else 'image', timestr=timestr) if settings.TESTING: basepath = settings.BASE_DIR + '/uploads' url = 'https://resource.lylinux.net/{type}/{timestr}/{filename}'.format( - type='files' if not isimage else'image', timestr=timestr, filename=filename) + type='files' if not isimage else 'image', timestr=timestr, filename=filename) if not os.path.exists(basepath): os.makedirs(basepath) savepath = os.path.join(basepath, filename) @@ -256,17 +256,23 @@ def refresh_memcache(request): return HttpResponse(e) -def page_not_found_view(request): +def page_not_found_view(request, exception): + if exception: + logger.error(exception) url = request.get_full_path() return render(request, 'blog/error_page.html', {'message': '哎呀,您访问的地址 ' + url + ' 是一个未知的地方。请点击首页看看别的?', 'statuscode': '404'}) -def server_error_view(request): +def server_error_view(request, exception): + if exception: + logger.error(exception) return render(request, 'blog/error_page.html', {'message': '哎呀,出错了,我已经收集到了错误信息,之后会抓紧抢修,请点击首页看看别的?', 'statuscode': '500'}) -def permission_denied_view(request): +def permission_denied_view(request, exception): + if exception: + logger.error(exception) return render(request, 'blog/error_page.html', {'message': '哎呀,您没有权限访问此页面,请点击首页看看别的?', 'statuscode': '403'}) diff --git a/comments/models.py b/comments/models.py index 0f55201..9934ba4 100644 --- a/comments/models.py +++ b/comments/models.py @@ -13,7 +13,7 @@ class Comment(models.Model): last_mod_time = models.DateTimeField('修改时间', default=now) author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者', on_delete=models.CASCADE) article = models.ForeignKey(Article, verbose_name='文章', on_delete=models.CASCADE) - parent_comment = models.ForeignKey('self', verbose_name="上级评论", blank=True, null=True) + parent_comment = models.ForeignKey('self', verbose_name="上级评论", blank=True, null=True, on_delete=models.CASCADE) is_enable = models.BooleanField('是否显示', default=True, blank=False, null=False) class Meta: diff --git a/comments/templatetags/comments_tags.py b/comments/templatetags/comments_tags.py index b831e7d..a78e8b6 100644 --- a/comments/templatetags/comments_tags.py +++ b/comments/templatetags/comments_tags.py @@ -22,7 +22,7 @@ from comments.forms import CommentForm register = template.Library() -@register.assignment_tag +@register.simple_tag def parse_commenttree(commentlist, comment): """获得当前评论子评论的列表 用法: {% parse_commenttree article_comments comment as childcomments %} diff --git a/comments/tests.py b/comments/tests.py index fe54671..9a758a5 100644 --- a/comments/tests.py +++ b/comments/tests.py @@ -2,7 +2,7 @@ from django.test import Client, RequestFactory, TestCase from blog.models import Article, Category, Tag from django.contrib.auth import get_user_model from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse +from django.urls import reverse import datetime from accounts.models import BlogUser from comments.templatetags.comments_tags import * diff --git a/comments/urls.py b/comments/urls.py index f5af5fd..0bcb847 100644 --- a/comments/urls.py +++ b/comments/urls.py @@ -13,10 +13,11 @@ @time: 2016/11/12 下午3:03 """ -from django.conf.urls import url +from django.urls import path from . import views +app_name = "comments" urlpatterns = [ - # url(r'^postcomment/(?P\d+)$', views.CommentPostView.as_view(), name='postcomment'), - url(r'^article/(?P\d+)/postcomment$', views.CommentPostView.as_view(), name='postcomment'), + # url(r'^po456stcomment/(?P\d+)$', views.CommentPostView.as_view(), name='postcomment'), + path('article//postcomment', views.CommentPostView.as_view(), name='postcomment'), ] diff --git a/comments/views.py b/comments/views.py index 34c9338..a25ecad 100644 --- a/comments/views.py +++ b/comments/views.py @@ -46,7 +46,7 @@ class CommentPostView(FormView): article_id = self.kwargs['article_id'] article = Article.objects.get(pk=article_id) - if not self.request.user.is_authenticated(): + if not self.request.user.is_authenticated: email = form.cleaned_data['email'] username = form.cleaned_data['name'] @@ -64,12 +64,8 @@ class CommentPostView(FormView): comment.save(True) from DjangoBlog.blog_signals import comment_save_signal - port = 80 - try: - # django1.8 没有这个方法... - port = self.request.get_port() - except: - pass + + port = self.request.get_port() username = self.request.user.username if self.request.user else '' comment_save_signal.send(sender=self.__class__, comment_id=comment.id, username=username, serverport=port) return HttpResponseRedirect("%s#div-comment-%d" % (article.get_absolute_url(), comment.pk)) diff --git a/oauth/models.py b/oauth/models.py index 76900c8..4a00c97 100644 --- a/oauth/models.py +++ b/oauth/models.py @@ -6,7 +6,8 @@ from django.utils.timezone import now class OAuthUser(models.Model): - author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='用户', blank=True, null=True) + author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='用户', blank=True, null=True, + on_delete=models.CASCADE) openid = models.CharField(max_length=50) nikename = models.CharField(max_length=50, verbose_name='昵称') token = models.CharField(max_length=150, null=True, blank=True) diff --git a/oauth/templatetags/oauth_tags.py b/oauth/templatetags/oauth_tags.py index 96b74cd..c336b03 100644 --- a/oauth/templatetags/oauth_tags.py +++ b/oauth/templatetags/oauth_tags.py @@ -13,7 +13,7 @@ @time: 2017/3/4 下午3:22 """ from oauth.oauthmanager import get_oauth_apps -from django.core.urlresolvers import reverse +from django.urls import reverse from django import template from django.conf import settings diff --git a/oauth/urls.py b/oauth/urls.py index c0bc44a..53c4013 100644 --- a/oauth/urls.py +++ b/oauth/urls.py @@ -13,14 +13,15 @@ @time: 2016/11/26 下午5:25 """ -from django.conf.urls import url +from django.urls import path from django.views.decorators.cache import cache_page from . import views +app_name = "oauth" urlpatterns = [ - url(r'^oauth/authorize$', views.authorize), - url(r'^oauth/requireemail/(?P\d+).html', views.RequireEmailView.as_view(), name='require_email'), - url(r'^oauth/emailconfirm/(?P\d+)/(?P\S+).html', views.emailconfirm, name='email_confirm'), - url(r'^oauth/bindsuccess/(?P\d+).html', views.bindsuccess, name='bindsuccess'), - url(r'^oauth/oauthlogin$', views.oauthlogin,name='oauthlogin') + path(r'oauth/authorize', views.authorize), + path(r'oauth/requireemail/.html', views.RequireEmailView.as_view(), name='require_email'), + path(r'oauth/emailconfirm/)/.html', views.emailconfirm, name='email_confirm'), + path(r'oauth/bindsuccess/.html', views.bindsuccess, name='bindsuccess'), + path(r'oauth/oauthlogin', views.oauthlogin, name='oauthlogin') ] diff --git a/oauth/views.py b/oauth/views.py index 6975f13..a199718 100644 --- a/oauth/views.py +++ b/oauth/views.py @@ -10,7 +10,7 @@ from django.contrib.auth import login from django.shortcuts import get_object_or_404 from django.views.generic import FormView, RedirectView from oauth.forms import RequireEmailForm -from django.core.urlresolvers import reverse +from django.urls import reverse from DjangoBlog.utils import send_email, get_md5 from django.contrib.sites.models import Site from django.core.exceptions import ObjectDoesNotExist diff --git a/requirements.txt b/requirements.txt index 90da994..ecfbd56 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,23 +1,27 @@ appdirs==1.4.3 -coverage==4.4.1 -Django==1.11.7 +bottle==0.12.13 +certifi==2017.11.5 +chardet==3.0.4 +coverage==4.4.2 +Django==2.0.1 django-appconf==1.0.2 django-autoslug==1.9.3 django-compressor==2.2 django-debug-toolbar==1.9.1 django-haystack==2.6.1 django-ipware==1.1.6 -django-pagedown==0.1.3 +django-pagedown==1.0.4 django-uuslug==1.1.8 +idna==2.6 jieba==0.39 jsonpickle==0.9.5 markdown2==2.3.5 -mistune==0.8.1 +mistune==0.8.3 olefile==0.44 packaging==16.8 -Pillow==4.3.0 +Pillow==5.0.0 Pygments==2.2.0 -PyMySQL==0.7.11 +PyMySQL==0.8.0 pyparsing==2.2.0 python-memcached==1.58 python-slugify==1.2.4 @@ -27,8 +31,9 @@ requests==2.18.4 rjsmin==1.0.12 six==1.11.0 sqlparse==0.2.4 -Unidecode==0.4.21 +Unidecode==1.0.22 urllib3==1.22 webencodings==0.5.1 -WeRoBot==1.1.1 +WeRoBot==1.2.0 Whoosh==2.7.4 +xmltodict==0.11.0 diff --git a/servermanager/urls.py b/servermanager/urls.py index 5ee7703..d9775ab 100644 --- a/servermanager/urls.py +++ b/servermanager/urls.py @@ -13,11 +13,12 @@ @time: 2017/8/27 上午2:27 """ -from django.conf.urls import url +from django.urls import path from werobot.contrib.django import make_view from .robot import robot +app_name = "servermanager" urlpatterns = [ - url(r'^robot/', make_view(robot)), + path(r'robot', make_view(robot)), ]