7つの要点のまとめ
- 基礎の理解の徹底
- 一番重要な一つだけをピックアップする
- 自分の作業をクリアに説明できるようにする
- 情報量を減らし重要な部分を説明する
- 主体的に動き(タスクを振り)楽しむ
- どんなにキリが悪くても絶対に定時で作業をやめる
- 専門性を高め批判をしない
参考文献
牛尾 剛 (著)/文藝春秋/2023/世界一流エンジニアの思考法
参考文献
牛尾 剛 (著)/文藝春秋/2023/世界一流エンジニアの思考法
<script src="index.js"></script>
node index.js
undefined; null; 0; ''; NaN:
const hoge = () { // 処理 }
// ポップアップを出す window.alert('これはエラーです')
// buttonタグを取得 document.getElementsByTagName('button')
// buttonを押された時に処理 // addEventListenerは引数を2つ取る document.getElementsByTagName('button').addEventListener('click', () => { // 処理 })
// idを取得 // Elementとなりsは付かない document.getElementById('xx') // textContentに値を入れると書き換え可能 document.getElementById('xx').textContent = 'りんご'
const $button = document.getElementsByTagName('button')
const $button = document.getElementsByTagName('button') $button[0].addEventListener('click', (e) => { // $button[0]を表す e.target })
(() => { // 処理 })()
// querySelectorAllで全てのデータを取得 const $content = document.querySelectorAll('[data-content]') // initで初期化 // style.displayでCSS操作 const init = () => { $content[0].style.display = 'block' } init()
// 'use strict'という文字列をファイルまたは関数の先頭に書く 'user strict' // 処理
` aaa bbb ccc `
String(1); // => "1"
// ユーザー入力を文字列として受け取る const input = window.prompt("数字を入力してください", "42"); // 文字列を数値に変換する const num = Number(input);
function fn(...args) { // argsは、渡された引数が入った配列 console.log(args); // => ["a", "b", "c"] } fn("a", "b", "c");
// 関数の仮引数が1つのときは()を省略できる const fnC = x => {}; // 関数の処理が1つの式である場合に、ブロックとreturn文を省略できる const mulB = x => x * x;
function 高階関数(コールバック関数) { コールバック関数(); }
// コールバック関数となる無名関数をその場で定義して渡せます。 const array = [1, 2, 3]; array.forEach((value) => { console.log(value); });
const obj = { method: function() { return "this is method"; } }; // 短縮記法 const obj = { method() { return "this is method"; } }; console.log(obj.method()); // => "this is method"
const s = Symbol();
// 配列の繰り返し処理 const array = [1, 2, 3] array.forEach(value => { console.log(value); });
// 配列の各要素をテストする function isEven(num) { return num % 2 === 0; } const numbers = [1, 5, 10, 15, 20]; console.log(numbers.some(isEven)); // => true
// 配列から特定の値だけを集めた新しい配列を作る function isEven(num) { return num % 2 === 0; } const array = [1, 5, 10, 15, 20] console.log(array.filter(isEven)); // => [10, 20]
// for...in文は親オブジェクトのプロパティも引き継ぐためObject.keysメソッドを使う const obj = { 'a': 1, 'b': 2, 'c': 3 }; Object.keys(obj).forEach(key => { const value = obj[key]; console.log(`key:${key}, value:${value}`); }); // 非推奨 for (const i in obj) { console.log(i); // a,b,c console.log(obj[i]); // 1,2,3 }
const array = [1, 2, 3]; for (const value of array) { console.log(value); }
/ | object | map | array | set |
---|---|---|---|---|
キー | 文字列 | 指定なし | 重複OK | 重複NG |
for...in | o | x | o | x |
for...of | x | o | o | o |
const map = new Map(); const key1 = {}; map.set(key1, 'value1'); console.log(map.get(key1)) // value1
// arry1とarry2は違う配列となる const arry1 = [1,2,3,4,5]; const arry2 = [...arry1]; // スレッド演算子は引数となる場合はrest parameterという function sum(...args) { let r = 0; for(let v of args) { r += v; } return r; } const result = sum(1,2,3,4); console.log(result); // 10
const obj = { key: value } console.log(obj.key) console.log(obj['key']) // 削除はdeleteを使う delete obj.key
const obj = { key: undefined }; if ('key' in obj) { //処理 }
const obj = { "one": 1, "two": 2, "three": 3 }; // `Object.keys`はキーを列挙した配列を返す console.log(Object.keys(obj)); // => ["one", "two", "three"] // `Object.values`は値を列挙した配列を返す console.log(Object.values(obj)); // => [1, 2, 3] // `Object.entries`は[キー, 値]の配列を返す console.log(Object.entries(obj)); // => [["one", 1], ["two", 2], ["three", 3]]
const objA = {a: 'a'}; const objB = {b: 'b'}; const merged = Object.assign({}, objA, objB); console.log(merged); // => {a: 'a', b; 'b'}
// コンストラクターは大文字から始める function Person(){ this.name = name; } Preson.prototype.hello = function(){ // 処理 } const bob = new Person('Bob', 18); bob.hello();
if (arg instanceof Array) { // 処理 }
class Person { constructor(name, age) { this._name = name; this._age = age; } get name() { // 何らかの処理 return this._name; } set name(val) { // 何らかの処理 this._name = val; } } const p = new Person('Bob', 18); console.log(p.name) // get経由で呼ばれる p.name = 'Alice' // set経由で呼ばれる
const colors = [ {'color': 'red'}, {'color': 'blue'}, {'color': 'green'}, {'color': 'blue'} ] // 条件に一致する最初の要素を取得 const blueColor = colors.find((obj) => { return obj.color === 'blue'; }); console.log(blueColor); // => {'color': 'blue'}
const array = ["Java", "JavaScript", "Ruby"]; // `includes`は含まれているなら`true`を返す if (array.includes("JavaScript")) { console.log("配列にJavaScriptが含まれている"); }
const array = ['A', 'B', 'C']; const newArray = array.concat(['D', 'E']); console.log(newArray); // => ['A', 'B', 'C', 'D', 'E']
破壊的な方法 | 非破壊な方法 |
---|---|
array[index] = item | Array.prototype.with |
Array.prototype.pop | array.slice(0, -1)とarray.at(-1) |
Array.prototype.push | [...array, item] |
Array.prototype.splice | Array.prototype.toSpliced |
Array.prototype.reverse | Array.prototype.toReversed |
Array.prototype.sort | Array.prototype.toSorted |
Array.prototype.shift | array.slice(1)とarray.at(0) |
Array.prototype.unshift | [item, ...array] |
Array.prototype.copyWithin | なし |
Array.prototype.fill | なし |
// コールバック関数には要素, インデックス, 配列が引数として渡される const array = [1, 2, 3]; array.forEach((currentValue, index, array) => { console.log(currentValue, index, array); }); // コンソールの出力 // 1, 0, [1, 2, 3] // 2, 1, [1, 2, 3] // 3, 2, [1, 2, 3]
// mapメソッドは配列の要素を順番にコールバック関数へ渡し、コールバック関数が返した値から新しい配列を返す非破壊的なメソッド const array = [1, 2, 3]; // 各要素に10を乗算した新しい配列を作成する const newArray = array.map((currentValue, index, array) => { return currentValue * 10; }); console.log(newArray); // => [10, 20, 30] // 元の配列とは異なるインスタンス console.log(array === newArray); // => false
// filterメソッドは配列の要素を順番にコールバック関数へ渡し、コールバック関数がtrueを返した要素だけを集めた新しい配列を返す非破壊的なメソッド const array = [1, 2, 3]; // 奇数の値を持つ要素だけを集めた配列を返す const newArray = array.filter((currentValue, index, array) => { return currentValue % 2 === 1; }); console.log(newArray); // => [1, 3] // 元の配列とは異なるインスタンス console.log(array === newArray); // => false
// 検索対象となる文字列 const str = "???"; // replaceメソッドに文字列を指定した場合は、最初に一致したものだけが置換される console.log(str.replace("?", "!")); // => "!??" // replaceAllメソッドに文字列を指定した場合は、一致したものがすべて置換される console.log(str.replaceAll("?", "!")); // => "!!!"
// `function`キーワードからはじめる関数宣言 function fn1() {} // `function`を式として扱う関数式 const fn2 = function() {}; // Arrow Functionを使った関数式 const fn3 = () => {};
const obj = { // `function`キーワードを使ったメソッド method1: function() { }, // Arrow Functionを使ったメソッド method2: () => { } // メソッドの短縮記法で定義したメソッド method() { } }; // メソッド呼び出し obj.method();
// `fn`関数はメソッドではないのでベースオブジェクトはない fn(); // `obj.method`メソッドのベースオブジェクトは`obj` obj.method();
function outer() { // Arrow Functionで定義した関数を返す return () => { // この関数の外側には`outer`関数が存在する // `outer`関数に`this`を書いた場合と同じ return this; }; } // `outer`関数の返り値はArrow Functionにて定義された関数 const innerArrowFunction = outer(); console.log(innerArrowFunction()); // => undefined
class Point { constructor(x, y) { this.x = x; this.y = y; } }
class Person { hello() { // 処理 return this; } introduce() { //処理 } const bob = new Person() bob.hello().introduce() // 繋げて書ける }
class クラス { メソッド() { // このメソッドはプロトタイプメソッドとして定義される } } // クラスでは次のようにメソッドを定義できない class クラス { // SyntaxError メソッド: () => {} // SyntaxError メソッド: function(){} } const a = new クラス()
class 子クラス extends 親クラス { }
class Japanese extends Person { constructor(name, age, gender) { super(name, age); // 親の変数を呼ぶ this.gender = gender; } hello() { super.hello(); // 親のメソッドを呼ぶ // 処理 } }
try { console.log("try節:この行は実行されます"); // 未定義の関数を呼び出してReferenceError例外が発生する undefinedFunction(); // 例外が発生したため、この行は実行されません } catch (error) { // 例外が発生したあとはこのブロックが実行される console.log("catch節:この行は実行されます"); console.log(error instanceof ReferenceError); // => true console.log(error.message); // => "undefinedFunction is not defined" } finally { // このブロックは例外の発生に関係なく必ず実行される console.log("finally節:この行は実行されます"); }
try { // 例外を投げる throw new Error("例外が投げられました"); } catch (error) { // catch節のスコープでerrorにアクセスできる console.log(error.message); // => "例外が投げられました" }
// asyncPromiseTask関数は、Promiseインスタンスを返す function asyncPromiseTask() { return new Promise((resolve, reject) => { // さまざまな非同期処理を行う // 非同期処理に成功した場合は、resolveを呼ぶ // 非同期処理に失敗した場合は、rejectを呼ぶ }); } // asyncPromiseTask関数の非同期処理が成功した時、失敗した時に呼ばれる処理をコールバック関数として登録する asyncPromiseTask().then(()=> { // 非同期処理が成功したときの処理 }).catch(() => { // 非同期処理が失敗したときの処理 });
async function doAsync() { return "値"; } // doAsync関数はPromiseを返す doAsync().then(value => { console.log(value); // => "値" });
async function asyncMain() { // PromiseがFulfilledまたはRejectedとなるまで待つ await Promiseインスタンス; // Promiseインスタンスの状態が変わったら処理を再開する }
new Promise(function(resolve, reject) { // 同期処理 resolve('hello'); }).then(function(data) { // 非同期処理 // resolveの時に処理される }).catch(function(data) { // 非同期処理 // rejectの時に処理される(エラー処理を書く) }).finally(function() { // 非同期処理 // 終了処理 });
async function init() { let val = await sleep(0); val = await sleep(val); val = await sleep(val); val = await sleep(val); }
// 定義 const map = new Map(); const map = new Map([["key1", "value1"], ["key2", "value2"]]); // 新しい要素の追加 map.set("key", "value1"); // キーの存在確認 console.log(map.has("key")); // => true // 反復処理 const results = []; map.forEach((value, key) => { results.push(`${key}:${value}`); }); console.log(results); // => ["key1:value1","key2:value2"]
// JSONはダブルクォートのみを許容する const json = '{ "id": 1, "name": "js-primer" }'; const obj = JSON.parse(json); console.log(obj.id); // => 1 console.log(obj.name); // => "js-primer"
const obj = { id: 1, name: "js-primer", bio: null }; console.log(JSON.stringify(obj)); // => '{"id":1,"name":"js-primer","bio":null}' 実行
// 現在の時刻を表すインスタンスを作成する const now = new Date(); // 時刻値を取得する console.log(now.getTime());
for (let i=0; i < 5; i++) { // 毎回ランダムな浮動小数点数を返す console.log(Math.random()); }
// 名前つきエクスポートされたfooとbarをインポートする import { foo, bar } from "./my-module.js"; console.log(foo); // => "foo" console.log(bar); // => function bar()
// HTTPリクエスト const userId = "任意のGitHubユーザーID"; fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`);
// HTTPレスポンス const userId = "js-primer-example"; fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`) .then(response => { console.log(response.status); // => 200 return response.json().then(userInfo => { // JSONパースされたオブジェクトが渡される console.log(userInfo); // => {...} }); });
// commanderモジュールからprogramオブジェクトをインポートする import { program } from "commander"; // コマンドライン引数をcommanderでパースする program.parse(process.argv); // ファイルパスをprogram.args配列から取り出す const filePath = program.args[0];
// fs/promisesモジュール全体を読み込む import * as fs from "node:fs/promises"; // fs/promisesモジュールからreadFile関数を読み込む import { readFile } from "node:fs/promises";
$ npm test > mocha test/
formElement.addEventListener("submit", (event) => { // submitイベントの本来の動作を止める event.preventDefault(); console.log(`入力欄の値: ${inputElement.value}`); });
// コマンドライン引数の取得とオプションの設定 import {program} from 'commander'; program.option('-m, --month <number>'); program.parse(process.argv); const options = program.opts(); console.log(options.month;);
process.exit(1);
process.stdout.write('xxx');
// iは数字 i = i.toString().padStart(2, '0');
// 空白数を返す let fn_blank = (num) => { return ' '.repeat(num); }
<body> <h1>ToDo List</h1> <script type="module" src="./index.js"></script> </body>
// TodoListModelはAppクラスの外からは触る必要がないためプライベートフィールドとする export class App { #todoListModel = new TodoListModel(); }
// OKならtrue、キャンセルならfalseを返す let result = confirm('削除OK?')
参考文献
happiness-chain教材
JavaScript入門・完全版コース/プログラミング初心者向け、コスパ最強講座
JavaScript Primer
Commander.jsを使用してNode.jsのCLI引数を処理する
Node.jsで終了ステータスコードを使うなら押さえておきたいasyncと終了ステータスコードの話
Node.jsでコンソールの表示を上書きする
【JavaScript】padStartメソッドで0詰め2桁の数字を作る関数
JSのプライベートフィールドは接頭辞に#(シャープ)を付けて表示する
JavaScriptによる削除する前に確認メッセージ
CodeMafia, 2024, 「【JS】ガチで学びたい人のためのJavaScriptメカニズム」, udemy, (2024/4/16取得,https://www.udemy.com/).
※1,2列は算数の点数>=60の条件を検証している
※ 列がテストケース(下記例は4ケース)
変数 | 条件 | ポイント | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|---|
算数 | 算数の点数>=60 | on | 60 | - | - | - |
off | - | 59 | - | - | ||
in | - | - | 70 | 80 | ||
合計点 | (算数の点数+国語の点数)>=90 | on | - | - | 70/20 | - |
off | - | - | - | 80/9 | ||
in | 60/40 | 59/41 | - | - | ||
期待される結果 | 合格 | 不合格 | 合格 | 不合格 |
※上からNoが出たら以降の判定は行わないのがコツ
※ 列がテストケース(下記例は4ケース)
1 | 2 | 3 | 4 | |
---|---|---|---|---|
条件 | ||||
書籍を購入している | Yes | Yes | Yes | No |
4000円以上購入している | Yes | Yes | No | - |
離島に住んでいない | Yes | No | - | - |
アクション | ||||
送料無料 | Yes | No | No | No |
※例:L4(23)・・・2値条件が3つ
※ 行がテストケース(下記例は4ケース)
A | B | C | |
---|---|---|---|
1 | 0 | 0 | 0 |
2 | 0 | 1 | 1 |
3 | 1 | 0 | 1 |
4 | 1 | 1 | 0 |
※以下は状態遷移表
※列→行
イベント\状態 | ①初期状態 | ②動作中 | ③停止中 |
---|---|---|---|
スタートボタン | ② | ③ | ② |
リセットボタン | N/A | N/A | ① |
※以下は1スイッチカバレッジ
※イベントRはリセット、Sはスタート
※+はorの意味
※行→イベント→列へ遷移
※ 行列がテストケース(下記例は12ケース)
前状態\後状態 | ①初期状態 | ②動作中 | ③停止中 |
---|---|---|---|
①初期状態 | RR+SR | RS | SS |
②動作中 | RR+SR | RS+SS | - |
③停止中 | RR+SR | RS | SS |
参考文献
ひらまつ しょうたろう, 2023, 「はじめてのソフトウェアテスト技法【全てのエンジニアが知るべき最重要テスト技法を、丁寧な解説と演習問題で身につけよう】」, udemy, (2024/2/20取得,https://www.udemy.com/).
django-admin startproject helloworldproject . ←.を付けることでフォルダを一つ省略する
python manage.py runserver
settings.py
urls.py
urlpatterns = [
path('helloworld2/', HelloWorldClass.as_view())
]
views.py
アプリ
# ①アプリの作成 python manage.py startapp helloworldapp(=アプリ名) # ②Djangoのプロジェクトに対してアプリを作成したことを伝える # settings.py INSTALLED_APPS = [ ... 'helloworldapp.apps.HelloworldappConfig', # 一般的な書き方 ] # ③アプリとプロジェクトの繋ぎ # urls.py from django.urls import path, include urlpatterns = [ path('', include('helloworldapp.urls')), # helloworldapp/だと重複となりエラーとなるので注意 ]
# TodoModelテーブル class TodoModel(models.Model): title = models.CharField(max_length=100) # フィールドの設定 memo = models.TextField()
# ①設計図の作成 python manage.py makemigrations (アプリ名) # (アプリ名)は省略可 # ②テーブルの作成 python manage.py migrate
python manage.py createsuperuser
# admin.py # ①管理画面にデータの追加 from .models import TodoModel admin.site.register(TodoModel) # models.py # ②データ名の変更 def __str__(self): # オブジェクトを作成した際に文字列を返す return self.title
ListVeiw
# views.py from django.views.generic.list import ListView from .models import TodoModel class TodoList(ListView): template_name = 'list.html' model = TodoModel
# list.html <!-- object_listは指定したmodel(TodoModel)の全てのデータ --> {% for post in object_list %} <ul> <li>{{ post.title }}</li> <li>{{ post.memo }}</li> </ul> {% endfor %}
# urls.py urlpatterns = [ path('list/', TodoList.as_view()), path('detail/<int:pk>', TodoDetail.as_view()), # <int:pk>がポイント ]
# detail.html {{ object.title }}
# base.html {% block header %} {% endblock %}
# list.html {% extends 'base.html' %} ←base.htmlを読み込み {% block header %} this is list. {% endblock %}
# list.html {% block content %} <div class="container"> {% for item in object_list %} <div class="alert alert-{{ item.priority }}" role="alert"> ←{{ item.priority }}がポイント <p>{{ item.title }}</p> <a href="#" class="btn btn-info" tabindex="-1" role="button" aria-disabled="true">編集画面へ</a> <a href="#" class="btn btn-success" tabindex="-1" role="button" aria-disabled="true">削除画面へ</a> <a href="#" class="btn btn-primary" tabindex="-1" role="button" aria-disabled="true">詳細画面へ</a> </div> {% endfor %} </div> {% endblock %}
# 右のデータは管理画面の表示名、左のデータはBootstrapより CHOICE = (('danger', 'high'), ('warning', 'normal'), ('primary', 'low')) # TodoModelテーブル class TodoModel(models.Model): priority = models.CharField( max_length=50, choices=CHOICE, # 管理画面上で選択肢を与える ) duedate = models.DateField() # 時間の表示(本件には関係ない)
③マイグレーションファイルの作成とマイグレートによるテーブルの作成
CreateView
# urls.py from .views import TodoList, TodoDetail, TodoCreate urlpatterns = [ path('list/', TodoList.as_view(), name='list'), # nameを記述することにより画面遷移が可能となる path('detail/<int:pk>', TodoDetail.as_view(), name='detail'), path('create/', TodoCreate.as_view(), name='create'), ]
# views.py from django.views.generic import ListView, DetailView, CreateView from django.urls import reverse_lazy class TodoCreate(CreateView): template_name = 'create.html' model = TodoModel fields = ('title', 'memo', 'priority', 'duedate') # フォームの設定 success_url = reverse_lazy('list') # データ登録後listに画面遷移
# create.html {% extends 'base.html' %} {% block content %} <form action="" method="POST">{% csrf_token %} # {% csrf_token %}はセキュリティ対策となりここに書くのが一般的 {{ form.as_p}} # フォームの設定(詳細はviews.pyで設定) <input type="submit" value="create"> </form> {% endblock %}
DeleteView, UpdateView
urlタグの設定
# list.html {% block content %} <div class="container"> {% for item in object_list %} <div class="alert alert-{{ item.priority }}" role="alert"> <p>{{ item.title }}</p> # {% url 'update' item.pk %}がポイントとなりupdate画面へ遷移する <a href="{% url 'update' item.pk %}" class="btn btn-info" tabindex="-1" role="button" aria-disabled="true">編集画面へ</a> </div> {% endfor %} </div> {% endblock %}
# views.py from django.shortcuts import render def signupfunc(request): # httpresponseオブジェクトの作成 # {}はモデルの情報 return render(request, 'signup.html', {})
# views.py # ①ユーザーモデルのインポートとユーザーの取得 from django.contrib.auth.models import User def signupfunc(request): object = User.objects.get(username='s') # User.objects.all()で全てのユーザーを取得
# ②migrateの実行 # models.pyを修正していないためmigrationfileの作成は不要 python manage.py migrate
# ③ユーザーの作成 python manage.py createsuperuser
# signup.html # ①フォームをPOSTにする {% extends 'base.html' %} {% block content %} <body class="text-center"> <main class="form-signin"> <!-- 書く場所注意 --> <form method="POST">{% csrf_token %} <h1 class="h3 mb-3 fw-normal">Please sign in</h1> <div class="form-floating"> <input type="text" class="form-control" id="floatingInput" placeholder="username" name="username"> <label for="floatingInput">username</label> </div> <div class="form-floating"> <input type="password" class="form-control" id="floatingPassword" placeholder="Password" name="password"> <label for="floatingPassword">Password</label> </div> <button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button> <p class="mt-5 mb-3 text-muted">© 2017–2023</p> </form> </main> </body> {% endblock %}
# views.py # ②ユーザーの作成 # request.POSTでフォームからのデータを取得するのがポイント def signupfunc(request): # userの作成 if request.method == "POST": username = request.POST["username"] password = request.POST["password"] user = User.objects.create_user(username, "", password)
# views.py from django.db import IntegrityError def signupfunc(request): if request.method == "POST": username = request.POST["username"] password = request.POST["password"] try: user = User.objects.create_user(username, "", password) except IntegrityError: return render(request, 'signup.html', {"error": "このユーザーは既に登録されています"})
# ①signupと同じような画面を作成する # login.html
# ②authenticateで認証 # views from django.contrib.auth import authenticate, login def loginfunc(request): if request.method == "POST": username = request.POST["username"] password = request.POST["password"] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return render(request, 'login.html', {"context": "logged in"}) else: return render(request, 'login.html', {"context": "not logged in"}) return render(request, 'login.html', {"context": "get method"})
renderとredirect
modelsの記載例
# models.py from django.db import models class BoardModel(models.Model): title = models.CharField(max_length=100) content = models.TextField() author = models.CharField(max_length=50) # settings.pyで設定されたデフォルトの場所に保存するならブランクでよい sns_image = models.ImageField(upload_to="") good = models.IntegerField() read = models.IntegerField() readtext = models.TextField()
# views.py from .models import BoardModel def listfunc(request): object_list = BoardModel.objects.all() # キーはバリューと同じ名前が一般的 # list.htmlに{}書きでモデルのデータを渡す return render(request, "list.html", {"object_list": object_list})
# list.html {% block content %} <div class="container"> {% for item in object_list %} # object_listでviewsより受け取る <div class="alert alert-success" role="alert"> <p>タイトル:{{ item.title }}</p> # {{}}でデータを扱う <p>投稿者:{{ item.author }}</p> <a href="#" class="btn btn-primary" tabindex="-1" role="button" aria-disabled="true">Primary link</a> <a href="#" class="btn btn-secondary" tabindex="-1" role="button" aria-disabled="true">Link</a> </div> {% endfor %} # ここはendfor </div> {% endblock %}
# settings.py # 画像のURLとなり最後スラッシュを入れる MEDIA_URL = "medi/" # 画像の保存先(開発環境用) MEDIA_ROOT = BASE_DIR / "media"
# (プロジェクトの)urls.py from django.conf.urls.static import static urlpatterns = [ ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# models.py class ItemModel(models.Model): ... item_image = models.ImageField(upload_to="")
pip install pillow
# list.html <img class="card-img-top" src="{{ item.item_image.url }}" alt="{{ item.name }}" />
# 画像のURLとなり最後スラッシュを入れる STATIC_URL = 'static/' # 画像の保存先(本番環境用となり本番環境はSTATICFILES_DIRSからここに一つにまとめる) STATIC_ROOT = BASE_DIR / "staticfiles" # 画像の保存先(開発環境用となり複数の保存先を指定可) STATICFILES_DIRS = [str(BASE_DIR / "static")]
from django.conf.urls.static import static urlpatterns = [ ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
# base.html <head> {% block customcss %} {% endblock %} </head>
# signup.html {% extends 'base.html' %} <!-- staticfilesdirsの場所を読み込む --> {% load static %} {% block customcss %} <link href="{% static 'style.css' %}" rel="stylesheet"> # staticフォルダのcssを読み込む {% endblock %}
# settings.py # ulrs.pyのname=loginを参照する(reverseのイメージ) LOGIN_URL = "login"
# views.py # 関数呼び出し前に処理を加える(リストの表示前にログイン画面に飛ばす) from django.contrib.auth.decorators import login_required @login_required def listfunc(request): xxx
# list.html {% if user.authenticated %} # タイトルや投稿者 {% else %} please login {% endif %}
# ulrs.py from .views import signupfunc, loginfunc, listfunc, logoutfunc urlpatterns = [ path('logout/', logoutfunc, name="logout"), ]
# views.py from django.contrib.auth import authenticate, login, logout def logoutfunc(request): logout(request) return redirect("login")
# list.html ... {% endfor %} <a href="{% url 'logout' %}">logout</a> </div>
# urls.py from .views import signupfunc, loginfunc, listfunc, logoutfunc, detailfunc urlpatterns = [ path('detail/<int:pk>', detailfunc, name="detail"), ]
# views.py from django.shortcuts import render, redirect, get_object_or_404 # 引数pkがポイント def detailfunc(request, pk): # object = BoardModel.object.get(pk=pk) # 上記と同じくデータを取得しかつオブジェクトがなければ例外を返す object = get_object_or_404(BoardModel, pk=pk) return render(request, "detail.html", {"object": object})
# detail.html ... <p>タイトル:{{ object.title }}</p> <p>投稿者:{{ object.author }}</p> # 画像の表示方法 <p><img src="{{ object.snsimage.url }}" width=300></p> ...
# list.html # item.pkを渡すのがポイント ... <p>タイトル:<a href="{% url 'detail' item.pk %}">{{ item.title }}</a></p> ...
# urls.py path('good/<int:pk>', goodfunc, name="good"),
# views.py def goodfunc(request, pk): object = get_object_or_404(BoardModel, pk=pk) object.good = object.good + 1 object.save() # ポイント return redirect("list")
# detail.html <a href="{% url 'good' object.pk %}" class="btn btn-primary" tabindex="-1" role="button" aria-disabled="true">いいねする</a> # list.html # disabledでクリック出来ないようにする(好み) <a href="#" class="btn btn-primary disabled" tabindex="-1" role="button" aria-disabled="true">いいね{{ item.good }}件</a>
# urls.py from .views import signupfunc, loginfunc, listfunc, logoutfunc, detailfunc, goodfunc, readfunc urlpatterns = [ path('read/<int:pk>', readfunc, name="read"), ]
# views.py def readfunc(request, pk): object = get_object_or_404(BoardModel, pk=pk) username = request.user.get_username() if username in object.readtext: return redirect("list") else: # 既読回数を増やす object.read = object.read + 1 # 既読ユーザーを入れる object.readtext = object.readtext + ' ' + username object.save() return redirect("list")
# detail.html <a href="{% url 'read' object.pk %}" class="btn btn-secondary" tabindex="-1" role="button" aria-disabled="true">既読にする</a>
# urls.py from .views import signupfunc, loginfunc, listfunc, logoutfunc, detailfunc, goodfunc, readfunc, \ BoardCreate urlpatterns = [ path('create/', BoardCreate.as_view(), name="create") ]
# views.py from django.views.generic import CreateView from django.urls import reverse_lazy class BoardCreate(CreateView): template_name = "create.html" model = BoardModel fields = ("title", "content", "author", "snsimage") success_url = reverse_lazy("list")
# create.html {% extends "base.html" %} {% block content %} {% if user.is_authenticated %} <!-- fileを扱う場合はenctypeの指定かつ複数のデータを扱う場合はmultipartを使う --> <form method="POST" enctype="multipart/form-data">{% csrf_token %} <!-- {{ form.as_p }} --> <p>title:<input type="text" name="title"></p> <p>content:<input type="text" name="content"></p> <p><input type="file" name="snsimage"></p> <!-- フロント側は隠す --> <input type="hidden" name="author" value="{{ user.username }}"> <input type="submit" value="create"> </form> {% else %} please login {% endif %} {% endblock %}
# models.py from django.db import models # 画像をアップできるようにバリデーションを外すのがポイント class BoardModel(models.Model): # nullとblankを許容する(セットで設定:nullはDB関係、blanckはform関係) good = models.IntegerField(null=True, blank=True, default=1) read = models.IntegerField(null=True, blank=True, default=1) readtext = models.TextField(null=True, blank=True, default="a")
# models.py class Question(models.Model): question_text = models.CharField(max_length=200) class Choice(models.Model): # リレーションシップの定義(各々のChoiceが一つのQuestionに関連付けられる) question = models.ForeignKey(Question, on_delete=models.CASCADE)
# <テーブル1><テーブル2>_set.allでテーブル1に紐付くテーブル2のデータを全て取得する question.choice_set.all
# views.py def index(request): # オブジェクトをソートして取得 latest_question_list = Question.objects.order_by("-pub_date")[:5]
# 名前空間により他のアプリと区別する app_name = "polls" urlpatterns = [ path("index/", views.index, name="index"),
# index.html {% for question in latest_question_list %} <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> {% endfor %}
python -m pip install django-debug-toolbar
heroku apps:create ecapp
environの理解
デプロイ
git push heroku xxxx:main # 強制プッシュ git push heroku xxxx:main --force
CLOUDINARY_STORAGE = { 'CLOUD_NAME': 'drsbhpxje', # アプリ消去時の再設定忘れない 'API_KEY': env('CLOUDINARY_API_KEY'), 'API_SECRET': env('CLOUDINARY_API_SECRET') }
heroku pg:reset DATABASE_URL
// heroku run python manage.py makemigrations twapp heroku run python manage.py migrate -a twapp
heroku run python manage.py createsuperuser
docker compose exec web flake8 --max-line-length 400
# views.py class ItemList(ListView): template_name = 'list.html' model = ItemModel # メソッドをオーバーライドし商品をid順に取得する def get_queryset(self): return ItemModel.objects.all().order_by('id') class ItemDetail(DetailView): template_name = 'detail.html' model = ItemModel # メソッドをオーバーライドしURLから取得されるオブジェクトに加えて最新のDBデータを取得する def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['latest_item'] = ItemModel.objects.latest('id')
# views.py def add_to_cart_from_list_func(request, pk): # セッションのカートを取得、なければ新しく作成 cart = request.session.get('cart', []) cart.append(pk) # カートをセッションに保存 request.session['cart'] = cart return redirect("list")
# models.py class CartItemModel(models.Model): # 中間テーブルの作成 cart = models.ForeignKey(CartModel, on_delete=models.CASCADE, related_name='cart_items') item = models.ForeignKey(ItemModel, on_delete=models.CASCADE, related_name='item_carts')
# views.py # 中間オブジェクトを作成 cart_item_object= CartItemModel.objects.create(cart=cart_object, item=item_object) cart_item_object.save() # カートアイテムの数を取得 cart_item_count = cart_object.cart_items.all().count()
# カートアイテムを取得 cart_items = cart_object.cart_items.all() # カートの商品数と合計金額を算定 for cart_item in cart_items: total_price += cart_item.item.price
# カートアイテムからpkに一致する最初のデータを削除
cart_object.cart_items.filter(item__id=pk).first().delete()
# カートアイテムの削除 cart_object.cart_items.filter(item__id=pk).delete() # cart_object.save() # 不要
{% url 'twapp:tweet_good' tweet.id %}?param={{ param_value }}
# クエリパラメータの受け取り param_value = request.GET["param"] if param_value in ["all", "follow"]: # URLのパス部分を生成 url = reverse('twapp:tweet_list') else: url = reverse('twapp:tweet_list_id', kwargs={'id': tweetmodel.customusermodel_id}) # クエリパラメータを追加 redirect_url = f'{url}?param={param_value}'
docker compose exec web python manage.py showmigrations
docker compose exec web python manage.py migrate twapp 0001_initial←戻したいファイル名
方法②リセット
docker compose down docker volume rm django_tw_db-data
参考文献
基礎
・株式会社CODOR (大橋亮太), 【徹底的に解説!】Djangoの基礎をマスターして、3つのアプリを作ろう!(Django2版 / 3版を同時公開中です)
・公式チュートリアル
・pyhaya’s diary
応用
・上記の各リンク参照
主要なコマンド | 内容 | 使い方例 |
---|---|---|
sys.argv | コマンドライン引数へアクセス | sys.argv[0] 実行ファイル名を取得 |
sys.exit() | プログラムの終了 | sys.exit("エラーが発生") 終了時のコメントが可能 |
sys.path | 検索パスの操作 | sys.path os, pathlibと同じくパスを表示 |
sys.stdin | 標準入力へアクセス | sys.stdin.readline() input()と同じく入力を受け取る |
sys.stdout | 標準出力へアクセス | sys.stdout.write('Hello') print()と同じく出力する |
sys.version | Pythonのバージョンへアクセス | ※あまり使わない |
sys.platform | OSへアクセス | ※あまり使わない |
参考文献
2023年12月8取得/Python公式
print(""" 1 2 3 """) >> ←空行 1 2 3 ←空行
l = [0, 1, 1, 2] a = set(l) print(a) >> {0, 1, 2} # 集合になる
a = 0 if a: print(OK) else: print(NG) >> NG # 数値が0の場合はFalseとなるためNGとなる(0以外の数値はTrue)
for _ in range(10):
d = {"a": 1, "b": 2} for k, v in d.items():
def circle_area_func(pi): def circle_area(radius): return pi * radius * radius return circle_area ca1 = circle_area_func(3.14) # 関数内関数を実行するには外側の関数の返り値を変数に格納し実行する必要がある print(ca1(10)) >> 314.0
# python app.py b import sys print(sys.argv) >> [app.py, b]
class Preson: def __init__(self) ←必ずselfが必要
class AdvanceCar: def __init__(self, _enable_auto_run=False): self._enable_auto_run = enable_auto_run ←変数名に_を付ける @property ←プロパティのゲッター def enable_auto_run(self): return self._enable_auto_run ←変数を返す advanced_car = AdvancedCar() print(advanced_car.enable_auto_run) ←False(呼び出しの括弧は不要) advanced_car.enable_auto_run = True ←エラーとなる(書き換え不可) ----------------------------------------- # プロパティに外から値を設定できるようにしたい場合はセッターを作る @enable_auto_run.setter ←プロパティのセッター def enable_auto_run(self, is_enable): self._enable_auto_run = is_enable advanced_car.enable_auto_run = True ←エラーとならない(書き換え可能)
class PersonCarRobot(Car, Person): ←Carが優先 ...
class Preson: kind = "human" ←ここで定義 def who_are_you(self): print(self.kind) ←呼び出す際はインスタンス変数と同じくselfを付ける a = Person() a.who_are_you() b = Preson() b.who_are_you()
import logging logging.basicConfig(level=logging.INFO) ←ログレベルの設定 logging.info('info') ←ログの表示
import logging
logger = logging.getLogger(__name__) ←__name__を渡すのがコツ
import logging h = logging.FileHandler('logtest.log') ←logtest.logに出力する logger.addHandler(h) ←ロガーにハンドラーを渡す
from email import message import smtplib ... # SMTPサーバー名やポート番号を設定していく
import logging ←ロガーを作成する import logging.handlers ←addHandlerでSMTPHandlerを指定する ...
import json with open('test.json', 'w') as f: json.dump(j, f) with open('test.json', 'r') as f: json.load(f)
import requests payload = {'key1': 'value1'} r = requests.get('http://~', params=payload) ←payloadでデータを渡す r.text ←テキストで出力 r.json() ←JSON形式で出力
from flask import Flask from flask import g from flask import render_template from flask import request from flask import Response app = Flask(__name__) # トップページ @app.route('/') def hello_world(): return 'top' # <変数>でデータを渡す @app.route('/hello') @app.route('/hello/<username>') def hello_world2(username=None): return f'hello world!{username}' def main(): app.debug = True # サーバーの起動 app.run() if __name__=='__main__': main()
# 基本形 import threading def worker1(): ←worker1, 2を並列で処理 ... def worker2(): ←worker1, 2を並列で処理 ... if __name__ == '__main__': t1 = threading.Thread(target=worker1) ←スレッドの作成 t2 = threading.Thread(target=worker2) ←スレッドの作成 t1.start() ←スレッドの実行 t2.start() ←スレッドの実行
# 基本形 import multiprocessing def worker1(): ←worker1, 2を並列で処理 ... def worker2(): ←worker1, 2を並列で処理 ... if __name__ == '__main__': t1 = multiprocessing.Process(target=worker1) ←スレッドの作成 t2 = multiprocessing.Process(target=worker2) ←スレッドの作成 t1.start() ←スレッドの実行 t2.start() ←スレッドの実行
参考文献
酒井 潤 (著)/KADOKAWA/2022/シリコンバレー一流プログラマーが教える Pythonプロフェッショナル大全
種類 | 特徴 |
---|---|
Zero-shot | プロンプトに例を与えない |
Few-shot | プロンプトに例を与える(特定の形式で応答させるため) |
Zero-shot CoT | 一言(ステップバイステップなど)追加する(正確に応答させるため) |
名称 | 機能 |
---|---|
Model I/O | ・Language models ・Prompts ・Output parsers |
Chains | |
Memory | |
Data connection(現在:Retrieval) | |
Agents | |
Callbacks |
参考文献
吉田 真吾 (著), 大嶋 勇樹 (著)/技術評論社/2023/ChatGPT/LangChainによるチャットシステム構築[実践]入門
はるすと/2023年11月24取得/ホストとは?デプロイ・リリースとの違いも初心者向けにわかりやすく解説
江戸達博/2023年11月26取得/サーバーレスとは何か? EC2とLambdaの違いも解説
@YotaHamasaki(yoo2315)/2023年11月26取得/Cloud9でインスタンスの再起動をしても繋がらない時