Django前后端分离开发-新闻管理系统(二)

项目源码下载:https://github.com/Cherish-sun/NEWS/tree/master

一、Models数据结构

数据表结构

二、创建模型 models.py

# Create your models here.
from django.db import models
import datetime
from django.contrib.auth.models import User
from DjangoUeditor.models import UEditorField
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token


class Category(models.Model):
    title = models.CharField(max_length=20, verbose_name='名称', help_text="大类")

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['title']
        verbose_name = '新闻类别'
        verbose_name_plural = verbose_name


class Item(models.Model):
  title = models.CharField(max_length=20, verbose_name='名称', help_text="名称")
  created_date = models.DateTimeField(default=datetime.datetime.now, verbose_name='创建时间', help_text="创建时间")
  completed = models.BooleanField(default=False, verbose_name='是否完成', help_text="是否完成")
  categorys = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items', help_text="大类")

  def __str__(self):
      return self.title

  class Meta:
      ordering = ['title']
      verbose_name = '新闻子栏目'
      verbose_name_plural = verbose_name


class Tag(models.Model):
    name = models.CharField(max_length=50, verbose_name=u'名称', help_text="名称")
    slug = models.SlugField(max_length=50, verbose_name=u'描述')

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['id']
        verbose_name = '标签'
        verbose_name_plural = verbose_name


class Article(models.Model):
    title = models.CharField(max_length=100, verbose_name='标题', help_text="名称")
    slug = models.SlugField(unique_for_year='publish_date', verbose_name='描述')
    # author = models.CharField(max_length=100, verbose_name='作者', help_text="作者")
    author = models.ForeignKey(User, related_name='author', on_delete=models.CASCADE, verbose_name='作者', help_text="作者")
    # content = models.TextField(verbose_name='内容')
    content = UEditorField(u'内容', height=400, width=600, default='', imagePath="upload/",
                       toolbars='mini', filePath='upload/', blank=True)
    status = models.CharField(max_length=2, verbose_name='状态', help_text="状态")
    tags = models.ManyToManyField(Tag, related_name='tags', blank=True, help_text="标签")
    publish_date = models.DateTimeField(default=datetime.datetime.now(), verbose_name='发布日期', help_text="发布日期")
    expiration_date = models.DateTimeField(blank=True, null=True, verbose_name='有效日期', help_text="有效日期")
    is_active = models.BooleanField(default=True, blank=True, verbose_name='是否热门', help_text="是否热门")
    item = models.ForeignKey(Item, related_name='item', on_delete=models.CASCADE, verbose_name='类别名称', help_text="类别名称")
    pic = models.ImageField(upload_to='uploads', verbose_name='图片', help_text="图片")
    praise_num = models.IntegerField(default=0, verbose_name='点赞', help_text="点赞")
    read_num = models.IntegerField(default=0, verbose_name='浏览数', help_text="浏览数")
    fav_num = models.IntegerField(default=0, verbose_name='收藏数', help_text="收藏数")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '新闻文章'
        verbose_name_plural = verbose_name


class Ad(models.Model):
    title = models.CharField(max_length=50, verbose_name='标题', help_text="标题")
    pic = models.ImageField(upload_to='uploads', verbose_name='广告图', help_text="广告图")
    adurl = models.URLField(verbose_name='地址', help_text="地址")
    adlocation = models.CharField(max_length=2, verbose_name='位置', help_text="位置")  # a1,a2,a3,b1,b2,b3....
    status = models.CharField(max_length=1, default=1, verbose_name='状态', help_text="状态")


class UserFav(models.Model):
    """
    用户收藏
    """
    user = models.ForeignKey(User, related_name='user', on_delete=models.CASCADE, verbose_name="用户")
    articles = models.ForeignKey(Article, related_name='articles', on_delete=models.CASCADE, verbose_name="文章",
                             help_text="文章id")
    add_time = models.DateTimeField(default=datetime.datetime.now, verbose_name=u"添加时间")

    class Meta:
        verbose_name = '用户收藏'
        verbose_name_plural = verbose_name
        unique_together = ("user", "articles")

    def __str__(self):
        return self.user.username

按住Ctrl+Alt+l 快捷键可以将代码格式化

二、安装DjangoUeditor,富文本编辑器

下载地址:https://github.com/wsf31325909/DjangoUeditor

解压后,把DjangoUeditor文件夹拷贝到项目目录下面

注意:直接pip install DjangoUeditor的方法会出问题

settings.py中添加app
INSTALLED_APPS = [
    'DjangoUeditor',
]

三、数据库迁移 , 打开pycharm底端Terminal依次输入以下迁移命令

