Django 從 SQLite 切換到 MySQL 時總是提示 No module named ‘MySQLdb’

初次使用 Django ,預設的資料庫是 SQLite ,想切換使用 MySQL,配置了資料庫之後,runserver 總是會出錯

'Did you install mysqlclient or MySQL-python?' % e
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'.
Did you install mysqlclient or MySQL-python?

後來查資料,看來是 python3 之後,原本的 python2 的 mysqldb 已經不能連接 mysql 了,要改成使用pymysql,來連接 mysql 。

於是我嘗試使用 pip 安裝了 PyMySQL,還是報錯,所以我再查了一下,原來還要在網站設定的 __init__.py 文件中再添加

import pymysql
pymysql.install_as_MySQLdb()

這樣就可以正常連接 MySQL 了,供大家參考

Django 將所有的 app 放到統一的目錄下進行管理

Django 的 project 寫久了,app 會越來越多,然後就零散在整個專案下,很雜亂,所以研究了一下,能不能將 app 集中放在同個資料夾下面做管理

看了一下網路上的文章後,方法很簡單

首先在專案資料夾底下新建一個資料夾 apps

接著,將設計的好的 app,拖放到 apps 中

記得最後要修改 settings.py 運行時的的搜尋路徑

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 在這行底下添加
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

另外,不要忘記 import sys

最後,啟動伺服器 runserver,測試看看有沒有設置成功

Flask 下使用 APscheduler

因為工作關係,目前執行的專案是採用 flask,因為要做工作的排程,所以用了 APscheduler 這個模組。

在 flask 下,如果要使用 APscheduler 可以考慮使用 flask 延伸模組 flask-apsheduler

基本使用方法

  from flask import Flask
from flask_apscheduler import APScheduler


class Config(object):
    JOBS = [
        {
            'id': 'job1',
            'func': 'jobs:job1',
            'args': (1, 2),
            'trigger': 'interval',
            'seconds': 10
        }
    ]

    SCHEDULER_API_ENABLED = True


def job1(a, b):
    print(str(a) + ' ' + str(b))

if __name__ == '__main__':
    app = Flask(__name__)
    app.config.from_object(Config())

scheduler = APScheduler()
# it is also possible to enable the API directly
# scheduler.api_enabled = True
scheduler.init_app(app)
scheduler.start()
app.run()

 

一些心得

這個專案是跑在 ubuntu 加上 gunicorn,在使用 gunicorn 的時候,定時任務會重複啟動很多次,找了一下網路上的資源,問題在使用 gunicorn 對 flask 應用進行控制的時候如果設置了 gunicorn 的 --worker 參數大於 1 時,會出現一個定時任務執行多次的問題,此時要給 gunicorn 提供一個額外的 --preload 參數,這樣 flask 的 app 在 run 定時任務就只會執行一次。

env/bin/gunicorn module_containing_app:app -b 0.0.0.0:8080 --workers 3 --preload

 

還有,當 flask 在 debug 模式下使用 flask-apscheduler 定時任務時也會執行多次,問題與上面的問題類似,只要在 debug 模式下給 app.run() 添加一個參數 use_reloader 即可。

app.run(debug=True, use_reloader=False)

 

MySQL 修改 root 用戶密碼

  • 關閉 MySQL 服務。
sudo /usr/local/mysql/support-files/mysql.server stop
  • 安全模式啟動 MySQL
sudo /usr/local/mysql/bin/mysqld_safe --skip-grant-tables
  • 修改 root 密碼

逐一輸入以下命令,修改 root 密碼並退出。

mysql -u root
UPDATE mysql.user SET

這裡要注意一下,5.7後的版本,mysql.user 表裡面的 password 改成了:authentication_string

authentication_string=PASSWORD('my-new-password') WHERE User='root';

FLUSH PRIVILEGES;

運行完以上命令後,root 的密碼就修改成你設置的密碼了。

  • 測試
    運行以下命令測試密碼是否修改成功。
mysql -u root -p

 

然後輸入你新設置的密碼。

如果輸入無誤,應該會出現 MySQL 命令行窗口,如下:

mysql>

 

SQL: ALTER TABLE 紀錄

假設現在我們已經建立好一個 customers 資料表:
| ——| —— | —— | —— |
| C_Id | Name | Address | Phone |
| ——| —— | —— | —— |

接著,我們可以用這指令去:

  • 增加欄位 (ADD COLUMN)
ALTER TABLE table_name ADD column_name datatype;

 

例如,如果我們想增加一個 Discount 欄位:

ALTER TABLE customers ADD Discount VARCHAR(10);

 

  • 更改欄位資料型別 (ALTER COUMN TYPE)
ALTER TABLE table_name ALTER COLUMN column_name datatype;

 

例如,更改 Discount 欄位的資料型別:

ALTER TABLE customers ALTER COLUMN Discount DECIMAL(18, 2);

 

  • 刪除欄位 (DROP COLUMN)
ALTER TABLE table_name DROP COLUMN column_name;

 

例如,刪除 Discount 欄位:

ALTER TABLE customers DROP COLUMN Discount;

 

在 Raspberry pi 3 上面使用 waveshare 3.5 吋 TFT 螢幕

在 Raspberry pi 3 可以直接透過 HDMI 輸出畫面到螢幕上,目標是做出小型遊戲機,因此我們要使用 retropie 這個 O.S.。必較麻煩的是,要額外將 3.5 吋 TFT 螢幕接到 Raspberry pi 的 GPIO 腳位。

 

