☆☆ 新着記事 ☆☆

2018年5月31日木曜日

Python 3 CGI Programming(2) - Text入力・ラジオボタン form = cgi.FieldStorage()


html側で組んだフォームデータを受けて、Python 3 でcgiの処理をするスクリプトを書いてみた。
フォームから、引き渡される値が何なのか、どうやって値を出すのかに非常に苦労したけど、よく分かった。 詳細は、下記参照。

(Pythonをネットで調べると、Python 2系と3系の記述が混載されていて非常に苦労する。)

1.CGIの環境設定
Python 3 CGI Programming (1) を参照。



2. 基本の Python3 スクリプト

(Python/html 基本構文)

print "Content-type: text.html\r\n\r\n"
print "<html>"
print "<head><title>My First CGI Program</title></head>"
print "<body>"
print "<p> It worked !!!</p>"

for i in range(5)
   print "<h>Hello world</h>"

print"</body>"
print"</html>"

*Python 2.7の場合、printの後は( ) で囲まなくても良いようですね。

基本は、print を使って、html文を書き出すということだと理解しました。


(基本構文)

print("Content-type: text/html; charset=UTF-8\n")
import cgi

form = cgi.FieldStorage()

htm = '''<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8"/>
<title>py3.cgi</title>
</head>
<body>
<form method="POST">
<input type="text" name="ptest"/>
<input type="submit"/>
</form>
<div>%s</div>
</body>
</html>
'''
print(htm % form.getvalue('ptest'))


(発展)
#helloworld.py
import cgi
 
print("Content-type: text/html\r\n\r\n")
print("<html><body>")
print("<h1> Hello Program! </h1>")
# Using the inbuilt methods
 
form = cgi.FieldStorage()
if form.getvalue("name"):
    name = form.getvalue("name")
    print("<h1>Hello" +name+"! Thanks for using my script!</h1><br />")
if form.getvalue("happy"):
    print("<p> Yayy! I'm happy too! </p>")
if form.getvalue("sad"):
    print("<p> Oh no! Why are you sad? </p>")
 
# Using HTML input and forms method
print("<form method='post' action='helloworld.py'>")
print("<p>Name: <input type='text' name='name' /></p>"#テキスト入力
print("<input type='checkbox' name='happy' /> Happy")   #Radio Button
print("<input type='checkbox' name='sad' /> Sad")        #Radio Button
print("<input type='submit' value='Submit' />")
print("</form")
print("</body></html>")


(発展2)
#whichsubject.py
#!/usr/bin/python
# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()


# Get data from fields
if form.getvalue('dropdown'):
   subject = form.getvalue('dropdown')
else:
   subject = "Not submitted"


print ('''
"<Content-type:text/html\r\n\r\n>"
"<html>"
"<head>"
"<title>Dropdown Box - Sixth CGI Program</title>"
"</head>"
"<body>"
''')

# html form expression
print('''
<form action = "/cgi-bin/subject.py" method = "post" target = "_blank">
<select name = "dropdown">
<option value = "Maths" selected>Maths</option>
<option value = "Physics">Physics</option>
</select>
<input type = "submit" value = "Submit"/>
</form>''')

print ("<h2> Selected Subject is %s</h2>" % subject)
print ("</body></html>")
 


3.  htmlファイル と Python3 スクリプトを分けてみる。

以上は、全て直接, pyファイルを参照しているが、次に html ファイルと pyのファイルを分けて作ってみる。


#html : calc simple.html
<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
        <title>メトリック・コンバーター</title>
    </head>
    <body>
<form action = "./cgi-bin/querytest.py" method = "post">
 <p>Length: <input type='number' name='length' min='1' max='1000'/></p>
  <input type = "submit" value = "Submit"/>

</form>
 </body>

</html>



#Python 3 : querytest.py
print("Content-type: text/html; charset=UTF-8\n")
import cgi

htm = '''<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8"/>
<title>py3.cgi</title>
</head>
<body>
%s
</body>
</html>
'''
form = cgi.FieldStorage()
print(htm % form.getvalue('length'))       #html 内に数字を渡す(?)
 


(結果)

* form.getvalue(名前)は、html (requestサイト)のName属性で受け渡しが確認できることを確認。


(更に)

#html ファイル


コマンドライン

解説

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>メトリック・コンバーター</title>
    </head>
    <body>

<form action = "./cgi-bin/querytest.py" method = "post" target = "_blank">
 <p>Unit:  <select name = "dropdown"></p>
   <option value = "null"> ----</option>
   <option value = "feet"> feet</option>
   <option value = "inch"> inch</option>
  </select>

 <p>Length: <input type='number' name='length' value='%s' min='1' max='1000'/></p>
  <input type = "submit" value = "Submit"/>
</form>

 </body>

</html> 
 
 

 

 
 
 
 
 
 
 
 
 
 
 
#ドロップダウン 
getvalue(dropdown)の値として、Option のValueの値が格納される。
 
 
 
#テキスト・フィールド
getvalue(length)の値として、inputされた値が格納される。

 

 #Python スクリプトファイル:

記述内容


解説

 print("Content-type: text/html; charset=UTF-8\n")
import cgi

# Create instance of FieldStorage
form = cgi.FieldStorage()


if str(form.getvalue('dropdown')) == 'feet':
    num = form.getvalue('length')
    length = int(num)
    cm = length * 30.48
    print('You entered ' + str(length) + ' feet, which is  ')
    print(str(cm) + " cm")
    print(', also same as ' +str(cm/100) + " m")
 
else:
    print("I haven't done yet that far!!")


#print ("<Content-type:text/html\r\n\r\n>")
#print ("""
#       <html>
#       <head>
#       <title>Getting Tired?</title>
#       </head>
#       <body>""")
#print ("</body></html>")
# Get data from fields

 

 


ドロップダウンから渡される値(option value)が 'feet' であれば。

htmel側で入力は数値と指定しても、引き渡しは文字形式なので、数値タイプに変更。









#pythonのスクリプト側でhtmlを記載する良い方法は良く分からない。

 
結果、


(htmlサイド)

(スクリプトサイド)




p = "今回は非常に苦労した!!"
print (p*5)

今回は非常に苦労した!!今回は非常に苦労した!!今回は非常に苦労した!!今回は非常に苦労した!!今回は非常に苦労した!!"

参考)

