☆☆ 新着記事 ☆☆

2019年1月29日火曜日

リンクを新しいウィンドウで開く(HTML / Javascript)





<html>
<a href="リンク先のURL" target="_blank">リンクのテキスト</a>
* target="_blank":これを指定しなければ、新しいタグで表示される。




<javascript>
<body>
  <a href="javascript:void(0);" onclick="window.open('リンク先のURL','_blank')">
    新しいウィンドウで開く</a>
</body>

2019年1月28日月曜日

TypeError: 'str' object does not support item assignment

リストを操作していると、上記のようなエラーになることがあります。 これは、リストのように見える値が、実はストリング(文字列)だった場合に発生するエラーのようです。
自分の場合は、csvファイルからデータを読み込んだ時に、2元リストのデータを読み込んだ時に、このエラーが発生しました。

以下、対処方法です。


(問題の確認)

◆リストの要素へのアクセス
a=["1","2","3","4"]

print(a[0]) #1
print(a[1]) #2

◆リストがストリング形式だと。
a = str(["1","2","3","4"])

print(a[0]) #[
print(a[1])  # '
*ひとつひとつのキャラクターが認識されてしまう。

a_new=a.replace(',',':')
print(a_new) ♯ ['1': '2': '3': '4']
*文字ブロックだから、replaceは出来る。

◆List()関数で再変換してみる。
a = str(["1","2","3","4"])
list(a)
print(a)   ♯['1', '2', '3', '4']
print(a[0]) #[
print(a[1])  # '
*変化なし。外見はリストに見えるけど、実質はstringのまま。

◆split / joinしてみる。(動作確認)

(1) Split してみる。
a = str ( ["1","2","3","4"] )
b=a.split(',') ←カンマ区切りでsplit。
  
print(b)   # ["['1'", " '2'", " '3'", " '4']"] <-- 戻り値はリスト形式。
print(b[0])   # ['1'
print(b[1])   # '2'

(2)join
a = str(["1","2","3","4"])
b=a.split(',')
a=(',').join(b) <- カンマ区切り文字として結合。

(変換対象文字列、区切り書式の書き方は、splitとは逆なので注意。)

print(a)    # ['1', '2', '3', '4']
print(a[0]) # [
print(a[1]) # '

*最初と同じで、効果なし。

◆' [ ' , ' ] ' や (クォート)を地道に削除する。

a = str(["1","2","3","4"])
new_a=a.replace('[','')
new_a=a.replace(']','')
new_a=a.replace('\'','')
print(new_a)  # [1, 2, 3, 4]

前処理終了。 ここから、やりたい処理にはいる。

例)shuffleをする。 ただし、まだ変数 'new_a' は、ひと塊のstringsなので
ここで処理しても、以下のエラーとなる。

x[i], x[j] = x[j], x[i]
TypeError: 'str' object does not support item assignment.

なので、以下のように、splitしてから処理する。

====Python3.6の場合
import random
a = str(["1","2","3","4"])
new_a=a.replace('[','')
new_a=a.replace(']','')
new_a=a.replace('\'','')
print(new_a)     # 1, 2, 3, 4
b=new_a.split(',')
random.shuffle(b)
new_a=b
print(new_a)       # [ ' 2', ' 4',' 3', '1']

*Python3.7は、上記のような挙動はしないようです。
replace の ('[')や(']') が機能しません。





2019年1月25日金曜日

Python CSVを扱う時のリストと辞書を研究する

Excelだと簡単な表の操作も、Pythonで扱おうとすると難しく感じます。 それは、データがチュートリアルに出てくる単純なリストや辞書ではないから。

「リストを内包するリスト」、「辞書を内包するリスト」、「リストを内包する辞書」、また更に、辞書を内包する、とか、どんどん構造が深くなっていきます。

そこで、リスト、辞書の表現形式とPythonのスクリプトの基本を確認しておきます。


PythonでCSVを扱う基本操作は、こちらを確認ください。

関連記事: Python 3でCSVファイルの操作

writer.writerows(array2d) <- 2元配列の使い方

<前提>

1. Listの書き込み、読み込み

(sample)
sample=['name','Freddie', 'song', 'Rock you', 'Year', '1977']

(書き込み)
 import csv
sample=['name','Freddie', 'song', 'Rock you', 'Year', '1977']
with open ('a.csv','w', newline='') as f:
    mySample = csv.writer(f, delimiter=",")
    mySample.writerow (sample)


(作成されたcsvの内容確認)

これで、' a.csv ' が作成される。

この a.csv を
1) text editorで開くと、

   name,Freddie,song,Rock you,Year,1977

という文字列になる。(あたり前ですが。)

2) excelで開く


要素が1つずつ、セルに格納されている。

読み込み

 このa.csvを読みだしてみる。

import csv
with open("a.csv","r") as f:
    reader=csv.reader(f)
    for line in reader:
        print(line)  # --①
   print(line[1]) # --②
Output
① ['name', 'Freddie', 'song', 'Rock you', 'Year', '1977']
記述したそのままですね。
② Freddie  
要素が取り出せます。

因みに、a.csvを以下のように2行に書いて①で再読み込みすると


IDEで1行ずつ表示させる。
import csv
with open("a.csv","r") as f:
    reader=csv.reader(f)
   
    for line in reader:
        print(line)

['name', 'Freddie', 'song', 'Rock you', 'Year', '1977']
['name', 'Charlie', 'song', 'Attention', 'Year', '2018']

 print(line[1])
で、以下の要素が取り出せる。
 'Freddie'
 'Charlie'



list()関数で、別のリストを作成して表示させる。

[['name', 'Freddie', 'song', 'Rock you', 'Year', '1977'], ['name', 'Charlie', 'song', 'Attention', 'Year', '2016']]
2次元リストになっている。

そこで、しつこいようだが、このリストをCSVに書き込んでみる。

import csv
sample=[
    ['name', 'Freddie', 'song', 'Rock you', 'Year', '1977'],
    ['name', 'Charlie', 'song', 'Attention', 'Year', '2016']
    ]
with open ('a.csv','w', newline='') as f:
    mySample = csv.writer(f, delimiter=",")
    mySample.writerow (sample)

