[不做怎麼知道系列之Android開發者的30天後端養成故事 Day7] - 資料飛來飛去 #怎麼傳資料? #DjangoForm #JsonRequest

大家好,我們又見面了,今天來看看怎麼在網頁上,直接對資料庫新增資料吧!

透過 Form 的方式來新增資料

Django 有個很方便的功能是,定義好 form 的格式後,它會幫你把欄位給補到 html 去,來看看怎麼做吧~

models.py,是之前 Day4Django Girls Tutorial 借過來的 Post model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.db import models
from django.utils import timezone
from 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,因為其他的欄位是作者、建立的時間、發布的時間,不是讓使用者自己填的。

1
2
3
4
5
6
7
8
9
10
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
class Meta:
model = Post
fields= {
'title',
'content'
}

views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from django.shortcuts import render
from django.http import JsonResponse
from django.http import HttpRequest

from .forms import PostForm
from .models import Post

# 這次我們試著接受 Form 的 POST
# 收到的 form 如果合法,我們就存到 DB 去
def 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)

# 上次新增的 view
def hello(request):
return render(request, 'blog/index.html', {
"first_var": "Hello Man",
"second_var": 87.8787,
"third_list": ["歡迎", "你好", "我是 RS", "來比對我阿"]
})

/templates/blog/post_create.html

1
2
3
4
5
6
7
8
9
{% extends 'blog/base.html' %}

{% block content %}
<form method="POST"> {% csrf_token %}
<!-- 從 context 拿出 form -->
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

這邊有看到 csrf_tokentemplate tag,先不要理它,那是 django 內建預設的 authentication 方法,我們先用用看。

urls.py

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib import admin
from django.urls import path

from blog.views import hello, post_create_view,
test_json_response_view

urlpatterns = [
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 長這樣:

1
2
3
4
5
6
method = POST
url = 127.0.0.1:8000/test
body = {
"title": "Add article by postman POST with json body",
"content": "yohohoho."
}

希望收到的 response 長這樣:

1
2
3
{
"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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.handlers.wsgi import WSGIRequest

import json

from .forms import PostForm
from .models import Post

# 讓這支 API 免 csrf authentication
# (之後我們再來深入!)
@csrf_exempt
def 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 data
data = json.loads(request.body)
print("get POST request data: ", data)

# save to db
Post.objects.create(title=data['title'], content=data['content'])

# check posts in db
print('all posts in db: ', Post.objects.all())

# send response to client
return JsonResponse({'status': 'ok, I got you.'})
else:
print("get unknown request: ", request)
return JsonResponse({'status': 'no, I don\'t know it.'})

# ----------- 以下在這個範例用不到 -----------
# Form 的 request
def 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 testing
def hello(request):
return render(request, 'blog/index.html', {
"first_var": "Hello Man",
"second_var": 87.8787,
"third_list": ["歡迎", "你好", "我是 RS", "來比對我阿"]
})

urls.py

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib import admin
from django.urls import path

from blog.views import hello, post_create_view, test_json_response_view

urlpatterns = [
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

單日心得總結

恩… 其實我犯了一個錯誤,我在 Day5Day6 提到說要開 API,原本以為開個 API 應該可以用很簡單的方式做,才知道我把這個餅畫得太大,就不知道該怎麼寫這一篇,所以你可以觀察到,恩,我漏了一天,這件事對你們來說雖然沒什麼,但是對我來講是沒有達到對自己的承諾,昨天隨著時間越拖越晚,就漸漸進入到一個低潮的狀態,謝謝我的女朋友給我打氣,今天才能再復活。

老實說,學會了之後再回去看都會覺得不難,但是我在走這段路的時候,真的是覺得超級難懂,為什麼還有 csrf token 問題、在 postman 明明加上 csrf token 卻還是沒辦法 POST 成功,我沒想到會這麼早碰到 authentication 的問題 QQ,還傻傻地想要在這篇一起把它給解決了,年輕人終究是年輕人。

感謝看到文章最後的你們,還有感謝我的女朋友。

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。


  • 喜歡我的文章嗎? 趕快來看看我都發了什麼文章吧:我的文章目錄
  • 歡迎閱讀我的上一篇: [不做怎麼知道系列之Android開發者的30天後端養成故事 Day6] - 運用框架的槓桿 #前後端怎麼結合 #框架的威力 #Django Template Engine
  • 歡迎閱讀我的下一篇: [不做怎麼知道系列之Android開發者的30天後端養成故事 Day8] - 換個皮 #怎麼套用前端樣版? #DjangoFileManagment #StaticFiles
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021-2022 Sam Ho
  • Visitors: | Views:

請我喝杯咖啡吧~

支付宝
微信