Python3 Advanced Tutorial 7 - CGI Programming
https://youtu.be/x_1rgQwk5fM
PythonのCGIでGETやPOSTの値を受け取ってみる
http://atomiyama.com/linux/page/python-cgi-01/
CGI Programming in Python
https://www.geeksforgeeks.org/cgi-programming-python/
How to pass Drop Down Box Data to Python CGI script?
https://www.tutorialspoint.com/How-to-pass-Drop-Down-Box-Data-to-Python-CGI-script
Python - CGI Programming
https://www.tutorialspoint.com/python/python_cgi_programming.htm
input関数|Python用語辞典
https://tech-joho.info/input%E9%96%A2%E6%95%B0/
セレクトボックスを作る
http://www.tagindex.com/html_tag/form/select.html
Pythonの%演算子による文字列フォーマット
https://qiita.com/takahiro_itazuri/items/e585b46d096036bc837f


◆こんなのもある。
https://www.jiriki.co.jp/blog/python/python-postmethod-form

1.htmlサイド
<html>
<head>
<title>Form test</title>
</head>
 
<body>
<h1>Python Form test</h1><hr>
 
<form name="Form" method="POST" action="/cgi-bin/form.py">
name: <input type="text" size="30" name="name">
mail: <input type="text" size="30" name="mail">
<input type="submit" value="submit" name="button">
</form>
</body>
</html>
 
2. pyサイド
 
#!/usr/bin/env python
import cgi
 
print "Content-Type: text/html\n"
 
print "<html><body>"
 
form = cgi.FieldStorage()
form_check = 0
if form.has_key("name") and form.has_key("mail") :
  form_check = 1
if form_check == 0 :
  print "<h1>ERROR !</h1>"
else :
  print "<h2>PRINT</h2><hr>"
  print "<b>name: </b>", form["name"].value
  print "<b>mail: </b>", form["mail"].value
 
print "</body></html>"
 
◆こんなのもある。
GETメソッドとPOSTメソッドの比較
 
 

Django (17) (18) 2つ目のDBの連結



データ・ベースの連結
 
現在の /music/ のページ。
 
 
 
 
1)  APPL(music)フォルダ内の "models.py" を修正する。


from django.db import models

class Album(models.Model):
    artist = models.CharField(max_length=250)
    album_title = models.CharField(max_length=500)
    genre = models.CharField(max_length=100)
    album_logo = models.CharField(max_length=1000)

    def __str__(self):
  return self.album_title + " - " + self.artist


class Song(models.Model):
    #Foreign KeyでAlbum DBと紐付いている
    album = models.ForeignKey(Album,on_delete=models.CASCADE) 
    file_type = models.CharField(max_length=10)
    song_title = models.CharField(max_length=250)

    def __str__(self):
  return self.song_title  # Titleを表示させる。

  
*) 今回の場合、Databaseのテーブルのストラクチャー変更をしていないので、migrationをする必要はない。
*) この段階で、/music/を表示しても、Song D.Bにはオブジェクトが登録されていないので、Albumの情報しか
 相変わらず表示されない。