a.csv を、テキスト・エディータで開くと、
"['name', 'Freddie', 'song', 'Rock you', 'Year', '1977']","['name', 'Charlie', 'song', 'Attention', 'Year', '2016']"

Excelで開くと
 
 
1つのセルに内包されるリストの要素が、全て1つの要素として格納されている。
これをしつこいようですが、再度、読み込む。
 
import csv
with open("a.csv","r") as f:
    reader=csv.reader(f)
    for line in reader:
        print(line)
        print(line[1])


Output:
["['name', 'Freddie', 'song', 'Rock you', 'Year', '1977']", "['name', 'Charlie', 'song', 'Attention', 'Year', '2016']"]
['name', 'Charlie', 'song', 'Attention', 'Year', '2016']

そのままですね。


2. 辞書の読み込み・書き込み


では、 前にCSVを変更した以下のように表示させるには、どうすれば良いか?




のように記述するのは、どうしたら良いか?

これと全く同じではないけど、利用目的を考えるとDictionaryなんでしょうね、


import csv
sample=[
    {'name':'Freddie', 'song':'Rock you', 'year': '1977'},
    {'name': 'Charlie', 'song': 'Attention', 'year': '2016'}
    ]
with open("a.csv",'w') as f:
    fieldnames = ['name', 'song','year']
    writer=csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(sample)


 
*1行、空いてしまうので、後述のように、lineterminator='\n' をオプションで指定する。
 
 
辞書のvalueにリストも入れられる。
 
import csv
sample = [
    {'name': 'Justine', 'rank':'1', 'score':'10', 'record': ['10', '20', '30']},
    {'name': 'Puth', 'rank':'2', 'score':'20', 'record': ['20', '30', '40']},
    {'name': 'Shia', 'rank':'3', 'score':'30', 'record': ['50', '60', '70']},
    ]
with open("a.csv",'w') as f:
    fieldnames = ['name', 'rank','score','record']
    writer=csv.DictWriter(f, fieldnames=fieldnames,lineterminator='\n')
    writer.writeheader()
    writer.writerows(sample)

 
 
3. 辞書の読み込み
 
==csv.readerで読み込む。
import csv
with open("a.csv","r") as f:
    reader = csv.reader(f)
    for line in reader:
        print(line)
['name', 'rank', 'score', 'record']
['Justine', '1', '10', "['10', '20', '30']"]
['Puth', '2', '20', "['20', '30', '40']"]
['Shia', '3', '30', "['50', '60', '70']"]
 
[['name', 'rank', 'score', 'record'], ['Justine', '1', '10', "['10', '20', '30']"], ['Puth', '2', '20', "['20', '30', '40']"], ['Shia', '3', '30', "['50', '60', '70']"]]
 
==csv.DictReaderで読み込む。
 
import csv
with open("a.csv","r") as f:
    reader = csv.DictReader(f)
   b=[]
    for line in reader:
        print(line)
        b.append(line)
print(b)

OrderedDict([('name', 'Justine'), ('rank', '1'), ('score', '10'), ('record', "['10', '20', '30']")])
OrderedDict([('name', 'Puth'), ('rank', '2'), ('score', '20'), ('record', "['20', '30', '40']")])
OrderedDict([('name', 'Shia'), ('rank', '3'), ('score', '30'), ('record', "['50', '60', '70']")])

[OrderedDict([('name', 'Justine'), ('rank', '1'), ('score', '10'), ('record', "['10', '20', '30']")]), OrderedDict([('name', 'Puth'), ('rank', '2'), ('score', '20'), ('record', "['20', '30', '40']")]), OrderedDict([('name', 'Shia'), ('rank', '3'), ('score', '30'), ('record', "['50', '60', '70']")])]
 

 
ところで、こんな数字をValueとしてもつ、CSVファイルがあったとする。
 
 
 
textで開くとこんな感じ。
 
question,answer,option1,option2,option3,tip
1?,1,1,2,3,one
2?,2,2,3,4,two
3?,3,3,4,5,three
4?,4,4,5,6,four
5?,5,5,6,7,five
 
 
これを、Pythonのcsvモジュールを使って読み込むと、IDEでのprint outは、こんな感じ。
 
[{'question': '1?', 'answer': '1', 'option1': '1', 'option2': '2', 'option3': '3', 'tip': 'one'}, {'question': '2?', 'answer': '2', 'option1': '2', 'option2': '3', 'option3': '4', 'tip': 'two'}, {'question': '3?', 'answer': '3', 'option1': '3', 'option2': '4', 'option3': '5', 'tip': 'three'}, {'question': '4?', 'answer': '4', 'option1': '4', 'option2': '5', 'option3': '6', 'tip': 'four'}, {'question': '5?', 'answer': '5', 'option1': '5', 'option2': '6', 'option3': '7', 'tip': 'five'}]
 
text形式に変換される。 
 
従って、このままではintegerとして扱えない。
 
a=[
    {'question': '1?', 'answer': '1', 'option1': '1', 'option2': '2',
     'option3': '3', 'tip': 'one'},
    {'question': '2?', 'answer': '2', 'option1': '2', 'option2': '3',
     'option3': '4', 'tip': 'two'}
    ]
b=a[0][option1]+a[1][option1]
print(b)
NameError: name 'option1' is not defined
 
となるのに対し、
a=[
    {'question': '1?', 'answer':'1','option1':1,'option2': '2',
     'option3': '3', 'tip': 'one'},
    {'question': '2?','answer': '2','option1':2,'option2': '3',
     'option3': '4', 'tip': 'two'}
    ]
のように、要素のValueが数字であれば、計算ができる。
 
b=a[0]['option1']+a[1]['option1']
print(b)  #Output: 3

 
因みに、enumerate()で辞書にindex番号をつけると、integer形式の数字が付与される。
keyに紐づくbalueの形式には影響しない。
 
b=dict(list(enumerate(a,start=1)))
 
{1: {'question': '1?', 'answer': '1', 'option1': 1, 'option2': '2', 'option3': '3', 'tip': 'one'}, 2: {'question': '2?', 'answer': '2', 'option1': 2, 'option2': '3', 'option3': '4', 'tip': 'two'}}