python manage.py makemigrations  # 迁移到我们数据库
python manage.py migrate # 同步到数据库
python manage.py createsuperuser # 创建超级用户, 根据提示输入用户名、邮箱、密码,用于django后台管理系统登陆
迁移成功

四、后台管理系统admin.py配置

from django.contrib import admin
from .models import *


# Register your models here.
class ArticleAdmin(admin.ModelAdmin):
    # 列表显示字段
    list_display = ('title', 'item', 'status', 'author', 'publish_date',
                'expiration_date', 'is_active')

    list_filter = ('author', 'status', 'is_active', 'publish_date',
               'expiration_date')
    # 每页记录数
    list_per_page = 25
    # 查询字段
    search_fields = ('title', 'tags', 'slug', 'content')

    class Media:
        js = ('/static/ueditor/ueditor.config.js', '/static/ueditor/ueditor.all.min.js',)


class TagAdmin(admin.ModelAdmin):
    list_display = ('name', 'article_count')

    def article_count(self, obj):
        return Article.objects.filter(tag=obj).count()


class CategoryAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'item_count')

    def item_count(self, obj):
        # return obj.item_set.count()
        return Item.objects.filter(categorys=obj).count()


class ItemAdmin(admin.ModelAdmin):
    list_display = ('title', 'created_date', 'categorys', 'completed')


class AdAdmin(admin.ModelAdmin):
    list_display = ('title', 'pic', 'adurl', 'adlocation', 'status')


admin.site.register(Category, CategoryAdmin)
admin.site.register(Item, ItemAdmin)
admin.site.register(Tag, TagAdmin)
admin.site.register(Article, ArticleAdmin)
admin.site.register(Ad, AdAdmin)

这时运行程序,浏览器依次打开 http://127.0.0.1:8000/和http://127.0.0.1:8000/admin,如下图,说明以上配置成功,后台管理界面可以添加一些分类等测试数据

运行结果

admin

五、创建序列化器serializers

serializers是一个数据转换器,序列化主要是处理输入数据和输出数据(序列化输出、反序列化输入)

将复杂的数据结构与json或者xml这个格式互相转换
实例对象 <=> 原生数据类型 <=> JSON(XML)
User <=> b'{"name": 1}' <=> {"name": 1}

• serializers有以下几个作用:

1、将queryset与model实例等进行序列化,转化成json格式,返回给用户(api接口)。
2、将post与patch/put的上来的数据进行验证。
3、对post与patch/put数据进行处理。
* 推荐用ModelSerializer继承了Serializer的相关功能,是对model实现序列化的封装(代码少)

序列化详细介绍:http://www.careeru.cn/blog/article/?id=85
进入article目录下创建serilaizes.py文件

# -*- coding: utf-8 -*-
"""
@version: v1.0
@author: wyq
@license: Apache Licence
@contact: 976367613@qq.com
@site:
@software: PyCharm
@file: serilaizes.py
@time: 2019/3/1 16:48
"""
from rest_framework import serializers
from django.contrib.auth.models import User, Group
from .models import Category, Item, Tag, Article, Ad, UserFav
from rest_framework.validators import UniqueValidator, UniqueTogetherValidator  # 序列化验证
from rest_framework.compat import authenticate  # 权限验证


# user序列化类 继承ModelSerializer
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定模型名称
        model = User
        # 指定需要字段,全部用"__all__"
        fields = "__all__"
    # fields = ('url', 'username', 'email', 'groups')


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')


# 分类
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = "__all__"


# 实现新闻类别增加类别下面的栏目数据,采用自定义字段方法实现
class CategoryitemsSerializer(serializers.ModelSerializer):
    # 通过SerializerMethodField增加新字段值
    items = serializers.SerializerMethodField()

    class Meta:
        model = Category
        fields = "__all__"

    # 在序列化对象里添加自定义内容 函数名为:# 方法写法:get_ + 字段
    def get_items(self, obj):
        items = Item.objects.filter(categorys=obj.id)
        if items:
            items_serializer = ItemnocateSerializer(items, many=True, context={'request': self.context['request']})
            return items_serializer.data


class CategoryStringSerializer(serializers.ModelSerializer):
    # 用__str__方法表示只读关系 items 为外键关系中的related_name
    items = serializers.StringRelatedField(many=True)

    class Meta:
        model = Category
        # fields = ('id', 'title','items')
        fields = "__all__"


class CategoryPrimaryKeySerializer(serializers.ModelSerializer):
    # 用主键表示关系
    items = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Category
        fields = "__all__"


class CategorySlugSerializer(serializers.ModelSerializer):
    # 选取关系对象中任意一个字段(唯一标识)表示关系
    items = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='title'
    )

    class Meta:
        model = Category
        fields = "__all__"


