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>

 

『海軍陸戰隊軍事常備訓練役』後記

今天不聊技術,來聊聊當兵生活。當然了,請不要跟我戰我四個月很廢很怎樣,其實我也很不爽整個兵役制度,但是沒辦法,規定就是這樣,跟我戰也沒有實質意義。

那就切入正題了。是的,我消失的這四個月去服了兵役,最近要退伍了,趁著連假的時候來聊聊四個月兵役、海軍陸戰隊在幹嘛?

先介紹一下,我是4個月的海陸,全名是『海軍陸戰隊軍事常備訓練役』。

要帶的東西

首先,先幫各位整理要帶的東西:

  • 徵集令
  • 身分證
  • 健保卡
  • 手錶
  • 內褲
  • 錢(帶個兩千左右,然後盡可能換成零錢,進去你會知道零錢有多重要!)
  • 高中或大學的軍訓課折抵役期

各位應該會覺得,怎麼要帶的東西這麼少?是的,班長會帶各位去營長買,所以根本不用擔心。

第一次的交通

因為我的戶籍地在中壢,因此我是在中壢火車站報到。

當天會有區公所的人來帶各位,所以完全不用擔心。火車的部分,不用錢,坐莒光號,由於路途遙遠,車上會在中午供應免費的便當。

除了這台車會消失在火車時刻表上,窗外還會貼著『入營專車』,整台車死氣沈沈的,搞得很像什麼 地獄列車 之外,車上也是有賣飲料、零嘴。

到了左營火車站後,會有專車來載我們,整台車更是死氣沈沈,大概半小時時間,就會到龍泉新訓中心了。

一進去,就會到你所屬的連隊,順便告訴各位一個小口訣:快樂五、天堂六、地獄七、超級八。喔對,我就是在超級八的八連…所以我這宅宅都熬過去了,各位一定也可以。

新訓生活

一開始進軍營,會有班長來隨便抓人分班,好像都是分 1~9 班。分完班,知道自己哪排哪班(一定要記清楚)

前幾天真的很多事情,一進去就是先寫資料。會利用空餘時間帶大家去營站採買、拿裝備、換裝、剪頭髮(我這建議在外面先剪,不然髮婆一分鐘一顆頭,都用扯的)

第一個晚上洗澡很可怕,雖然不像以前那樣洗澡,衛浴設備也不錯,但是一堆人在擠,班長在後面喊,一直叫你快洗,所以也就索性三個人擠一間坦誠相見,但也不至於會要你撿肥皂。

然後第一個睡覺,真的很難熬,心理怕的要死,各種不適應,床不適應、枕頭不適應、沒有女友陪也不適應,真的超抖!

對了,現在都有冷氣了,所以倒是不用擔心太熱睡不著的問題。

接著是,第二天早上起床,起床後去連集合場集合,當然就是繼續罵一直罵不停罵,吃飯、繼續寫資料、調(幹)整(醮)你的裝備、互相認識同梯,前三天大概就都這樣過的。

在龍泉放過懇親後,時間就是用飛的,基本上就是照表操課…

首先一睜開眼就『早點名』,反正就跟著排隊,然後喊什麼『捍衛中華民國』『嚴守軍人武德』『一路陸戰隊』『終身陸戰隊』的精神口號

然後開始晨操,晨操就基本會有跑步、伏地挺身,其他的內容就看值星班長的心情

接著是單戰、手榴彈投擲、刺槍。

單戰就是要背誦一堆『抬頭觀察、由左至右、由近而遠…』『親愛的共軍,我們的檳榔跟你們的椰子一樣大』這種奇怪的台詞,然後還要你實際做出來,整個很羞恥之外,還要吃土、爬阿爬 滾啊滾、整個迷彩濕到內褲、內褲又濕回頭盔。

手榴彈投擲的部分,因為我手有痼疾,所以有『免計測證明』,如果你有痼疾,那也會建議去開一張,這張護身符真的很有用。

刺槍的話,就是拿著一個槍,在那刺來刺去,三公斤雖然看似沒什麼,拿久就很有什麼了(燦笑

還有我最喜歡的莒光課,就是寫寫大兵、看看莒光園地, 然後房業涵好正

喔對,有公差一定要出,公差有的很爽、有的很累,不過事情忙完可以投飲料。

然後最後一週會要游泳,長度是 50 公尺,深度約兩米,很容易就過去的。這部分就會游的就很爽,整個禮拜都爽爽過,不會的話,就盡量學,班長會很有耐心的教你。

手機的部分應該是大家最關心的,新訓是會把大家手機鎖在手機櫃,定點定時開放使用,大家只要表現好,基本上就很多時間能用手機, 手機用到都不怕兵變 。然後就切記不可以使用相機功能、開分享、定位。

打靶的話,聽說是要走一小時到靶場,但是我們那天下雨,所以搭軍卡上去靶場,沒走到真的有點可惜。然後我們在上面住了兩晚,晚上真的不要亂跑,很可怕、很不乾淨。
然後,打靶部分,基本上助教都會很仔細的教導,切記!不要白目、該做的動作要正確,不要嬉鬧,那就不會有太大問題了!

回家的話,外面有超多計程車,在營區門口就會看到一堆司機在拉人,我都是找人一起搭、分攤會很便宜。貴的話是貴在每週都搭高鐵回家,超燒錢…

下部隊

新訓待 42 天就會下部隊了,基本上部隊比較自由、伙食也好很多。

在下部隊前會大抽,我是 66 旅 部槍兵,基本上下部隊,兵種只是抽形式的,什麼槍都會去碰到、都要學,就盡力學、盡力記。那因為剛好我們營要下基地,我們不會跟到,所以基本上都是在幫忙下部隊的準備,掃地、檢整、打飯…等等。

我們剛好有遇到聯翔操演,基本上就是整晚不能開燈,然後小武裝,在妳守備的點蹲一整晚,記得要帶防蚊液!

還有遇到一次的夜行軍,基本上就跟著部隊一起走,然後走五十分鐘休息十分鐘,走 15 公里,整個又黑又無聊,但我覺得是個滿有趣的回憶。

下部隊後,時間過得更快,進去後,比新訓還好適應,會發現真的沒什麼,時間過很快。

總結

說真的,當初我進去的時候,怕到整個快哭了,但其實就適應後,真的就還好。

就造表操課,不去數日子的話,時間真的過很快!

然後在裡面就不要不長眼就好,是或不是、絕對服從,基本上就不會被刁難。

我一個弱弱的宅宅,平常也沒在運動、入伍前伏地挺身做五下就不行了,也都撐過來了,所以你們一定也可以!

報告班長,二兵___於海軍陸戰隊軍事訓練常備役 34 梯,2017/06/28 入伍 ,2017/10/11 退伍。

一日陸戰隊,終身陸戰隊!

永遠忠誠!

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");
        }
    }
}