2019年1月19日土曜日

flask セッションを理解する


◇基本の書き方
import os
from flask import Flask, session
app = Flask(__name__)
app.secret_key = os.urandom(24)
@app.route('/python', methods=['GET', 'POST'])
def index():
    if request.method == "POST":
    entered_answer = request.form.get('answer_python', '')
    if not entered_answer:
      flash("Please choose an answer", "error")

*secret_keyに、ランダムな文字列を固定的に割り当てたい場合、
 Pythonのコマンドラインで、
 >>> import secrets
 >>> secrets.token_hex(16)
 '253147b9664959d8440ba041296b4bf6'

 app.config['SECRET_KEY'] = '253147b9664959d8440ba041296b4bf6'

 とすることも可能。

セッションの削除

書き方例
1) session.pop('visits', None) # delete visits
2) session.clear()

参考)

https://overiq.com/flask-101/sessions-in-flask/

2019年1月13日日曜日

MariaDB (Mysql) のインストール ・コマンド一覧


◆ログイン
mysql -u root -p
オプション: -u
ユーザ名指定
オプション: -p
ログインにパスワードプロンプト要求

( データベース名が該当する箇所は、拡張子 .dbは不要。 名前だけ。

◆DB一覧表示
show databases;

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |


◆DBの作成
create database データベース名;
MariaDB [(none)]> create database msg;

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| msg                |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)


◆DBの削除
DROP DATABASE  データベース名;

◆使用するDBの指定
use データベース名;

MariaDB [(none)]> use msg


◆レコードを検索する
SELECT * FROM テーブル名;

◆ログアウト
exit;

◆テーブルの一覧表示
show tables;

MariaDB [msg]> show tables;  ♯DBを選択した後で、[ ]内に選択中のDB名
+---------------+
| Tables_in_msg |
+---------------+
| tw_msg        |
+---------------+
1 row in set (0.00 sec)




◆テーブルの内容確認
(use database名でデータベースを指定した後)
select * from テーブル名


1. MariaDBのパッケージを確認 と削除[@ lib]# cd /var/lib
[@ lib]#  rpm -qa | grep maria
mariadb-5.5.60-1.el7_5.x86_64
mariadb-server-5.5.60-1.el7_5.x86_64
mariadb-libs-5.5.60-1.el7_5.x86_64


[@ lib]# yum remove mariadb
============================================================================================================================
 Package                          Arch                     Version                            Repository               Size
============================================================================================================================
Removing:
 mariadb                          x86_64                   1:5.5.60-1.el7_5                   @base                    49 M
Removing for dependencies:
 mariadb-server                   x86_64                   1:5.5.60-1.el7_5                   @base                    58 M

Removed:
  mariadb.x86_64 1:5.5.60-1.el7_5
Dependency Removed:
  mariadb-server.x86_64 1:5.5.60-1.el7_5

Remove  1 Package (+1 Dependent package)
Complete!

[ lib]# yum remove mariadb-libs
Removed:
  mariadb-libs.x86_64 1:5.5.60-1.el7_5
Dependency Removed:
  perl-DBD-MySQL.x86_64 0:4.023-6.el7                             postfix.x86_64 2:2.10.1-6.el7

[root@cnewgwb6 lib]# rpm -qa | grep maria
[root@cnewgwb6 lib]#

[root@cnewgwb6 lib]# ls -a
.    ..
authconfig    dbus    letsencrypt  mysql    php    postfix     selinux    tuned

[@ lib]# rm -rf mysql
[@lib]# ls -a

2. MariaDBの再インストール


[ lib]# yum install mariadb mariadb-server

Installed:
  mariadb.x86_64 1:5.5.60-1.el7_5                           mariadb-server.x86_64 1:5.5.60-1.el7_5
Dependency Installed:
  mariadb-libs.x86_64 1:5.5.60-1.el7_5                          perl-DBD-MySQL.x86_64 0:4.023-6.el7
Complete!

[root@cnewgwb6 lib]# rpm -qa | grep maria
mariadb-5.5.60-1.el7_5.x86_64
mariadb-server-5.5.60-1.el7_5.x86_64
mariadb-libs-5.5.60-1.el7_5.x86_64
[root@cnewgwb6 lib]# ls -a
authconfig    dbus    letsencrypt  mysql  php   postfix     selinux    tuned <-再びディレクトリが出来ています。


文字コードの設定
[@ lib]# vi /etc/my.cnf

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
character-set-server=utf8
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
#
# include all files from the config directory
#
!includedir /etc/my.cnf.d
サービスの起動
[@ lib]# systemctl enable mariadb.service
Created symlink from /etc/systemd/system/multi-user.target.wants/mariadb.service to /usr/lib/systemd/system/mariadb.service.
[@lib]# systemctl start mariadb.service

2019年1月11日金曜日

(詳述) Virtualenvとmod_wsgiで、Python Flaskを動かす

以前、virtualenv と venv の違いについて書きましたが、

【 「Pythonの仮想環境  venv と virtualenvのもっとも大きな違い 」 】

その後、調べるにつけ、Pythonアプリはvirtualenv環境下で動かすべき、という記事を沢山見つけましたので、やってみます。


Virtualenv環境

・CentOS 7 に標準のPython 2.7 とは別のバージョン(Python 3.7)をインストール。

・Apache(httpd 2.4)のVirtual Hostは、mod_wsgi開発者のGraham Dumpletonさんが強く推奨する
  Daemon Mode (デーモン・モード)で記述。

・wsgiスクリプトには、virtualenvを自動起動する為の activate_this.py をinvokeする設定を入れます。

途中で解説を入れながら、ステップ・バイ・ステップで、1つずやります。

1. ディレクトリ・ファイル構成
virtualenvでは、仮想環境構築用のディレクトリとPythonアプリ(今回はflask)は、別ディレクトリに作成することが推奨されていますので、それに準拠します。

vitualenv を走らせるには、2つのファイルを記述する事がポイントになります。
・ httpdのconf ファイルに<virtual host>の記述
・ wsgiスクリプト


