シンプルなカレンダーフォームを作る方法
日付選択をする際にでてくるあのカレンダーを作る方法を紹介します。
documentではdomに属性をつけてオプションを指定しているのがほとんどですが、属性をつけるとごちゃごちゃするので、jsに書きます。
準備
以下のライブラリが必要です。
リンクを付けましたので、ダウンロードしてください。
もしくは、npmで環境を整えても良いです。
- jquery
- https://jquery.com/download/
npm install jquery
- air-datepicker
- https://github.com/t1m0n/air-datepicker
npm install air-datepicker
ダウンロードしてサンプルを作っているので、npmで用意した場合はそれぞれの環境に置き換えてください。
おそらく、node_modules以下にファイルがあるはずです。
inputをクリックするとカレンダーが表示されるサンプル
sample.html
<html> <head> <link href="../dist/css/datepicker.min.css" rel="stylesheet" type="text/css"> <script src="./jquery-3.2.1.min.js"></script> <script src="../dist/js/datepicker.min.js"></script> <!-- Include English language --> <script src="../dist/js/i18n/datepicker.en.js"></script> <script src="./sample.js"></script> </head> <body> <div> <input type='text' id="jsDatePicker"/> </div> </body> </html>
sample.js
(function() { // docs // http://t1m0n.name/air-datepicker/docs/ function sample1() { console.log("called init function."); $('#jsDatePicker').datepicker({ position: "right top", language: 'en', minDate: new Date() // Now can select only dates, which goes after today }); } function init() { sample1(); } document.addEventListener("DOMContentLoaded", function() { init(); }, false) })()
カレンダーの日付をクリックするとアラートが表示されるサンプル
onSelectオプションを使用するとできます。
callbackで渡される引数には以下の値が入ります。
- fd: フォーマットされた日付
- date: date object
- inst: datepickerのインスタンス
これを使うと、選択された日付のタスクを横に出すとかできます。
multipleDates: true
をオプションに追加した場合は、dateが配列になります。
range: true
に設定した場合は、開始日と終了日が入った配列になります。
function sample2() { console.log("called init function."); $('#jsDatePicker').datepicker({ position: "right top", language: 'en', multipleDates: false, minDate: new Date(), // Now can select only dates, which goes after today onSelect: function(fd, date, inst) { alert('selected date.'); console.log(fd); // 10/17/2018 console.log(date); // date.getFullYear() // date.getMonth() // date.getDate() } }); }
最後に
air-datepickerのドキュメントはとても読みやすいので参照してみてください。
今回紹介したサンプルもドキュメントに書かれているサンプルから取っています。
Django+herokuでS3を使わない画像の保存方法
cloudinaryというアドオンを使って、画像を保存します。
画像の保存というとamazon s3が思い浮かぶと思いますが、あれほんの少しお金かかりますよね?
スタートということで、完全無料でやるためにcloudinaryを使ってみます。
cloudinaryのアドオンは↓です。
https://elements.heroku.com/addons/cloudinary
無料の範囲は↓です。
Storage: 10 GB Monthly Bandwidth: 20 GB Total Images & Videos: 300,000 Monthly Transformations: 20,000
準備
ライブラリをインストールする
pip install cloudinary
herokuでアドオンを追加して、画面の流れに沿って操作してください。
画像をアップロードする
import cloudinary import cloudinary.uploader import cloudinary.api cloudinary.config( cloud_name="xxxxx", api_key="xxxxxxxxxx", api_secret="xxxxxxxxxxxxxxxx" ) def upload(image): result = cloudinary.uploader.upload(image) if __name__ == '__main__': upload('sample.jpg')
ちなみに、urlを指定しても保存してくれます。
upload('http://sample.com/sample.jpg)
Djangoのtemplateで画像を表示する
settingsにcloudinary
を追加する
INSTALLED_APPS = [ ... 'cloudinary', ... ]
tempalteで以下のようにする
<!DOCTYPE html> <html> <head> {% load cloudinary %} </head> <body> {% cloudinary "public_id" crop="fill" %} </body> </html>
もちろん、view内でpublic_id部分を置換しても良いです。
置換する場合は↓のようにします。
{% cloudinary public_id crop="fill" %}
context = { 'public_id': 'xxxxxxxxxxxxxxx', } return self.render_to_response(context)
public_idを自分で設定する場合
アップロードする際にpublic_id
を指定します。
result = cloudinary.uploader.upload(image, public_id='kyaro_kyawawa')
画像のアップロードは↓にもっと詳しいドキュメントが書かれています。
参考にすると役に立つはずです。
できるだけ早く、無料でwebサービスを開発するまで
無料でwebサービスを作り、公開するまでの流れを紹介したいと思います。
今回BookStackerhttp://www.book-stacker.comというサービスを作ったので、その際の開発の流れを紹介します。
以下の流れで開発を行いました。
- タスクを洗い出す(3h)
- 仕様を書き出す(3h)
- 開発をする(4day)
- リリースする(3h)
- 運用する(...)
合計で一週間ぐらいです。
タスクを洗い出す
タスクには以下の3つ書き出しました。
- やらなければならないこと
- やったほうがよいこと
- やらなくてもよいこと
それぞれについて解説します。
やらなければならないこと
これは作ろうとしているサービスの必須機能です。
「これを作れば公開できる」といったものです。
BookStackerなら以下の項目です。(一部抜粋)
- 本の一覧を表示する
- 本の情報をDBに保存する
やったほうがよいこと
必須ではないけど、やっておくと何かとメリットがあるものです。
- レスポンシブデザイン
- ドメイン登録
- グーグルアナリティクス
やらなくてもよいこと
やってもいいけど、やらなくてもいいといった少し迷う定義です。
- リファクタリング
- 画面レイアウト調整
- SPA化
仕様を書き出す
タスクができたら今度は仕様を書き出しました。
仕様を書く際はエクセルやスプレッドシートなどを使って作成することもあると思います。
これはおすすめしません。必要なのは文字であって、表ではないからです。
というわけで、マークダウンで書きました。
タスク管理なら、こんな感じです。
# タスク管理 ## /task/create タスクを登録する method: post params: title: type: str valid: required: true body: type: str valid: required: false max length: 2000
viewの仕様も、apiの仕様もこのように書くことができ、またgitで管理できるので表計算ソフトより効率が良いです。
画面のレイアウトは紙に書いて、壁に貼り付けました。開発が終わったら取ってファイリングします。
開発をする
タスクを出して、仕様を書き出したらいよいよ開発です。
開発に使う言語は何でも良いです。作れればなんでも良いのです。一番慣れている言語が一番はやく開発できるでしょう。
BookStackerではpythonを使って開発をしました。
無料で運用することを決めているので、herokuの無料枠を使いました。
herokuの無料枠ではmysqlよりもpostgresqlのほうがデータが入るので、postgresqlを使用しました。
(ClearDB MySQLのfreeプランの場合は5MBまでしかデータが入りません。それに対して、postgresqlなら10000行データが入ります。)
できる限りテーブル数を削減すればかなりのデータが入ることでしょう。
実装する順番について
「やらなければならない」タスクから取り掛かります。
そして、それが終わったらherokuにデプロイします。
「やったほうがよいこと」「やらなくてもよいこと」については運用しつつ開発するのが良いでしょう。
リリースする
git push heroku master
!
以上が開発の流れです。
これから残りの機能を実装しつつ、運用したいと考えています。
注意
herokuの無料プランを使うと、無料でサービスを公開できます。
ですが、無料枠から離れた場合結構お金がかかります。
最低で7ドル(120円*7=840円)ぐらいです。
また、postgresも入れると+9ドル(120円*9=1080円)です。
合計しておよそ2000円です。
これならvps借りて運用したほうがまだ安いです。
javascriptのreduceを使って配列を更新する方法
reduceを使用すると、ある配列を使って単一の値を計算したい場合に使えます。
いくつかreduceを使った例を紹介します。
配列内のデータを加算する
var datas = [1,2,3,4,5] var result = datas.reduce(function(num, item) { // numの初期値は0 return num + item; }, 0); // result == 15
配列内のデータを逆順にする
reverse
を使ったほうが良いけども
var datas = [1,2,3,4,5,6] var result = datas.reduce(function(table, item) { console.log(table, item); table.unshift(item); return table; }, []); // result = [6,5,4,3,2,1] // ↓ console.log(table, item) // [] 1 // [1] 2 // [2, 1] 3 // [3, 2, 1] 4 // [4, 3, 2, 1] 5 // [5, 4, 3, 2, 1] 6
一次元の配列を3つ区切りの二次元配列にしたい場合
↓の例の場合、[1,2,3,4,5,6]
が[[1,2,3],[4,5,6]]
に変換されます。
var datas = [1,2,3,4,5,6]; var result = datas.reduce(function(table, item) { // tableが更新されていく // itemには要素が入っている console.log(table, item); const last = table[table.length - 1]; // ↑ [[1,2,3][4,]] の場合、[4]を取得している if (last.length === 3) { table.push([item]); } else { last.push(item); } return table; }, [[]]); // result == [[1,2,3],[4,5,6]]
二次元配列を一次元配列にしたい場合
var datas = [[1,2,3], [4,5,6]]; var result = datas.reduce(function(table, item) { return table.concat(item); }, []); // result == [1,2,3,4,5,6]
Djangoでcssファイルから画像ファイルを読み込む方法
Djangoでcssファイルから画像ファイルをurlで指定する方法について紹介します。
やることは簡単です。
Djangoの設定ファイルで以下のような設定をしていると思います。
STATIC_URL = '/static/' STATIC_ROOT = 'staticfiles'
この設定をしている場合、staticファイルは/static/
がurlのルートとなります。
また、staticのルートディレクトリはstaticfiles
になります。
つまり、staticfiles/img/sample.png
というファイルをcssファイルから読み込みたい場合以下のようになります。
background-image: url("/static/img/sample.png");
ただ、staticファイルのurlルートを変更した場合にはcssの中を修正する必要が出てきます。
そのときはとても面倒になるので、scssで変数として管理しておくと良いでしょう。
おまけ
staticファイルをhtmlファイルから使用する方法も紹介します。
{% load static %}
を入れると、{% static "img/sample.png" %}
のように指定できます。
/static/img/sample.png
に置換されます。
{% load static %} <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script> <img src="{% static "img/sample.png" %}" alt="sample" >
javascriptでカレンダーを作成する
html、css、javascriptを使ってカレンダーを作成します。
この記事では、htmlとcssの部分についてはcodepenで見つけたデザインを使用しています。
なので、javascriptをメインで紹介したいと思います。
参考にしたデザインはこちらです。
https://codepen.io/jamiemggs/pen/xdvaJv
最終的に、このようなカレンダーができます。
成果物について
表示する項目
- 今月のカレンダーを表示する
- 月の移動はしない
- 先月、来月の日付を表示する
- 先月、来月の日付を表示しないこともできる
html
jsCalendarに対してdomを追加します。
javascriptを使って、jsCalendarにhandlebars.jsで生成したdomを追加します。
<div id="jsCalendar" class="calendar"></div>
css
cssについてはcodepenのをそのまま使用します。
handlebar
この例ではテンプレートにhandlebars.jsを使用しています。
handlebars.jsについてはこちらを確認してください。
https://github.com/wycats/handlebars.js/
<div class="jzdbox1 jzdcal"> <div class="jzdcalt">{{year}}年{{month}}月</div> <span>Su</span> <span>Mo</span> <span>Tu</span> <span>We</span> <span>Th</span> <span>Fr</span> <span>Sa</span> {{#each dates}} {{#if this }} <span>{{date}}</span> {{else}} <span class="jzdb"><!--BLANK--></span> {{/if}} {{/each}} </div>
{{#if this }}
に気がつくまで時間がかかりました。
このテンプレートに渡されるデータの構造について。
year: 2018 month: 10 dates: [ { month: 10 date: 1 } ]
datesの配列にはnullが入ることもある。
nullの項目が日付の非表示に対応する形です。
javascript
ES2015の書き方をしている箇所があります。
import $ from 'jquery'; import hb_calendar from 'HandleBars/calendar'; (function() { class Calendar { constructor() { this.element = { template_target: { calendar: "#jsCalendar", } } } render(calendar_data) { // handlebarsは入れるtemplateを入れるtargetを作って let target = $(this.element.template_target.calendar); // templateからhtml文字列を作って let html = hb_calendar({ year: calendar_data.year, month: calendar_data.month, dates: calendar_data.dates, }); // targetにhtmlをappendする。これだけ! target.append(html); } createCalendarData(allowBlank) { allowBlank = allowBlank || false; let today = new Date(); let year = today.getFullYear(); let month = today.getMonth(); let lastMonthDateObj = new Date(year, month, 0); // 先月の最終日 let nextMonthDateObj = new Date(year, month + 1, 1); // 来月の初日 let startDate = new Date(year, month, 1); // 今月の初日 let endDate = new Date(year, month + 1 , 0); // 今月の最終日 // Sunday is 0, Monday is 1, and so on. let firstDateNum = startDate.getDate(); let lastDateNum = endDate.getDate(); let dates = [] // まずは、先月の日付を入れる。 for (let di = 0; di < startDate.getDay(); di++) { if (allowBlank) { dates.push(null) } else { dates.push( { month: lastMonthDateObj.getMonth() + 1, date: lastMonthDateObj.getDate() - di, } ); } } // 次に日付を入れる for (var di = firstDateNum; di <= lastDateNum; di++) { dates.push( { month: month + 1, date: di, } ) } // 最後に来月の日付をいれる for (let di = 0; di < endDate.getDay(); di++) { if (allowBlank) { dates.push(null); } else { dates.push( { month: nextMonthDateObj.getMonth() + 1, date: 1 + di, } ) } } // datesにカレンダーの情報が入っている。 // あとはレンダリングするだけ console.log(dates); return { year: year, month: month + 1, dates: dates, }; } } function init() { let calendar = new Calendar(); let datas = calendar.createCalendarData(false); calendar.render(datas); } $(window).on('load', function() { console.log("called ready function"); init(); }) })();
pythonのファイルをherokuで定期的に実行する方法
この記事ではpythonのファイルに書かれたprint()
を定期的に実行する方法を紹介します。
↓のページを参考にしています。
https://devcenter.heroku.com/articles/clock-processes-python
herokuで適当なアプリケーションを作成していて、remoteへpushできるまで準備が整っている状態を想定しています。
また、custom clock processes
を対象にしています。
pythonファイルを作成する
スケジュール用のライブラリをインストールします。
pip install apscheduler
1分間隔でログをだすようにコードを書きます。
batch.py
from apscheduler.schedulers.blocking import BlockingScheduler sched = BlockingScheduler() @sched.scheduled_job('interval', minutes=1) def timed_job(): print('This job is run every three minutes.') sched.start()
apscheduler
ではなく、schedule
ライブラリを使ってもよいです。
pip install schedule
import schedule import time def job(): print("hello every 10 seconds.") #10秒毎にjobを実行 schedule.every(10).seconds.do(job) while True: schedule.run_pending() time.sleep(1)
Procfileを作成する
clock: python batch.py
requirements.txtを用意する
pip freeze > requirements.txt
herokuにpushする
git add ./ git commit -m "first commit" git push heroku master
↓のようにログが確認できます。
heroku[clock.1]: Starting process with command `python batch.py` heroku[clock.1]: State changed from starting to up app[api]: Build succeeded app[clock.1]: This job is run every three minutes. app[clock.1]: This job is run every three minutes.
注意
custom clock processes
の場合起動中はdynoを消費し続けます。
なので、web1, clock1でscaleしていると、webのみの場合の2倍早く消費されます。
無料内で定期バッチを実行する場合は、add-onを使ったほうが良いでしょう。
(ただし、10分、1時間、1日ごとのみ指定可能です)
add-onの場合は、実行時のみ消費されるので低コストです。
1日ごとに論理削除されたレコードを削除したいといった場合はadd-onを使ったほうがよさそうです。