我一開始撞牆滿多次,不過其實滿簡單的,所以就紀錄一下實作方法。

  • 首先預備工作,要先下載三個檔案:
  • 將上面三個檔案都丟到 /home/pi 路徑下。
  • 要進行 SPI 設定
    • 在 terminal 上輸入 sudo raspi-config
    • 進入 advances settings ,開啟 spi
  • 在 terminal 上執行 tar xvf LCD-show.tar ,來解壓縮檔案
  • 編譯 fbcp
    • 執行 cd fbcp 進入 fbcp 資料夾
    • 執行 sudo mkdir build 創建資料夾
    • 執行 cd ./build 進入 build 資料夾
    • 執行 sudo cmake ..
    • 執行 sudo make
  • 到這步已經差不多了,接著只要執行 sudo bash /home/pi/driver_workaround.sh,此時會看到螢幕由白變黑。
  • 最後,執行 sudo /home/pi/rpi-fbcp/build/fbcp &,就會看到畫面了。

備註:這次我是採用 3.5 吋 LCD 螢幕, 所以無法確定其他尺寸的 GPIO LCD 螢幕,是否可以運作。

在 Weebly 上使用 Gandi 的域名

由於朋友最近正在研究 Weebly ,提到了『自定義域名』功能,所以我也來研究了一下,雖然我覺得我應該不會再用到,不過還是紀錄下來。

自定義域名 功能允許您設置您的 Weebly 網站綁上自己的域名。首先你必須先尋找、購買新的域名,並且在 weebly 設定好。

  • 登錄 Gandi,選擇我的帳戶 。
Imgur
  • 點選你要指向的域名,並單擊進去管理頁面。
Imgur
  • 在最底下,會有個區域檔,選擇編輯區域
Imgur
  • 你應該會看到一個警告訊息,這是 Gandi 為確保你的網域正常運作所做的機制。你只需要點選右邊的 建立新版本
Imgur
  • 接著找一下 Host 欄位是 @的 ,點選他右邊的鉛筆。
Imgur
  • 在  欄位中,填寫上 weebly 提供的 IP 地址之一。Weebly 提供的的IP地址有 199.34.228.55199.34.228.56199.34.228.57199.34.228.58199.34.228.59199.34.228.100

上述選一個就好(如果你有使用到 SSL,那麼你就需要使用特定的IP地址)。如果你覺得這步驟很繁雜的話,你就直接填入 199.34.228.59。 填好後,點擊送出按鈕。

Imgur
  • 接下來,向下滾動頁面,以確保wwwCNAME記錄指向@。如果沒有,記得要修改它。

這樣就完成了!

接著 Gandi 的可能需要長達 24 小時的時間來更新他們的記錄(通常很快,幾分鐘就會更新完畢了)。

Altera USB Blaster 驅動程式簽章問題

最近修了『微處理機設計』課程,使用到了 Altera 的 DE0 板。安裝了 DE0 的 USB 驅動程式遇到一個問題,就是我的數位簽章雜湊出現什麼問題的。我查了一些資料,覺得有點複雜,所以把它記錄下來:

主要問題是在用 Windows 8 中 Altera 提供拒絕正確安裝驅動程式,因為他要強制驅動程式簽章。因此,我搜索了一圈,發現在Altera論壇的解決方案:

http://alteraforums.net/forum/showthread.php?p=157605

按照以下步驟就能解決這問題了:

  1. 點 WinKey + R.
  2. 輸入 shutdown.exe /r /o /f /t 00
  3. 按 OK
  4. 電腦會重開機並且進入 “Choose an option” 選單
  5. 選擇 Troubleshoot
  6. 選擇 Advanced options
  7. 選擇 Windows Startup Settings
  8. 選擇 Restart 按鈕
  9. 系統將會再次進入 Advanced Boot Options 選單
  10. 選擇 Disable Driver Signature Enforcement (第七個,所以按數字鍵 7 或者 F7)
  11. 電腦將會再次重新啟動,就可以繞過數位簽章檢查,直接安裝 Altera 的 DE0 板的驅動程式

在 github 滾回到某個特定的 commit

和朋友在協作的時候,朋友不小心 push 錯東西,導致需要滾回到先前正確的版本,感覺以後會常常用到,所以記錄下來。

首先有先滾回你要的那個 commit id
git reset --hard <old-commit-id>

這時候你會發現你已經退回到你要的那個版本了,再來再把它 push 上去你 GitHub 的 repository 就完成了。

git push -f <remote-name> <branch-name>

筆記: 這個操作,會複寫 commit id 之後的歷史,所以要謹慎使用。

新手問題:Fragment 中使用 button setonclicklistener

自己本身沒有系統的去學習 android,就是想到什麼做什麼的,今天在自學的過程中發現了一些問題。

就是說用 fragment 按鈕點擊的時候碰到了問題。在寫完之後,AS 沒有任何報錯,但是啟動的時候就會 crash 掉。

cal = (Button) findViewById(R.id.submit);
cal.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // do something ...
    }
});

 

此時我們的程式碼是正常的,但是運行後就會 crash,我們必須要在讓他 implements view.oncilcklisrener。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {
    public static void main(String args[]) {

        // String to be scanned to find the pattern.
        String line = "This order was placed for QT3000! OK?";
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);
        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }
}