2) Amin Panelとの連携

from django.contrib import admin
from .models import Album, Song                               #Song Data Baseの追加

admin.site.register(Album)  


admin.site.register(Song)                                              #Song Data Baseの追加
 
*) この段階で, AdminのDB操作画面に、DBへの登録・管理画面が追加される。



ターミナルからのデータ投入


Admin画面で登録の確認

 
 



*現時点では、/music/ は、文頭の表示から変更されていない。


Terminalからobjectの確認

(*上記、terminalのコマンドの続き。)


もう一つのデータ・登録方法 ( 'create' function)





参考)
Django Tutorial for Beginners - 17 - Adding Songs to our Database
https://youtu.be/TnU_I8DKKYQ

Django Tutorial for Beginners - 18 - Related Objects Set
https://youtu.be/uvafEFi2bY4



Django (13) - (16) Detail 画面の作成







(views.pyの変更)

コマンドライン
解説
 
from django.http import HttpResponse
from . models import Album
 
 
def index(request):  

 #-----Python DB 組み込み--------------
   all_albums = Album.objects.all()


 #-----html--------------
  html = ’’
  for album in all_albums:
       url = '/music/' + str(album.id) + '/'


       html += '<a href=" ' +url + ' "> + album.album_title +  ' </a><br>'

Return HttpResponse(html)
("<h1> This is the Music App Homepage!</h1>")
def detail(request, album_id):
    return HttpResponse("<h2> Details for Album id: " + str(album_id) + "</h2>")
 


 
 

<-model.pyからAbumモジュールのインポート


<-Albumのオブジェクトを変数に入れる。(DBの組み込み)
 



#urls.pyで作成した /music/712/の 
 構成を表記
 
リンク名作成方法の指定
 
 
h1の記述は削除







(views.pyの変更2: htmlと区分できるようにstructure変更)
前回のhtml部分の全削除


コマンドライン
解説

def index(request):  

 #-----Python DB 組み込み--------------
   all_albums = Album.objects.all()


 #-----html--------------
 

Return HttpResponse(html)
 
def detail(request, album_id):
    return HttpResponse("<h2> Details for Album id: " + str(album_id) + "</h2>")
 
 

 
 

 

<-model.pyからAbumモジュールのインポート


<-Albumのオブジェクトを変数に入れる。
 
#urls.pyで作成した /music/712/の 
 構成を表記
 
リンク名作成方法の指定
 
 
h1の記述は削除





Python 正規表現(regular expression)の記述例



◇エスケープ・シーケンスの取り扱い

Pythonでは、通常の文字列では表せない文字(タブや改行など)をバックスラッシュ' \ 'をつけたエスケープシーケンス(\t\nなど)で記述する。

\t: タブ挿入
\n: 改行

WindowsだとBack Slashは '¥' の半角記号になるので、これが、Windows上のPythonで
上手く機能しているか、確認する。

(bloggerって、'ろ' の後ろは、' \ ' になるんですね。)



機能、してますね。

◇実際に使ってみる。

基本構文

import re

pattern = ("""
Jessica is 23 years old and she is an engineer of Google.
James is 33 years old and he is an employee of Ford Mortor.
Edward is 103 years old and he was born in 1900.
Alex has just bought a book of 123456 pages.
""")

ages = re.findall(r'\d{1,3}', pattern)  # search 1- 3 digit(s) number
print(ages)

names = re.findall(r'[A-Z][a-z]*', pattern) #Search words started with capital letter.
print(names)


結果

['23', '33', '103', '190', '0']

['Jessica', 'Google', 'James', 'Ford', 'Mortor', 'Edward', 'Oscar']

発展) Dictionaryへの結果の登録

import re

pattern = ("""
Jessica is 23 years old.
James is 33 years old.
Edward is 103 years old and he was born in 1900.
""")

ages = re.findall(r'\d{1,3}', pattern)  # search 1- 3 digit(s) number
print(ages)

names = re.findall(r'[A-Z][a-z]*', pattern) #Search words started with capital letter.
print(names)

x = 0
ageDict = {}
for eachName in names:
    ageDict[eachName] = ages[x]
    x+=1

print(ageDict)

['23', '33', '103', '190', '0','123', '456']
['Jessica', 'James', 'Edward']
{'Jessica': '23', 'James': '33', 'Edward': '103','Alex': '190'}
書き方解説)
Re.findall: 文字列を検索する。
   \d{1,3}
\d  : 任意の数字
{1,3 } : 1~3回の繰り返し
最大3桁の文字列として区切って検索するという意味。


正規表現の記述例:
(?P<任意の変数>[0-9]+):  任意の桁の数字を引いてくる

参考)