(仮想環境構築)
 /home/virtual_test
                  |
                  |---virtual_test_child <-- 仮想化する対象のディレクトリーです。
                                  |
                                  |----- bin  <-- activate_this.pyは、ここに自動生成されます。
                                           |-----

(Flaskアプリ)
 /var/www/html/virtual_test_app
                              |-----app.wsgi
                              |-----app.py
                              |----- templates
                                            |---sample01.html
                                            |---sample02.html

では、やってみます。

1. 仮想環境の構築

[@ home]# mkdir virtual_test
[@ home]# cd virtual_test
[@ virtual_test]# mkdir virtual_test_child
[@ virtual_test]# virtualenv virtual_test_child
Using base prefix '/usr/local'
New python executable in /home/virtual_test/virtual_test_child/bin/python3
Also creating executable in /home/virtual_test/virtual_test_child/bin/python
Installing setuptools, pip, wheel...
done.
(virtual_test_child) [@ virtual_test]# python -V
Python 3.6.8
(virtual_test_child) [@ virtual_test]# which python
/home/virtual_test/virtual_test_child/bin/python <-- されます。
(virtual_test_child) [@ virtual_test]# pip freeze
(virtual_test_child) [@ virtual_test]#

2. Pythonのインストール

1)ツールのインストール
(virtual_test_child) [@ virtual_test]# yum groupinstall "development tools"
(エラー表示)
Maybe run: yum groups mark install (see man yum)
No packages in any requested group available to install or update

(対処):epel が上手く機能していない可能性があるため
(virtual_test_child) [@ virtual_test]# yum clean all
(virtual_test_child) [@ virtual_test]# yum --disablerepo=\* --enablerepo=base,updates groupinstall "Development Tools"

(同じエラー表示)
Maybe run: yum groups mark install (see man yum)
No packages in any requested group available to install or update

(確認)
(virtual_test_child) [@ virtual_test]# yum grouplist
Installed Groups:
   Development Tools

うーむ。 グローバルなものが参照されちゃうんですね。

(以上、エラー対処は、2015/12/11
 https://www.centos.org/forums/viewtopic.php?t=55400 を参照しました。)


#yum list installed で確認すると、必要なツールは全て、インストールされている表示になって
しまいます。

なので、これ以上、virtualenv環境でのツールのインストールはしません。

初めて、Pythonをソース・コードからインストールされる方は、こちらも参考にしてみてください。
必要なパッケージをインストールしています。

【 「これで動く (1) !! WebArena VPS(CentOS7)でFlaskを動かす 」 】



virtual_test_child) [@ virtual_test]# wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz
2019-01-09 20:48:59 (10.8 MB/s) - ‘Python-3.7.2.tgz’ saved
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# tar zxvf Python-3.7.2.tgz
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  Python-3.7.2  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# cd Python-3.7.2
(virtual_test_child) [@ Python-3.7.2]# ./configure --enable-shared
(virtual_test_child) [@ Python-3.7.2]#  ./configure --enable-optimizations
(virtual_test_child) [@ Python-3.7.2]# make && make altinstall
(error)
ModuleNotFoundError: No module named '_ctypes'
凄く時間がかかって、この結果はがっかりします。
原因は、 libffi-develがインストールされていないから。
https://bugs.python.org/issue31652

(virtual_test_child) [@ Python-3.7.2]# yum install libffi-devel
の前に、
以下のdependenciesがインストールされているか確認。
(virtual_test_child) [@ Python-3.7.2]# yum list installed | grep -ie httpd-devel -e python-deve
l
httpd-devel.x86_64                     2.4.6-88.el7.centos        @base
python-devel.x86_64                    2.7.5-76.el7               @base

インストールされていますね。

では、
(virtual_test_child) [@ Python-3.7.2]# yum install libffi-devel
Complete!

もう一回、最適化とコンパイル。

(virtual_test_child) [@ Python-3.7.2]#  ./configure --enable-optimizations
(virtual_test_child) [@ Python-3.7.2]# make && make altinstall
Installing collected packages: setuptools, pip
Successfully installed pip-18.1 setuptools-40.6.2

無事にpythonがインストールされました。

3.  mod_wsgiをインストールする

(virtual_test_child) [@ Python-3.7.2]# cd ..  <- pythonをインストールしたdirectoryに戻る
(virtual_test_child) [@ virtual_test]#wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.6.tar.gz
2019-01-10 01:34:34 (932 KB/s) - ‘4.5.6.tar.gz’ saved
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  4.5.6.tar.gz  Python-3.7.2  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# tar zxvf 4.5.6.tar.gz

(virtual_test_child) [@ virtual_test]# which python3
/home/virtual_test/virtual_test_child/bin/python3
(virtual_test_child) [@ virtual_test]# deactivate
[@ virtual_test]# cd /
[@ /]# find -name apxs
./usr/bin/apxs
[@ /]# cd /home
[@ home]# ls -a
.  ..  virtual_test
[@ home]# cd virtual_test
[@ virtual_test]# ls -a
.   4.5.6.tar.gz    Python-3.7.2      virtual_test_child
..  mod_wsgi-4.5.6  Python-3.7.2.tgz
[@ virtual_test]# source virtual_test_child/bin/activate
(virtual_test_child) [@ virtual_test]# cd mod_wsgi-4.5.6
(virtual_test_child) [@ mod_wsgi-4.5.6]# ./configure --with-apxs=/usr/bin/apxs --with-python=/usr/bin/python3
configure: creating ./config.status
config.status: creating Makefile

(virtual_test_child) [@ mod_wsgi-4.5.6]# make && make install
Libraries have been installed in:
   /usr/lib64/httpd/modules
chmod 755 /usr/lib64/httpd/modules/mod_wsgi.so <-後でmod_wsgi.soが、pythonのshared libraryを使えているか確認します。

4. Flaskをインストールする

(virtual_test_child) [@ mod_wsgi-4.5.6]# python3 -m pip install flask==
Collecting flask==
(virtual_test_child) [@ mod_wsgi-4.5.6]# pip install flask==1.0.2
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0


必要な環境構築が終わりましたので、各ファイルを置いていきます。

