大家好,我们又见面了,今天来看看怎么在网页上,直接对资料库新增资料吧!
透过 Form 的方式来新增资料
Django 有个很方便的功能是,定义好 form 的格式后,它会帮你把栏位给补到 html 去,来看看怎么做吧~
models.py
,是之前 Day4 从 Django Girls Tutorial 借过来的 Post
model
from django.db import modelsfrom django.utils import timezonefrom django.contrib.auth.models import User class Post(models.Model): # 这边我把 author 加了 null=True author = models.ForeignKey(User, on_delete=models.CASCADE, null=True) title = models.CharField(max_length=200) content = models.TextField() created_date = models.DateTimeField( default=timezone.now() ) published_date = models.DateTimeField( blank=True, null=True ) def publish(self): self.published_date = timezone.now() self.save() def __str__(self): return self.title
新增 forms.py
定义好 Form 的栏位之后,透过 views.py
把 form 包在 context 传给 html,就可以在 html 上,呈现出我们想要让使用者填的栏位,在这边我只显示 title 和 content,因为其他的栏位是作者、建立的时间、发布的时间,不是让使用者自己填的。
from django import formsfrom .models import Postclass PostForm(forms.ModelForm):class Meta:model = Postfields= {'title','content'}
views.py
from django.shortcuts import renderfrom django.http import JsonResponsefrom django.http import HttpRequestfrom .forms import PostFormfrom .models import Post# 这次我们试着接受 Form 的 POST# 收到的 form 如果合法,我们就存到 DB 去def post_create_view(request):form = PostForm(request.POST or None)if form.is_valid():form.save()context = {'form': form}return render(request, 'blog/post_create.html', context)# 上次新增的 viewdef hello(request):return render(request, 'blog/index.html', {"first_var": "Hello Man","second_var": 87.8787,"third_list": ["欢迎", "你好", "我是 RS", "来比对我阿"]})
/templates/blog/post_create.html
{% extends 'blog/base.html' %}{% block content %}<form method="POST"> {% csrf_token %}<!-- 从 context 拿出 form -->{{ form.as_p }}<input type="submit" value="Submit"></form>{% endblock %}
这边有看到 csrf_token 的 template tag,先不要理它,那是 django 内建预设的 authentication 方法,我们先用用看。
urls.py
from django.contrib import adminfrom django.urls import pathfrom blog.views import hello, post_create_view, test_json_response_viewurlpatterns = [ path('admin/', admin.site.urls), path('blog/', hello),# 新增一个 让使用者发布文章的页面 path('blog/create/', post_create_view)]
来新增资料看看啰
来到 127.0.0.1/blog/create
,可以看到画面上已经有丑丑的简易输入格 XD,这是 django 的 form 帮我们做的,如果不符合你想要的,也可以参考 官方文件 来变成你想要的样式。
点下 Submit 后
点下 Submit 后,可以在 开发者工具 的 网路,看到我们从前端传出去的 request,收到 200 OK
的回应,表示应该是没问题才对。
来到 admin 看看是不是真的有存进去 DB
有耶,hen 棒~
再进去到里面,看看是不是真的刚刚新增的那一笔
好的,那么还有没有别的方式来传资料呢 ?
既然你诚心诚意的发问了,那我就大发慈悲的告诉你,有的 ! 那么就是今天的主题:开 API,因为有些情况是希望除了透过网页的方式传资料,有可能是 mobile app 要传资料到我们后端资料库,这时候就需要一支 API 来沟通。
假设我想要让前端,透过一个 POST
塞入 JSON 资料,来新增一笔发文呢?
我的最初想法是,在 Android 端,可以用 Retrofit
轻鬆丢出一个含有 JSON 资料的 POST request,我就想试试看后端要怎么做,才能吃下含 JSON 的 POST request,我们来看看怎么做。
上範例 !
根据 TDD(Test Driven Development),我们先定义出最后要测试的 request 和 response 长什么样子。
利用 Postman 来模拟传、收 request 的情境
request 长这样:
method = POSTurl = 127.0.0.1:8000/testbody = {"title": "Add article by postman POST with json body","content": "yohohoho."}
希望收到的 response 长这样:
{"status": "ok, I got you."}
先据透,最后在 Postman 的结果长这样:
那要怎么做呢?
整体概念是,urls.py
会收到 request,再根据我们自定义的 url 规则,将 request 转发到 views.py
里的 test_json_response_view(request)
,然后再将 request 里的 body 解析为 JSON 格式,并转成 Post
物件再透过 django model 存到 DB 里,再回个 response 回去,that's it !
views.py
from django.shortcuts import renderfrom django.http import JsonResponsefrom django.views.decorators.csrf import csrf_exemptfrom django.core.handlers.wsgi import WSGIRequestimport jsonfrom .forms import PostFormfrom .models import Post# 让这支 API 免 csrf authentication# (之后我们再来深入!)@csrf_exemptdef test_json_response_view(request: WSGIRequest):print('-----------------------------------')if request.method == 'GET':print("get GET request: ", request)return JsonResponse({'first': 'content', 'second': 'test'})elif request.method == 'POST':# get json datadata = json.loads(request.body)print("get POST request data: ", data)# save to dbPost.objects.create(title=data['title'], content=data['content'])# check posts in dbprint('all posts in db: ', Post.objects.all())# send response to clientreturn JsonResponse({'status': 'ok, I got you.'})else:print("get unknown request: ", request)return JsonResponse({'status': 'no, I don\'t know it.'})# ----------- 以下在这个範例用不到 -----------# Form 的 requestdef post_create_view(request):form = PostForm(request.POST or None)print("form valid: ", form.is_valid, ", request: ", request)if form.is_valid():form.save()context = {'form': form}return render(request, 'blog/post_create.html', context)# template tag testingdef hello(request):return render(request, 'blog/index.html', {"first_var": "Hello Man","second_var": 87.8787,"third_list": ["欢迎", "你好", "我是 RS", "来比对我阿"]})
urls.py
from django.contrib import adminfrom django.urls import pathfrom blog.views import hello, post_create_view, test_json_response_viewurlpatterns = [ path('admin/', admin.site.urls), path('blog/', hello), path('blog/create/', post_create_view),# 转发 request 到 views.py 的 JSON API path('test/', test_json_response_view)]
Django 跑起来
$ python manage.py runserver
再到 Postman 送出 request ! 所以结果就是前面所看到的这张
给没用过 postman 的人们的简易导览,思考顺序是从红色(request method and url) → 橘色(put json data in body) → 黄色(get response)
如果是 GET 的话,也可以用浏览器访问 127.0.0.1:8000/test/
,就回一个含有 JSON 的 response,这样就达到一支 API 可以同时符合 GET 和 POST 两种。
再到 admin 确认是不是有真的存进去 DB
单日心得总结
恩... 其实我犯了一个错误,我在 Day5 和 Day6 提到说要开 API,原本以为开个 API 应该可以用很简单的方式做,才知道我把这个饼画得太大,就不知道该怎么写这一篇,所以你可以观察到,恩,我漏了一天,这件事对你们来说虽然没什么,但是对我来讲是没有达到对自己的承诺,昨天随着时间越拖越晚,就渐渐进入到一个低潮的状态,谢谢我的女朋友给我打气,今天才能再复活。
老实说,学会了之后再回去看都会觉得不难,但是我在走这段路的时候,真的是觉得超级难懂,为什么还有 csrf token 问题、在 postman 明明加上 csrf token 却还是没办法 POST 成功,我没想到会这么早碰到 authentication 的问题 QQ,还傻傻地想要在这篇一起把它给解决了,年轻人终究是年轻人。
感谢看到文章最后的你们,还有感谢我的女朋友。
我是 RS,这是我的 不做怎么知道系列 文章,我们 明天见。
喜欢我的文章吗? 赶快来看看我都发了什么文章吧:我的文章目录
欢迎阅读我的上一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day6] - 运用框架的槓桿 #前后端怎么结合 #框架的威力 #Django Template Engine
欢迎阅读我的下一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day8] - 换个皮 #怎么套用前端样版? #DjangoFileManagment #StaticFiles