renran-专题模块

专题部分

在models.py中,创建文章投稿记录的模型,代码:

class ArticlePostLog(BaseModel):
    """文章的投稿记录"""
    POST_STATUS = (
        (0,"未审核"),
        (1,"审核通过"),
        (2,"审核未通过"),
    )
    user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="投稿人")
    special = models.ForeignKey(Special, on_delete=models.CASCADE, verbose_name="专题")
    article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name="文章")
    status = models.IntegerField(choices=POST_STATUS, default=0, verbose_name="审核状态")
    manager = models.IntegerField(default=None, null=True,blank=True, verbose_name="审核人")
    post_time = models.DateTimeField(default=None, null=True,blank=True, verbose_name="审核时间")

    class Meta:
        db_table = "rr_article_post"
        verbose_name = "文章的投稿记录"
        verbose_name_plural = verbose_name

数据迁移

python manage.py makemigrations
python manage.py migrate

创建专题的测试数据, 把专题相关模型注册到adminx.py文件, 添加测试数据

# 专题测试数据
INSERT INTO renran.rr_special (id, orders, is_show, is_deleted, created_time, updated_time, name, image, notice, article_count, follow_count, collect_count, user_id) VALUES (1, 0, 1, 0, '2020-01-15 08:27:39.044094', '2020-01-15 08:27:39.044126', '相亲', 'group1/M00/00/00/wKjDgF4ezPuAO9nlAAB7habsNjs0280196', '相亲相爱', 0, 0, 0, 1);
INSERT INTO renran.rr_special (id, orders, is_show, is_deleted, created_time, updated_time, name, image, notice, article_count, follow_count, collect_count, user_id) VALUES (2, 1, 1, 0, '2020-01-15 08:29:15.513292', '2020-01-15 08:29:15.513346', '相爱', 'group1/M00/00/00/wKjDgF4ezVuADywFAAB7habsNjs8789529', '相亲相爱', 0, 0, 0, 1);
INSERT INTO renran.rr_special (id, orders, is_show, is_deleted, created_time, updated_time, name, image, notice, article_count, follow_count, collect_count, user_id) VALUES (3, 2, 1, 0, '2020-01-15 08:29:15.513292', '2020-01-15 08:29:15.513346', '篮球', 'group1/M00/00/00/wKjDgF4ezVuADywFAAB7habsNjs8789529', '篮球', null, null, null, 1);


# 专题管理员
INSERT INTO renran.rr_special_manager (id, orders, is_show, is_deleted, created_time, updated_time, special_id, user_id) VALUES (1, 0, 1, 0, '2020-01-15 08:35:28.645931', '2020-01-15 08:35:28.645962', 1, 1);
INSERT INTO renran.rr_special_manager (id, orders, is_show, is_deleted, created_time, updated_time, special_id, user_id) VALUES (2, 0, 1, 0, '2020-01-15 08:35:33.216625', '2020-01-15 08:35:33.216656', 2, 1);
INSERT INTO renran.rr_special_manager (id, orders, is_show, is_deleted, created_time, updated_time, special_id, user_id) VALUES (3, 0, 1, 0, '2020-01-15 08:35:37.345065', '2020-01-15 08:35:37.345094', 3, 1);

# 专题投稿记录

服务端提供我管理的专题列表,视图接口代码:

from .models import Special
from .serializers import SpecialModelSerializer
class SpecialListAPIView(ListAPIView):
    queryset = Special.objects.all()
    serializer_class = SpecialModelSerializer
    permission_classes = [IsAuthenticated]

    def list(self, request, *args, **kwargs):
        user = request.user
        ret = self.get_queryset().filter(mymanager__user=user)
        queryset = self.filter_queryset(ret)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

客户顿实现发布文章以后的投稿页面

<template>
    <div id="writed">
      <div class="_3PLTX">
        <div class="_2Mx1k">
          <div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>
          <ul class="zelSB">
            <li class="_35P4c"><i class="fa fa-weibo"></i>微博</li>
            <li class="_1c1Eo"><i class="fa fa-wechat"></i>微信</li>
            <li class="_1HWk1"><i class="fa fa-link"></i>复制链接</li>
            <li class="_3FrjS _3Qjz6 _2_WAp _2po2r cRfUr" title="">
              <span class="">更多分享</span>
            </li>
          </ul>
        </div>
        <div class="_3Q2EW" @click="$router.back()">×</div>
        <div class="_1s967"></div>
        <div class="_2w_E5">
          <div class="_23R_O">
            <div class="_1WCUC">
              <i class="fa fa-search fa-2x"></i><input type="text" placeholder="搜索专题">
            </div>
            <div class="_3dZoJ">向专题投稿,让文章被更多人发现</div>
          </div>
          <div>
            <div class="_18jMg">
              <h3>我管理的专题<a href="">新建</a></h3>
              <ul class="_1hEmG">
                <li v-for="special in my_special_list">
                  <a>收录</a>
                  <img alt="png" :src="special.image">
                  <span class="_1CN24" :title="special.name">{{special.name}}</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>最近投稿</h3>
              <ul class="_1hEmG">
                <li>
                  <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                  <span class="_1CN24" title="摄影">摄影</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>推荐专题</h3>
              <div>
                <ul class="_1hEmG">
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                    <span class="_1CN24">摄影<em>154.8K篇文章,2575.1K人关注</em></span>
                    <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/95/1.jpg">
                    <span class="_1CN24">故事<em>192.2K篇文章,1920.7K人关注</em></span>
                    <a data-collection-id="95" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                </ul>
                <div class="_27pBl">没有更多了 </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
    export default {
        name: "PostArticle",
        data(){
           return {
             my_special_list:[],
             token: "",
             article_id: 0,
             article_name:"",
           }
        },
        created() {
            this.token = this.$settings.check_user_login(this);
            // 从本地存储中提取当前文章的ID和标题
            this.article_id   = sessionStorage.current_article_id;
            this.article_name = sessionStorage.current_article_name;
        },
        methods:{
          get_my_special_list(){
            // 获取我管理的专题列表
            this.$axios.get(`${this.$settings.Host}/article/special/list/`,{
              params:{
                article_id: this.article_id,
              },
              headers:{
                Authorization: "jwt " + this.token,
              }
            }).then(response=>{
              this.my_special_list = response.data;
            }).catch(error=>{
              this.$message.error("对不起,获取专题列表失败!");
            });
          }
        }
    }
</script>

<script>
    export default {
        name: "Writed",
        data(){
           return {
             my_special_list:[],
             token: "",
             article_id: 0,
           }
        },
        created() {
          this.article_id = this.$route.params.id;
          this.token = this.get_login_user();
          this.get_article();
          this.get_my_special_list();
        },
        methods:{
          get_article(){
            // 获取当前ID对应的文章内容

          },
           get_login_user(){
            // 获取登录用户
            return localStorage.user_token || sessionStorage.user_token;
          },
          get_my_special_list(){
            // 获取我管理的专题列表
            this.$axios.get(`${this.$settings.Host}/article/special/list/`,{
              params:{
                article_id: this.article_id,
              },
              headers:{
                Authorization: "jwt " + this.token,
              }
            }).then(response=>{
              this.my_special_list = response.data;
            }).catch(error=>{
              this.$message.error("对不起,获取专题列表失败!");
            });
          }
        }
    }
</script>