ファイル名:venv_mossymob.tk.conf
設置場所:/etc/httpd/conf.d


LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so

 <VirtualHost *:80>
    ServerName mossymob.tk
 
  WSGIDaemonProcess virtual_test_app user=apache group=apache python-home=/home/virtual_test/virtual_test_child

  WSGIScriptAlias /virtual_test_app /var/www/html/virtual_test_app/app.wsgi

<Directory /var/www/html/virtual_test_app>
 WSGIProcessGroup virtual_test_app
 WSGIApplicationGroup %{GLOBAL}
 Order allow,deny
 Allow from all
</Directory>
    CustomLog /home/virtual_test/access.log common
    ErrorLog /home/virtual_test/error.log
    LogLevel info
  </VirtualHost>


WSGIDaemonProcessへの python-home オプションの指定
(公式: https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html


Embeded ModeやDaemon Modeで1つのアプリケーションを1つのデーモン・グループで使用する場合など、多くの場合、以下のpython-home オプションを、WSGIDaemonProcessに、使用するpythonのルート・ディレクトリを明記してあげれば、この1行だけの追加でVirtualenv に対応できるようになるそうです。

WSGIDaemonProcess myapp python-home=/usr/local/venvs/myapps

Virtualenvで使用するpythonのパスは、
which python や python -c 'import sys; print(sys.prefix)' で、確認できます。

今回は、virtualenv のディレクトリにPythonをインストールしていますので、

(virtual_test_child) [virtual_test]# which python
/home/virtual_test/virtual_test_child/bin/python

(virtual_test_child) [ virtual_test]# python -c 'import sys; print(sys.prefix)'
/home/virtual_test/virtual_test_child

なので、 python-home=/home/virtual_test/virtual_test_child をWSGIDaemon Process で
指定しています。



ファイル名:app.wsgi
設置場所:/var/www/html/virtual_test_app

# coding: utf-8
activate_this ='/home/virtual_test/virtual_test_child/bin/activate_this.py'
with open(activate_this) as file_:
    exec(file_.read(), dict(__file__=activate_this))
import sys
sys.path.insert(0, '/var/www/html/virtual_test_app')
from app import app as application
*activate_this.pyは、virtualenvを作成した際に、binディレクトリ内に自動で生成されています。



ファイル名:app.py
設置場所:/var/www/html/virtual_test_app
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
    message="Hi, there!"
    return render_template("sample01.html", message=message)
   
@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_num']
       
    return render_template("sample02.html", result=result)
if __name__ == '__main__':
    app.run()

ファイル名: sample01.html
設置場所:/var/www/html/virtual_test_app/templates
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/virtual_test_app/add" method="post"> 
<p>Input the number you like:</p>
<input type="text" name="new_num" >
<input type="submit" value="Do">
</form>
 </body>
</html>
*form actionの参照ディレクトリの記述は気をつけましょう。
*sample02.htmlは、resultを表示しているだけですし、今まで多く書いてきていますので
 今回は記述を省略します。


これで、http:mossymob.tk/virtual_test_app にブラウザでアクセスすると、


 
 
無事に値がsample01.htmlからsample02に引き渡されて、
ルーティングもできることが確認できました。


* mod_wsgi が、シェアード・ライブラリを使用できているかの確認。

(シェアド・ライブラリを使えていなくてもmod_wsgiは動きますが、メモリーを大量に消費してい
 思わぬ問題を引き起こす可能性があるそうです。)
 

上でmod_wsgi.soが格納されたdirectoryがありましたが、そこで、以下の ’ldd’ コマンドを実行。

# cd  /usr/lib64/httpd/modules/

[ modules]# ldd mod_wsgi.so
        linux-vdso.so.1 =>  (0x00007ffe424ed000)
        libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007f6138849000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f613862d000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f6138428000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007f6138225000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f6137f23000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f6137b55000)
        /lib64/ld-linux-x86-64.so.2 (0x000055a55f838000)

 以上のようなリストが表示されていれば大丈夫。


これで、お終いです。

参考)
mod_wsgiのモード別の<Virtual Host>の記述方法(公式)
https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html


(後日再挑戦)

◇virtual host

LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
  <VirtualHost *:80>
   ServerName uslife.mossymob.tk
   DocumentRoot /var/uslife/html
  <Directory /var/uslife/html>
   Require all granted
  </Directory>
  
   WSGIDaemonProcess forum user=apache group=apache python-home=/home/venv_env/python37
   WSGIScriptAlias /app/forum /var/uslife/html/app/forum/app.wsgi
  
  <Directory /var/uslife/html/app/forum>
  WSGIProcessGroup forum
  WSGIApplicationGroup %{GLOBAL}
    Require all granted
  </Directory>
     CustomLog /home/venv_env/access.log common
     ErrorLog /home/venv_env/error.log
     LogLevel info
  </VirtualHost>

◇ app.py

from flask import Flask,render_template,request
app = Flask(__name__)
@app.route('/')
def index():
    message="Hi, there!"
    return render_template("sample01.html", message=message)
   
@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_num']
    #else:
    #    result = "No wish! Ah?"
       
    return render_template("sample02.html", result=result)
if __name__ == '__main__':
    app.run()

◇html
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/add" method="post"> 
<p>Input the number you like:</p>
<input type="text" name="new_num" >
<input type="submit" value="Do">
</form>
 </body>
</html>

これで動く。 まだ、ルーティングの記述方法が良く理解できていないようだ。


sample01.html
http://uslife.mossymob.tk/app/forum/

sample02.html
http://uslife.mossymob.tk/app/forum/add

2019年1月6日日曜日

Wordpress 5つのマイグレーション・ツールとAll-in-One WP Migration 


どんなに便利だと言われるPlug-inのマイグレーション(引越し)・ツールでも、簡単にマイグレーションは出来ませんね。 データ移行は簡単にできましたが、ブラウザで表示させようとすると、全てのページが404エラーになりました。 このエラー対応も含めて、メモしておきます。



1.マイグレーション・ツールの選択。

こんな8つのマイグレーション・ツールから選ぶ。
https://www.wpsuperstars.net/top-wordpress-migration-plugins/

