日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Web框架之Django_08 重要组件(form组件、cookie和session组件)

發布時間:2024/9/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Web框架之Django_08 重要组件(form组件、cookie和session组件) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

閱讀目錄

  • 一、form組件

  • 二、cookie與session

Django中操作Cookie
摘要:

  • form組件
  • cookie組件
  • session組件

一、form組件

  • form介紹
    我們之前在html頁面中利用form表單向后端提交數據時候,都需要對用戶的輸入進行校驗,比如校驗用戶是否輸入正確(長度、格式…),如果用戶輸入的內容有誤則需要在相應的位置顯示對應的錯誤信息來提醒用戶,提高前端的交互效率。
    Django form組件就是實現上述功能的一個功能組件。 from組件主要功能有:
    #生成頁面可用的html標簽
    #對用戶條件的數據進行校驗
    #保留上次輸入內容
  • 先來看看自己手寫注冊功能的過程:
-------------------------------------------------------------------- 注:如果你對python感興趣,我這有個學習Python基地,里面有很多學習資料,感興趣的+Q群:895817687 --------------------------------------------------------------------# views.py # 注冊 def register(request):error_msg = ""if request.method == "POST":username = request.POST.get("name")pwd = request.POST.get("pwd")# 對注冊信息做校驗if len(username) < 6:# 用戶長度小于6位error_msg = "用戶名長度不能小于6位"else:# 將用戶名和密碼存到數據庫return HttpResponse("注冊成功")return render(request, "register.html", {"error_msg": error_msg})# register.html !DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>注冊頁面</title> </head> <body> <form action="/reg/" method="post"><p>用戶名:<input type="text" name="name"></p><p>密碼:<input type="password" name="pwd"></p><p><input type="submit" value="注冊"><p style="color: red">{{ error_msg }}</p></p> </form> </body> </html>
  • 校驗數據 使用form組件實現注冊功能:
from django import forms # 按照Django form組件的要求自己寫一個類 class MyForm(forms.Form):name = forms.CharField(label='用戶名', max_length=6)pwd = forms.CharField(label='密碼', max_length=8, min_length=4)def register(request):form_obj = MyForm()if request.method == 'POST':# 實例化form對象的時候,把post提交過來的數據直接傳進去form_obj = MyForm(request.POST)# 調用form_obj校驗數據的方法if form_obj.is_valid(): # 這里is_valid()如果驗證全部通過,則返回Truereturn HttpResponse('注冊成功')return render(request, 'register.html', {'form_obj': form_obj})

這里我們使用PythonConsole來測試:

依次輸入:(帶#的為結果) from app01 import views form_obj = views.MyForm({'name': 'hhh', 'pwd': '123'}) form_obj.is_valid() #False form_obj.errors #{'pwd': ['Ensure this value has at least 4 characters (it has 3).']} form_obj.cleaned_data #{'name': 'hhh'}

##form_obj.is_valid() 校驗提交的信息,如果全部通過,則返回True,否則為False
#from_obj.errors 查看錯誤的信息,結果是一個字典格式,key為錯誤的字段,value為錯誤的原因,注意這里面是一個列表,說明原因可以有多個,這里需要說明:所有校驗未通過的字段及錯誤信息提示都在這里放著,以鍵值對的形式存放。
##form_obj.cleaned_data 查看校驗通過的數據,這里存放這所有校驗通過的字段及其值,以字典形式存放。
特別補充:
如果:多串字段:不進行校驗,所以不會在cleaned_data和errors中
少傳字段: 也會校驗少傳的字段,會在errors中,且該字段描述:{‘pwd’: [‘This field is required.’]}
所有Form中的字段默認都是要校驗,但是可以通過設置required = False來更過。

  • 渲染標簽
# views from django import forms # 按照Django form組件的要求自己寫一個類 class MyForm(forms.Form):name = forms.CharField(max_length=6)pwd = forms.CharField(max_length=8, min_length=4)def register(request):form_obj = MyForm()if request.method == 'POST':# 實例化form對象的時候,把post提交過來的數據直接傳進去form_obj = MyForm(request.POST)# 調用form_obj校驗數據的方法if form_obj.is_valid(): # 這里is_valid()如果驗證全部通過,則返回Truereturn HttpResponse('注冊成功')return render(request, 'register.html', {'form_obj': form_obj}) <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post"> {# .as_p代表將所有的字段都對應input框渲染給前端顯示#}{{ form_obj.as_p }}</form> </body> </html>


可以看到,前面的Name和Pwd是Django自己渲染加上的,如果想要自定義,可以在MyForm類的對應字段里加上:label='用戶名’和labe
上面是第一種渲染方式,可以看出可拓展性較差

  • 第二種渲染方式: 多加幾個校驗字段
from django import forms # 按照Django form組件的要求自己寫一個類 class MyForm(forms.Form):name = forms.CharField(max_length=6, label='用戶名')pwd = forms.CharField(max_length=8, min_length=4, label='密碼')email = forms.EmailField(label='郵箱') <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post"> <p>{{ form_obj.name }}</p> <p>{{ form_obj.pwd }}</p> <p>{{ form_obj.email }}</p> </form> </body> </html>


加入input框前的名字:

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post"> <p>{{ form_obj.name.label }}{{ form_obj.name }}</p> <p>{{ form_obj.pwd.label }}{{ form_obj.pwd }}</p> <p>{{ form_obj.email.label }}{{ form_obj.email }}</p> </form> </body> </html>


此種方法還是有缺點,比如字段如果有100個,難道要100個全部輸嗎?所以應該還有更好的方法:

  • 第三種渲染方式:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post"> {% for foo in form_obj %}<p>第三種渲染方式:{{ foo.label }}{{ foo }}</p> {% endfor %} </form> </body> </html>


這里提一下:如果想要取消前端校驗,可以在form表單中加入:novalidate
這里需要知道:
1、如果Django創建的form表單在提交的時候數據不合法(校驗不通過),則會自動保留填寫的信息,不會清空。
2、Django創建的表單是沒有提交按鈕的,需要自己創建。
接下來,添加校驗不通過時候的提示信息:只需在恰當的位置添加

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %}<p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors }}</span></p> {% endfor %}<input type="submit"> </form> </body> </html>


這里,提示錯誤信息在下面顯示,如果想讓它在每個字段的input框后面顯示可以加個0

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %}<p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors.0 }}</span></p>{% endfor %}<input type="submit"> </form> </body> </html>


繼續走向個性化:提示的錯誤信息是英文,我看不懂,那就改成中文:
修改錯誤提示信息為自定義信息

from django import forms # 按照Django form組件的要求自己寫一個類 class MyForm(forms.Form):name = forms.CharField(max_length=6, label='用戶名', error_messages={'max_length': '用戶名最大長度為6位','required': '用戶名必須不能為空'})pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={'max_length': '密碼最大長度為8位','min_length': '密碼最小長度為4位','required': '用戶名必須不能為空'})email = forms.EmailField(label='郵箱', error_messages={'required': '郵箱必須不能為空','invalid': '郵箱格式不合法'})

測試測試:

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %}<p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors.0 }}</span></p>{% endfor %}<input type="submit"> </form> </body> </html>


這里有個小點需要說明:默認google瀏覽器的表單輸入框如果要求最大6位,就只能輸入6位最大,再多輸入沒有反應,這個為了測試方便,可以認為在每次提交前通過右鍵檢查,人為刪除限制的html代碼

  • 常用字段與插件: 這里系統的在補充一些Form類在創建的時候會涉及到的字段和插件,自對用于對用戶請求數據的驗證,插件用于自動生成html

initial

初始值,input框里面的初始值

class LoginForm(forms.Form):username = forms.CharField(min_length=8,label="用戶名",initial="張三" # 設置默認值)pwd = forms.CharField(min_length=6, label="密碼")

error_messages(這個上面以提到)
重寫錯誤信息。

class LoginForm(forms.Form):username = forms.CharField(min_length=8,label="用戶名",initial="張三",error_messages={"required": "不能為空","invalid": "格式錯誤","min_length": "用戶名最短8位"})pwd = forms.CharField(min_length=6, label="密碼")

PasswordInput

pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={'max_length': '密碼最大長度為8位','min_length': '密碼最小長度為4位','required': '用戶名必須不能為空'}, widget=forms.widgets.PasswordInput(attrs={'type': 'password'}))# 將input改成password類型,這樣輸入的就不是明文了


radioSelect
將下拉式選擇框轉變成單選形式

gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "保密")),label="性別",initial=3,widget=forms.widgets.RadioSelect()

單選Select

class LoginForm(forms.Form):...hobby = forms.ChoiceField(choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),label="愛好",initial=3,widget=forms.widgets.Select())

多選Select

class LoginForm(forms.Form):...hobby = forms.MultipleChoiceField(choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),label="愛好",initial=[1, 3],widget=forms.widgets.SelectMultiple())

單選checkbox

class LoginForm(forms.Form):...keep = forms.ChoiceField(label="是否記住密碼",initial="checked",widget=forms.widgets.CheckboxInput())

多選checkbox

class LoginForm(forms.Form):...hobby = forms.MultipleChoiceField(choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),label="愛好",initial=[1, 3],widget=forms.widgets.CheckboxSelectMultiple()

choice字段注意事項
在使用選擇標簽時,需要注意choices的選項可以配置從數據庫中獲取,但是由于是靜態字段 獲取的值無法實時更新,需要重寫構造方法從而實現choice實時更新。

方式一:

from django.forms import Form from django.forms import widgets from django.forms import fieldsclass MyForm(Form):user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),initial=2,widget=widgets.Select)def __init__(self, *args, **kwargs):super(MyForm,self).__init__(*args, **kwargs)# self.fields['user'].choices = ((1, '上海'), (2, '北京'),)# 或self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

方式二:

from django import forms from django.forms import fields from django.forms import models as form_modelclass FInfo(forms.Form):authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 單選
  • DjangoForm所有內置字段
  • Hook方法(鉤子函數)
    鉤子函數分為:局部鉤子和全局鉤子
    這里還需要注意:鉤子函數是在對校驗通過的字段進行進一步校驗。所以需要寫在字段下面
    局部鉤子
    我們在Fom類中定義 clean_字段名() 方法,就能夠實現對特定字段進行校驗。
# 局部鉤子def clean_name(self):name = self.cleaned_data.get('name')if '666' in name:# 用add_error添加錯誤提示self.add_error('name', '666不對')return name


全局鉤子
我們在Fom類中定義 clean() 方法,就能夠實現對字段進行全局校驗。

# 輸入兩次密碼一致性的全局鉤子 設置兩個密碼字段pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={'max_length': '密碼最大長度為8位','min_length': '密碼最小長度為4位','required': '用戶名必須不能為空'}, widget=forms.widgets.PasswordInput(attrs={'type': 'password'}))confirm_pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={'max_length': '密碼最大長度為8位','min_length': '密碼最小長度為4位','required': '用戶名必須不能為空'}, widget=forms.widgets.PasswordInput(attrs={'type': 'password'}))# 全局鉤子:def clean(self):pwd = self.cleaned_data.get('pwd')confirm_pwd = self.cleaned_data.get('confirm_pwd')if pwd != confirm_pwd:self.add_error('confirm_pwd', '密碼兩次輸入不一致')return self.cleaned_data

  • 最后說說注冊的實際流程:也就是我們通過校驗成功后如何將注冊信息存入數據庫:
def reg(request):# 生成一個空對象form_obj = MyForm()if request.method == 'POST':print(request.POST)form_obj = MyForm(request.POST)if form_obj.is_valid():# print(form_obj.cleaned_data)# 這里打散傳值需要注意的是模型表字段名要與模型中的字段名相同,不然肯定會報錯。# 所以平時要養成習慣,很多地方需要一樣,以便于代碼的可讀性# models.User.objects.create(**form_obj.cleaned_data)return render(request,'reg.html',locals())
  • 二、cookie與session

Cookie介紹
Cookie的由來
大家都知道HTTP協議是無狀態的。

無狀態的意思是每次請求都是獨立的,它的執行情況和結果與前面的請求和之后的請求都無直接關系,它不會受前面的請求響應情況直接影響,也不會直接影響后面的請求響應情況。

一句有意思的話來描述就是人生只如初見,對服務器來說,每次的請求都是全新的。

狀態可以理解為客戶端和服務器在某次會話中產生的數據,那無狀態的就以為這些數據不會被保留。會話中產生的數據又是我們需要保存的,也就是說要“保持狀態”。因此Cookie就是在這樣一個場景下誕生。
什么是Cookie
Cookie具體指的是一段小信息,它是服務器發送出來存儲在瀏覽器上的一組組鍵值對,下次訪問服務器時瀏覽器會自動攜帶這些鍵值對,以便服務器提取有用信息。