◇メタ文字
メタ文字説明指定例合致する
.任意の一文字
(any character,  except for new line)
a.cabc, acc, aac
^行の先頭
(Match the beginning of string)
^abcabcdef
$行の末尾
(Match the end of string)
abc$defabc
*0回以上の繰り返し
(Match 0 or more)
ab*a, ab, abb, abbb
+1回以上の繰り返し
(Match 1 or more)
ab+ab, abb, abbb
?0回または1回
(Match 0 or 1)
ab?a, ab
{m}m回の繰り返し
(range or "varaiance")
a{3}aaa
{m,n}m〜n回の繰り返し
{1,3} expecting 1-3
a{2, 4}aa, aaa, aaaa
[★]★のどれか1文字[a-c]
[a-cl-p]
a, b, c
little bother
★|★★のどれか
(either or)
a|b
nu|un
a, b
A nut for a jar of tuna.



◇特殊シーケンス(identifiers)
特殊シーケンス説明同じ意味の正規表現
\d任意の数字
(any number)
[0-9]
\D任意の数字以外
(anything but a number)
[^0-9]
\s任意の空白文字
(space)
[\t\n\r\f\v]
\S任意の空白文字以外
anything but a space
[^\t\n\r\f\v]
\w任意の英数字
any character
[a-xA-Z0-9_]
\W任意の英数字以外
anything but a character
[\a-xA-Z0-9_]
\A文字列の先頭^
\Z文字列の末尾 $



特殊シーケンス

説明

\b

任意の数字

(any number)

\n

new line

\s

space

\t

tab

\e

escape

\f

form feed

\r

return


良く使うパターン。

1)特定の文字列をどこかに含む
^(?=.*カレー).*$

’カレー'屋さんとか、 '今日、カレー食べる?' 'GoGo カレー'  などの
カレーという文字列を含む文字列がヒットする。

◇指定の箇所まで抽出(スライシング)

文字列[開始位置:終了位置:ステップ]

スライシングは開始位置は含み、終了位置は含まない。
スペースも、1インデックス分としてカウントする。

>>> s='Hello World!'
>>> s[1:5]
'ello'
>>> s[0:6:2] ♯0番目から6番目の間を2文字目毎にとってくる。
'Hlo'
>>> s[0:6:-1]
''
>>> s[::-1] ♯後ろから。
'!dlroW olleH'


 Pythonの正規表現:

import re: とか使うらしい。 別途、まとめる。

◇スペースを排除するだけなら、
文字列.strip(削除したい文字列)   で、'削除したい文字列'を省略することで
前後の余白を削除できる。

a=[
    {'area': 'ALL   ', 'original_area': 'CA ', 'number': '1?', '},
    {'area': 'ALL', 'original_area': 'CA ', 'number': '2'},
    ]
questoins=[]
for i in range(len(a)):
    area=(a[i]['area'])
    area=area.strip()
    if area =='ALL' or area =='CA':
        print(a[i])
       
で、areaの値に空白が含まれている場合でも、条件にマッチさせることができる。

◇メール・アドレスや . を削除する


Python
import re

message="
My office email address is test2018@test.com.
But my personal one is test.craig@g.co.jp.Please visit our web site @ https://test.test.com
Company information is here at https://test.test.com/about 
Sincerely, 15 Jan, 2019 "

new_message=' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)", " ", message).split())

print(new_message)


Output:
My office email address is test2018 com But my personal one is test craig co jp Please visit our web site Company information is here at Sincerely 15 Jan 2019


My office email address is test2018@test.com. But my personal one is test.craig@g.co.jp.Please visit our web site @ https://test.test.com.Company information is here at https://test.test.com/aboutSincerely,15 Jan, 2019

Python


(解説)
' '. :区切り文字をつけないで連結。
test = ['ab', 'c', 'de']
result = ''.join(test)
print(result)abcde
result2 = ','.join(test)
print(result2): ab,c,de

.split() : ()内の文字で分割する。
a = "abbaccadda"
sep = a.split("a")
print(sep) : ['', 'bb', 'cc', 'dd', '']
sep2 = a.split("ac")
print(sep2)
['abb', 'cadda']
*区切りに使用した文字列は、戻り値からは消えてしまう。

re.sub():re.sub(正規表現“置換する文字列”置換対象の文字列)
[] のどれか1文字
参考)
Pythonでエスケープシーケンスを無視(無効化)するraw文字列
https://note.nkmk.me/python-raw-string-escape/

書きながら覚えよう!Pythonで正規表現を使う方法【初心者向け】
https://techacademy.jp/magazine/15635

Python 3 Programming Tutorial - Regular Expressions / Regex with re
https://youtu.be/sZyAn2TW7GY