1.Duplicator
Not only does it handle standard migrations, it can also help you clone your site to a new domain name, set up staging versions of your site, or just back up your site to protect from data loss.
There’s just one caveat – you’ll need a little technical knowledge. If acronyms like FTP make you tremble in fear – I’d stick with one of the more user-friendly plugins further down this list.

Price: Free with a pro version that unlocks extra features, starting at $39.
(新しいドメイン名のサイトへの移行もサポートしているらしいです。 ftp などの言葉が心配なようなら、使うのはちょっと難しい、とのこと。)

2. All-in-One WP Migration
is a free plugin with premium extensions that’s focused entirely on migrating your site to a new server or domain name.
It covers moving both your database and your files, which means it handles all aspects of migration.
The free version of the plugin supports moving sites up to 512MB in size. If your site is any larger, you’ll need to go with the unlimited version, which removes the size limit.

3. VaultPress
The only downside with VaultPress is that it’s a subscription service
Price: $3.50 per month or $39 per year
(これ、無料版がありません。)

4. WP Migrate DB
isn’t a self-contained migration plugin like Duplicator and BackupBuddy. As you might be able to glean from the name, it’s focused entirely on your WordPress database.
(DBに特化しています。)

5.UpdraftPlus Migrator Extension
Best of all, everything can be done directly from your WordPress dashboard. If you’re just moving hosts while keeping the same URL, you can probably get away with the free version of UpdraftPlus. Just do a backup and restore to your new server.But if you need to change URLs or move to a local environment, then you need the paid Migrator add-on.
(移転先が同じURLでよければ、これも良いかも。)



という感じなのだそうです。 だいたい、ネット検索で出てくるツールを網羅しているのではないでしょうか? 



ということで、初めてなので、2. All-in-One WP Migration で、やってみます。
(テーマ・Plug In ・メディア(イメージ)など、全部、移転できるそうなので便利。)

移転するのは、自分のこんなWPのページ。


 
 
 (移転元のページでデータのExport)

1.word pressの管理画面にログインしてAll-in-Oneを検索


 
 
2.Activateされたら、エクスポートします。
 
 


3. 自分のPCをエクスポート先に指定


4.いろいろオプションがあるみたい。
(今回は指定なし。)


5.ダウンロード開始



6.Exportしてしまうと、データが消えてしまうので、バックアップを作成し、
  新しいサイトがアップするまで、WPのサイトをそのまま保持。




これで、サイトが維持されているようになるので、確認してみてください。


 
 (移転先でのページでデータのImport)

1.移転先のword pressの管理画面にログインしてAll-in-Oneを検索
  先程の要領で、All-in-One WP Migration を有効化します。

2. さっきダウンロードしたファイルのインポート
  スクリーンショットをとる間もなく、ここまで来てしまいました。
 


完了画面 がすぐにでます。

これでおしまいのよう!!

**ここでパーマリンクの設定と.htaccessの設定というプロセスがあります。
何度目かで気が付きました。 詳細、下記。)

投稿一覧やURLで確認して、みます。




これで完了!


と思ったのですが、、、ホームページは見られますが、個々の投稿のリンクをクリックしても記事が表示されません。

これに対応します。

2.404エラー対応。




パーマリンクの再設定というプロセスを忘れていました。
又、そのページの下段に以下のような注意書きがあります。 以降の記述は、この注意書きに基づいた手順を踏んでいなかった為、発生したようです。

「.htaccess ファイルが書き込み可能であれば自動的に実行されますが、書き込み可能でなければ、mod_rewrite ルールを .htaccess ファイルに追加する必要があります。フィールド内をクリックし、CTRL + a を押してすべてを選択してください。」






1) .htaccessの記述内容確認。

まず、wordpressの各ファイルが格納されているディレクトリ直下にある、 .htaccessの内容を確認します。(直下にない場合もある。)

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /posts/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /posts/index.php [L]
</IfModule>

直下にない場合は、.htaccessを作ってコピペ

直下にある場合は、以下に続く。



これ、標準的な記述のようで、問題はなさそです。 
特に、RewriteEngineをOnにする記述が書いてあるか、確認します。

2) mod_rewrite の確認、
サーバーにSSH接続して、以下のコマンドを実行。

$ httpd -M

rewrite_module (shared) <- これが表示されていればOK


3)httpd.confの変更
サーバーの以下のディレクトリーに格納されている httpd.conf ファイルに記述を追加します。

/etc/httpd/conf/httpd.conf

httpd.confには、以下の内容がデフォルトで記述されています。


# Deny access to the entirety of your server's filesystem. You must
# explicitly permit access to web content directories in other
# <Directory> blocks below.
#
<Directory />
    AllowOverride none
    Require all denied
</Directory>

Defaultの<Directory>は、こういう設定になっていて、別の設定にするなら個別に設定しろ、という記述。 そして以下に、以下のような個別の<Direcotry>設定が続いている。


# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "/var/www/html"
#
# Relax access to content within /var/www.
#
<Directory "/var/www">
    AllowOverride None
    # Allow open access:
    Require all granted
</Directory>
# Further relax access to the default document root:
<Directory "/var/www/html">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks
    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None
    #
    # Controls who can get stuff from this server.
    #
    Require all granted
</Directory>

 なので、wordpressの各ファイル(そして、.htaccessも)が設置されている
<Directory>を指定して、以下のように設定してみる。

<Directory "/var/www/html/posts">

    Options Indexes FollowSymLinks

    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride ALL
    #
    # Controls who can get stuff from this server.
    #
    Require all granted
</Directory>

これでブラウザ経由で、各投稿を表示できるようになりました。





使っているのが、vpsサーバーなので、httpdファイルを自分で変更しなくてはいけませんでしたが、シェアード・タイプのサーバーなら、どうなのでしょう?

マニュアルは、この投稿の404までの手続が、ポータルとphpMyAdminページを使ってできると書いていますが。
(ロリポップ・サーバーの例)

https://lolipop.jp/manual/startup/move-wordpress/



(参考)

https://www.digitalocean.com/community/tutorials/how-to-set-up-mod_rewrite-for-apache-on-centos-7#step-3-%E2%80%93-setting-up-a-htaccess-file