Cookie的原理
cookie的工作原理是:由服務器產生內容,瀏覽器收到請求后保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣服務器就能通過Cookie的內容來判斷這個是“誰”了。

查看Cookie
我們使用Chrome瀏覽器,打開開發者工具。

Django中操作Cookie

前提:

  • 我們在后端views中視圖函數的返回參數render(),HttpResponse(),redirect(),通過查看它們的源碼發現加括號后世界上返回的是一個對象,也就是我們返回到前端的是一個對象,以前我們是直接返回,現在要用到cookie和session就得在返回前對這個對象進行操作設置Cookie
# views def login(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')if username == 'sgt' and password == '123':# 用戶登錄校驗成功,下一步設置cookie,需要知道用哪一個網頁使用cookieobj = redirect('/index/')# 設置cookieobj.set_cookie('name', 'sgt', expires=15) # 過期時間15秒return obj# 這個obj就是進行操作,設置好cookie的redirect('/index/')return render(request, 'login.html')def index(request):return render(request, 'index.html')# 在login.html登錄頁面,進行登錄,如果用戶名和密碼為sgt和123,則跳轉到inde.html,同時在跳轉之前設置cookie,通過在index頁面右鍵檢查,查看cookie可


當然上面的設置cookie為了演示創建過程,并沒有加任何安全措施,在實際使用中我們肯定會對他進行加密處理:做一下更安全性的操作處

