美文网首页初见
Django REST Framework 后端开发

Django REST Framework 后端开发

作者: Xtuphe | 来源:发表于2020-05-19 16:12 被阅读0次

环境安装:

安装新版python

# 查看python版本
$ python -V

建议安装最新版,看网上有些方法装下来的python版本也不是最新的,可以去官网查看最新版安装链接,下载后解压,安装。

# 下载
$ wget https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
# 解压
$ tar zxvf Python-3.8.3.tgz
$ cd Python-3.8.3/  
# 配置
$ ./configure
# pip是python的包管理软件,如果没有的话需安装
$ yum -y install python-pip

DRF默认用SQLite作为数据库,公司的centos服务器没有SQLite需要安装

# 安装SQLite
$ yum install sqlite-devel

(optional)为了使包配置独立于其他的项目,可以创建一个虚拟环境

$ python3 -m venv env
$ source env/bin/activate

要退出虚拟环境,在任意地方deactivate即可

$ deactivate
# 安装Django
$ pip install django
# 安装DRF
$ pip install djangorestframework

创建项目

# 创建项目
$ django-admin startproject 项目名
# 创建app
$ python manage.py startapp forum

然后需要在项目下settings.py中修改已安装的app

INSTALLED_APPS = [
    ...
    'rest_framework',
    'forum',
]

打🐎

创建模型

# models.py
class Article(models.Model):
    title = models.CharField(max_length=100, default='')
    content = models.TextField(default='')
    created = models.DateTimeField(auto_now_add=True)
    last_modify_date = models.DateTimeField(auto_now=True)
    author = models.TextField()
    dingId = models.TextField(default='lost')
    avatar = models.TextField(default='0')
    type = models.TextField(default='0')
    likes = models.IntegerField(default=0)
    comments = models.IntegerField(default=0)
    reports = models.IntegerField(default=0)
    selected = models.BooleanField(default=False)
    deleted = models.BooleanField(default=False)

    class Meta:
        db_table = 'article'

模型迁移至数据库

$ python manage.py makemigrations snippets
$ python manage.py migrate
# 将会在SQLite建立名为article的表

序列化,将实例转化为json

# serializers.py
from rest_framework import serializers
from forum.models import Article
class ArticleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = '__all__' 
        # fields = ('id', 'title', 'content', 'last_modify_date', 'created')

接口Views

# views.py
from rest_framework import viewsets
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

短短这几行就实现了增删改查,真是十分好用

Router

# urls.py
from rest_framework.routers import DefaultRouter
from forum import views


forumPrefix = 'api/forum/'
forumRouter = DefaultRouter()
forumRouter.register('article', views.ArticleViewSet)
forumRouter.register('comment', views.CommentViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path(forumPrefix, include(forumRouter.urls)),
]

运行

一切准备就绪,此时cd到项目根目录,然后访问http://127.0.0.1:8000/api/forum/ 就可以看到新写的接口了,推荐用Postman测试

$ python manage.py runserver

Validating models...

0 errors found
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

如果需要在服务器上长期运行:

$ nohup python3 manage.py runserver 0.0.0.0:8000 > out.log 2>&1 &
# 查看输出
$ tail -f out.log

参数过滤

安装requests

$ pip install requests

安装django-url-filter
安装django-filter

$ pip install django-filter
$ pip install django-url-filter
# views
from url_filter.integrations.drf import DjangoFilterBackend


class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    filter_backends = [DjangoFilterBackend]
    filter_fields = ['selected', 'deleted', 'reports', 'type']

比如我想筛选用户A点赞数为5到10的文章,前端可以直接把筛选条件拼在url后,十分好用!

.../forum/articles/?author=A&likes__range=5,10

详细的使用说明在:https://django-url-filter.readthedocs.io/en/latest/

排序

# views
from rest_framework import filters
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    filter_backends = [filters.OrderingFilter, DjangoFilterBackend]
    filter_fields = ['selected', 'deleted', 'reports', 'type']
    ordering_fields = ('id', 'created', 'last_modify_date')

比如要按创建时间倒序排列

.../forum/articles/?ordering=-create

真好用!详细说明在:https://www.django-rest-framework.org/api-guide/filtering/

@action为viewsets添加更多功能


class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    filter_backends = [filters.OrderingFilter, DjangoFilterBackend, filters.SearchFilter]
    ordering_fields = ('id', 'created', 'last_modify_date')
    filter_fields = ['selected', 'deleted', 'reports', 'type']
    search_fields = ['id', 'title', 'content']
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    @action(detail=True, method=['GET'])
    # detail=False时,对所有集合产生效果,method默认为GET可省略
    def like(self, request, pk=None):
        article = self.get_object()
        article.likes += 1
        article.save()
        return Response(article.likes)

修改viewset的CURD方法

class UserViewSet(viewsets.ViewSet):
  
    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

跨域

由于我之前没接触过后端开发,跨域可真是恶心死我了,看网上有说用corsheaders的,我试了不太好使,也有说自己写一个middleware的,然后按网上的说法我上线后新款iPhone跟模拟器都没问题,但剩下的90%的设备还是存在跨域问题,最终发现,Access-Control-Allow-Methods不能为*

在app下新建middlewares.py

# middlewares.py
from django.utils.deprecation import MiddlewareMixin


class MiddleWare(MiddlewareMixin):
    def process_response(self, request, response):
        response['Access-Control-Allow-Origin'] = "*"
        if request.method == 'OPTIONS':
            response['Access-Control-Allow-Methods'] = "POST, GET, DELETE, OPTIONS, DELETE"
            response['Access-Control-Max-Age'] = 1728000
            response["Access-Control-Allow-Headers"] = "Content-Type, x-requested-with"
            return response

        return response

修改settings

# settings.py
MIDDLEWARE = [
    ...
    'forum.middlewares.MiddleWare',
]

Token

安装Simple JWT

$ pip install djangorestframework-simplejwt

在setting中添加默认鉴权类

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}

在urls.py添加对外接口

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

创建超级用户

$ python manage.py createsuperuser
# 更改密码
$ python manage.py changepassword [<username>]

用curl获取token

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "davidattenborough", "password": "boatymcboatface"}' \
  http://localhost:8000/api/token/

...
{
  "access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU",
  "refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"
}

返回的两个token,access默认5分钟过期,过期后用refresh刷新,refresh默认1天过期,可以在settings修改过期时间

# Django project settings.py

from datetime import timedelta

...

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1)
}

详细使用方法:
https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html

Settings 中Debug改为false后static文件404

正式发布时,Debug是要改为false的,否则系统会把所有的请求缓存到内存上,造成进程占用的内存越来越大,而debug=false后,DRF管理界面css样式就获取不到了

简单粗暴的解决方式是

$ python3 manage.py runserver --insecure

这样做和debug=true时类似,效率十分低,且有安全隐患
https://docs.djangoproject.com/en/3.0/ref/contrib/staticfiles/#module-django.contrib.staticfiles

我看了半天,最后的处理方法是发布前collectstatic收集静态文件,把整个文件夹丢到服务器上,修改setting里STATIC_URL为服务器上文件夹存放的目录

$ python3 manage.py collectstatic

其他

# settings.py
# 修改时区
TIME_ZONE = 'Asia/Shanghai'
# 全局分页
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 5  # 每页数目
}
# 设置Shell共享库位置
$ export LD_LIBRARY_PATH="/usr/local/lib"
# 使设置生效
$ source ~/.bashrc

相关文章

网友评论

    本文标题:Django REST Framework 后端开发

    本文链接:https://www.haomeiwen.com/subject/uekbohtx.html