(以下は、)

URLを一括返還するPlug in

ちょっと調べると、いろいろあるようですが、
Velvet Blues Update URLs (urlの一括返還)
Search Regex (文字列の検索、置き換え等のツール)


その後もいろいろ使えそうなので、Search Regexでやってみます。

Pluginを有効にします。



文字列を検索して、変換するのは以下の画面のようです。




(移転前のURL)
http://mossymob.net/blog/archives/146
(移転後のURL)
http://mossymob.tk/posts/archives/146

なので、
Search Pattern :mossymob.net/blog
Replace Ptern : mossymob.tk/posts

に変換してみます。

Invalid regular expression: Delimiter must not be alphanumeric or backslash
というエラー。


(まとめ) Post Method対応のFlask Appをサブディレクトリーで動かす


Flaskアプリケーションを、サブ・ディレクトリで動かす。しかも、Post Methodのルーティング(@aoo.route()) も機能させる。 はまると、はまりますので、機能する設定を、まとめておきます。
(エンベデッド・モードです。)


このエンベデッド・モードの書き方で、別のsub-domain名をつけたURLのサブディレクトリーでも
APPLIを複数、動かすことができます。



1.conf.ファイル

etc/httpd/conf.d に作ったconfファイルの内容。
実際には、httpd.confにも、Virtual Host を使う宣言を1行書く必要があります。
詳細は、こちら。【 これで動く (3) !! WebArena VPS(CentOS7)でFlaskを動かす (routingの確認)

Directory: /etc/httpd/conf.d


LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
 <VirtualHost *:80>
   ServerName mossymob.tk
   ServerAlias www.mossymob.tk
   WSGIScriptAlias /firstapp /var/www/html/firstapp/myapp.wsgi
   <Directory "/var/www/html/firstapp/">
    Options Includes ExecCGI FollowSymLinks
    Require all granted
   </Directory>
   CustomLog /var/www/html/access.log common
   ErrorLog /var/www/html/error.log
   LogLevel info
 </VirtualHost>
 

注意点)
◆モードについて
モードは、エンベデッド・モード(Embeded Mode)です。 mod_wsgiのデフォルトは、エンベデッド・モードです。 エンベデッド・モードは、wsgiファイルが変更になると、自動でリロードするところです。
pyファイルや、confファイルが変更されても、自動ロードされませんので、手動でリロードする必要があります。

◆WSGIScriptAliasについて
WSGIScriptAliasは2つの引数をとります。
最初は、wsgiのMounting Point。 2つ目は、wsgiファイルまでのFull Path.。 第一引数は省略も可能。省略した場合はルートディレクトリになりますので、サブ・ディレクトリでFlask Appを動かしたい場合は、Mouting Pointを明記しないと、上手く機能しません。



2. app.py

Directory: /var/www/html/firstapp/app.py

app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
    message="Hi, There!"
    return render_template("sample01.html", message=message)

@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_wish']
    else:
        result = "Function add() is alive, but not a intended way."
    return render_template("sample02.html", result=result)

if __name__ == '__main__':
    app.run(debug=true)

注意点)
@app.route() は、ブラウザとアクセスするurlと、動かすfunctionを紐づける(Mapping)する機能です。 urlにアクセスされることをtriggerにして、functionが動きます。

3. wsgiファイル

Directory: /var/www/html/firstapp/myapp.wsgi

# coding: utf-8
import sys
sys.path.insert(0, '/var/www/html/firstapp')
from app import app as application
注意点)
特にありません。よくTutorialにあるそのままです。


4.sample01.html

Directory : /var/www/html/firstapp/templates/sample01.html


<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/firstapp/add" method="post">
<p>Input the num you like:</p>
<input type="text" name="new_wish" >
<input type="submit" value="Do">
</form>
 </body>
</html>
注意点)
form action のパスを、flask appのマウンティング・ポイント(endpoint)からの相対パスで記述します。 これに気づかずに、はまりました。

WSGIScript Aliasとこの<form action>のパスの記述方法が、気を付けるべき点でした。


2つのアプリをサブ・ディレクトリーで動かす場合は、シンプルに以下のVirtual Hostの設定でOK.




LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
 <VirtualHost *:80>
    ServerName mossymob.tk
    ServerAlias www.mossymob.tk

   #Description for 'First APP'
    WSGIScriptAlias /firstapp /var/www/html/firstapp/myapp.wsgi
  Alias posts var/www/html/firstapp/posts
    <Directory "/var/www/html/firstapp/">
     Options Includes ExecCGI FollowSymLinks
     Require all granted
    </Directory>

   #Description for 'Second APP'
    WSGIScriptAlias /secondapp /var/www/html/secondapp/myapp.wsgi
    <Directory "/var/www/html/secondapp/">
     Options Includes ExecCGI FollowSymLinks
     Require all granted
    </Directory>

    CustomLog /var/www/html/access.log common
    ErrorLog /var/www/html/error.log
    LogLevel info
  </VirtualHost>



以上

2019年1月5日土曜日

mod_wsgi と関連するVirtual Hostに関するいろいろメモ

これはmod_wsgiとVirtualHostの基本を理解する為の単なるメモです。 


1. mod_wsgi

1) Daemon Mode と Embeded Mode.
Defaultはエンベデッド・モード

wsgiファイルとして、以下の内容をブラウザでアクセスすると、どちらのモードか分かる。

myapp.wsgi
def application(environ, start_response):
    status = '200 OK'
    if not environ['mod_wsgi.process_group']:
      output = u'EMBEDDED MODE'
    else:
      output = u'DAEMON MODE'
    response_headers = [('Content-Type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output.encode('UTF-8')]

2. Apache Virtual Host:
 https://httpd.apache.org/docs/2.4/

1) <Directory> Directive
<Directory> and </Directory> are used to enclose a group of directives that will apply only to the named directory, sub-directories of that directory, and the files within the respective directories. Any directive that is allowed in a directory context may be used. Directory-path is either the full path to a directory, or a wild-card string using Unix shell-style matching.

2)DocumentRoot Directive
This directive sets the directory from which httpd will serve files. Unless matched by a directive like Alias, the server appends the path from the requested URL to the document root to make the path to the document.

 Example:
