- 2019-05-19 开始学习第六章,现在才开始编辑第七章.我真的好拖延啊.
7-1 文章模块models.py设计 - python manage.py startapp articles
- zanhu/artivles/models.py
from django.db import models
from six import python_2_unicode_compatible
@python_2_unicode_compatible
class Article(models.Model):
STATUS = (("D", "Draft"), ("P", "Published"))
title = models.CharField(max_length=255, null=False, unique=True, verbose_name='标题')
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="author", on_delete=models.SET_NULL, verbose_name='作者')
image = models.ImageField(upload_to='articles_pictures/%Y/%m/%d/', verbose_name='文章图片')
slug = models.SlugField(max_length=80, null=True, blank=True, verbose_name='(URL)别名')
status = models.CharField(max_length=1, choices=STATUS, default='D', verbose_name='动态') # 默认存入草稿箱
content = models.TextField(verbose_name='内容')
edited = models.BooleanField(default=False, verbose_name='是否可编辑')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
verbose_name = '文章'
verbose_name_plural = verbose_name
ordering = ("created_at",)
def __str__(self):
return self.title
7-2 使用python-slugify和django-taggit
- python-slugify 网址显示题目的拼音.
7-3 models.py中自定义QuerySet
from django.db import models
from six import python_2_unicode_compatible
from slugify import slugify
from taggit.managers import TaggableManager
from django.conf import settings
@python_2_unicode_compatible
class ArticleQuerySet(models.query.QuerySet):
"""自定义QuerySet,提高模型类的可用性"""
def get_published(self):
"""返回已发表的文章"""
return self.filter(status="P")
def get_drafts(self):
"""返回草稿箱的文章"""
return self.filter(status="D")
def get_counted_tags(self):
"""统计所有已发布的文章中,每一个标签的数量(大于0的)"""
tag_dict = {}
query = self.filter(status='P').annotate(tagged=Count('tags')).filter(tags__gt=0)
for obj in query:
for tag in obj.tags.names():
if tag not in tag_dict:
tag_dict[tag] = 1
else:
tag_dict[tag] += 1
return tag_dict.items()
@python_2_unicode_compatible
class Article(models.Model):
STATUS = (("D", "Draft"), ("P", "Published"))
title = models.CharField(max_length=255, null=False, unique=True, verbose_name='标题')
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="author", on_delete=models.SET_NULL, verbose_name='作者')
image = models.ImageField(upload_to='articles_pictures/%Y/%m/%d/', verbose_name='文章图片')
slug = models.SlugField(max_length=80, null=True, blank=True, verbose_name='(URL)别名')
status = models.CharField(max_length=1, choices=STATUS, default='D', verbose_name='动态') # 默认存入草稿箱
content = models.TextField(verbose_name='内容')
edited = models.BooleanField(default=False, verbose_name='是否可编辑')
tags = TaggableManager(help_text='多个标签使用,(英文)隔开', verbose_name='标签')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
objects = ArticleQuerySet.as_manager()
class Meta:
verbose_name = '文章'
verbose_name_plural = verbose_name
ordering = ("created_at",)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
# 根据作者和标题生成文章在URL中的别名
self.slug = slugify(self.title)
super(Article, self).save(*args, **kwargs)
- zhanhu/config/setting/base.py
THIRD_PARTY_APPS = [
"crispy_forms",
"allauth",
"allauth.account",
"allauth.socialaccount",
"rest_framework",
"sorl.thumbnail",
"taggit",
]
LOCAL_APPS = [
'users.apps.UsersConfig',
'news.apps.NewsConfig',
'articles.apps.ArticlesConfig',
# Your stuff: custom apps go here
]
7-4 完成文章列表页开发
- articles/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
# Create your views here.
from django.views.generic import ListView
from dacall.articles.models import Article
class ArticlesListView(LoginRequiredMixin, ListView):
"""已发布的文章列表"""
model = Article
paginate_by = 10
context_object_name = "articles"
template_name = "articles/article_list.html" # 可省略
def get_context_data(self, *args, **kwargs):
context = super(ArticlesListView, self).get_context_data(*args, **kwargs)
context['popular_tags'] = Article.objects.get_counted_tags()
return context
def get_queryset(self, **kwargs):
return Article.objects.get_published()
- /articles/urls.py
#!/usr/bin/python3
# -*- coding:utf-8 -*-
# __author__ = '__Jack__'
from django.urls import path
from zanhu.articles import views
app_name = 'articles' # Django > 2.0,这样模板中可以使用"{% url 'articles:list' %}","articles"是总urls.py中定义的namespace
urlpatterns = [
path('', views.ArticlesListView.as_view(), name='list'),
path('write-new-article/', views.CreateArticleView.as_view(), name='write_new'),
path('drafts/', views.DraftsListView.as_view(), name='drafts'),
path('edit//', views.EditArticleView.as_view(), name='edit_article'),
path('/', views.DetailArticleView.as_view(), name='article'),
]
- config/urls.py
from django.conf import settings
from django.urls import include, path
from django.conf.urls.static import static
from django.views.generic import TemplateView
from django.views import defaults as default_views
from dacall.news.views import NewsListView
urlpatterns = [
path('', NewsListView.as_view(), name='home'),
# User management
path("users/", include("dacall.users.urls", namespace="users")),
path("accounts/", include("allauth.urls")),
path('news/', include('dacall.news.urls', namespace='news')),
path('articles/', include('dacall.articles.urls', namespace='articles')),
# Your stuff: custom urls includes go here
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
# This allows the error pages to be debugged during development, just visit
# these url in browser to see how these error pages look like.
urlpatterns += [
path(
"400/",
default_views.bad_request,
kwargs={"exception": Exception("Bad Request!")},
),
path(
"403/",
default_views.permission_denied,
kwargs={"exception": Exception("Permission Denied")},
),
path(
"404/",
default_views.page_not_found,
kwargs={"exception": Exception("Page not Found")},
),
path("500/", default_views.server_error),
]
if "debug_toolbar" in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns
- /templates/base.html
{% load static compress thumbnail %}
{% block title %}赞乎{% endblock title %}
{% compress css %}
{% block css %}{% endblock css %}
{% endcompress %}
{% if messages %}
{% for message in messages %}
{% compress js %}
{% block js %}{% endblock js %}
{% endcompress %}
{% endfor %}
{% endif %}
{% block content %}{% endblock content %}
7-5 用户发表文章与保存草稿
- forms.py
from django import forms
from dacall.articles.models import Article
class ArticleForm(forms.ModelForm):
# status = forms.CharField(widget=forms.HiddenInput()) # 隐藏
# edited = forms.BooleanField(widget=forms.HiddenInput(), required=False, initial=False) # 隐藏
# content = MarkdownxFormField()
class Meta:
model = Article
fields = ["title", "content", "image"]
- url
path('write-new-article/', views.CreateArticleView.as_view(), name='write_new'),
path('drafts/', views.DraftsListView.as_view(), name='drafts'),
path('edit//', views.EditArticleView.as_view(), name='edit_article'),
- views.py
class DraftsListView(ArticlesListView):
"""草稿箱文章列表"""
def get_queryset(self, **kwargs):
# 当前用户的草稿
return Article.objects.filter(user=self.request.user).get_drafts()
class CreateArticleView(LoginRequiredMixin, CreateView):
"""创建文章"""
model = Article
message = "您的文章已创建成功!" # Django框架中的消息机制
form_class = ArticleForm
template_name = 'articles/article_create.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super(CreateArticleView, self).form_valid(form)
def get_success_url(self):
"""创建成功后跳转"""
messages.success(self.request, self.message) # 消息传递给下一次请求
return reverse_lazy('articles:list')
7-6 实现Markdown编辑与实时预览
- 安装markdownx
- settting/base.py
THIRD_PARTY_APPS = [
"crispy_forms",
"allauth",
"allauth.account",
"allauth.socialaccount",
"rest_framework",
"sorl.thumbnail",
"taggit",
"markdownx",
]
- 总url.py
# 第三方应用
# path('comments/', include('django_comments.urls')),
path('markdownx/', include('markdownx.urls')),
- forms
from django import forms
from markdownx.fields import MarkdownxFormField
from dacall.articles.models import Article
class ArticleForm(forms.ModelForm):
status = forms.CharField(widget=forms.HiddenInput()) # 隐藏
edited = forms.BooleanField(widget=forms.HiddenInput(), required=False, initial=False) # 隐藏
content = MarkdownxFormField()
class Meta:
model = Article
fields = ["title", "content", "image", "tags", "status", "edited"]
pipenv install django-markdownx 没有成功
后来是 pip install django-markdownx成功的.
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic
- python manage.py collectstatic 这步骤
7-7 通用类视图CreateView源码详解
7-8 用户浏览文章内容
class DetailArticleView(LoginRequiredMixin, DetailView):
"""文章详情"""
model = Article
template_name = 'articles/article_detail.html'
path('/', views.DetailArticleView.as_view(), name='article'),
7-9 django-contrib-comments实现评论文章
7-10 用户编辑文章
7-11 通用类视图UpdateView源码详解
7-12 Django Template Language语法精讲
7-13 Django Template Language语法精讲
7-14 模型类和视图的测试用例
7-15 本章总结与课后作业.