作者是一个技术小白,这也是本人的第一篇文章,虽然网上关于Django和Android结合搭建app的文章很多,但是还是想要根据自己在搭建过程中遇到的问题写一篇学习笔记,同时也供他人借鉴一下。
说明:本示例app为本人实现 的一个很简单的记账软件,不喜勿喷。
附github地址:https://github.com/Kingqibin/paykeep
环境要求:
代码实现
pip install django
django-admin startproject paykeep # 创建项目
django-admin startapp paykeep_service # 主要的服务内容
startproject命令主要的作用是开启了一个项目的成熟框架,在之后的操作中只需要修改一下里面的参数。
startapp命令主要的功能是创建实现功能的模板。
以下在搭建时主要就是修改paykeep和paykeep_service文件夹下的主要内容。
(1)修改app.py的内容:
class PaykeepServiceConfig(AppConfig):
name = 'paykeep_service' #修改name为你项目的名称
(2)修改model.py的内容:
from django.db import models
# 以下定义自己的类模型,以及相对应的数据段
class Pay(models.Model):
id = models.IntegerField(null=False, primary_key=True)
item_spend = models.CharField(null=False, max_length=50)
money = models.FloatField(null=False)
year = models.IntegerField(null=False)
month = models.IntegerField(null=False)
day = models.IntegerField(null=False)
isPri = models.BooleanField(null=False)
data_added = models.DateTimeField(auto_now_add=True)
# 以下的函数的作用是在展示 调试时显示相应的数据内容,可以自行配置
def __str__(self):
temp = "id is : " + str(self.id) + "--item is : " + str(self.item_spend)
return temp
关于更多的类型数据定义可以自行google相关的django API。
(3)修改最重要的view.py的内容:
from django.shortcuts import render
from .models import Pay #!!!
from django.http import HttpResponse#!!!
from django.core.exceptions import ObjectDoesNotExist
def pay(request):
# 解析请求方式:
if request.method == 'POST':
item_spend = request.POST.get('item_spend')
id = request.POST.get('id')
money = request.POST.get('money')
year = request.POST.get('year')
month = request.POST.get('month')
day = request.POST.get('day')
isPri = request.POST.get('isPri')
fun = request.POST.get('fun')
# 功能解析
if fun == '1':
Pay.objects.create(id=id, item_spend=item_spend, money=money, year=year, month=month, day=day, isPri=isPri)
try:
t = Pay.objects.get(id=id)
return HttpResponse("add_ok")
except ObjectDoesNotExist:
return HttpResponse("add_error")
elif fun == '2':
try:
temp = Pay.objects.get(id=id)
temp.delete()
return HttpResponse("delete_ok")
except ObjectDoesNotExist:
return HttpResponse("not_found")
else:#注意代码对齐
return HttpResponse("error")
以上为本程序实现所需要的核心代码部分,其中我在使用时的django请求方式好像只能用get和post(因为我在网络方面也是小白,具体的咱也不是太清楚,感兴趣的同学可以详细研究下,看其它地博主好像可以用)。因此使用了一个比较蠢的功能解析(即传fun字段来判断要执行哪一个功能)的方式来实现。
另外在网络响应时使用的是HttpResponse具体的其它功能读者可以自行google API。
(1)修改setting.py的内容:
···
DEBUG = False
ALLOWED_HOSTS = ['*'] # 可访问的ip
···
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'paykeep_service', # 项目名字
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware', # 注释掉
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
应该只需要做以上的修改就好,具体的可以参考github的源码。
(2)修改重要的urls.py的内容:
from django.contrib import admin
from django.urls import path
from paykeep_service.views import pay
urlpatterns = [
path('admin/', admin.site.urls),
path('add_pay/', pay),# !!!!!!!!!!!!!!!!
]
这里的 add_pay/ 为请求方式,pay 为在view.py中定义的方式名,这里一定要对应。如果在view中写了更多的请求功能调用也可以在这里一一列明。
python manage.py migrate
python manage.py runserver 0.0.0.0:10000
允许接入的ip地址(0.0.0.0)表示允许所有的ip接入,10000端口表示开放的端口。如果使用的是云服务器,一定要在安全组里面配置一下哟。
目前为止,关于后台的搭建已经基本完成,因为我对于后台的了解也不是太多,所以讲的一些东西可能会不太准确,但是操作基本都是正确的。另外推荐大家在搭建好后台后使用postman进行一下响应的测试,看看传入响应的数据后是否会产生预期的效果,如果没用可能需要改一下代码了。防止在后面搭建完app后再反过头来修改后台,浪费时间。本人在写后台时也是经过了很长时间的调试才达到最后的效果,大家要保持耐心哟~提醒一下,如果模型更改了就要按照第5部重新部署一下数据库文件。
在这里假设大家对一些基础的android操作都已经很熟悉了,因此只是写一些与网络通信的介绍,其它的可以去github参照下源代码。按照国际惯例先贴代码:
// 添加支出记录:
private void addPay(final Pay pay,final int n){
//开启网络传输线程------这里可以使用rxjava等热门的框架代替,这里从简
new Thread(new Runnable() {
@Override
public void run() {
//okhttp 客户端
OkHttpClient client = new OkHttpClient();
//请求体----添加你需要上传的字段
RequestBody requestBody = new FormBody.Builder()
.add("id",String.valueOf(pay.getId()))
.add("item_spend",pay.getName())
.add("money",String.valueOf(pay.getMoney()))
.add("year",String.valueOf(pay.getYear()))
.add("month",String.valueOf(pay.getMonth()))
.add("day",String.valueOf(pay.getDay()))
.add("isPri",pay.isPrivate()?"True":"False")
.add("fun",String.valueOf(1))
.build();
// 请求构建 添加你自己的ip地址 另外 请求方式 add_pay 要与urls.py中定义的相同
Request request = new Request.Builder()
.url("http://"+ip+"/add_pay/")
.post(requestBody)
.build();
try {
Response response = client.newCall(request).execute();
//请求处理
String rd = response.body().string();
Log.d(TAG, "get response : "+rd);
if (rd.isEmpty()){
runOnUiThread(new Runnable() {
@Override
public void run() {
if (n==1)
Toast.makeText(MainActivity.this,"啊咧咧~下次再上传~",Toast.LENGTH_SHORT).show();
}
});
}else {
if (rd.equals("add_ok")){
runOnUiThread(new Runnable() {
@Override
public void run() {
pay.setUploaded(true);
pay.save();
refreshSum();
if (n==1)
Toast.makeText(MainActivity.this,"添加成功",Toast.LENGTH_SHORT).show();
}
});
}else {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(n==1)
Toast.makeText(MainActivity.this,"添加失败",Toast.LENGTH_SHORT).show();
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (n==1)
Toast.makeText(MainActivity.this,"啊咧咧~下次再上传~",Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
}
// 删除消费记录 几乎跟上面相同
private void deletePay(final Pay pay,final int pos){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("id",String.valueOf(pay.getId()))
.add("item_spend",pay.getName())
.add("money",String.valueOf(pay.getMoney()))
.add("year",String.valueOf(pay.getYear()))
.add("month",String.valueOf(pay.getMonth()))
.add("day",String.valueOf(pay.getDay()))
.add("isPri",pay.isPrivate()?"True":"False")
.add("fun",String.valueOf(2))
.build();
Request request = new Request.Builder()
.url("http://"+ip+"/add_pay/")
.post(requestBody)
.build();
try {
Response response = client.newCall(request).execute();
String rd = response.body().string();
Log.d(TAG, "get response : "+rd);
if (rd.isEmpty()){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"啊咧咧~电波无法到达~",Toast.LENGTH_SHORT).show();
}
});
}else {
if (rd.equals("delete_ok")){
runOnUiThread(new Runnable() {
@Override
public void run() {
pays.remove(pos);
adapter.notifyItemRemoved(pos);
recyclerView.scrollToPosition(pos);
LitePal.delete(Pay.class,pay.getId());
refreshSum();
Toast.makeText(MainActivity.this,"消除成功",Toast.LENGTH_SHORT).show();
}
});
}else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"消除失败",Toast.LENGTH_SHORT).show();
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"啊咧咧~电波无法到达~",Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
}
其它的一些安卓代码,大家有兴趣的话参见github,我在这里就只放核心了,如有问题可在评论区留言。
目前为止项目基本就结束了!因为写文章时离项目完成有一段时间了,所以大家如果觉得我写的有问题,不清楚的地方都可以在评论区留言,我及时修改(只要我看地到-哈哈牛逼地叉会儿腰)
转载请声明出处,谢谢