REST 框架包含了处理ViewSet的抽象,这样开发者就可以专注于API的状态和交互,而不用去管URL的构造,URL会按照
公共约定自动构造。
ViewSet类和View类差不多,不同的是ViewSet提供如read,update等方法,而不是get或是put
一个ViewSet类只绑定一组方法处理程序,当它被实例化为一组views时,通常用一个Router类来处理复杂的url。

重构代码以使用ViewSets

首先将我们现有的UserListUserDetail重构合并为UserViewSet
编辑views.py

from rest_framework import viewsets


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    这个ViewSet提供`list`和`detail`两个功能
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

这里我们使用的ReadOnlyModelViewSet类会提供默认的只读操作。
像以前一样,我们依然定义querysetserializer_class属性,只不过之前需要在两个类里面定义,现在只需要定义一遍。

接下来我们将现有的SnippetList, SnippetDetail, SnippetHighlight重构合并为SnippetViewSet
编辑views.py阅读全文 “Django REST framework 学习纪要 Tutorial 6 ViewSets & Routers”

目前我们使用主键来表示模型之间的关系。在本章,我们将提高API的凝聚性和可读性。

为我们API的根节点创建URL

之前我们给snippetsusers创建了URL接口,但我们没有一个根节点的URL。
在此我们创建一个简单的,基于函数的views,并为它加上@api_view装饰器,修改snippets/views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse


@api_view(['GET'])
def api_root(request, format=None):
    return Response({
        'users': reverse('user-list', request=request, format=format),
        'snippets': reverse('snippet-list', request=request, format=format)
    })

需要注意两点:
* 我们使用REST框架中的reverse方法来返回完全符合规则的url
* url参数将会与我们之后在snippets/urls中定义的相同

编写snippets/urls.py阅读全文 “Django REST framework 学习纪要 Tutorial 5 Relationships & Hyperlinked APIs”

目前为止,我们的代码没有限制谁可以编辑和删除代码片段,此节我们需要实现以下功能
* 代码片段需要与创建者关联
* 只有通过验证的用户才能创建代码片段
* 只有创建者才能修改或删除代码片段
* 没有通过验证的用户拥有只读权限

给model添加字段

我们需要添加两个字段,一个用于存储代码片段的创建者信息,一个用于存储代码的高亮信息

    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
    owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
    highlighted = models.TextField()

同时,我们需要在该模型类执行保存操作时,自动填充highlighted字段,使用pygments库。
首先,导入一些包

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight

然后为Snippet重写父类的save方法

    def save(self, *args, **kwargs):
        """
        use the 'pygments' library to create a highlighted HTML
        representation of code snippet
        """
        lexer = get_lexer_by_name(self.language)
        linenos = self.linenos
阅读全文 “Django REST framework 学习纪要 Tutorial 4 Authentication & Permissions”

基于类的views

之前我们创建的views都是基于函数的,我们也可以基于类来写views

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class SnippetList(APIView):
    """
    list all snippets, or create a new snippet
    """
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data,
阅读全文 “Django REST framework 学习纪要 Tutorial 3 Class-based Views”

Request 对象

REST 框架引入了Request对象,继承于HttpRequest,相比HttpRequest提供了更多请求解析,最核心的功能是request.data属性,类似于request.POST,以下是不同之处。
* request.POST
1. 只能处理form表单数据;
2. 只能处理POST请求。
* request.data
1. 能够处理任意一种数据;
2. 能够处理POST、PUT、PATCH请求

Response对象

REST框架也引入了Response对象,它是一个TemplateResponse类型,能够将未处理的文本转换为合适的类型返回给客户端

return Response(data)

状态码

REST框架提供了更可读的状态信息,比如HTTP_400_BAD_REQUEST

API views封装

  • 对于函数views,可以使用@api_view装饰器
  • 对于类views,可以继承于APIView

views应用

  • 修改snippets/views.py
阅读全文 “Django REST framework 学习纪要 Tutorial 2 Requests and Responses”

依赖

  • Python 3.6.3 [ Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6) 都可以 ]
  • Django 1.11.7 [ Django (1.10, 1.11, 2.0 alpha) 都可以 ]

安装、创建并配置虚拟环境

mkdir django_rest_framework && cd django_rest_framework
pyenv virtualenv 3.6.3 django_rest_framework
pyenv local django_rest_framework
  • 安装相关包
pip install django djangorestframework
pip install pygments  # 项目中会用到,提供代码高亮功能

Django项目初始化

  • 创建tutorial项目与snippets应用
django-admin startproject tutorial
cd tutorial/

python manage.py
阅读全文 “Django REST framework 学习纪要 Tutorial 1 Serialization”

环境