<style scoped>
::selection {
  color: #fff;
  background: #1890ff;
}
.writed{
  width: 100%;
  height: 100%;
  max-width: 100vw;
  max-height: 100vh;
  color: rgba(0,0,0,.65);
  font-size: 14px;
  font-variant: tabular-nums;
  line-height: 1.5;
}
.writed *{
  box-sizing: border-box;
}
._3PLTX{
      position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #fff;
    z-index: 1010;
    overflow-y: auto;
}
._3PLTX ._2Mx1k {
    background-color: #f2f2f2;
    padding-bottom: 110px;
}
._3PLTX ._2Mx1k ._3CoyQ {
    padding: 80px 0 40px;
    text-align: center;
}
._3PLTX ._2Mx1k ._3CoyQ ._2-ZiM {
    display: inline-block;
    height: 40px;
    font-size: 28px;
    font-weight: 500;
    color: #333;
    margin-bottom: 24px;
}
._3PLTX ._2Mx1k ._3CoyQ ._2ajaT {
    font-size: 16px;
    font-weight: 600;
    color: #42c02e;
}
._3PLTX ._2Mx1k ._3CoyQ ._2ajaT:before {
    content: "";
    display: inline-block;
    width: 18px;
    height: 10px;
    border: 3px solid #42c02e;
    border-width: 0 0 4px 4px;
    transform: rotate(-45deg);
    transition: 0s;
    position: relative;
    bottom: 4px;
    right: 8px;
}
._3PLTX ._2Mx1k .zelSB {
    text-align: center;
    color: #fff;
    font-size: 14px;
}
._3PLTX ._2Mx1k .zelSB>li {
    display: inline-block;
    width: 124px;
    line-height: 38px;
    border-radius: 100px;
    margin: 0 15px;
    cursor: pointer;
    padding: 0;
    text-align: center;
}
._3PLTX ._2Mx1k .zelSB li._35P4c {
    background-color: #e05244;
}
._3PLTX ._2Mx1k .zelSB>li i {
    margin-right: 5px;
}
._3PLTX ._2Mx1k .zelSB li._1c1Eo {
    background-color: #07b225;
}
._3PLTX ._2Mx1k .zelSB li._1HWk1 {
    background-color: #3194d0;
}
._2po2r {
    padding: 10px 20px;
    line-height: 20px;
    white-space: nowrap;
    text-align: left;
    position: relative;
    border-bottom: 1px solid #d9d9d9;
}
.cRfUr {
    border-bottom: 1px solid #d9d9d9;
}
._2po2r:last-child {
    border-radius: 0 0 4px 4px;
    border-bottom: 0;
}
._3PLTX ._2Mx1k .zelSB>li {
    display: inline-block;
    width: 124px;
    line-height: 38px;
    border-radius: 100px;
    margin: 0 15px;
    cursor: pointer;
    padding: 0;
    text-align: center;
}
._3PLTX ._2Mx1k .zelSB li._3Qjz6 {
    background-color: #a7a7a7;
    position: relative;
}
._3PLTX ._3Q2EW {
    position: fixed;
    top: 50px;
    right: 100px;
    font-size: 30px;
    font-weight: 700;
    padding: 5px;
    cursor: pointer;
}
._3PLTX ._1s967 {
    height: 40px;
    border-radius: 50% 50% 0 0/100% 100% 0 0;
    background-color: #fff;
    margin-top: -40px;
}
._3PLTX ._2w_E5 {
    margin: 40px auto 0;
    width: 700px;
    font-size: 14px;
}
._3PLTX ._2w_E5 ._23R_O {
    margin-bottom: 36px;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC {
    float: right;
    border: 1px solid #d9d9d9;
    position: relative;
    width: 200px;
    height: 34px;
    border-radius: 17px;
    padding: 5px 20px 5px 30px;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC i {
    position: absolute;
    left: 10px;
    top: 50%;
    margin-top: -8px;
    font-size: 16px;
    color: #ccc;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC input {
    line-height: 24px;
    height: 24px;
    width: 100%;
    font-size: 14px;
    background-color: transparent;
}
._3PLTX ._2w_E5 ._23R_O ._3dZoJ {
    font-size: 16px;
    font-weight: 500;
    line-height: 38px;
}
._3PLTX ._2w_E5 ._18jMg {
    position: relative;
    margin-bottom: 50px;
}
._3PLTX ._2w_E5 ._18jMg h3 {
    margin-bottom: 0;
    height: 40px;
    line-height: 40px;
    padding: 0 6px 0 14px;
    background-color: #f2f2f2;
    font-size: 14px;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg h3 a {
    margin-left: 15px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG {
    position: relative;
    margin: 1px 0 0 1px;
    zoom: 1;
    min-height: 72px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG:after, ._3PLTX ._2w_E5 ._18jMg ._1hEmG:before {
    content: " ";
    display: table;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li {
    float: left;
    width: 234px;
    border: 1px solid #f2f2f2;
    position: relative;
    margin: -1px 0 0 -1px;
    list-style-type: none;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li a {
    position: absolute;
    top: 24px;
    right: 15px;
}
img {
    vertical-align: middle;
    border-style: none;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li img {
    position: absolute;
    left: 15px;
    height: 40px;
    width: 40px;
    top: 15px;
    border-radius: 10%;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li ._1CN24 {
    display: block;
    font-weight: 700;
    color: #595959;
    width: 100%;
    padding: 0 60px 0 75px;
    line-height: 70px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC input {
  line-height: 24px;
  height: 24px;
  width: 100%;
  font-size: 14px;
  background-color: transparent;
  outline: none;
  border: 0;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC i {
    position: absolute;
    left: 10px;
    top: 50%;
    margin-top: -8px;
    font-size: 16px;
    color: #ccc;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC {
    float: right;
    border: 1px solid #d9d9d9;
    position: relative;
    width: 200px;
    height: 34px;
    border-radius: 17px;
    padding: 5px 20px 5px 30px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 {
    width: 49.85666666%;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li img {
    position: absolute;
    left: 15px;
    height: 40px;
    width: 40px;
    top: 15px;
    border-radius: 10%;
}
img {
    vertical-align: middle;
    border-style: none;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li ._1CN24 {
    display: block;
    font-weight: 700;
    color: #595959;
    width: 100%;
    padding: 0 60px 0 75px;
    line-height: 70px;
    overflow: hidden;
    -o-text-overflow: ellipsis;
    text-overflow: ellipsis;
    white-space: nowrap;
}
._1hEmG a{
  cursor: pointer;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 {
    display: block;
    padding: 18px 65px 16px;
    line-height: 1;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 em {
    font-weight: 400;
    font-style: normal;
    color: #999;
    display: block;
    margin-top: 8px;
    font-size: 12px;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li a {
    position: absolute;
    top: 24px;
    right: 15px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG:after {
  clear: both;
  visibility: hidden;
  font-size: 0;
  height: 0;
}
._3PLTX ._27pBl {
    padding: 30px 0;
    text-align: center;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 {
    display: block;
    padding: 18px 65px 16px;
    line-height: 1;
}
</style>

前端指定路由,代码:

import Vue from 'vue'

import PostArticle from "@/components/PostArticle";
Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    ,{
      path: "/post",
      name: 'PostArticle',
      component: PostArticle,
    },
  ]
})

序列化器,代码:

from .models import Special
class SpecialModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Special
        fields = ["id","name","image","article_count","follow_count","collect_count"]

路由,代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    path("image/", views.ImageAPIView.as_view()),
    path("collection/", views.CollecionAPIView.as_view()),
    re_path("collection/(?P<pk>\d+)/", views.CollecionDetailAPIView.as_view()),
    re_path("special/list/", views.SpecialListAPIView.as_view()),
]

from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register("", views.ArticleAPIView)
urlpatterns += router.urls

实现专题收录文章的功能

修改发布文章以后的跳转页面代码,并修改路由中原来的Writed的路由地址

Write.vue组件中发布文章以后跳转到投稿页面,代码:

public_article(is_public){
              // 文章发布状态的切换
              let article_id = this.article_list[this.current_article].id;
              this.$axios.put(`${this.$settings.Host}/article/public/${article_id}/`,{
                  is_public: is_public,
              },{
                  headers:{
                      Authorization: "jwt " + this.token,
                  }
              }).then(response=>{
                  this.article_list[this.current_article].is_public=is_public;
                  this.is_show_article_menu = false;
                  if(is_public){
                      // 对页面进行跳转到文章发布投稿页面
                      sessionStorage.current_article_id = this.article_list[this.current_article].id;
                      sessionStorage.current_article_name=this.article_list[this.current_article].name;
                      this.$router.push("/post");
                  }else{
                      this.$message.success("文章设置成功!");
                  }

              }).catch(error=>{
                  this.$message.error("操作失败!请联系客服工作人员!");
              })
          },

router/index.js,代码:

import Vue from 'vue'
import Router from 'vue-router'

import PostArticle from "@/components/PostArticle";
Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    /// 。。、、
    ,{
      path: "/post",
      name: 'PostArticle',
      component: PostArticle,
    },
  ]
})

服务端提供收录文章到我管理的专题中的接口

from .models import Special,ArticlePostLog,SpecialArticle
from datetime import datetime
class ArticlePostAPIView(APIView):
    permission_classes = [IsAuthenticated]
    def post(self,request):
        """文章投稿"""
        user = request.user
        article_id = request.data.get("article_id")
        special_id = request.data.get("special_id")

        try:
            article = Article.objects.get(user=user, pk=article_id)
        except Article.DoesNotExist:
            return Response("对不起, 当前文章不存在!", status=status.HTTP_400_BAD_REQUEST)

        # 验证专题是否存在
        try:
            special = Special.objects.get(pk=special_id)
        except Special.DoesNotExist:
            return Response("对不起, 当前专题不存在!", status=status.HTTP_400_BAD_REQUEST)

        # 判断当前文章是否向专题投稿
        article_post_log_list = ArticlePostLog.objects.filter(special=special, article=article).order_by("-id")
        # 判断是否有投稿历史
        if len(article_post_log_list) > 0:
            # 查看最后一次投稿记录的审核状态
            if article_post_log_list[0].status != 2:
                return Response("对不起, 文章已经向当前专题投稿了!", status=status.HTTP_400_BAD_REQUEST)

        # 判断当前投稿人是否属于专题的管理员
        try:
            """专题管理员"""
            special_manage = SpecialManager.objects.get(user=user, special=special)
            ArticlePostLog.objects.create(
                user=user,
                special=special,
                article=article,
                status=1,
                manager=user.id,
                post_time=datetime.now(),
                orders=0,
            )

            SpecialArticle.objects.create(
                special=special,
                article=article,
                orders=0,
            )

        except SpecialManager.DoesNotExist:
            """并非管理员"""
            ArticlePostLog.objects.create(
                user=user,
                special=special,
                article=article,
                status=0,
                manager=user.id,
                post_time="",
                orders=0,
            )

        except:
            return Response("投稿失败!")

        return Response("投稿成功!")

urls.py路由:

    path("post/", views.ArticlePostAPIView.as_view()),

前端发送ajax,请求投稿,代码:

<template>
    <div id="writed">
      <div class="_3PLTX">
        <div class="_2Mx1k">
          <div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>
          <ul class="zelSB">
            <li class="_35P4c"><i class="fa fa-weibo"></i>微博</li>
            <li class="_1c1Eo"><i class="fa fa-wechat"></i>微信</li>
            <li class="_1HWk1"><i class="fa fa-link"></i>复制链接</li>
            <li class="_3FrjS _3Qjz6 _2_WAp _2po2r cRfUr" title="">
              <span class="">更多分享</span>
            </li>
          </ul>
        </div>
        <div class="_3Q2EW" @click="$router.back()">×</div>
        <div class="_1s967"></div>
        <div class="_2w_E5">
          <div class="_23R_O">
            <div class="_1WCUC">
              <i class="fa fa-search fa-2x"></i><input type="text" placeholder="搜索专题">
            </div>
            <div class="_3dZoJ">向专题投稿,让文章被更多人发现</div>
          </div>
          <div>
            <div class="_18jMg">
              <h3>我管理的专题<a href="">新建</a></h3>
              <ul class="_1hEmG">
                <li v-for="special in my_special_list">
                  <a @click.stop="article_post(special.id)">收录</a>
                  <img alt="png" :src="special.image">
                  <span class="_1CN24" :title="special.name">{{special.name}}</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>最近投稿</h3>
              <ul class="_1hEmG">
                <li>
                  <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                  <span class="_1CN24" title="摄影">摄影</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>推荐专题</h3>
              <div>
                <ul class="_1hEmG">
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                    <span class="_1CN24">摄影<em>154.8K篇文章,2575.1K人关注</em></span>
                    <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/95/1.jpg">
                    <span class="_1CN24">故事<em>192.2K篇文章,1920.7K人关注</em></span>
                    <a data-collection-id="95" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                </ul>
                <div class="_27pBl">没有更多了 </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
    export default {
        name: "PostArticle",
        data(){
           return {
             my_special_list:[],
             token: "",
             article_id: 0,
             article_name:"",
           }
        },
        created() {
            this.token = this.$settings.check_user_login(this);
            // 从本地存储中提取当前文章的ID和标题
            this.article_id   = sessionStorage.current_article_id;
            this.article_name = sessionStorage.current_article_name;
            if(this.token){
                this.get_special_list();
            }
        },
        methods:{
          get_special_list(){
            // 获取我管理的专题列表
            this.$axios.get(`${this.$settings.Host}/article/special/list/`,{
              headers:{
                Authorization: "jwt " + this.token,
              }
            }).then(response=>{
              this.my_special_list = response.data;
            }).catch(error=>{
              this.$message.error("对不起,获取专题列表失败!");
            });
          },
          article_post(special_id){
              // 文章投稿
              this.$axios.post(`${this.$settings.Host}/article/post/`,{
                  article_id: this.article_id,
                  special_id: special_id,
              },{
                  headers:{
                      Authorization: "jwt " + this.token,
                  }
              }).then(response=>{
                  // 更新收录状态
                  for(let special of this.my_special_list ){
                      if(special.id == special_id){
                          special.is_post = true;
                      }
                  }
                  this.$message.success("投稿成功!");
              }).catch(error=>{
                  this.$message.error("投稿失败!");
              })
          }
        }
    }
</script>

在专题列表中展示当前文章的收录状态

视图代码:

from .models import SpecialManager
class SpecialListAPIView(APIView):
    """我管理的专题列表"""
    permission_classes = [IsAuthenticated]
    def get(self,request):
        user = request.user
        article_id = request.query_params.get("article_id")
        manage_list = SpecialManager.objects.filter(user=user)
        data = []
        for item in manage_list:
            try:
                # 查询当前专题下所有的文章列表是否存在当前文章
                item.special.post_article_list.get(article_id=article_id)
                status = True
            except SpecialArticle.DoesNotExist:
                status = False
            data.append({
                "id": item.special.id,
                "name": item.special.name,
                "image": item.special.image.url if item.special.image else "",
                "is_post": status, # 专题对于当前文章的收录状态
            })
        return Response(data)

前端组件中在原有代码中增加is_post的判断显示

<template>
    <div id="writed">
      <div class="_3PLTX">
        <div class="_2Mx1k">
          <div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>
          <ul class="zelSB">
            <li class="_35P4c"><i class="fa fa-weibo"></i>微博</li>
            <li class="_1c1Eo"><i class="fa fa-wechat"></i>微信</li>
            <li class="_1HWk1"><i class="fa fa-link"></i>复制链接</li>
            <li class="_3FrjS _3Qjz6 _2_WAp _2po2r cRfUr" title="">
              <span class="">更多分享</span>
            </li>
          </ul>
        </div>
        <div class="_3Q2EW" @click="$router.back()">×</div>
        <div class="_1s967"></div>
        <div class="_2w_E5">
          <div class="_23R_O">
            <div class="_1WCUC">
              <i class="fa fa-search fa-2x"></i><input type="text" placeholder="搜索专题">
            </div>
            <div class="_3dZoJ">向专题投稿,让文章被更多人发现</div>
          </div>
          <div>
            <div class="_18jMg">
              <h3>我管理的专题<a href="">新建</a></h3>
              <ul class="_1hEmG">
                <li v-for="special in my_special_list">
                  <a v-if="special.is_post">已收录</a>
                  <a @click.stop="article_post(special.id)" v-else>收录</a>
                  <img alt="png" :src="special.image">
                  <span class="_1CN24" :title="special.name">{{special.name}}</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>最近投稿</h3>
              <ul class="_1hEmG">
                <li>
                  <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                  <span class="_1CN24" title="摄影">摄影</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>推荐专题</h3>
              <div>
                <ul class="_1hEmG">
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                    <span class="_1CN24">摄影<em>154.8K篇文章,2575.1K人关注</em></span>
                    <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/95/1.jpg">
                    <span class="_1CN24">故事<em>192.2K篇文章,1920.7K人关注</em></span>
                    <a data-collection-id="95" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                </ul>
                <div class="_27pBl">没有更多了 </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
    export default {
        name: "PostArticle",
        data(){
           return {
             my_special_list:[],
             token: "",
             article_id: 0,
             article_name:"",
           }
        },
        created() {
            this.token = this.$settings.check_user_login(this);
            // 从本地存储中提取当前文章的ID和标题
            this.article_id   = sessionStorage.current_article_id;
            this.article_name = sessionStorage.current_article_name;
            if(this.token){
                this.get_special_list();
            }
        },
        methods:{
          get_special_list(){
            // 获取我管理的专题列表
            this.$axios.get(`${this.$settings.Host}/article/special/list/`,{
              params:{
                article_id: this.article_id,
              },
              headers:{
                Authorization: "jwt " + this.token,
              }
            }).then(response=>{
              this.my_special_list = response.data;
            }).catch(error=>{
              this.$message.error("对不起,获取专题列表失败!");
            });
          },
          article_post(special_id){
              // 文章投稿
              this.$axios.post(`${this.$settings.Host}/article/post/`,{
                  article_id: this.article_id,
                  special_id: special_id,
              },{
                  headers:{
                      Authorization: "jwt " + this.token,
                  }
              }).then(response=>{
                  // 更新收录状态
                  for(let special of this.my_special_list ){
                      if(special.id == special_id){
                          special.is_post = true;
                      }
                  }
                  this.$message.success("投稿成功!");
              }).catch(error=>{
                  this.$message.error("投稿失败!");
              })
          }
        }
    }
</script>

创建专题的测试数据, 把专题相关模型注册到adminx.py文件, 添加测试数据

# 专题测试数据
INSERT INTO renran.rr_special (id, orders, is_show, is_delete, created_time, updated_time, name, image, notice, article_count, follow_count, user_id) VALUES 
(1, 0, 1, 0, '2020-01-15 08:27:39.044094', '2020-01-15 08:27:39.044126', '相亲', 'group1/M00/00/00/wKj8k16Xsx2ASsq_AAAhSb9-85M7053496', '相亲相爱', 0, 0, 1),
(2, 1, 1, 0, '2020-01-15 08:29:15.513292', '2020-01-15 08:29:15.513346', '相爱', 'group1/M00/00/00/wKj8k16Xsx2ASsq_AAAhSb9-85M7053496', '相亲相爱', 0, 0, 1),
(3, 2, 1, 0, '2020-01-15 08:29:15.513292', '2020-01-15 08:29:15.513346', '篮球', 'group1/M00/00/00/wKj8k16Xsx2ASsq_AAAhSb9-85M7053496', '篮球', 0, 0, 1);


# 专题管理员
INSERT INTO renran.rr_special_manager (id, orders, is_show, is_delete, created_time, updated_time, special_id, user_id) VALUES 
(1, 0, 1, 0, '2020-01-15 08:35:28.645931', '2020-01-15 08:35:28.645962', 1, 1),
(2, 0, 1, 0, '2020-01-15 08:35:33.216625', '2020-01-15 08:35:33.216656', 2, 1),
(3, 0, 1, 0, '2020-01-15 08:35:37.345065', '2020-01-15 08:35:37.345094', 3, 1);

因为需要查找到当前登录所管理的专题列表,所以调整模型,增加关联字段:

class SpecialManager(BaseModel):
    """专题管理员"""
    user = models.ForeignKey(User,related_name="special_list", on_delete=models.DO_NOTHING, verbose_name="管理员")
    special = models.ForeignKey(Special,related_name="manager_list", on_delete=models.CASCADE, verbose_name="专题")

    class Meta:
        db_table = "rr_special_manager"
        verbose_name = "专题的管理员"
        verbose_name_plural = verbose_name

视图接口代码:

from .models import Special,SpecialArticle
from .serializers import SpecialModelSerializer
class SpecialListAPIView(ListAPIView):
    serializer_class = SpecialModelSerializer
    permission_classes = [IsAuthenticated]

    def list(self, request, *args, **kwargs):
        user = request.user
        queryset= Special.objects.filter(manager_list__user=user,manager_list__is_delete=False, manager_list__is_show=True).order_by("orders","-id")
        # 接受当前发布的文章ID,和每一个专题进行关系的判断,是否收录了当前文章
        article_id = request.query_params.get("article_id")
        for special in queryset:
            try:
                ret = SpecialArticle.objects.get(article_id=article_id,special=special)
                special.status = ret.status
            except SpecialArticle.DoesNotExist:
                special.status=-1 # 没有投稿/收录记录

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

序列化器,代码:

from .models import Special
class SpecialModelSerializer(serializers.ModelSerializer):
    """专题的序列化器"""
    status = serializers.IntegerField(label="收录状态")
    class Meta:
        model = Special
        fields = ["id","name","image","article_count","follow_count","status"]

路由,代码:

path("special/", views.SpecialListAPIView.as_view()),

客户在点击发布文章以后的投稿页面,需要显示发布界面。创建组件PostArticle.vue,页面代码如下:

<template>
    <div id="writed">
      <div class="_3PLTX">
        <div class="_2Mx1k">
          <div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>
          <ul class="zelSB">
            <li class="_35P4c"><i class="fa fa-weibo"></i>微博</li>
            <li class="_1c1Eo"><i class="fa fa-wechat"></i>微信</li>
            <li class="_1HWk1"><i class="fa fa-link"></i>复制链接</li>
            <li class="_3FrjS _3Qjz6 _2_WAp _2po2r cRfUr" title="">
              <span class="">更多分享</span>
            </li>
          </ul>
        </div>
        <div class="_3Q2EW" @click="$router.back()">×</div>
        <div class="_1s967"></div>
        <div class="_2w_E5">
          <div class="_23R_O">
            <div class="_1WCUC">
              <i class="fa fa-search fa-2x"></i><input type="text" placeholder="搜索专题">
            </div>
            <div class="_3dZoJ">向专题投稿,让文章被更多人发现</div>
          </div>
          <div>
            <div class="_18jMg">
              <h3>我管理的专题<a href="">新建</a></h3>
              <ul class="_1hEmG">
                <li v-for="special in my_special_list">
                  <a v-if="special.status==-1">收录</a>
                  <a v-else>已收录</a>
                  <img alt="png" :src="special.image">
                  <span class="_1CN24" :title="special.name">{{special.name}}</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>最近投稿</h3>
              <ul class="_1hEmG">
                <li>
                  <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                  <span class="_1CN24" title="摄影">摄影</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>推荐专题</h3>
              <div>
                <ul class="_1hEmG">
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                    <span class="_1CN24">摄影<em>154.8K篇文章,2575.1K人关注</em></span>
                    <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/95/1.jpg">
                    <span class="_1CN24">故事<em>192.2K篇文章,1920.7K人关注</em></span>
                    <a data-collection-id="95" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                </ul>
                <div class="_27pBl">没有更多了 </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
    export default {
        name: "PostArticle",
        data(){
           return {
             token: "",
             my_special_list:[],
             article_id: 0,     // 文章ID
             article_name:"",   // 文章标题
           }
        },
        created() {
            this.token = this.$settings.check_user_login(this);
            // 从本地存储中提取当前文章的ID和标题
            this.article_id   = sessionStorage.current_article_id;
            this.article_name = sessionStorage.current_article_name;
            this.get_my_special_list();
        },
        methods:{
          get_my_special_list(){
            // 获取我管理的专题列表
            this.$axios.get(`${this.$settings.Host}/article/special/`,{
              params:{
                // 需要发送当前文章ID到后端,方便判断专题和文章之间的绑定关系
                article_id: this.article_id,
              },
              headers:{
                Authorization: "jwt " + this.token,
              }
            }).then(response=>{
              this.my_special_list = response.data;
            }).catch(error=>{
              this.$message.error("对不起,获取专题列表失败!");
            });
          }
        }
    }
</script>

<style scoped>
::selection {
  color: #fff;
  background: #1890ff;
}
.writed{
  width: 100%;
  height: 100%;
  max-width: 100vw;
  max-height: 100vh;
  color: rgba(0,0,0,.65);
  font-size: 14px;
  font-variant: tabular-nums;
  line-height: 1.5;
}
.writed *{
  box-sizing: border-box;
}
._3PLTX{
      position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #fff;
    z-index: 1010;
    overflow-y: auto;
}
._3PLTX ._2Mx1k {
    background-color: #f2f2f2;
    padding-bottom: 110px;
}
._3PLTX ._2Mx1k ._3CoyQ {
    padding: 80px 0 40px;
    text-align: center;
}
._3PLTX ._2Mx1k ._3CoyQ ._2-ZiM {
    display: inline-block;
    height: 40px;
    font-size: 28px;
    font-weight: 500;
    color: #333;
    margin-bottom: 24px;
}
._3PLTX ._2Mx1k ._3CoyQ ._2ajaT {
    font-size: 16px;
    font-weight: 600;
    color: #42c02e;
}
._3PLTX ._2Mx1k ._3CoyQ ._2ajaT:before {
    content: "";
    display: inline-block;
    width: 18px;
    height: 10px;
    border: 3px solid #42c02e;
    border-width: 0 0 4px 4px;
    transform: rotate(-45deg);
    transition: 0s;
    position: relative;
    bottom: 4px;
    right: 8px;
}
._3PLTX ._2Mx1k .zelSB {
    text-align: center;
    color: #fff;
    font-size: 14px;
}
._3PLTX ._2Mx1k .zelSB>li {
    display: inline-block;
    width: 124px;
    line-height: 38px;
    border-radius: 100px;
    margin: 0 15px;
    cursor: pointer;
    padding: 0;
    text-align: center;
}
._3PLTX ._2Mx1k .zelSB li._35P4c {
    background-color: #e05244;
}
._3PLTX ._2Mx1k .zelSB>li i {
    margin-right: 5px;
}
._3PLTX ._2Mx1k .zelSB li._1c1Eo {
    background-color: #07b225;
}
._3PLTX ._2Mx1k .zelSB li._1HWk1 {
    background-color: #3194d0;
}
._2po2r {
    padding: 10px 20px;
    line-height: 20px;
    white-space: nowrap;
    text-align: left;
    position: relative;
    border-bottom: 1px solid #d9d9d9;
}
.cRfUr {
    border-bottom: 1px solid #d9d9d9;
}
._2po2r:last-child {
    border-radius: 0 0 4px 4px;
    border-bottom: 0;
}
._3PLTX ._2Mx1k .zelSB>li {
    display: inline-block;
    width: 124px;
    line-height: 38px;
    border-radius: 100px;
    margin: 0 15px;
    cursor: pointer;
    padding: 0;
    text-align: center;
}
._3PLTX ._2Mx1k .zelSB li._3Qjz6 {
    background-color: #a7a7a7;
    position: relative;
}
._3PLTX ._3Q2EW {
    position: fixed;
    top: 50px;
    right: 100px;
    font-size: 30px;
    font-weight: 700;
    padding: 5px;
    cursor: pointer;
}
._3PLTX ._1s967 {
    height: 40px;
    border-radius: 50% 50% 0 0/100% 100% 0 0;
    background-color: #fff;
    margin-top: -40px;
}
._3PLTX ._2w_E5 {
    margin: 40px auto 0;
    width: 700px;
    font-size: 14px;
}
._3PLTX ._2w_E5 ._23R_O {
    margin-bottom: 36px;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC {
    float: right;
    border: 1px solid #d9d9d9;
    position: relative;
    width: 200px;
    height: 34px;
    border-radius: 17px;
    padding: 5px 20px 5px 30px;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC i {
    position: absolute;
    left: 10px;
    top: 50%;
    margin-top: -8px;
    font-size: 16px;
    color: #ccc;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC input {
    line-height: 24px;
    height: 24px;
    width: 100%;
    font-size: 14px;
    background-color: transparent;
}
._3PLTX ._2w_E5 ._23R_O ._3dZoJ {
    font-size: 16px;
    font-weight: 500;
    line-height: 38px;
}
._3PLTX ._2w_E5 ._18jMg {
    position: relative;
    margin-bottom: 50px;
}
._3PLTX ._2w_E5 ._18jMg h3 {
    margin-bottom: 0;
    height: 40px;
    line-height: 40px;
    padding: 0 6px 0 14px;
    background-color: #f2f2f2;
    font-size: 14px;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg h3 a {
    margin-left: 15px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG {
    position: relative;
    margin: 1px 0 0 1px;
    zoom: 1;
    min-height: 72px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG:after, ._3PLTX ._2w_E5 ._18jMg ._1hEmG:before {
    content: " ";
    display: table;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li {
    float: left;
    width: 234px;
    border: 1px solid #f2f2f2;
    position: relative;
    margin: -1px 0 0 -1px;
    list-style-type: none;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li a {
    position: absolute;
    top: 24px;
    right: 15px;
}
img {
    vertical-align: middle;
    border-style: none;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li img {
    position: absolute;
    left: 15px;
    height: 40px;
    width: 40px;
    top: 15px;
    border-radius: 10%;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li ._1CN24 {
    display: block;
    font-weight: 700;
    color: #595959;
    width: 100%;
    padding: 0 60px 0 75px;
    line-height: 70px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC input {
  line-height: 24px;
  height: 24px;
  width: 100%;
  font-size: 14px;
  background-color: transparent;
  outline: none;
  border: 0;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC i {
    position: absolute;
    left: 10px;
    top: 50%;
    margin-top: -8px;
    font-size: 16px;
    color: #ccc;
}
._3PLTX ._2w_E5 ._23R_O ._1WCUC {
    float: right;
    border: 1px solid #d9d9d9;
    position: relative;
    width: 200px;
    height: 34px;
    border-radius: 17px;
    padding: 5px 20px 5px 30px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 {
    width: 49.85666666%;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li img {
    position: absolute;
    left: 15px;
    height: 40px;
    width: 40px;
    top: 15px;
    border-radius: 10%;
}
img {
    vertical-align: middle;
    border-style: none;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li ._1CN24 {
    display: block;
    font-weight: 700;
    color: #595959;
    width: 100%;
    padding: 0 60px 0 75px;
    line-height: 70px;
    overflow: hidden;
    -o-text-overflow: ellipsis;
    text-overflow: ellipsis;
    white-space: nowrap;
}
._1hEmG a{
  cursor: pointer;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 {
    display: block;
    padding: 18px 65px 16px;
    line-height: 1;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 em {
    font-weight: 400;
    font-style: normal;
    color: #999;
    display: block;
    margin-top: 8px;
    font-size: 12px;
}
._3PLTX ._2w_E5 a {
    color: #42c02e;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG li a {
    position: absolute;
    top: 24px;
    right: 15px;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG:after {
  clear: both;
  visibility: hidden;
  font-size: 0;
  height: 0;
}
._3PLTX ._27pBl {
    padding: 30px 0;
    text-align: center;
}
._3PLTX ._2w_E5 ._18jMg ._1hEmG ._3GDE6 ._1CN24 {
    display: block;
    padding: 18px 65px 16px;
    line-height: 1;
}
</style>

前端指定路由,代码:

import Vue from 'vue'

import PostArticle from "@/components/PostArticle";
Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    ,{
      path: "/post",
      name: 'PostArticle',
      component: PostArticle,
    },
  ]
})

在写文章页面组件中在用户发布文章以后,进行页面跳转。

<script>
    ....
        methods:{
          ....
            
          pub_article(){
              // 切换文章的发布状态
              let article = this.article_list[this.current_article];
              this.$axios.patch(`${this.$settings.Host}/article/public/${article.id}/`,{},{
                  headers:{
                      Authorization: "jwt "+this.token,
                  }
              }).then(response=>{
                  // 切换成功
                  if(article.pub_date || article.is_public){
                      // 取消发布
                      article.is_public=false;
                      article.pub_date=null;
                  }else{
                      // 立即发布
                      article.is_public=true;
                      // 进入发布页面
                      sessionStorage.current_article_id=article.id;
                      sessionStorage.current_article_name=article.name;
                      this.$router.push("/post");
                  }

                  // 关闭菜单
                  this.is_show_article_menu = false;
              }).catch(error=>{
                  this.$message.error("切换文章发布状态失败!");
              })
          },
          
        }
    }
</script>

客户端在页面加载成功以后,像服务端请求获取当前用户管理的专题列表。

实现文章向专题进行投稿的功能

服务端提供收录文章到我管理的专题中的接口

from .models import Special,SpecialArticle
class PostArticleAPIView(APIView):
    """文章投稿的api接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """文章投稿"""
        user = request.user
        article_id = request.data.get("article_id")
        special_id = request.data.get("special_id")

        # 验证文章是否存在
        try:
            article = Article.objects.get(user=user, pk=article_id)
        except Article.DoesNotExist:
            return Response({"message":"对不起, 当前文章不存在!"}, status=status.HTTP_400_BAD_REQUEST)

        # 验证专题是否存在
        try:
            special = Special.objects.get(pk=special_id)
        except Special.DoesNotExist:
            return Response({"message":"对不起, 当前专题不存在!"}, status=status.HTTP_400_BAD_REQUEST)

        # 判断当前文章是否向专题投稿
        try:
            special_article = SpecialArticle.objects.get(special=special, article=article)
            if special_article.status == 0 or special_article.status == 1:
                return Response({"message":"对不起, 当前文章已经投稿了,或在审核中!"}, status=status.HTTP_400_BAD_REQUEST)
            elif special_article.status == 2:
                return Response({"message":"对不起, 当前文章已经被收录,不能重复投稿!"}, status=status.HTTP_400_BAD_REQUEST)
            elif special_article.status == 3:
                """之前审核没通过,继续投稿"""
                special_article.status=1
                special_article.save()
                return Response({"message":"文章重新投稿成功!","status":1}, status=status.HTTP_200_OK)

        except SpecialArticle.DoesNotExist:
            special_article = SpecialArticle.objects.create(
                special=special,
                article=article,
                status=1,
            )

            if special.user == user:
                """如果当前投稿用户是当前专题的管理员,则默认跳过审核阶段"""
                special_article.status = 2
                special_article.user = user
                return Response({"message": "投稿成功!","status":2}, status=status.HTTP_200_OK)

            return Response({"message":"投稿成功!","status":1}, status=status.HTTP_200_OK)

urls.py路由:

    path("post/", views.PostArticleAPIView.as_view()),

前端发送ajax,请求投稿,代码:

<template>
    <div id="writed">
      <div class="_3PLTX">
        <div class="_2Mx1k">
          <div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>
          <ul class="zelSB">
            <li class="_35P4c"><i class="fa fa-weibo"></i>微博</li>
            <li class="_1c1Eo"><i class="fa fa-wechat"></i>微信</li>
            <li class="_1HWk1"><i class="fa fa-link"></i>复制链接</li>
            <li class="_3FrjS _3Qjz6 _2_WAp _2po2r cRfUr" title="">
              <span class="">更多分享</span>
            </li>
          </ul>
        </div>
        <div class="_3Q2EW" @click="$router.back()">×</div>
        <div class="_1s967"></div>
        <div class="_2w_E5">
          <div class="_23R_O">
            <div class="_1WCUC">
              <i class="fa fa-search fa-2x"></i><input type="text" placeholder="搜索专题">
            </div>
            <div class="_3dZoJ">向专题投稿,让文章被更多人发现</div>
          </div>
          <div>
            <div class="_18jMg">
              <h3>我管理的专题<a href="">新建</a></h3>
              <ul class="_1hEmG">
                <li v-for="special,key in my_special_list">
                  <a v-if="special.status==-1" @click="post_article(my_special_list,key)">收录</a>
                  <a v-else>已收录</a>
                  <img alt="png" :src="special.image">
                  <span class="_1CN24" :title="special.name">{{special.name}}</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>最近投稿</h3>
              <ul class="_1hEmG">
                <li>
                  <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                  <span class="_1CN24" title="摄影">摄影</span>
                </li>
              </ul>
            </div>
            <div class="_18jMg">
              <h3>推荐专题</h3>
              <div>
                <ul class="_1hEmG">
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/83/1.jpg">
                    <span class="_1CN24">摄影<em>154.8K篇文章,2575.1K人关注</em></span>
                    <a data-collection-id="83" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                  <li class="_3GDE6">
                    <img alt="png" src="https://upload.jianshu.io/collections/images/95/1.jpg">
                    <span class="_1CN24">故事<em>192.2K篇文章,1920.7K人关注</em></span>
                    <a data-collection-id="95" data-post-text="投稿" data-posting-text="投稿中" data-posted-text="等待审核">投稿</a>
                  </li>
                </ul>
                <div class="_27pBl">没有更多了 </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

文章详情页

在PostArticle.vue中打通跳转到文章详情页的链接:

<div class="_3CoyQ">
            <router-link :to="`/article/${article_id}`" class="_2-ZiM">{{article_name}}</router-link>
            <br>
            <router-link :to="`/article/${article_id}`" class="_2ajaT">发布成功,点击查看文章</router-link>
          </div>

在router/index.js中创建路由,代码:

import Vue from 'vue'
import Router from 'vue-router'
import Article from "@/components/Article";
Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    ,{
       name:"Article",
       path:"/article/:id",
       component: Article,
     },
  ]
})

创建Article.vue组件:

<template>
  <div class="_21bLU4 _3kbg6I">
   <Header></Header>
   <div class="_3VRLsv" role="main">
    <div class="_gp-ck">
     <section class="ouvJEz">
      <h1 class="_1RuRku">废掉一个人最快的方法,就是让他闲着</h1>
      <div class="rEsl9f">
       <div class="_2mYfmT">
        <a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer"><img class="_13D2Eh" src="https://upload.jianshu.io/users/upload_avatars/18529254/.png?imageMogr2/auto-orient/strip|imageView2/1/w/96/h/96/format/webp" alt="" /></a>
        <div style="margin-left: 8px;">
         <div class="_3U4Smb">
          <span class="FxYr8x"><a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer">書酱</a></span>
          <button data-locale="zh-CN" type="button" class="_3kba3h _1OyPqC _3Mi9q9 _34692-"><span>关注</span></button>
         </div>
         <div class="s-dsoj">
          <time datetime="2020-01-08T12:01:00.000Z">2020.01.08 20:01:00</time>
          <span>字数 2,510</span>
          <span>阅读 168</span>
         </div>
        </div>
       </div>
      </div>
      <article class="_2rhmJa">
       <div class="image-package">
        <div class="image-container" style="max-width: 640px; max-height: 420px; background-color: transparent;">
         <div class="image-container-fill" style="padding-bottom: 65.63%;"></div>
         <div class="image-view" data-width="640" data-height="420">
          <img src="https://upload-images.jianshu.io/upload_images/18529254-f62fac0d998cff23?imageMogr2/auto-orient/strip|imageView2/2/w/640/format/webp" />
         </div>
        </div>
        <div class="image-caption"></div>
       </div>
       <p>文/小鸟飞过</p>
       <p>罗曼&middot;罗兰说:“生活中最沉重的负担不是工作,而是无聊。”</p>
       <div class="image-package">
        <div class="image-container" style="max-width: 700px; max-height: 152px; background-color: transparent;">
         <div class="image-container-fill" style="padding-bottom: 14.069999999999999%;"></div>
         <div class="image-view" data-width="1080" data-height="152">
          <img src="http://upload-images.jianshu.io/upload_images/18529254-a932f0ad8fbd51bb?imageMogr2/auto-orient/strip|imageView2/2/w/1080/format/webp" />
         </div>
        </div>
        <div class="image-caption"></div>
       </div>
       <p><strong>废掉一个人最快的方法</strong></p>
       <p><strong>就是让他闲着</strong></p>
       <p>这段时间,综艺节目《妻子的浪漫旅行第三季3》正在热播,四对明星夫妻的相处模式曝光,也让观众更了解了曾经饱受争议的女人唐一菲。</p>
       <p>有人很喜欢她大大咧咧的女侠性格,有人为她叫屈,当然还是有人骂她,说她旧事重提。</p>
       <p>而我,则是觉得非常惋惜。</p>
       <p>唐一菲是中央戏剧学院表演系毕业,真正的科班出身。</p>
       <p>从2003年到2011年,基本保证每年都有作品,要么拍电视剧、要么拍电影,2008年出演新版《红楼梦》的秦可卿也是颇为动人。</p>
       <div class="image-package">
        <div class="image-container" style="max-width: 533px; max-height: 510px; background-color: transparent;">
         <div class="image-container-fill" style="padding-bottom: 95.67999999999999%;"></div>
         <div class="image-view" data-width="533" data-height="510">
          <img src="http://upload-images.jianshu.io/upload_images/18529254-d92ace292d78aecb?imageMogr2/auto-orient/strip|imageView2/2/w/533/format/webp" />
         </div>
        </div>
        <div class="image-caption"></div>
       </div>
       <p>可是自2012年结婚后,8年时间里,只拍了一部电视剧,就再也没了一点儿消息,仿佛整个人生都停滞了。</p>
       <p>她在《妻子3》中展现出的婚姻状态是非常可悲的。</p>
       <p>一喝酒,就是吐槽自己的人生被毁了。</p>
       <div class="image-package">
        <div class="image-container" style="max-width: 532px; max-height: 394px;">
         <div class="image-container-fill" style="padding-bottom: 74.06%;"></div>
         <div class="image-view" data-width="532" data-height="394">
          <img data-original-src="//upload-images.jianshu.io/upload_images/18529254-5f20af5bb10bfa12" data-original-width="532" data-original-height="394" data-original-format="image/jpeg" data-original-filesize="17915" data-image-index="3" style="cursor: zoom-in;" class="image-loading" />
         </div>
        </div>
        <div class="image-caption"></div>
       </div>
       <p>要么直接形容老公凌潇肃是缩头乌龟。</p>
       <div class="image-package">
        <div class="image-container" style="max-width: 506px; max-height: 360px;">
         <div class="image-container-fill" style="padding-bottom: 71.15%;"></div>
         <div class="image-view" data-width="506" data-height="360">
          <img data-original-src="//upload-images.jianshu.io/upload_images/18529254-f2478cdc59c7e193" data-original-width="506" data-original-height="360" data-original-format="image/jpeg" data-original-filesize="23772" data-image-index="4" style="cursor: zoom-in;" class="image-loading" />
         </div>
        </div>
        <div class="image-caption"></div>
       </div>
       <p>作者简介:小鸟飞过,富小书的人,富书专栏作者,写温暖的文字,传递美好的情感;本文首发富小书(ID:fxsfrc),你身边最好的闺蜜,富书2018重磅推出新书《好好生活》。</p>
       <p><strong>注:本文章图片来源网络,如有侵权,请联系删除。</strong></p>
      </article>
      <div></div>
      <div class="_1kCBjS">
       <div class="_18vaTa">
        <div class="_3BUZPB">
         <div class="_2Bo4Th" role="button" tabindex="-1" aria-label="给文章点赞">
          <i aria-label="ic-like" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-like"></use>
           </svg></i>
         </div>
         <span class="_1LOh_5" role="button" tabindex="-1" aria-label="查看点赞列表">8人点赞<i aria-label="icon: right" class="anticon anticon-right">
           <svg viewbox="64 64 896 896" focusable="false" class="" data-icon="right" width="1em" height="1em" fill="currentColor" aria-hidden="true">
            <path d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"></path>
           </svg></i></span>
        </div>
        <div class="_3BUZPB">
         <div class="_2Bo4Th" role="button" tabindex="-1">
          <i aria-label="ic-dislike" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-dislike"></use>
           </svg></i>
         </div>
        </div>
       </div>
       <div class="_18vaTa">
        <a class="_3BUZPB _1x1ok9 _1OhGeD" href="/nb/38290018" target="_blank" rel="noopener noreferrer"><i aria-label="ic-notebook" class="anticon">
          <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
           <use xlink:href="#ic-notebook"></use>
          </svg></i><span>随笔</span></a>
        <div class="_3BUZPB ant-dropdown-trigger">
         <div class="_2Bo4Th">
          <i aria-label="ic-others" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-others"></use>
           </svg></i>
         </div>
        </div>
       </div>
      </div>
      <div class="_19DgIp" style="margin-top:24px;margin-bottom:24px"></div>
      <div class="_13lIbp">
       <div class="_191KSt">
        &quot;小礼物走一走,来简书关注我&quot;
       </div>
       <button type="button" class="_1OyPqC _3Mi9q9 _2WY0RL _1YbC5u"><span>赞赏支持</span></button>
       <span class="_3zdmIj">还没有人赞赏,支持一下</span>
      </div>
      <div class="d0hShY">
       <a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer"><img class="_27NmgV" src="https://upload.jianshu.io/users/upload_avatars/18529254/.png?imageMogr2/auto-orient/strip|imageView2/1/w/100/h/100/format/webp" alt="  " /></a>
       <div class="Uz-vZq">
        <div class="Cqpr1X">
         <a class="HC3FFO _1OhGeD" href="/u/a70487cda447" title="書酱" target="_blank" rel="noopener noreferrer">書酱</a>
         <span class="_2WEj6j" title="你读书的样子真好看。">你读书的样子真好看。</span>
        </div>
        <div class="lJvI3S">
         <span>总资产0</span>
         <span>共写了78.7W字</span>
         <span>获得6,072个赞</span>
         <span>共1,308个粉丝</span>
        </div>
       </div>
       <button data-locale="zh-CN" type="button" class="_1OyPqC _3Mi9q9"><span>关注</span></button>
      </div>
     </section>
     <div id="note-page-comment">
      <div class="lazyload-placeholder"></div>
     </div>
    </div>
    <aside class="_2OwGUo">
     <section class="_3Z3nHf">
      <div class="_3Oo-T1">
       <a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer"><img class="_3T9iJQ" src="https://upload.jianshu.io/users/upload_avatars/18529254/.png?imageMogr2/auto-orient/strip|imageView2/1/w/90/h/90/format/webp" alt="" /></a>
       <div class="_32ZTTG">
        <div class="_2O0T_w">
         <div class="_2v-h3G">
          <span class="_2vh4fr" title="書酱"><a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer">書酱</a></span>
         </div>
         <button data-locale="zh-CN" type="button" class="tzrf9N _1OyPqC _3Mi9q9 _34692-"><span>关注</span></button>
        </div>
        <div class="_1pXc22">
         总资产0
        </div>
       </div>
      </div>
      <div class="_19DgIp"></div>
     </section>
     <div>
      <div class="">
       <section class="_3Z3nHf">
        <h3 class="QHRnq8 QxT4hD"><span>推荐阅读</span></h3>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="这些话没人告诉你,但必须知道的社会规则">
          <a class="_1-HJSV _1OhGeD" href="/p/a3e56a0559ff" target="_blank" rel="noopener noreferrer">这些话没人告诉你,但必须知道的社会规则</a>
         </div>
         <div class="_19haGh">
          阅读 5,837
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="浙大学霸最美笔记曝光:真正的牛人,都“变态”到了极致">
          <a class="_1-HJSV _1OhGeD" href="/p/d2a3724e2839" target="_blank" rel="noopener noreferrer">浙大学霸最美笔记曝光:真正的牛人,都“变态”到了极致</a>
         </div>
         <div class="_19haGh">
          阅读 12,447
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="征服一个女人最好的方式:不是讨好她,而是懂得去折腾她">
          <a class="_1-HJSV _1OhGeD" href="/p/f6acf67f039b" target="_blank" rel="noopener noreferrer">征服一个女人最好的方式:不是讨好她,而是懂得去折腾她</a>
         </div>
         <div class="_19haGh">
          阅读 5,311
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="告别平庸的15个小方法">
          <a class="_1-HJSV _1OhGeD" href="/p/cff7eb6b232b" target="_blank" rel="noopener noreferrer">告别平庸的15个小方法</a>
         </div>
         <div class="_19haGh">
          阅读 7,040
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="轻微抑郁的人,会说这3句“口头禅”,若你一个不占,偷着乐吧">
          <a class="_1-HJSV _1OhGeD" href="/p/2a0ca1729b4b" target="_blank" rel="noopener noreferrer">轻微抑郁的人,会说这3句“口头禅”,若你一个不占,偷着乐吧</a>
         </div>
         <div class="_19haGh">
          阅读 16,411
         </div>
        </div>
       </section>
      </div>
     </div>
    </aside>
   </div>
   <Footer></Footer>
  </div>
</template>

<script>
    import Header from "./common/Header";
    import Footer from "./common/Footer";
    export default {
        name: "Article",
        components:{
          Header,
          Footer,
        }
    }
</script>

<style scoped>
*,:after,:before {
	box-sizing: border-box
}

a:hover {
	color: #fa9e87
}

a:active {
	color: #c75342
}

a:active,a:hover {
	text-decoration: none;
	outline: 0
}

a[disabled] {
	color: rgba(0,0,0,.25);
	cursor: not-allowed;
	pointer-events: none
}

img {
	vertical-align: middle;
	border-style: none
}

svg:not(:root) {
	overflow: hidden
}
[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea {
	-ms-touch-action: manipulation;
	touch-action: manipulation
}

button,input,optgroup,select,textarea {
	margin: 0;
	color: inherit;
	font-size: inherit;
	font-family: inherit;
	line-height: inherit
}

button,input {
	overflow: visible
}

button,select {
	text-transform: none
}[type=reset],[type=submit],button,html [type=button] {
	-webkit-appearance: button
}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner {
	padding: 0;
	border-style: none
}

input[type=checkbox],input[type=radio] {
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	padding: 0
}

input[type=date],input[type=datetime-local],input[type=month],input[type=time] {
	-webkit-appearance: listbox
}

textarea {
	overflow: auto;
	resize: vertical
}

fieldset {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0
}

legend {
	display: block;
	width: 100%;
	max-width: 100%;
	margin-bottom: .5em;
	padding: 0;
	color: inherit;
	font-size: 1.5em;
	line-height: inherit;
	white-space: normal
}

progress {
	vertical-align: baseline
}

::selection {
	color: #fff;
	background: #ec7259
}

.anticon {
	display: inline-block;
	color: inherit;
	font-style: normal;
	line-height: 0;
	text-align: center;
	text-transform: none;
	vertical-align: -.125em;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale
}

.anticon>* {
	line-height: 1
}

.anticon svg {
	display: inline-block
}

.anticon:before {
	display: none
}

.anticon .anticon-icon {
	display: block
}

.anticon[tabindex] {
	cursor: pointer
}

._3Vh8Z9-info ._3Vh8Z9-notice-content .anticon,._3Vh8Z9-loading ._3Vh8Z9-notice-content .anticon {
	color: #0681d0
}

._3Vh8Z9-success ._3Vh8Z9-notice-content .anticon {
	color: #42c02e
}

._3Vh8Z9-warning ._3Vh8Z9-notice-content .anticon {
	color: #fa0
}

._3Vh8Z9-error ._3Vh8Z9-notice-content .anticon {
	color: #f50
}


._1OyPqC {
	position: relative;
	flex-shrink: 0;
	display: inline-flex;
	justify-content: center;
	align-items: center;
	border-radius: 50px;
	touch-action: manipulation;
	cursor: pointer;
	background-image: none;
	white-space: nowrap;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
	transition: all .2s cubic-bezier(.645,.045,.355,1);
	font-size: 14px;
	padding: 4px 12px;
	color: #969696;
	background-color: #fff;
	border: 1px solid #999
}

._1OyPqC+._1OyPqC,._1OyPqC>.anticon+span,._1OyPqC>span+.anticon {
	margin-left: 8px
}

._1OyPqC:focus,._1OyPqC:hover {
	color: #7d7d7d;
	background-color: #fff;
	border-color: #999
}

._1OyPqC:active {
	color: #636363;
	background-color: #fff;
	border-color: #999
}

body.reader-night-mode ._1OyPqC {
	color: #b3b3b3;
	background-color: #3d3d3d;
	border-color: #999
}

body.reader-night-mode ._1OyPqC:focus,body.reader-night-mode ._1OyPqC:hover {
	color: #ccc;
	background-color: #3d3d3d;
	border-color: #999
}

body.reader-night-mode ._1OyPqC:active {
	color: #e6e6e6;
	background-color: #3d3d3d;
	border-color: #999
}

._3Mi9q9,._3Mi9q9[disabled]:hover {
	color: #ec7259;
	background-color: #fff;
	border-color: #ec7259
}

._3Mi9q9:focus,._3Mi9q9:hover {
	color: #ec7259;
	background-color: #fef8f7;
	border-color: #ec7259
}

._3Mi9q9:active {
	color: #ec7259;
	background-color: #fdf1ee;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9,body.reader-night-mode ._3Mi9q9[disabled]:hover {
	color: #ec7259;
	background-color: #3d3d3d;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9:focus,body.reader-night-mode ._3Mi9q9:hover {
	color: #ec7259;
	background-color: #46403f;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9:active {
	color: #ec7259;
	background-color: #4f4240;
	border-color: #ec7259
}

._3Mi9q9._2SIRy5:before {
	content: "";
	position: absolute;
	border-radius: inherit;
	border: 0 solid #ec7259;
	animation: ZAhfCQ .3s ease-out forwards
}

._3Mi9q9._1YbC5u,._3Mi9q9._1YbC5u[disabled]:hover {
	color: #fff;
	background-color: #ec7259;
	border-color: #ec7259
}

._3Mi9q9._1YbC5u:focus,._3Mi9q9._1YbC5u:hover {
	color: #fff;
	background-color: #ed7961;
	border-color: #ec7259
}

._3Mi9q9._1YbC5u:active {
	color: #fff;
	background-color: #ee806a;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9._1YbC5u,body.reader-night-mode ._3Mi9q9._1YbC5u[disabled]:hover {
	color: #fff;
	background-color: #ec7259;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9._1YbC5u:focus,body.reader-night-mode ._3Mi9q9._1YbC5u:hover {
	color: #fff;
	background-color: #ed7961;
	border-color: #ec7259
}

body.reader-night-mode ._3Mi9q9._1YbC5u:active {
	color: #fff;
	background-color: #ee806a;
	border-color: #ec7259
}

._3tVfGA {
	color: #999
}

._3tVfGA hr {
	margin: 16px 0;
	border: none;
	border-top: 1px solid #eee
}

body.reader-night-mode ._3tVfGA hr {
	border-color: #2f2f2f
}

.PY53UF:hover>i {
	visibility: visible;
	opacity: 1
}

.PY53UF>span {
	margin-right: 4px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap
}

.PY53UF>i {
	font-size: 12px;
	visibility: hidden;
	opacity: 0
}


._3VRLsv {
	box-sizing: content-box;
	width: 1000px;
	padding-left: 16px;
	padding-right: 16px;
	margin-left: auto;
	margin-right: auto
}

._3Z3nHf,.ouvJEz {
	background-color: #fff;
	border-radius: 4px;
	margin-bottom: 10px
}

body.reader-night-mode ._3Z3nHf,body.reader-night-mode .ouvJEz {
	background-color: #3d3d3d
}

._3kbg6I {
	background-color: #f9f9f9
}

body.reader-night-mode ._3kbg6I {
	background-color: #2d2d2d
}

._3VRLsv {
	display: flex;
	justify-content: center;
	align-items: flex-start;
	min-height: calc(100vh - 66px);
	padding-top: 10px;
	font-size: 16px
}

._gp-ck {
	flex-shrink: 0;
	width: 730px;
	margin-bottom: 24px;
	margin-right: 10px
}

.ouvJEz {
	padding: 24px
}

._2OwGUo {
	flex-shrink: 0;
	width: 260px
}

._3Z3nHf {
	padding: 16px
}

.QxT4hD {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 16px;
	padding-left: 12px;
	border-left: 4px solid #ec7259;
	font-size: 18px;
	font-weight: 500;
	height: 20px;
	line-height: 20px
}

._3Fatyw>i {
	font-size: 18px;
	margin-right: 4px
}

.nnghRR>p {
	margin-bottom: 0
}


.LtPwLP>div {
	min-height: 100px;
	flex-grow: 1
}

.LtPwLP img {
	width: 150px;
	height: 100px;
	border-radius: 4px;
	border: 1px solid #f2f2f2;
	flex-shrink: 0
}

._3nj4GN>span {
	margin-left: 8px;
	line-height: 20px
}

._3nj4GN .anticon {
	font-size: 22px
}

.rEsl9f {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 32px;
	font-size: 13px
}

.s-dsoj {
	display: flex;
	color: #969696
}

.s-dsoj>:not(:last-child) {
	margin-right: 10px
}

._3tCVn5 i {
	margin-right: .5em
}

._2mYfmT {
	display: flex;
	align-items: center
}

._13D2Eh {
	display: block;
	border-radius: 50%;
	border: 1px solid #eee;
	min-width: 48px;
	min-height: 48px;
	width: 48px;
	height: 48px
}

body.reader-night-mode ._13D2Eh {
	border-color: #2f2f2f
}

._3U4Smb {
	display: flex;
	align-items: center;
	margin-bottom: 6px
}

.FxYr8x {
	font-size: 16px;
	font-weight: 500;
	margin-right: 8px
}

._3kba3h {
	padding: 2px 9px
}

._2rhmJa code,._2rhmJa pre,._2rhmJa pre[class*=language-] {
	font-family: Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;
	font-size: 12px
}

._2rhmJa {
	font-weight: 400;
	line-height: 1.8;
	margin-bottom: 20px
}


._2rhmJa h1,._2rhmJa h2,._2rhmJa h3,._2rhmJa h4,._2rhmJa h5,._2rhmJa h6 {
	margin-bottom: 16px
}

._2rhmJa h1 {
	font-size: 26px
}

._2rhmJa h2 {
	font-size: 24px
}

._2rhmJa h3 {
	font-size: 22px
}

._2rhmJa h4 {
	font-size: 20px
}

._2rhmJa h5 {
	font-size: 18px
}

._2rhmJa h6 {
	font-size: 16px
}

._2rhmJa p {
	margin-bottom: 20px;
	word-break: break-word
}

._2rhmJa hr {
	margin: 0 0 20px;
	border: 0;
	border-top: 1px solid #eee!important
}

body.reader-night-mode ._2rhmJa hr {
	border-color: #2f2f2f!important
}

._2rhmJa blockquote {
	padding: 20px;
	background-color: #fafafa;
	border-left: 6px solid #e6e6e6;
	word-break: break-word;
	font-size: 16px;
	font-weight: normal;
	line-height: 30px;
	margin: 0 0 20px
}

body.reader-night-mode ._2rhmJa blockquote {
	background-color: #595959;
	border-color: #262626
}

._2rhmJa blockquote h1:last-child,._2rhmJa blockquote h2:last-child,._2rhmJa blockquote h3:last-child,._2rhmJa blockquote h4:last-child,._2rhmJa blockquote h5:last-child,._2rhmJa blockquote h6:last-child,._2rhmJa blockquote li:last-child,._2rhmJa blockquote ol:last-child,._2rhmJa blockquote p:last-child,._2rhmJa blockquote ul:last-child {
	margin-bottom: 0
}

._2rhmJa blockquote .image-package {
	width: 100%;
	margin-left: 0
}

._2rhmJa ol,._2rhmJa ul {
	word-break: break-word;
	margin: 0 0 20px 20px
}

._2rhmJa ol li,._2rhmJa ul li {
	line-height: 30px
}

._2rhmJa ol li ol,._2rhmJa ol li ul,._2rhmJa ul li ol,._2rhmJa ul li ul {
	margin-top: 16px
}

._2rhmJa ol {
	list-style-type: decimal
}

._2rhmJa ul {
	list-style-type: disc
}

._2rhmJa code {
	padding: 2px 4px;
	border: none;
	vertical-align: middle;
	white-space: pre-wrap
}

._2rhmJa :not(pre) code {
	color: #c7254e;
	background-color: #f2f2f2
}

body.reader-night-mode ._2rhmJa :not(pre) code {
	background-color: #262626
}

._2rhmJa pre,._2rhmJa pre[class*=language-] {
	word-wrap: normal;
	word-break: break-all;
	white-space: pre;
	overflow-x: scroll;
	overscroll-behavior-x: contain;
	margin-top: 0;
	margin-bottom: 20px;
	border-radius: 4px;
	z-index: 0;
	padding: 1em;
	line-height: 1.5;
	color: #ccc;
	background: #2d2d2d
}

._2rhmJa pre[class*=language-] code,._2rhmJa pre code {
	padding: 0;
	background-color: transparent;
	color: inherit;
	white-space: pre;
	vertical-align: unset
}

._2rhmJa table {
	width: 100%;
	margin-bottom: 20px;
	border-collapse: collapse;
	border: 1px solid #eee;
	border-left: none;
	word-break: break-word
}

body.reader-night-mode ._2rhmJa table,body.reader-night-mode ._2rhmJa table td,body.reader-night-mode ._2rhmJa table th {
	border-color: #2f2f2f
}

._2rhmJa table td,._2rhmJa table th {
	padding: 8px;
	border: 1px solid #eee;
	line-height: 20px;
	vertical-align: middle
}

._2rhmJa table th {
	font-weight: bold
}

._2rhmJa table thead th {
	vertical-align: middle;
	text-align: inherit
}

._2rhmJa table tr:nth-of-type(2n) {
	background-color: hsla(0,0%,70.2%,.15)
}

._2rhmJa table .image-package {
	width: 100%;
	margin-left: 0
}

._2rhmJa img {
	max-width: 100%
}

._2rhmJa .image-package {
	width: 100%;
	margin: 0;
	padding-bottom: 25px;
	text-align: center;
	font-size: 0
}

._2rhmJa .image-package img {
	max-width: 100%;
	width: auto;
	height: auto;
	vertical-align: middle;
	border: 0
}

body.reader-night-mode ._2rhmJa .image-package img {
	opacity: .85
}

._2rhmJa .image-package .image-container {
	position: relative;
	z-index: 95;
	background-color: #e6e6e6;
	transition: background-color .1s linear;
	margin: 0 auto
}

body.reader-night-mode ._2rhmJa .image-package .image-container {
	background-color: #595959
}

._2rhmJa .image-package .image-container-fill {
	z-index: 90
}

._2rhmJa .image-package .image-container .image-view {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	overflow: hidden
}

._2rhmJa .image-package .image-container .image-view-error {
	cursor: pointer;
	color: grey
}

body.reader-night-mode ._2rhmJa .image-package .image-container .image-view-error {
	color: #b3b3b3
}

._2rhmJa .image-package .image-container .image-view-error:after {
	content: "\56FE\7247\83B7\53D6\5931\8D25\FF0C\8BF7\70B9\51FB\91CD\8BD5";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100%;
	transform: translate(-50%,-50%);
	color: inherit;
	font-size: 14px
}

._2rhmJa .image-package .image-container .image-view img.image-loading {
	opacity: .3
}

._2rhmJa .image-package .image-container .image-view img {
	transition: all .15s linear;
	z-index: 95;
	opacity: 1
}

._2rhmJa .image-package .image-caption {
	min-width: 20%;
	max-width: 80%;
	min-height: 43px;
	display: inline-block;
	padding: 10px;
	margin: 0 auto;
	border-bottom: 1px solid #eee;
	font-size: 13px;
	color: #999
}

._2rhmJa .image-package .image-caption:empty {
	display: none
}

body.reader-night-mode ._2rhmJa .image-package .image-caption {
	border-color: #2f2f2f
}

._2rhmJa .math-block[mathimg="1"] {
	display: block;
	margin: 1em auto
}

._2rhmJa .math-inline[mathimg="1"] {
	display: inline;
	margin: 0 3px;
	vertical-align: middle
}

._2rhmJa .math-block[mathimg="1"],._2rhmJa .math-inline[mathimg="1"] {
	max-width: 100%
}

body.reader-night-mode ._2rhmJa .math-block[mathimg="1"],body.reader-night-mode ._2rhmJa .math-inline[mathimg="1"] {
	filter: invert(.8)
}

._3GbnS5 {
	padding: 0;
	line-height: 1.5;
	position: relative;
	width: 100%;
	height: 1px;
	margin: 20px 0;
	border: none;
	border-top: #b3b3b3;
	display: table;
	white-space: nowrap;
	text-align: center
}

._3GbnS5:after,._3GbnS5:before {
	content: "";
	display: table-cell;
	position: relative;
	top: 50%;
	left: 0;
	width: 50%;
	border-top: 1px solid;
	border-top-color: inherit;
	transform: scaleY(.5) translateY(50%);
	transform-origin: 50% 50% 0;
	transform-origin: initial
}

._2Lt-af {
	display: inline-block;
	padding: 0 12px;
	font-size: 14px;
	font-weight: normal;
	text-align: center;
	white-space: nowrap;
	color: #b3b3b3;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none
}

._2Lt-af>a {
	margin-left: .5em
}

._19DgIp {
	width: 100%;
	height: 1px;
	margin: 16px 0;
	background-color: #eee
}

body.reader-night-mode ._19DgIp {
	background-color: #2f2f2f
}

._1kCBjS {
	justify-content: space-between;
	font-size: 14px;
	color: #969696;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none
}

._1kCBjS,._3BUZPB,._18vaTa {
	display: flex;
	align-items: center
}

._3BUZPB>span {
	margin-left: 8px
}

._3BUZPB:not(:last-child) {
	margin-right: 12px
}

._2Bo4Th {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	color: #969696;
	border: 1px solid #eee;
	border-radius: 50%;
	font-size: 18px;
	cursor: pointer
}

body.reader-night-mode ._2Bo4Th {
	border-color: #2f2f2f
}


._1LOh_5 {
	cursor: pointer
}

._1LOh_5 .anticon {
	font-size: 12px
}

._1x1ok9 {
	cursor: pointer
}

._1x1ok9 .anticon {
	font-size: 16px
}

._1yN79W {
	background-color: #f2f2f2
}

._1yN79W:-ms-input-placeholder {
	color: #999
}

._1yN79W::-ms-input-placeholder {
	color: #999
}

._1yN79W::placeholder {
	color: #999
}

body.reader-night-mode ._1yN79W {
	background-color: #333
}

._3uZ5OL {
	text-align: center;
	padding: 48px 64px;
  ext-align: center;
  padding: 48px 64px;
  width: 50%;
  position: fixed;
  top: 0;
  height: 540px;
  border-radius: 5px;
  left: 0;
  right: 0;
  bottom: 0;
  background: #eee;
  z-index: 999;
  margin: auto;
}

._2PLkjk {
	display: flex;
	justify-content: center;
	align-items: center;
	margin-bottom: 24px
}

._2R1-48 {
	min-width: 50px;
	min-height: 50px;
	width: 50px;
	height: 50px;
	border-radius: 50%;
	border: 1px solid #eee
}

._2h5tnQ {
	font-size: 24px;
	font-weight: 500;
	margin-left: 16px
}

._1-bCJJ {
	flex-wrap: wrap
}

._1-bCJJ,.LMa6S_ {
	display: flex;
	justify-content: center
}

.LMa6S_ {
	align-items: center;
	width: 162.5px;
	height: 56px;
	font-size: 16px;
	color: #969696;
	margin-bottom: 12px;
	margin-right: 12px;
	border-radius: 10px;
	border: 1px solid #eee;
	cursor: pointer;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none
}

body.reader-night-mode .LMa6S_ {
	border-color: #2f2f2f
}

.LMa6S_._1vONvL {
	color: #ec7259
}

.LMa6S_._1vONvL,body.reader-night-mode .LMa6S_._1vONvL {
	border-color: #ec7259
}

.LMa6S_._1sSZ6C {
	cursor: not-allowed;
	color: #969696;
	opacity: .5
}

.LMa6S_>i {
	font-size: 20px
}

.LMa6S_>span {
	font-size: 28px;
	font-style: italic
}

.LMa6S_:nth-child(3n) {
	margin-right: 0
}

.LMa6S_:nth-last-child(-n+3) {
	margin-bottom: 0
}

.LMa6S_:last-child {
	margin-right: 0
}

._2ByDWa>span {
	font-size: 16px;
	font-style: normal;
	opacity: 1
}

._2ByDWa>input {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100%;
	height: 36px;
	margin: 0 auto;
	text-align: center;
	transform: translate(-50%,-50%);
	background-color: transparent;
	opacity: 0;
	cursor: pointer
}

._2ByDWa>input::-webkit-inner-spin-button,._2ByDWa>input::-webkit-outer-spin-button {
	display: none
}

._2ByDWa._1vONvL>span {
	opacity: 0
}

._2ByDWa._1vONvL>input {
	opacity: 1;
	cursor: text
}

._3PA8BN>i {
	font-size: 30px
}

._3PA8BN>span {
	font-size: 16px;
	font-style: normal;
	margin-left: 4px
}

._3PA8BN,._3PA8BN._1vONvL {
	color: #404040
}

body.reader-night-mode ._3PA8BN,body.reader-night-mode ._3PA8BN._1vONvL {
	color: #b3b3b3
}

._1yN79W {
	display: block;
	width: 100%;
	height: 80px;
	resize: none;
	margin-top: 12px;
	padding: 12px;
	border: none;
	border-radius: 10px
}

._1_B577 {
	font-size: 15px;
	margin: 12px 0
}

._3A-4KL {
	margin-top: 24px;
	font-size: 18px;
	font-weight: normal;
	padding: 10px 48px
}

.d0hShY {
	display: flex;
	align-items: center;
	background-color: #fafafa;
	border-radius: 4px;
	padding: 12px 16px
}

body.reader-night-mode .d0hShY {
	background-color: #333
}

._27NmgV {
	border-radius: 50%;
	border: 1px solid #eee;
	min-width: 50px;
	min-height: 50px;
	width: 50px;
	height: 50px
}

body.reader-night-mode ._27NmgV {
	border-color: #2f2f2f
}

.Uz-vZq {
	flex-grow: 1;
	margin: 0 12px;
	overflow: hidden
}

.Cqpr1X {
	display: flex;
	align-items: center;
	margin-bottom: 2px
}

.HC3FFO {
	flex-shrink: 0;
	font-size: 16px;
	font-weight: 500
}
._3GlyHK,.HC3FFO {
	margin-right: 6px
}
._2WEj6j {
	font-size: 14px;
	color: #666;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap
}
.lJvI3S {
	font-size: 14px;
	color: #969696
}
.lJvI3S>span {
	margin-right: 12px
}
.lJvI3S>span:last-child {
	margin-right: 0
}
._3MbC71>span {
	margin-right: 6px
}
._14FSyQ,.H4XBOO>img {
	width: 24px;
	height: 24px;
	min-width: 24px;
	min-height: 24px;
	border-radius: 50%;
	border: 2px solid #fff
}
body.reader-night-mode .H4XBOO>img {
	border-color: #3d3d3d
}
._13lIbp {
	display: flex;
	flex-direction: column;
	align-items: center;
	margin: 40px 0 32px
}

._191KSt {
	font-size: 16px;
	font-weight: 500;
	margin-bottom: 16px
}
._3zdmIj {
	color: #666;
	margin-top: 24px
}

._37OvKa>i {
	color: #ec7259;
	font-size: 20px;
	margin-right: 8px
}


._3S34Y_>img {
	width: 144px;
	height: 144px;
	margin-bottom: 12px
}

._2JdSds>span {
	margin-left: 2px;
	pointer-events: none
}

._3yPTTQ>i {
	font-size: 16px;
	margin-right: 4px
}

</style>

在当前页面中查询当前文章的基本内容

服务端视图中提供API接口

from rest_framework.generics import RetrieveAPIView
from .serializers import ArticleInfoModelSerializer
class ArticleInfoAPIView(RetrieveAPIView):
    """文章详情信息"""
    serializer_class = ArticleInfoModelSerializer
    queryset = Article.objects.filter(is_public=True)

序列化器代码:

from users.models import User
class AuthorModelSerializer(serializers.ModelSerializer):
    """文章作者"""
    class Meta:
        model = User
        fields = ["id","nickname","avatar"] # 自己编写需要显示的字段即可

from .models import ArticleCollection
class CollectionInfoModelSerializer(serializers.ModelSerializer):
    """文集信息"""
    class Meta:
        model = ArticleCollection
        fields = ["id","name"] # 自己编写需要显示的字段即可

class ArticleInfoModelSerializer(serializers.ModelSerializer):
    user = AuthorModelSerializer()
    collection = CollectionInfoModelSerializer()
    class Meta:
        model = Article
        fields = [
            "name", "render","content", "user",
            "collection", "updated_time",
            "read_count", "like_count",
            "collect_count", "comment_count",
            "reward_count",
        ]

路由代码:

    re_path("^(?P<pk>\d+)/$", views.ArticleInfoAPIView.as_view()),

客户端代码:

<template>
  <div class="_21bLU4 _3kbg6I">
   <Header></Header>
   <div class="_3VRLsv" role="main">
    <div class="_gp-ck">
     <section class="ouvJEz">
      <h1 class="_1RuRku">{{article.name}}</h1>
      <div class="rEsl9f">
       <div class="_2mYfmT">
        <router-link to="" class="_1OhGeD"><img class="_13D2Eh" :src="article.user.avatar" alt="" /></router-link>
        <div style="margin-left: 8px;">
         <div class="_3U4Smb">
          <span class="FxYr8x"><a class="_1OhGeD" href="">{{article.user.nickname}}</a></span>
          <button data-locale="zh-CN" type="button" class="_3kba3h _1OyPqC _3Mi9q9 _34692-"><span>关注</span></button>
         </div>
         <div class="s-dsoj">
          <time :datetime="article.updated_time">{{article.updated_time|timeformat}}</time>
          <span>字数 {{article.content.length}}</span>
          <span>阅读 {{article.read_count}}</span>
         </div>
        </div>
       </div>
      </div>
      <article class="_2rhmJa" v-html="article.render">
      </article>
      <div></div>
      <div class="_1kCBjS">
       <div class="_18vaTa">
        <div class="_3BUZPB">
         <div class="_2Bo4Th" role="button" tabindex="-1" aria-label="给文章点赞">
          <i aria-label="ic-like" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-like"></use>
           </svg></i>
         </div>
         <span class="_1LOh_5" role="button" tabindex="-1" aria-label="查看点赞列表">8人点赞<i aria-label="icon: right" class="anticon anticon-right">
           <svg viewbox="64 64 896 896" focusable="false" class="" data-icon="right" width="1em" height="1em" fill="currentColor" aria-hidden="true">
            <path d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"></path>
           </svg></i></span>
        </div>
        <div class="_3BUZPB">
         <div class="_2Bo4Th" role="button" tabindex="-1">
          <i aria-label="ic-dislike" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-dislike"></use>
           </svg></i>
         </div>
        </div>
       </div>
       <div class="_18vaTa">
        <a class="_3BUZPB _1x1ok9 _1OhGeD" href="/nb/38290018" target="_blank" rel="noopener noreferrer"><i aria-label="ic-notebook" class="anticon">
          <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
           <use xlink:href="#ic-notebook"></use>
          </svg></i><span>随笔</span></a>
        <div class="_3BUZPB ant-dropdown-trigger">
         <div class="_2Bo4Th">
          <i aria-label="ic-others" class="anticon">
           <svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
            <use xlink:href="#ic-others"></use>
           </svg></i>
         </div>
        </div>
       </div>
      </div>
      <div class="_19DgIp" style="margin-top:24px;margin-bottom:24px"></div>
      <div class="_13lIbp">
       <div class="_191KSt">
        &quot;小礼物走一走,来简书关注我&quot;
       </div>
       <button type="button" class="_1OyPqC _3Mi9q9 _2WY0RL _1YbC5u"><span>赞赏支持</span></button>
       <span class="_3zdmIj">还没有人赞赏,支持一下</span>
      </div>
      <div class="d0hShY">
       <a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer"><img class="_27NmgV" src="https://upload.jianshu.io/users/upload_avatars/18529254/.png?imageMogr2/auto-orient/strip|imageView2/1/w/100/h/100/format/webp" alt="  " /></a>
       <div class="Uz-vZq">
        <div class="Cqpr1X">
         <a class="HC3FFO _1OhGeD" href="/u/a70487cda447" title="書酱" target="_blank" rel="noopener noreferrer">書酱</a>
         <span class="_2WEj6j" title="你读书的样子真好看。">你读书的样子真好看。</span>
        </div>
        <div class="lJvI3S">
         <span>总资产0</span>
         <span>共写了78.7W字</span>
         <span>获得6,072个赞</span>
         <span>共1,308个粉丝</span>
        </div>
       </div>
       <button data-locale="zh-CN" type="button" class="_1OyPqC _3Mi9q9"><span>关注</span></button>
      </div>
     </section>
     <div id="note-page-comment">
      <div class="lazyload-placeholder"></div>
     </div>
    </div>
    <aside class="_2OwGUo">
     <section class="_3Z3nHf">
      <div class="_3Oo-T1">
       <a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer"><img class="_3T9iJQ" src="https://upload.jianshu.io/users/upload_avatars/18529254/.png?imageMogr2/auto-orient/strip|imageView2/1/w/90/h/90/format/webp" alt="" /></a>
       <div class="_32ZTTG">
        <div class="_2O0T_w">
         <div class="_2v-h3G">
          <span class="_2vh4fr" title="書酱"><a class="_1OhGeD" href="/u/a70487cda447" target="_blank" rel="noopener noreferrer">書酱</a></span>
         </div>
         <button data-locale="zh-CN" type="button" class="tzrf9N _1OyPqC _3Mi9q9 _34692-"><span>关注</span></button>
        </div>
        <div class="_1pXc22">
         总资产0
        </div>
       </div>
      </div>
      <div class="_19DgIp"></div>
     </section>
     <div>
      <div class="">
       <section class="_3Z3nHf">
        <h3 class="QHRnq8 QxT4hD"><span>推荐阅读</span></h3>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="这些话没人告诉你,但必须知道的社会规则">
          <a class="_1-HJSV _1OhGeD" href="/p/a3e56a0559ff" target="_blank" rel="noopener noreferrer">这些话没人告诉你,但必须知道的社会规则</a>
         </div>
         <div class="_19haGh">
          阅读 5,837
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="浙大学霸最美笔记曝光:真正的牛人,都“变态”到了极致">
          <a class="_1-HJSV _1OhGeD" href="/p/d2a3724e2839" target="_blank" rel="noopener noreferrer">浙大学霸最美笔记曝光:真正的牛人,都“变态”到了极致</a>
         </div>
         <div class="_19haGh">
          阅读 12,447
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="征服一个女人最好的方式:不是讨好她,而是懂得去折腾她">
          <a class="_1-HJSV _1OhGeD" href="/p/f6acf67f039b" target="_blank" rel="noopener noreferrer">征服一个女人最好的方式:不是讨好她,而是懂得去折腾她</a>
         </div>
         <div class="_19haGh">
          阅读 5,311
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="告别平庸的15个小方法">
          <a class="_1-HJSV _1OhGeD" href="/p/cff7eb6b232b" target="_blank" rel="noopener noreferrer">告别平庸的15个小方法</a>
         </div>
         <div class="_19haGh">
          阅读 7,040
         </div>
        </div>
        <div class="cuOxAY" role="listitem">
         <div class="_3L5YSq" title="轻微抑郁的人,会说这3句“口头禅”,若你一个不占,偷着乐吧">
          <a class="_1-HJSV _1OhGeD" href="/p/2a0ca1729b4b" target="_blank" rel="noopener noreferrer">轻微抑郁的人,会说这3句“口头禅”,若你一个不占,偷着乐吧</a>
         </div>
         <div class="_19haGh">
          阅读 16,411
         </div>
        </div>
       </section>
      </div>
     </div>
    </aside>
   </div>
   <Footer></Footer>
  </div>
</template>

<script>
    import Header from "./common/Header";
    import Footer from "./common/Footer";
    export default {
        name: "Article",
        data(){
            return {
                token: "",
                article_id: 0,
                article: {
                    user:{},
                    collection:{},
                },
            }
        },
        created(){
            this.token = this.$settings.check_user_login(this);
            this.article_id = this.$route.params.id;
            this.get_article();
        },
        filters:{
            timeformat(time){
                return time.split(".")[0].replace("T"," ")
            }
        },
        methods:{
            get_article(){
                // 获取文章信息
                this.$axios.get(`${this.$settings.Host}/article/${this.article_id}/`).then(response=>{
                    this.article = response.data;
                }).catch(error=>{
                    this.$message.error("当前文章已删除!");
                    this.$router.go(-1);
                });
            }
        },
        components:{
          Header,
          Footer,
        }
    }
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值