用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo

写完了写完了


先说明当前开发的版本

python-->3.6.2

django -->2.0.4

djangorestframework-->3.8.2

django-rest-framework-mongoengine-->3.3.1

mongoengine-->0.15.0

mongo-->3.6.4

操作系统为deepin 15.5beta(操作系统随意,只是我在windows下无法使用uwsgi,如果会的朋友希望你能告诉我方法

postman 6.0.4

pycharm-community 2017.1-1


安装请善用project interpreter


首先创建python空项目,名字随意

创建完成之后,在命令行里cd创建的目录,然后输入

django-admin.py startproject demo .

注意后面的点,表示在此目录下新建,若没有也行,只是会多一层目录

其中这个demo是项目名,可以更改

若windows情况下报错,可以在python目录内找到django-admin.py这个文件,然后将它复制到你的项目根目录,然后命令行输入(大概,具体忘了

python django-admin.py startproject demo .

成功之后能看见新生成的文件

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第1张图片

之后创建应用,依旧在命令行输入,这次不需要加点

django-admin.py startapp service

成功之后

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第2张图片

现在打开demo目录下的settings.py

在  INSTALLED_APPS 中插入

'rest_framework',
'service.apps.ServiceConfig',
'rest_framework_mongoengine',

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第3张图片

其中 1和3 是restful和mongo app的导入

2 是在应用app目录下的apps.py 下的类名

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第4张图片

然后 settings.py 中继续添加代码:

from mongoengine import connect
connect('test')

其中 test 是数据库库名,不用提前创建

这样数据库的连接就弄好了,就两行代码

然后把 settings.py 中的  DATABASES 写成:

DATABASES = {
    'default': {
        'ENGINE': None,
    }
}

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第5张图片

最后把 ALLOWED_HOSTS修改成:

ALLOWED_HOSTS = ['*']

这里意思是允许任何ip访问,当然不想的朋友也能够自己写允许访问的ip

然后打开 service 目录下的 models.py ,这里是定义数据表结构的类,这里我们简单弄弄:

import mongoengine

class User(mongoengine.Document):
    # 默认id
    # 名字,字符串字段,最大长度36位,默认字符KirisameMarisa,允许为空
    name = mongoengine.StringField(max_length=36, default='KirisameMarisa')
    # 年龄,整型字段,最大长度5,不允许位空
    age = mongoengine.IntField(max_length=5, null=False)

    # 更多字段请百度

然后在 service 目录下新建 serializers.py

from .models import User
from rest_framework_mongoengine import serializers as mongo_serializers

# 名字随意
class UserSerializer(mongo_serializers.DocumentSerializer):
    class Meta:
        # 对应类名
        model = User
        # 各个字段,其中_id是默认id字段
        fields = ('id', 'name', 'age')

然后在 service 目录下 views.py 添加代码(views是写数据传入后要执行的操作):

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import User
from .serializers import UserSerializer

# 规定该方法只能通过post、get和delete请求
@api_view(['POST', 'GET', 'DELETE'])

# request就是你的请求
def user_api(request):

    # 如果请求是get
    if request.method == 'GET':

        # 获取user表全部的用户
        users = User.objects.all()

        # 将获取结果序列化,当many=True的时候才允许返回多条数据,不然报错
        serializer = UserSerializer(users, many=True)

        # serializer.data是一个字典,status是状态码,2XX是成功返回
        return Response(serializer.data, status=status.HTTP_200_OK)

    # 如果请求是post
    elif request.method == 'POST':

        # request.data也是一个字典,有兴趣可以 print(request.data)
        serializer = UserSerializer(data=request.data)

        # 如果数据符合规定,字符长度之类的
        if serializer.is_valid():

            # 保存
            serializer.save()

            # 同上
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        # 如果不符合规定
        return Response(status=status.HTTP_400_BAD_REQUEST)

    # 如果是delete请求
    elif request.method == 'DELETE':

        # 删除全部用户
        User.objects.all().delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

# 同上
@api_view(['GET', 'PUT', 'DELETE'])

# name是参数,这不是我常用的方法,仅仅是和大家说有这样的用法
def another_user_api(request, username):

    # 同上
    if request.method == 'GET':

        # 获取单个用户,其中name是字段名,username是参数
        # user = User.objects.get(name=username)

        # 由于我在models中没写不允许字段重复,所有get方法当有字段重复时会报错
        # filter就是根据条件查找,first很容易理解,就是第一条数据
        user = User.objects.filter(name=username).first()

        # 将结果序列化,不需要many=True
        serializer = UserSerializer(user)

        # 同上
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    # put一般是修改
    elif request.method == 'PUT':
        
        # 同上
        user = User.objects.filter(name=username).first()
        
        # 同上,request.data是传入的要修改的新数据
        # 先把要修改的那条数据从数据库中获取,然后修改数据,保存
        serializer = UserSerializer(user, data=request.data)
        
        # 同样要检查数据合法性
        if serializer.is_valid():
            
            # 合法
            serializer.save()
            return Response(serializer.data, status=status.HTTP_202_ACCEPTED) 
        
        # 不合法
        return Response(status=status.HTTP_400_BAD_REQUEST)
    
    elif request.method == 'DELETE':

        # 同上
        user = User.objects.filter(name=username).first()
        
        # 删除
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

写的很详细了注释

随后在 service 目录下创建 urls.py ,并写上:

from django.conf.urls import url
from . import views

urlpatterns = [
    # 定义url,移动端通过这个url访问服务端
    url(r'^users/$', views.user_api),
    # username就是之前views中another_user_api方法中的参数
    url(r'^users/(?P[A-Za-z0-9]+)/$', views.another_user_api)
]

demo 目录的 urls.py 修改:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 前面没必要添加,导入service.urls
    url(r'^', include('service.urls'))
]

以上两个文件注意目录

这时候我们的服务器已经可以使用了

在命令行中进入有 manage.py 的目录,输入

python manage.py runserver

默认使用的是本机8000端口,若被使用,请参考下面

若成功,顺利打开服务器

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第6张图片

无视我的python3.6

若是在公网中布置,出于安全考虑先把 settings.py 中的 DEBUGALLOWED_HOSTS 修改成:

DEBUG = False

然后命令行要这样写(或者8000端口被占用也可以这样写换成其他端口)

python manage.py runserver 0.0.0.0:XXXX

其中XXXX是开放端口

成功开启之后打开postman调试,在postman能使用的在android中也能使用,IOS应该也可以只是我没开发过不清楚

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第7张图片

注意 GET 方法 

ip地址+端口+在urls中定义好的地段就是访问服务端的url,注意"/"也不能漏

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第8张图片

这个挺好理解的吧,指定的url访问指定的方法

若是访问成功,在命令行中有响应信息


2XX是访问成功,400是请求错误,500是服务器错误

插入数据看看

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第9张图片

注意 POST 请求,Body就像是模拟请求数据,就像网页表单中的

访问成功下面就有返回信息

我们在添加一条,让两条数据不一样,然后获取全部数据看看返回

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第10张图片

可以看到,旧的数据在上面,新的数据在下面,虽然id不是整型,但是也可以用来排序

修改 views.py 代码,让返回结果变成根据 id 降序排列:

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第11张图片

users = User.objects.all().order_by('-id')

postman再次查询所有用户

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第12张图片

和之前返回的数据不一样,新的在上旧的在下

将请求换成 DELETE 会删除所有用户

现在测试另一个URL

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第13张图片

请注意URL,后面带中文就报错,换成英文就没事,我们增添一个name为英文的用户试试

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第14张图片

这时我们缺省了 name 字段,系统会自动填充在 models.py 定义好的字符串

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第15张图片

现在再次测试URL

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第16张图片

返回我们刚添加的用户,至于为什么会这样,因为


至于怎么解决,我几乎不会使用这样的URL,所以我没想过怎么解决,有需要的朋友可以扩展思维

现在修改这条数据,把年龄改成23

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第17张图片

删除也是可以运行的,不展示了


接下来写 uwsgi+nginx 的简单简单超简单的教程,不需要的可以跳过

至于怎么样安装请百度

现在我们复制一份我们刚才的项目到一个新建文件夹,名字随意,我的是 django_demo_1

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第18张图片

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第19张图片

现在修改其中一个项目的 views.py ,让其中一个项目按升序输出所有用户,另一个降序输出所有用户

项目A views.py


项目B views.py



在项目A目录下新建 start.ini 配置文件

# start.ini file
[uwsgi]
# 项目运行的端口
http = 127.0.0.1:8001
# 在app加载前切换到该目录,设置为Django项目根目录,manage.py所在目录
chdir = /media/aikoyanye/hdd/workspace/python/django_demo
# 加载指定的python WSGI模块,设置为Django项目的wsgi文件,wsgi.py文件所在目录
module = demo.wsgi
# 启动一个master进程来管理其他进程
master = true
# 工作的进程数
processes = 4
# 每个进程下的线程数量
threads = 2
# 当服务器退出的时候自动删除unix socket文件和pid文件
vacuum = true
# 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
daemonize = /media/aikoyanye/hdd/workspace/python/uwsgi.log
# uwsgi监听的http
socket = 127.0.0.1:9123

注意注释!!!

项目B下也新建 start.ini

# start.ini file
[uwsgi]
# 项目运行的端口
http = 127.0.0.1:8002
# 在app加载前切换到该目录,设置为Django项目根目录,manage.py所在目录
chdir = /media/aikoyanye/hdd/workspace/python/django_demo_1
# 加载指定的python WSGI模块,设置为Django项目的wsgi文件,wsgi.py文件所在目录
module = demo.wsgi
# 启动一个master进程来管理其他进程
master = true
# 工作的进程数
processes = 4
# 每个进程下的线程数量
threads = 2
# 当服务器退出的时候自动删除unix socket文件和pid文件
vacuum = true
# 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器
daemonize = /media/aikoyanye/hdd/workspace/python/django_demo_1/uwsgi.log
# uwsgi监听的http
socket = 127.0.0.1:9124

注意 http 和 socket 的端口

启动任然是命令行,cd在项目A\B的目录,然后分别启动:

uwsgi --ini start.ini

然后依旧

http://127.0.0.1:8001/users/
http://127.0.0.1:8002/users/
可以照常访问服务器

结束,终止所有uwsgi服务

sudo killall -9 uwsgi

然后在目录 /etc/nginx 下的 nginx.conf http 下添加代码:

upstream django {
    	server 127.0.0.1:9123; 
    	server 127.0.0.1:9124; 
	}


	server {
    	listen         8000; # 设置监听端口号
   		server_name    127.0.0.1; # 设置对外访问入口,可以是域名可以是IP地址,我设置的是IP 
   		charset        UTF-8;  # 设置访问的语言编码
   		client_max_body_size 75M;  # 
   		access_log     /var/log/nginx/test1_access.log; # 访问日志记录
   		error_log      /var/log/nginx/test1_error.log;  # 错误日志记

  		location / {   # 设置虚拟主机的基本信息
   		    uwsgi_pass django; # 刚才uwsgi设置的socket
   		    include /etc/nginx/uwsgi_params;
		}   
 	}

任然在 /etc/nginx 下新建文件 uwsgi_params ,复制粘贴:

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

开启服务

/etc/init.d/nginx start

然后重启uwsgi服务,先结束所有在开过,访问:

http://127.0.0.1:8000/users/

就会发现:

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第20张图片

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第21张图片

可以注意到返回的数据是先 倒叙 然后 升序 (或者先 升序 然后 倒叙

这里不解释太多,请参考 负载均衡

接下来准备开发移动端的代码,这里我选择android 因为我不会ios开发:)

首先修改 models.py 代码,让 name 字段不允许重复,并且新增 pwd 字段:

import mongoengine

class User(mongoengine.Document):
    # 默认id
    # 名字,字符串字段,最大长度36位,默认字符KirisameMarisa,允许为空,不允许重复,
    name = mongoengine.StringField(max_length=36, unique=True)
    # 年龄,整型字段,最大长度5,不允许位空
    age = mongoengine.IntField(max_length=5, null=False)
    # 密码,最长12,不允许为空
    pwd = mongoengine.StringField(max_length=12, null=False)

    # 更多字段请百度

修改 serializers.py 文件:

from .models import User
from rest_framework_mongoengine import serializers as mongo_serializers

# 名字随意
class UserSerializer(mongo_serializers.DocumentSerializer):
    class Meta:
        # 对应类名
        model = User
        # 各个字段,其中id是默认id字段
        fields = ('id', 'name', 'age', 'pwd')

让序列化把新增的 pwd 字段加进去

修改 views.py 的代码,在里面添加(随意项目A也行项目B也行:

# 这样做的话我每次都是POST请求,但是返回却是自定义
@api_view(['POST'])
def android_user_api(request):
    if request.method == 'POST':
        _data = dict(request.data)
        # 之前说过request.data是一个字典,可以利用这个
        if _data['method'][0] == '_GET':
            user = User.objects.get(name=_data['name'][0], pwd=_data['pwd'][0])
            serializer = UserSerializer(user)
            return Response(serializer.data, status=status.HTTP_200_OK)
        elif _data['method'][0] == '_POST':
            # request.data 中多余的数据不会保存到数据库中
            serializer = UserSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        elif _data['method'][0] == '_PUT':
            user = User.objects.get(name=_data['name'][0])
            serializer = UserSerializer(user, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        elif _data['method'][0] == '_DELETE':
            User.objects.get(name=_data['name'][0]).delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

然后修改 service 目录下的 urls.py :

from django.conf.urls import url
from . import views

urlpatterns = [
    # 定义url,移动端通过这个url访问服务端
    url(r'^users/$', views.user_api),
    # username就是之前views中another_user_api方法中的参数
    url(r'^users/(?P[A-Za-z0-9]+)/$', views.another_user_api),
    # 安卓端用api
    url(r'^android_user/$', views.android_user_api)
]

写的很简单粗暴,就是一个模拟登录注册的增删查改,再次之前先清空user表,我直接删除表了,在mongo shell中:

use test
db.user.drop()

然后重启 django 服务:

python manage.py runserver

在postman上可以测试,当读取数据位空时会报错,这是故意的,在 Android 端会用到报错

接下来可以动手打 Android 端的代码了,我用的是 kotlin ,java代码也差不多的

我会贴出kotlin代码,但是会讲清楚思路,用java的同学按照思路来执行也是可以使用的

首先导入jar包,用于访问url地址(文章末尾我会给出项目地址:


第二个包看情况导入,因为我是从自带的lib中提取的

然后在 Activity 中写一个静态的handler

companion object {
        val handler = Handler(){
            when(it.what){
                
            }
            return@Handler true
        }
    }

其中 it 是就是  msg

然后新建一个类 MyTextListener ,让它继承 TextHttpResponseHandler

import android.os.Handler
import android.os.Message
import com.loopj.android.http.TextHttpResponseHandler

// 对用activity中的handler,通过msg把数据传回activity,s_state是成功访问的状态码,f_state是访问失败的状态码
// 这个类可以自己定义,不一定按照我这种写法
// 花式构造函数
class MyTextListener(var handler: Handler, var s_state: Int, var f_state: Int): TextHttpResponseHandler() {

    val msg = Message.obtain()

    override fun onSuccess(p0: Int, p1: Array?, p2: String?) {
        // 成功访问
        msg.what = s_state
        msg.obj = p2
        handler.sendMessage(msg)
    }

    override fun onFailure(p0: Int, p1: Array?, p2: String?, p3: Throwable?) {
        // 失败访问
        msg.what = f_state
        handler.sendMessage(msg)
    }
}

然后实例化一个 AsyncHttpClient,用于访问url

val client = AsyncHttpClient()

实例化 RequestParams,用于存放访问url时附带的表单数据

val params = RequestParams()

如何访问?

// client.post(url, params,HttpResponseHandler)

client.post("http://10.0.2.2/android_user/", params, MyTextListener(MainActivity.handler, 2, 0x2))

如果你的 django 代码是复制我上面写的,请你这样写:

params.put("method", "_DELETE")
params.put("name", MainActivity.delete_name.text.toString())
// 虚拟机访问本机地址,如果是用真机的话,那就只能部署在公网上然后访问
client.post("http://10.0.2.2:8000/android_user/", params, MyTextListener(MainActivity.handler, 1, 0x1))

params.put("method", "_POST")
params.put("name", MainActivity.add_name.text.toString())
params.put("age", MainActivity.add_age.text.toString())
params.put("pwd", MainActivity.add_pwd.text.toString())
client.post("http://10.0.2.2:8000/android_user/", params, MyTextListener(MainActivity.handler, 2, 0x2))

params.put("method", "_GET")
params.put("name", MainActivity.get_name.text.toString())
params.put("pwd", MainActivity.get_pwd.text.toString())
client.post("http://10.0.2.2:8000/android_user/", params, MyTextListener(MainActivity.handler, 3, 0x3))

params.put("method", "_PUT")
params.put("name", MainActivity.put_name.text.toString())
params.put("age", MainActivity.put_age.text.toString())
params.put("pwd", MainActivity.put_pwd.text.toString())
client.post("http://10.0.2.2:8000/android_user/", params, MyTextListener(MainActivity.handler, 4, 0x4))

在 handler 处写判断:

val handler = Handler(){
            when(it.what){
                1 ->{

                } 0x1 ->{

                } 2 -> {

                } 0x2 ->{

                } 3 -> {

                } 0x3 -> {

                } 4 -> {

                } 0x4 -> {

                }
            }
            return@Handler true
        }

注意 1 0x1 这些是你自己定义的  成功访问码和失败访问码,这里写上你想要执行的代码即可

别忘了,权限,只需要一个访问网络权限就好了

然后就可以使用啦


用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第22张图片

可以看控制台输出:


用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第23张图片

可以看到,新添加的数据在下面显示,当然这是我自己写的

用django搭建移动端服务器(附上简单的uwsgi+nginx+mongo_第24张图片

模拟登录,可以看到数据是json格式传进来的,然后在自行解析,可以得到下面的数据

就这样一个移动端服务器写完了


忘记给了哈哈哈

github

你可能感兴趣的:(python,android,服务器,django)