# 子栏目
class ItemSerializer(serializers.ModelSerializer):
    # 正向嵌套
    categorys = CategorySerializer()

    class Meta:
        model = Item
        fields = "__all__"


class ItemnocateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = "__all__"


# 按serializers来序列化
class TagSerializer(serializers.ModelSerializer):
    # id = serializers.Field()
    name = serializers.CharField(required=True, max_length=100)
    slug = serializers.CharField(required=True, max_length=100)

    class Meta:
        model = Tag
        fields = ('id', 'name', 'slug')


class AdSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ad
        fields = "__all__"


class ArticleSerializer(serializers.ModelSerializer):
    # 外键相关对象
    item = ItemSerializer()
    author = UserSerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Article
        fields = "__all__"


class Hot_articleSerializer(serializers.ModelSerializer):
    item = ItemSerializer()
    author = UserSerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Article
        fields = "__all__"


class ArticlemodelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = "__all__"


class UserDetailSerializer(serializers.ModelSerializer):
    """
    用户详情序列化类
    """
    token = serializers.CharField(required=False, max_length=1024)

    class Meta:
        model = User
        fields = "__all__"


class UserRegSerializer(serializers.ModelSerializer):
    username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,
                                 validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])

    password = serializers.CharField(
    style={'input_type': 'password'}, help_text="密码", label="密码", write_only=True,
)
    token = serializers.CharField(required=False, max_length=1024)

    class Meta:
        model = User
        fields = ('username', 'password', 'token')


class UserLoginSerializer(serializers.ModelSerializer):
    """
    用户登录序列化类
    """
    username = serializers.CharField(required=True, max_length=100)
    password = serializers.CharField(required=True, max_length=100)
    token = serializers.CharField(required=False, max_length=1024)

    # attrs 为封装后的request
    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')

        if username and password:
            # 用户名称、密码登录验证
            user = authenticate(request=self.context.get('request'),
                            username=username, password=password)
            # The authenticate call simply returns None for is_active=False
            # users. (Assuming the default ModelBackend authentication
        # backend.)

            if not user:
                msg = '不能登录'
                raise serializers.ValidationError(msg, code='authorization')
        else:
            msg = '必须输入同时输入名称和密码'
            raise serializers.ValidationError(msg, code='authorization')

        attrs['user'] = user
        return attrs

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'token')


class UserSetPasswordSerializer(serializers.ModelSerializer):
    username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False)

    password = serializers.CharField(
    style={'input_type': 'password'}, help_text="密码", label="密码", write_only=True,
)
    newpassword = serializers.CharField(
    style={'input_type': 'password'}, help_text="新密码", label="新密码", write_only=True,
)

    # 验证用户名、密码是否正确
    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')

        if username and password:
            # 用户名称、密码登录验证
            user = authenticate(request=self.context.get('request'),
                            username=username, password=password)
            # The authenticate call simply returns None for is_active=False
            # users. (Assuming the default ModelBackend authentication
            # backend.)

            if not user:
                msg = '不能修改'
                raise serializers.ValidationError(msg, code='authorization')
        else:
            msg = '必须输入同时输入名称和密码'
            raise serializers.ValidationError(msg, code='authorization')

        attrs['user'] = user
        return attrs

    class Meta:
        model = User
        fields = ('username', 'password', 'newpassword')


class UserFavDetailSerializer(serializers.ModelSerializer):
    articles = ArticleSerializer()

    class Meta:
        model = UserFav
        fields = ('articles', 'id')


class UserFavSerializer(serializers.ModelSerializer):
    # 隐藏字段
    user = serializers.HiddenField(
    default=serializers.CurrentUserDefault()
)

    class Meta:
        model = UserFav
        validators = [
            UniqueTogetherValidator(
            queryset=UserFav.objects.all(),
            fields=('articles', 'user'),
            message="已经收藏"
        )
    ]

        fields = ('user', 'articles', 'id')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚...
    riverstation阅读 2,054评论 0 8
  • (一)、启动服务器 (二)、创建数据库表 或 更改数据库表或字段 Django 1.7.1及以上 用以下命令 1....
    夏天夏星阅读 5,594评论 0 17
  • Django 准备 “虚拟环境为什么需要虚拟环境:到目前位置,我们所有的第三方包安装都是直接通过 pip inst...
    33jubi阅读 1,313评论 0 5
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,688评论 0 10
  • 一、Django框架前言知识: 1、C/S和B/S的区别: C/S结构软件:客户端/服务端软件,即客户端要自己下载...
    月下独酌123阅读 4,472评论 0 36