CentOS-7-x86_64-Minimal-1708

Pyenv介绍

  • 可以实现多版本Python并存
  • 使用插件后,可以为不同的项目创建不同的虚拟环境

Pyenv安装

  • 安装依赖
yum -y install gcc git zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel
  • 下载pyenv源代码
git clone git://github.com/yyuu/pyenv.git ~/.pyenv
  • 添加环境变量
cat << "EOF" >> ~/.bashrc
export PYENV_ROOT="${HOME}/.pyenv"

if [ -d "${PYENV_ROOT}" ]; then
  export PATH="${PYENV_ROOT}/bin:${PATH}"
  eval "$(pyenv init -)"
fi
EOF

source ~/.bashrc
阅读全文 “Python版本管理工具 Pyenv的安装与使用”

0 环境

CentOS-7-x86_64-Minimal-1708

1 部署环境

CentOS-7-x86_64-Minimal-1708
阿里云下载源:https://mirrors.aliyun.com/centos/7.4.1708/isos/x86_64/CentOS-7-x86_64-Minimal-1708.iso

2 系统环境初始化

解决yum包无法正常安装和无法正常ssh的问题

vi /etc/sysconfig/network-scripts/ifcfg-ens33

ONBOOT=no改为ONBOOT=yes
(文件名不一定为ifcfg-ens33,不同的机器可能不一样,一般是以ifcfg开头的。)

重启网络

systemctl restart network

无法使用ifconfig查看IP

yum install net-tools

3 部署内容

部署说明

环境部署较为繁琐,因而写了个自动化部署环境的脚本。

由于MySQL服务器较为不稳定,因而用yum install --downloadonly命令将安装mysql所需的rpm包下了下来,放在了required_rpms文件夹内,和脚本放在了一起,在脚本中会自动调用。

shell脚本的内容都上传至了GitHub,但所需的MySQL的rpm包因为文件过大(部分文件超过了100M无法上传),所以gitignore掉了,把脚本的完整内容放在了百度网盘,大家直接在上一步初始化好的环境下运行即可。

自动化部署脚本下载地址

(下载地址可能会变,如若收藏请收藏文章链接,脚本下载链接如果改变会及时更新)
链接:https://pan.baidu.com/s/1gf4ETbl阅读全文 “个人技术博客项目开发纪要__1 环境部署”

环境

CentOS-7-x86_64-Minimal-1708

开发原因

  • 现有博客基于Hexo&Github,想搭建一个自己全栈开发的博客
  • 用于实验新技术
  • 阿里云买了得用起来

技术栈

  • 下述版本号为待定,但如果使用其它版本的话只会用更新的
  • 如有用到其它技术会及时更新下表
工具 版本 用途
Docker 17.06.2 开发环境容器化
Python 3.6.3 后端开发语言
Django 1.11.7 后端框架
Html/CSS/JS / 前端开发语言
jQuery 3.2.1 前端框架
Bootstrap 3.3.7 前端框架
Celery 4.1.0 异步任务
django-celery-beat 1.0.1 定时任务
Gunicorn 19.7.1
阅读全文 “个人技术博客项目开发纪要__序”

环境

Ubuntu 16.04

Python 3.5.2

问题

现有一个生成1-5随机数的函数random_5(概率平均),如何将此转换为生成1-7随机数random_7的函数(概率平均),不得使用random模块

思路一(False)

直接将random_5生成的随机数乘以7/5后再通过round函数进行四舍五入后输出

random_5输出 random_7输出
1 1
2 3
3 4
4 6
5 7

特别糟糕的想法…

思路二(False)

生成两次random_5,将两者的值相加后减一(random_5 + random_5 - 1),得出随机数1-9,而后再做一次判断,将8和9剔除掉,只在返回1-7的时候输出

不过很快就发现,只有在两次random_5都返回1的时候,才会返回1,概率远小于返回其它六个数

又是一个糟糕的想法…

思路三(True)


* 通过之前的两种思路,可以总结出将random_5返回的数据经过各种处理后不筛选返回1-7是不可能实现的(不能说不可能,只是我个人能力有限,暂时还没想出方法),那必须采用思路二中的筛选方法。
* 确定要使用筛选方法之后,目标就变成了生成等概率的、值取值范围大于1-7的随机数。
* 相加和返回值乘系数的方法都尝试过了,那么是否可以将两者结合一下呢。
* 首先思考乘系数,random_5 * 2 - 1的返回结果是[1, 3, 5, 7, 9],想要等概率生成1-10的话,比如再将此返回值加上随机生成的0和1,也就是random.randint(0,阅读全文 “将生成1-5随机数函数转换为1-7随机数函数的实现方法及其进阶”