obj.set_signed_cookie(key,value,salt='加密鹽', max_age=None, ...) 參數: key, 鍵 value='', 值 max_age=None, 超時時間 expires=None, 超時時間(IE requires expires, so set it if hasn't been already.) path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問 domain=None, Cookie生效的域名 secure=False, https傳輸 httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)

獲取Cookie

request.COOKIES['key']request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

參數:

default: 默認值
salt: 加密鹽
max_age: 后臺控制過期時間

刪除Cookie

def logout(request):obj = redirect("/login/")obj.delete_cookie("user") # 刪除用戶瀏覽器上之前設置的usercookie值return rep

只有已經登錄了,才能訪問網頁,否則跳轉到登錄頁面,
通過cookie來校驗登錄,同時通過登錄裝飾器來校驗登錄,實現登錄后自動跳轉到原來需要提示登錄的網頁

# 登錄頁面視圖函數 def login(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')if username == 'jason' and password == '123':old_path = request.GET.get('next')if old_path:# 如果原來頁面有,則自動跳轉obj = redirect(old_path)else:# 如果是直接進入登錄頁面,不是從其它頁面跳轉的,則默認跳到指定主頁面去obj = redirect('/home/')# 用戶登錄成功 朝瀏覽器設置一個cookieobj.set_cookie('name','jason',expires=3600) # 這個兼容性更高# obj.set_cookie('name','jason',max_age=5)return objreturn render(request,'login.html')# 登錄驗證裝飾器 from functools import wraps def login_auth(func):@wraps(func)def inner(request,*args,**kwargs):# 校驗cookie# print(request.get_full_path())old_path = request.get_full_path() # 拿到原來需要登錄的頁面路由if request.COOKIES.get('name'):return func(request,*args,**kwargs)# 如果未登錄,跳轉到登錄頁面,同時在路由后面拼接老頁面路由地址,用于登錄成功自動跳轉return redirect('/login/?next=%s'%old_path)return inner@login_auth def index(request):# # print(request.COOKIES.get('name'))# if request.COOKIES.get('name'):return HttpResponse('我是index頁面,只有登錄了才能看')@login_auth def home(request):return HttpResponse('我是home頁面,只有登錄了才能看')@login_auth def xxx(request):return HttpResponse('我是xxx頁面,只有登錄了才能看')

Session介紹
Cookie雖然在一定程度上解決了“保持狀態”的需求,但是由于Cookie本身最大支持4096字節,以及Cookie本身保存在客戶端,可能被攔截或竊取,因此就需要有一種新的東西,它能支持更多的字節,并且他保存在服務器,有較高的安全性。這就是Session。

問題來了,基于HTTP協議的無狀態特征,服務器根本就不知道訪問者是“誰”。那么上述的Cookie就起到橋接的作用。

我們可以給每個客戶端的Cookie分配一個唯一的id,這樣用戶在訪問時,通過Cookie,服務器就知道來的人是“誰”。然后我們再根據不同的Cookie的id,在服務器上保存一段時間的私密資料,如“賬號密碼”等等。

總結而言:Cookie彌補了HTTP無狀態的不足,讓服務器知道來的人是“誰”;但是Cookie以文本的形式保存在本地,自身安全性較差;所以我們就通過Cookie識別不同的用戶,對應的在Session里保存私密的信息以及超過4096字節的文本。

另外,上述所說的Cookie和Session其實是共通性的東西,不限于語言和框架。

  • session基本使用(設置,獲取)
    #設置session:
request.session['name']='jason'

設置session時候Django做了3件事:
①生成一個隨機的字符串
②在Django的session表存儲隨機字符串與數據記錄
③將隨機字符串發送給瀏覽器
#獲取session:
request.session.get(‘name’)

  • #Django中session的相關方法:
# 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1']# 所有 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems()# 會話session的key request.session.session_key# 將所有Session失效日期小于當前日期的數據刪除 request.session.clear_expired()# 檢查會話session的key在數據庫中是否存在 request.session.exists("session_key")# 刪除當前會話的所有Session數據 request.session.delete()# 刪除當前的會話數據并刪除會話的Cookie。 request.session.flush() 這用于確保前面的會話數據不可以再次被用戶的瀏覽器訪問例如,django.contrib.auth.logout() 函數中就會調用它。# 設置會話Session和Cookie的超時時間 request.session.set_expiry(value)* 如果value是個整數,session會在些秒數后失效。* 如果value是個datatime或timedelta,session就會在這個時間后失效。* 如果value是0,用戶關閉瀏覽器session就會失效。* 如果value是None,session會依賴全局session失效策略。

  • session版驗證登錄
# session版登錄 def login(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')if username == 'sgt' and password == '123456':# 設置sessionrequest.session['username'] = username# 跳轉到登錄頁面之前的URLnext_url = request.GET.get('next')# 這里需要判斷一下用戶是否是跳轉過來登錄的還是直接登錄的if next_url: # 如果有則跳轉到原頁面return redirect(next_url)else: # 否則默認指定跳轉到指定頁面return redirect('/index/')return render(request, 'login.html')# 登錄驗證裝飾器: # 登錄驗證的過程實際上是基于已登錄的狀態進行校驗的,也就是說,用戶登錄后, # 會在服務端生成一個cookie存儲下來,同時把一份cookie再發給瀏覽器, # 當用戶在某個跳轉到某個需要登錄次才能訪問的頁面時候,就會進行登錄校驗過程 # 會將瀏覽器的cookie發到服務端,和服務端存儲的cookie進行匹配,如果匹配到,就說明 # 服務端已經記錄這這個用戶的登錄狀態,允許訪問。from functools import wraps def login_auth(func):def inner(request, *args, **kwargs):# 獲取到驗證登錄的當前頁面的全部路由next_url = request.get_full_path()# 如果改用戶的session存在,說明已登錄if request.session.get('username'):return func(request, *args, **kwargs)# 發現未登錄,則跳轉到登錄頁面,同時路由后面拼接當前頁面路由else:return redirect('/login/?next=%s' % next_url)return inner@login_auth def logout(request):# 刪除所有當前請求相關的sessionrequest.session.delete()return redirect("/login/")@login_auth def index(request):current_user = request.session.get("user", None)return render(request, "index.html", {"user": current_user})
  • FBV加裝飾器(前面cookie和session加裝飾器都是使用FBV)
  • CBV加裝飾器:
# 需要導入一個method_decorator模塊 from django.utils.decorators import method_decorator 其它都一樣,主要在裝飾的方法上有區別: # @method_decorator(login_auth,name='get') # 第二種 name參數必須指定class MyHome(View):@method_decorator(login_auth) # 第三種 get和post都會被裝飾def dispatch(self, request, *args, **kwargs):super().dispatch(request,*args,**kwargs)# @method_decorator(login_auth) # 第一種def get(self,request):return HttpResponse('get')def post(self,request):return HttpResponse('post')

總結

以上是生活随笔為你收集整理的Web框架之Django_08 重要组件(form组件、cookie和session组件)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。