DocumentRoot "/usr/web"
then an access to http://my.example.com/index.html refers to /usr/web/index.html

だよねー。このドキュメント・ルートと、後で出てくるwsgiアプリのマウント・ポイントの書き方が大切。


3)  WSGIScriptAlias

基本的な設定の書き方は、URLのマウント・ポイントとWSGIアプリを明示的にマップさせる。
この場合、マッピングは固定されて、Confファイルの記述を変更し、httpdを再起動しない限り、変更は反映されない。

The main approach entails explicitly declaring in the main Apache configuration file the URL mount point and a reference to the WSGI application script file. In this case the mapping is fixed, with changes only being able to be made by modifying the main Apache configuration and restarting Apache. 

このディレクティブは、'WSGIScriptAlias'と呼ばれる。
For mod_wsgi, the directive is instead called WSGIScriptAlias:

WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
            ①             ②


This directive can only appear in the main Apache configuration files. The directive can be used at server scope but would normally be placed within the VirtualHost container for a particular site.


It cannot be used within either of the Location, Directory or Files container directives, nor can it be used within a “.htaccess” file.

① The first argument to the WSGIScriptAlias directive should be the URL mount point for the WSGI application. For this case the URL should not contain a trailing slash. The only exception to this is if the WSGI application is to be mounted at the root of the web server, in which case ‘/’ would be used.

② The second argument to the WSGIScriptAlias directive should be an absolute pathname to the WSGI application script file. (絶対パスで記述する。) It is into this file that the sample WSGI application code should be placed.

Note that an absolute pathname must be used for the WSGI application script file supplied as the second argument. It is not possible to specify an application by Python module name alone. A full path is used for a number of reasons, the main one being so that all the Apache access controls can still be applied to indicate who can actually access the WSGI application.
Because the Apache access controls will apply, if the WSGI application is located outside of any directories already configured to be accessible to Apache, it will be necessary to tell Apache that files within that directory can be used. To do this the Directory directive must be used:

<Directory /usr/local/www/wsgi-scripts>
    Require all granted
</Directory>

Note that it is highly recommended that the WSGI application script file in this case NOT be placed within the existing DocumentRoot for your main Apache installation, or the particular site you are setting it up for. This is because if that directory is otherwise being used as a source of static files, the source code for your application might be able to be downloaded.
You also should not use the home directory of a user account, as to do that would mean allowing Apache to serve up any files in that account. In this case any misconfiguration of Apache could end up exposing your whole account for downloading.
It is thus recommended that a special directory be setup distinct from other directories and that the only thing in that directory be the WSGI application script file, and if necessary any support files it requires.
A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com
    DocumentRoot /usr/local/www/documents
    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
    WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/myapp’ would then be used to access the the WSGI application.
Note that you obviously should substitute the paths and hostname with values appropriate for your system.

Mounting At Root Of Site
If instead you want to mount a WSGI application at the root of a site, simply list ‘/’ as the mount point when configuring the WSGIScriptAlias directive:

WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi

Do note however that doing so will mean that any static files contained in the DocumentRoot will be hidden and requests against URLs pertaining to the static files will instead be processed by the WSGI application.
In this situation it becomes necessary to remap using the Alias directive, any URLs for static files to the directory containing them:

Alias /robots.txt /usr/local/www/documents/robots.txt
Alias /favicon.ico /usr/local/www/documents/favicon.ico
Alias /media/ /usr/local/www/documents/media/

A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com
    DocumentRoot /usr/local/www/documents
    Alias /robots.txt /usr/local/www/documents/robots.txt
    Alias /favicon.ico /usr/local/www/documents/favicon.ico
    Alias /media/ /usr/local/www/documents/media/
    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
    WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi
    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/’ would then be used to access the the WSGI application.
Note that you obviously should substitute the paths and hostname with values appropriate for your system.

Delegation To Daemon Process
By default any WSGI application will run in what is called embedded mode. That is, the application will be hosted within the Apache worker processes used to handle normal static file requests.
When embedded mode is used, whenever you make changes to your WSGI application code you would generally have to restart the whole Apache web server in order for changes to be picked up. This can be inconvenient, especially if the web server is a shared resource hosting other web applications at the same time, or you don’t have root access to be able to restart the server and rely on someone else to restart it.
On UNIX systems when running Apache 2.X, an option which exists with mod_wsgi and that avoids the need to restart the whole Apache web server when code changes are made, is to use what is called daemon mode.
In daemon mode a set of processes is created for hosting a WSGI application, with any requests for that WSGI application automatically being routed to those processes for handling.
When code changes are made and it is desired that the daemon processes for the WSGI application be restarted, all that is required is to mark the WSGI application script file as modified by using the ‘touch’ command.
To make use of daemon mode for WSGI applications hosted within a specific site, the WSGIDaemonProcess and WSGIProcessGroup directives would need to be defined. For example, to setup a daemon process group containing two multithreaded process one could use:

WSGIDaemonProcess example.com processes=2 threads=15
WSGIProcessGroup example.com

A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com
    DocumentRoot /usr/local/www/documents
    Alias /robots.txt /usr/local/www/documents/robots.txt
    Alias /favicon.ico /usr/local/www/documents/favicon.ico
    Alias /media/ /usr/local/www/documents/media/
    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
    WSGIDaemonProcess example.com processes=2 threads=15 display-name=%{GROUP}
    WSGIProcessGroup example.com
    WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi
    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>
</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/’ would then be used to access the the WSGI application.
Note that you obviously should substitute the paths and hostname with values appropriate for your system.
As mentioned previously, the daemon processes will be shutdown and restarted automatically if the WSGI application script file is modified.
For the sample application presented in this document the whole application is in that file. For more complicated applications the WSGI application script file will be merely an entry point to an application being imported from other Python modules or packages. In this later case, although no change may be required to the WSGI application script file itself, it can still be touched to trigger restarting of the daemon processes in the event that any code in the separate modules or packages is changed.
Note that only requests for the WSGI application are handled within the context of the daemon processes. Any requests for static files are still handled within the Apache worker processes.