ひよっこエンジニアによる個人開発日誌


0.はじめに
---
地方の大学に通う大学3年生(文系)です。
個人でのwebアプリ開発に向けて備忘録を残していきます。
前提情報は簡単にまとめますが、それ以降は基本的には自分用のメモなのでかなり雑に書いていくと思います。

**【めちゃくちゃ長いので、サッと読みたい方は[Notion](https://silly-notify-89d.notion.site/Shifty-20d07368e71441c187b87f7a063f6d01)にアクセスしてください。】**

**追記(2023/3/22)
デプロイまで終了！めでたしめでたし**


### 簡単な経歴

- 経済学部所属のド文系
- プログラミング歴→半年程度
- 実装経験、開発経験ほぼなし
- Udemy,Qiitaを参考に独学(python,Djangp,PHP,Laravel,AWS,gitなど)


こんな感じです。
早く一人前になりたいです。

---
# 1.どんな人に読んでもらいたいか

- プログラミング初心者
- 個人開発が気になっている駆け出しエンジニア
- 初めてのアプリ開発何から始めればいいかわかんない！って人（技術的には全く参考になりません）
- 駆け出しエンジニアを高みの見物してみたいつよつよエンジニア



# 2.どんなアプリか

一言で表すと、【職場のシフトをみんなで作ろうよ！】です。


**リアルタイムでスタッフ全員がシフト管理に参加でき、面倒な再調整がなくなる**ことを目標としたサービスです。

簡単な特徴としては、
- 画面に表示されるカレンダーの日付に希望のシフトを埋めていく
- **他スタッフの入力状況がリアルタイムで確認できるので再調整が減る**（こだわりポイント）
- 定員に達した日程のシフトは自動的に確定されて入力ができなくなる
- シフトの共有、連絡をBOTが担当する
- 欠員が出た場合には全スタッフに向けて緊急アラートが通知され、素早い補充ができる


これだけでは伝わらないと思うので順を追って説明します。


### 従来のシフトアプリとの違い

現在のシフト管理アプリの市場はかなり飽和していて、特徴のあるアプリも多くリリースされています。
ここでは[シフトボード](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwjHvcjszt_8AhWIb94KHfsOCTwQFnoECAwQAQ&url=https%3A%2F%2Fshiftboard.jp%2F&usg=AOvVaw3B9nOMpXF4Z2jYA_tNYg7a)を例に従来のシフトアプリの共通点を簡単に説明していきます。

このアプリの基本的な使い方は
①従業員が各自希望のシフトを提出
②管理者がシフトの作成、共有、連絡等を行う
③管理者によってシフトの確定
④欠員等が出た場合の再調整を管理者が行う

こんな感じです。シフトボードに限らずですが、世の中の大半のシフト管理アプリはこの流れだと思います。

### 思ったこと

**管理者大変すぎない！？**

実際に私自身シフトボードを使っていますが、基本的にすることといえば
①希望のシフトを提出して
②管理者から欠員補充の連絡が来た場合に可能なら代わりに入り、そうでなければスルー

これだけです。

私の職場では欠員が出ることやシフトカットが非常に多く、管理者の方がかわいそうだなあと思っていました。


### なぜこうなっちゃうの？

管理者に負担が集中してしまう理由はただ一つです。

**従業員の自由度が低すぎる**ことです。



先ほど従来のシフト管理の流れを紹介しました。


>①従業員が各自希望のシフトを提出
②管理者がシフトの作成、共有、連絡等を行う
③管理者によってシフトの確定
④欠員等が出た場合の再調整を管理者が行う

従業員が②〜④のタスクに関われない（権利がない）ことが管理者への負担集中の最大の原因でしょう。


少し回りくどい書き方になってしまいましたが、
**①〜④まで全員でやれば良いんじゃない？というのが根本の考え方となります。**

### 解決できる課題

今回開発するサービスの特徴を再度まとめてみました。


>- 画面に表示されるカレンダーの日付に希望のシフトを埋めていく
>- **他スタッフの入力状況がリアルタイムで確認できるので再調整が減る**（こだわりポイント）
>- 定員に達した日程のシフトは自動的に確定されて入力ができなくなる
>- シフトの共有、連絡をBOTが担当する
>- 欠員が出た場合には全スタッフに向けて緊急アラートが通知され、素早い補充ができる



- 管理者
・希望のシフトを回収した後調整する必要がない
・BOTの導入によって定型的な連絡をする必要がなくなる
・欠員の補充は、自動の緊急アラート→スタッフが自由にスキマを埋めることで簡単に解決

- 従業員
・かなり自由にシフトを組める
・急なシフトカットや出勤時間の変更がなくなる



どうでしょうか？ここまで管理者の負担に注目してきましたが、実は従業員側にもメリットがあります。このサービスを導入することで多くの不満の解消につながると思います。


このwebアプリでは**リアルタイムで情報が連動してコミュニケーションエラーが減ること**が強みだと考えています。

# 3.使用技術

選定中...(2023/1/24)

# 4.日誌

雑に書いていきます！
かなり長くなると思われる＆読みづらいかも
## 2023/1/24
Qiitaで本記事を投稿しました。初投稿なので書き方合ってるかわからない。

**これまでの進捗状況**

今日から本格的に開発を進めていきたいと思いますが、開発に向けてこれまでコツコツと勉強してきたので軽くまとめます。

- progate(HTML/CSS,PHP,python)
- 学校の授業(python,Java,C,CS基礎知識)
- 基本情報技術者試験の程度の知識
- wordpressでの[webサイト](https://akitainu.info-matome.com/)構築（秋田犬可愛すぎるので興味のある方はぜひ）
- Udemy（[【徹底的に解説！】Djangoの基礎をマスターして、3つのアプリを作ろう！](https://www.udemy.com/share/102bRq3@jAJOmuFCNS8gCCOZ0IPijmjZ7NrMNk8X2wjllJFd8SkKhl9DdDAqY93C5p-pAE8iUA==/)など）

ザッとこんな感じです。ここから積み上げていきたいです。

**技術選定**

今のところこんな感じ…


フロントエンド→JavaScript
バックエンド→Python
フレームワーク→Django,Next.js
開発環境→vscode
インフラ関連→FirebaseかHeroku
データベース→MySQL→sqlite3（1/25追記）


このまま進めて良いのか不安しかないです！

## 2023/1/25

2日目です。周辺技術の勉強と並行しながら開発進めていこうと思います。
仮装環境構築
shiftproject
shiftappの設定とかをしました

**今やりたいこと**→
- カレンダーの埋め込み
- ログイン機能追加
- サイドバー情報
- 全体カレンダーからその日の細かい時間別シフトが確認できるページに遷移するようにする


**トップページ**
![名称未設定のノート-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/69eb1bd5-87d0-77cb-ac1d-66e1a48e5c0b.jpeg)
できるだけシンプルに
新規登録とログインボタン配置

**メインページ**

![名称未設定のノート-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/ad05a53c-f301-2f08-dc45-5d83ca75ed9d.jpeg)
中央にカレンダー配置
埋まった日はグレーに色が変わる（新規のクリックは不可、既にその日にシフトを出している人のみクリックできる）
右上に自分のアカウントアイコン
左にサイドバー（設定、ヘルプ、問い合わせ、ログアウトなど）

**カレンダーからの遷移先ページ**


![名称未設定のノート-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/b4b22a59-ac39-635d-8ef3-8e14a94b1c3a.jpeg)

スケジュールの細かい情報
１日のタイムスケジュールを載せる
全従業員のシフト提出状況を見られるようにする
時間を縦でみた時に定員に達している時間はグレーで色付け（追加の入力は不可、削除は可）、人が足りない場所は赤色で目立たせる


**カレンダー埋め込みたい！！**
参考ページ　[HTMLの基本、Webページにカレンダーを設置する方法](https://style.potepan.com/articles/21219.html)

>2
Googleカレンダーを利用する
3
カレンダーをJavaScriptで作成する
4
カレンダーをサーバー側で作る


GoogleカレンダーかJavascriptで迷ってます。

→カスタマイズ性の高い方を使いたいからJavascriptで埋め込みます。
→やっぱりDjangoにします。Javascriptよくわからない。。。

参考：[[python] Djangoで今日のカレンダーを表示する](https://qiita.com/junzai/items/a5cb45e236e0d45b8f83)
[datetime --- 基本的な日付型および時間型](https://docs.python.org/ja/3/library/datetime.html?highlight=calender)

Djangoで表示→Next.js使ってサイズ、レイアウトいじるみたいな感じかなあ

参考：[DjangoでWebアプリケーションを作成してみる](https://tech-blog.rakus.co.jp/entry/20220325/django)

[Pythonさえ分かればDjangoでWebアプリは作れる](https://qiita.com/pythonista/items/19613663ef7bb3c57d4f)←めっちゃわかりやすい　

**models.py**
[【Django】Model（モデル）とは：models.pyの書き方とデータベース連携（テーブル作成）](https://office54.net/python/django/django-model-database)

>DjangoはMTV（モデル・テンプレート・ビュー）という設計手法が使われています。
ＭはModel（モデル）、ＴはTemplate（テンプレート）、ＶはView（ビュー）を表します。
それぞれ次の機能を有します。
Model（モデル）：データベースとの連携を行う。該当ファイルはmodels.py
Template（テンプレート）：フロントエンド（HTML）を扱う。該当ファイルはtemplatesフォルダ内のhtmlファイル
View（ビュー）：バックエンドを扱う。該当ファイルはviews.py

udemyのdjangoチュートリアルで書いたmodels.py↓
    
    class TodoModel(models.Model): 
    title = models.CharField(max_length=100)
    memo = models.TextField()
    priority = models.CharField(
        max_length=50,
        choices = CHOICE
        )
    duedate = models.DateField()

形式こんな感じ

    class SampleModel(models.Models): # モデル名大文字
        title = models.CharField(max_length=100)
        memo = models.TextField()
        type = models.CharField(max_length=50)


[【django】モデルのフィールドについて：フィールドの型・オプション一覧](https://office54.net/python/django/model-field-options)

>フィールドとは、モデル定義で必ず１つ以上必要となる項目です。
データベースで言うと、テーブルのカラムにあたります。
フィールドはモデルクラスの属性として定義されます。
データベースで言うテーブルは、モデルにあたります。
このモデルを通してデータベースの操作（追加、削除、更新）を行います。
つまりDjangoでは、**モデルを使うことでSQL文（CREATEやINSERT）を使わないでデータベース操作を可能にします。**

>フィールドの型	扱うデータ
BooleanField	TrueまたはFalse
CharField	文字列
SlugField	文字列（制限あり）
IntegerField	整数
PositiveIntegerField	正の整数
TextField	長い文字列
DateField	日付
DateTimeField	日時
FileField	ファイルアップロード
ImageField	画像
URLField	URL
EmailField	メールアドレス
GenericIPAddressField	IPアドレス


SQL使わないってのがいまいちピンとこない。
明日からmodels.py書き込んでいく

## 2023/1/26
こんにちは。3日目です。大寒波のせいで水道管が凍結した模様です。
歯磨きできないの辛い。マウスウォッシュしてから大学行きました。

面白い記事見つけたので残しておきます。
[就活の話とPaizaのSランクが全く意味なかったという話](https://lanlib.com/2021/04/04/%e5%b0%b1%e6%b4%bb%e3%81%ae%e8%a9%b1%e3%81%a8paiza%e3%81%aes%e3%83%a9%e3%83%b3%e3%82%af%e3%81%8c%e5%85%a8%e3%81%8f%e6%84%8f%e5%91%b3%e3%81%aa%e3%81%8b%e3%81%a3%e3%81%9f%e3%81%a8%e3%81%84%e3%81%86/)


提出今日までの課題2つやってて全く進みませんでした、、、、
もう日付変わっちゃったけど2時間くらいやります。

ChatGPTを今更触ってみました
[Shift Management System](https://chat.openai.com/chat)
↑勝手にタイトル付けてくれるのすごい


![スクリーンショット 2023-01-27 1.12.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/0c838c12-9dbb-fceb-1a8c-071d6edebfd3.png)

　自分みたいな初学者にはちょうどいいヒントくれるからありがたい。ただ検索能力が上がんないままになりそう。   

## 2023/1/27

4日目です。
今更だけどもっと簡単なのにしとけばよかったと後悔し始めました。機能削ることも考えます。

データベースよくわかってないので復習しました
参照：[【入門】データベース設計まとめ](https://qiita.com/KNR109/items/5d4a1954f3e8fd8eaae7)

>リレーショナルデータベース(RDB)
RDBはデータベースの中で最も普及されているデータベースです。
RDBは二次元表の形式で管理されており、データの取り扱いを直感的に行うことができます。
id	name	address
1	山田  	東京都
2	鈴木 	大阪
3	長谷川	名古屋

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/30087e06-e2ec-8cad-59f8-622de21fc0f4.png)

引用: https://itmanabi.com/db-schema/

>3層に分ける理由
そもそもなぜ3層に分けるのかを疑問に思った方もいるかもしれません。
3層に分ける理由は、各スキーマにおいて変更があったとして他の2つには影響が起きないからです。
仕様変更が起きた際に都度データベース全体に影響があると時間が大幅にかかってしまいます。
3層スキーマでデータベースの設計をすることでビューやハードウェアを変更せずにデータベースの保守・運用をすることができます。

論理設計していきます（概念スキーマの定義）
>1エンティティの抽出
2エンティティの定義
3正規化
4ER図の作成

1.エンティティの抽出

>エンティティとは実体を表します。
具体的にECサイトにおけるエンティティは「店舗」「商品」「顧客」「注文」「決済」などがあります。
実際に開発するシステムにおいて必要なエンティティを抽出するのがエンティティの抽出のステップになります。

なるほど！この工程すっ飛ばしてました。書き出したい。
上の具体例だと店舗で商品を買いたい顧客が注文をする際に決済を行うという流れですね

同じように言語化すると、あるチームに所属するスタッフがシフトを全体で共有し、スケジュールを確定する。だから
「職場（チーム名）」「スタッフ」「シフト」「スケジュール」

こんな感じかな？不安です

2.エンティティの定義

>次に抽出エンティティがどのようなデータを保持するかを決定していきます。
エンティティが持つデータを属性(attribute)と呼びます。
テーブルでいう列の部分が属性に当たります。
店舗というエンティティはid,name,feeという属性(attribute)を持っているので列を下記のように定義します。

>店舗というエンティティはid,name,feeという属性(attribute)を持っているので列を下記のように定義します。
【店舗】
id	name	fee
1	ユニクロ	300
2	しまむら	200
3	ZARA	500

>【商品】
id	name	price
1	Tシャツ	1000
2	スキニー	200
3	コーチジャケット	500

同じようにまとめます
シフトボード参考に書く


【職場】
id name 
1  TOYOTA 
2  HONDA
3  SONY

【スタッフ】
id name　email 
1  山田　yamada@...
2  岡田　okada@...
3  田中　tanaka@...

【シフト】
id name start_time end_time
1  山田　8:00 17:00  
2  岡田　9:00 17:00 
3  田中　8:00 19:00 


スケジュールはちょっと難しかったのでChatGPTさんにお越しいただきました。

    class Schedule(models.Model):
    staff = models.ForeignKey(Staff, on_delete=models.CASCADE)
    start_date = models.DateField()
    end_date = models.DateField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    shift = models.ManyToManyField(Shift)

    def __str__(self):
        return self.staff.first_name + ' ' + self.staff.last_name + ': ' + str(self.start_date) + ' - ' + str(self.end_date)

>ここで、Scheduleクラスは、従業員、開始日、終了日、作成日時、更新日時を持つエンティティを表しています。
また、Staffは外部キーとして設定されています。
スケジュールに対応するシフトも管理することができます。
そして、管理アプリケーションは、スケジュールとシフトを管理するためのインターフェースを提供します。
例えば、従業員が自分のスケジュールを確認したり、変更したり、シフトを割り当てたりするためのフォームを提供することができます。
また、管理者がスケジュールとシフトを一覧表示し、従業員を割り当てるためのインターフェースを提供することもできます。

なんとなくわかった気がします


Q.shift = models.ManyToManyField(Shift)って具体的に何を書く？
A.shift = models.ManyToManyField(Shift) は、DjangoのORM(Object-Relational Mapping)を使って、スケジュールエンティティとシフトエンティティを多対多の関係にするために使用されます。これにより、スケジュールと複数のシフトを関連付けることができます。

【スケジュール】
id  start_date end_date
1   8:00 17:00  
2   9:00 17:00 
3   8:00 19:00 

スケジュールとシフト似てるなあってことでChatGPtの回答

Q.スケジュールとシフトの違いがよくわからない


A.スケジュールは、時間軸上に予定やタスクを記録したもので、それが何時から何時までの期間であるかを示します。一方、シフトは、特定の期間に従業員が勤務する時間の割り当てやスケジュールのことで、それが誰がどのような役割を担当するかを示します。 スケジュールは、特定の期間に予定やタスクを設定することができますが、シフトは特定の期間に従業員を割り当てることができます。 スケジュールとシフトは連携して使用することができ、シフトに対応するスケジュールを作成することもできます。

へーって感じです


3.正規化

>次に正規化をおこないます。正規化はエンティティ(テーブル)がデータを扱いやすようにするための設計です。
正規化をすることでデータの冗長性や不整合が発生する機会を減らすことができます。


[主キーとは](https://wa3.i-3-i.info/word1991.html)



正規化を深掘りした記事
[正規化の要点を理解する](https://qiita.com/mochichoco/items/2904384b2856db2bf46c)
>正規化の最大の目的はDB上で扱うデータの重複を排除し、「矛盾」の発生を「設計レベル」で防ぐことです。

第一正規化→第二正規化→第三正規化
わかりそうでわからない

**職場**
| id | 名前 |
| -- | --  |
|1|TOYOTA|
|2|HONDA|
|3|SONY|

**スタッフ**
|id|名前|email|
|--|--|--|
|1|山田|...|
|2|田中|...|
|3|岡田|...|

**シフト**
|id|名前|日付|出勤時刻|退勤時刻|
|--|--|--|--|--|
|1|山田|2/4|8:00|17:00|
|2|田中|2/3|9:00|17:00|
|3|岡田|2/5|7:00|16:00|


**スケジュール**
|id|名前|日付|出勤時刻|退勤時刻|
|--|--|--|--|--|
|1|山田|2/4|8:00|17:00|
|2|田中|2/3|9:00|17:00|
|3|岡田|2/5|7:00|16:00|



間違えてる気しかしないけどとりあえずイメージできた
idってもしかしていらないやつ？と思ったけどとりあえずこれで進める

4.ER図

[若手プログラマー必読！５分で理解できるER図の書き方５ステップ](https://www.ntt.com/business/sdpf/knowledge/archive_50.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/9fd60b9d-a475-df92-1888-0729eb0f349c.png)

引用：上記サイト

>ER図は、「エンティティ」と呼ばれるデータのまとまりや「アトリビュート」というエンティティの詳細情報、エンティティ同士の関係を表現する「リレーション」と「カーディナリティ」を組合せて書きます。

![スクリーンショット 2023-01-28 0.54.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/25449ebc-f485-5359-1c39-0661a8847d3e.png)


[draw.io](https://app.diagrams.net/)で作成

スタッフは職場とシフトそれぞれに多対多の関係を持つ

終わり
これでmodels.py書けるかなー

# 2023/1/28

溜まってた課題やってました。4年で単位とらなくていいように授業詰め込んでるのでキツキツです。がんばります。

あとwantedlyで長期インターンの募集調べてました。3月中には参加できるくらいスキル上げます。

----
models.py書き込んでいきます。

復習
[【django】モデルのフィールドについて：フィールドの型・オプション一覧](https://office54.net/python/django/model-field-options)

>EmailField：メールアドレス
メールアドレスを保持するためのフィールドです。
EmailField(max_length=254, **options)
入力された値に@（アットマーク）がないとエラーが発生する仕組み（バリデーション）になっています。
このフィールドではmax_lengthがデフォルトで設定されています。
そのためmax_lengthをオプションで指定する必要がありません。


>DateTimeField：日時
日付と時刻を保存するためのフィールドです。
この日付と時間はdatetime.datetimeインスタンスによって表される日付と時刻になります。
DateTimeField(auto_now=False, auto_now_add=False, **options)
引数のauto_nowとauto_now_addは、DateFieldのそれと同じです。

    class  Workplace(models.Model):
        name = models.CharField(max_length=100)

    class Staff(models.Model):
        name = models.CharField(max_length=100)
        email = models.EmailField(max_length=100)

    class Shift(models.Model):
        name = models.CharField(max_length=100)
        start_time = models.DateTimeField()
        end_time = models.DateTimeField()

これでできました。

この後の流れ確認
[Pythonさえ分かればDjangoでWebアプリは作れる](https://qiita.com/pythonista/items/19613663ef7bb3c57d4f)

次にモデルの有効化をします

    python manage.py makemigrations shiftapp 
出力結果↓
    
     migrations for 'shiftapp':
     shiftapp/migrations/0001_initial.py
    - Create model Shift
    - Create model Staff
    - Create model Workplace

データベースに反映させる


    python manage.py migrate shiftapp
出力結果↓

    Operations to perform:
    Apply all migrations: shiftapp
    Running migrations:
    Applying shiftapp.0001_initial... OK

Model終わり
合ってるのかな？モヤモヤする

寝ますおやすみなさい

# 2023/1/29
日曜日なので休みました。

# 2023/1/30

最近忙し過ぎてあまり時間取れてないけど頑張ります

前回までのあらすじ
midels.pyを作成しました。
今日からview作っていきます。

[【Django入門】viewsを使ってページを表示させよう](https://www.sejuku.net/blog/25952)

>・Model（データベースに格納されているデータ）
・Template（テンプレートファイルによって定義されたそれぞれのページのデザイン）
・View（どのページを表示させるかを決定する処理）


views.pyからさっき定義したモデルをインポート

    from django.shortcuts import render 
    from shiftapp.models import Workplace, Staff, Shift

今日はここまで

# 2023/1/31

8日目です
昨日長期インターンに応募してみました
受かるといいな

昨日のつづきでviews.py書いていきます

[【Django】クラスベースビュー(Class-based View)の操作入門｜PythonでWebアプリ開発#12](https://di-acc2.com/programming/python/5210/)

ここが一番わかりやすいかも

[GETとPOSTの違いについて](https://qiita.com/kanataxa/items/522efb74421255f0e0a1)
>GETは指定したリソースの表現を転送するようにリクエストするメソッドです。
つまり、何か情報を検索したり取得するために使うためのメソッドになります。

>POSTは指定したリソースを実装した機能に従って処理をする機能になります。
主に登録処理や更新処理などの、書き込みがありリソースが更新される可能性のある処理に対して使うメソッドになります。

とりあえずシフトの作成、修正、一覧、削除、ログイン機能を作ります

[【Django入門】viewsを使ってページを表示させよう](https://www.sejuku.net/blog/25952)
こちらのコードほぼコピペで使います

[【Django】ログイン機能の実装方法【LoginView】](https://kosuke-space.com/django-loginview)


    from django.shortcuts import render
    from shiftapp.models import Workplace, Staff, Shift


    def create_post(request):
    "シフトを入力する"

    post = Post()

    if request.method =='GET':
        form = PostForm(instance=post)

        return render(request,
                      'shiftapp/post_form.html',  
                      {'form': form})  
    if request.method == 'POST':
        form = PostForm(request.POST, instance=post)

        if form.is_valid():
            post = form.save(commit=False)
            post.save()

        return redirect('shiftapp:read_post')

    def read_post(request):
    
    "シフトの一覧を表示する"
    posts = Post.objects.all().order_by('id')
    return render(request,
                  'shiftapp/post_list.html',  
                  {'posts': posts})      

    def edit_post(request, post_id):   
    "シフトを調整する"
    post = get_object_or_404(Post, pk=post_id)

    if request.method == 'GET':
        form = PostForm(instance=post)

        return render(request,
                      'shiftapp/post_form.html',  
                      {'form': form, 'post_id': post_id})  
    elif request.method == 'POST':
         form = PostForm(request.POST, instance=post)

        if form.is_valid():
            post = form.save(commit=False)
            post.save()

        return redirect('shiftapp:read_post')

    def delete_post(request, post_id):
    post = get_object_or_404(Post, pk=post_id)
    post.delete()

    return redirect('shiftapp:read_post')

    class PostForm(ModelForm):
    'フォーム定義'
    class Meta:
        model = Post
        fields = ('name', 'micropost')
    
むずい…
課題の言語化ができてない
とりあえず終わらせたいのでこのまま進めます

---
余談メモ

管理者と従業員の区別いらないかも→LINEみたいに誰でもグループチャット作れるみたいな感じにする
管理者の申請関連とかなしが楽


----
次はTemplate の作成                 

[【Django入門】templateとHTMLを使ってWebページを表示しよう](https://www.sejuku.net/blog/26407)

settings.pyに

    'DIRS': [BASE_DIR / 'templates'],

これ書く

shiftproject/shiftapp/templates/post_form(list).htmlを2つ作る

```post_list.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Shift Management System</title>
</head>
<body>
  <!-- Page content goes here -->
</body>
</html>
```
```post_form.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Post Form</title>
</head>
<body>
    <h4>Post の編集</h4>
    {% if post_id %}
    <form action="{% url 'sample_app:edit_post' post_id=post_id %}" method="post">
    {% else %}
    <form action="{% url 'sample_app:create_post' %}" method="post">
    {% endif %}
      {% csrf_token %}
      {{ form }}
          <button type="submit">送信</button>
    </form>
    <a href="{% url 'sample_app:read_post' %}">戻る</a>
</body>
</html>
```

:::note alert
そろそろ何やってるかわかんなくなってきた
とりあえず実行して出力結果見ながら修正します

:::

**ルーティング定義**
URLと処理の紐付け

![スクリーンショット 2023-02-01 0.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/2b7645f5-162b-8aaa-c141-11bddda245f4.png)

ダメみたいです…
調整していきます
（１時間後追記：一旦全部消して作り直します、、）
[【徹底的に解説！】Djangoの基礎をマスターして、3つのアプリを作ろう！（Django2版 / 3版を同時公開中です）](
https://www.udemy.com/course/django-3app/learn/lecture/14179087#notes)
これの社内SNSアプリの作り方に沿って振り返ってみます

関数ベースビューを使っていきます

**会員登録画面**

shiftproject/shiftproject/templates/signup.htmlを作成

```shiftapp/urls.py
from django.urls import path
from .views import signupfunc

urlpatterns = [
    path('signup/', signupfunc),
]
```
```views.py
from django.shortcuts import render

def signupfunnc(request):
        return render(request, 'signup.html',{'some':'somedata'})
```
[【Django】views.py：renderメソッドの使い方（引数：request、context、template）](
https://office54.net/python/django/views-render-how-to)

>renderメソッドは、指定したテンプレートにコンテキスト（辞書型データ）を反映し、レンダリングしたHttpResponseオブジェクトを返します。
つまりデータベースのデータなどを反映させたHTMLページを作成して、HTTPレスポンスとしてブラウザに返すということです。
関数ベースのビューで最もよく使われるメソッドです。
renderメソッドはプログラムの先頭でdjango.shortcutsからインポートする必要があります。

```signup.html
{{some}} #データを扱うときは二重括弧
```
今日はここまで
明日からテスト期間なので水木金あまり作業できません

# 2023/2/1
2月です！

インターンと課題一日中やってましためちゃ疲れた
今日は作業できませんーーーー
明日と明後日もテストがあるからちょっと厳しいかも、、、
せめて一日2時間は取りたいな


# 2023/2/2

21時まで学校でテストがあったので何もできてません、、、
が、ほぼ一日中勉強してたので充実した日でした。

あと昨日からプログラミングインターン（1ヶ月）に参加し始めたので、そっちに少し時間を割くことになりそうです。
インターン体験記も更新していきたいと思います。

明日乗り切れば大学関連の山は終わりです！明日も時間的に余裕ないのでおそらくお休みします。
土曜から再開したいと思いまーす。

バイトもやめて学校も終わるのでこちらに集中できそうです。
春休みはエンジニアの長期インターンと個人開発を進めつつ就活も計画的にやりたいね。


書きたいこと多すぎて駄文ですorz
ではまた

# 2023/2/3


**もはや開発日誌ではなくなってきている気がする**

やっと！大学関連の予定がひと段落つきました！
Javaの講義（オンデマンド）を今学期履修してたんですけど、自分は一気にまとめて片付けてしまうタイプなので結構溜めちゃってました。
というわけで今日は一日中Javaを書いてました。

```java
   class Test {
    public static void main(String[]args){
     ...
```
こんな感じで
Javaよくわからんというのが感想でした。良い経験にはなったと思います。Udemyで講義とって復習するのもアリかな。

明日からまた再開しようと思います。

# 2023/2/4
今日もちょっとインターンにかかりきりでした。
流石に明日から再開します…

# 2023/2/5~2/11
まずすぎる！1週間くらいできてない


ただ一つ言い訳をさせていただくと今TECH-BASEっていう長期インターンに参加してるので、だらけてるわけではないです、、、
明日は絶対やります！

ちなみにTECH_BASEの長期インターンは未経験者には超オススメです。（後日記事書きます）
PHPとSQLが学べて成果物も作れます。一応チーム経験も積めます。
回し者みたいになったけどほんとにオススメです。楽しいよ

# 2023/2/12

インターン先で成果物を作ることになりました。
今どっちつかず状態なので、こっちはキッパリと休む宣言をしておきたいと思います。
3/1までインターンなのでそれ以降から再開したいと思います。

インターン先ではPHPとMySQLを使った成果物を作るというミッションが出ているのでそっちの記事も書く予定です。

# 2023/2/20

たまにはインターンの経過方向します。
PHPで簡易掲示板を作れるようになりました。
で、思ったことなんですけど今までこの記事で書いてきたアプリ制作、PHPでよくね？ってなってます

Laravelとか使って作れそう。というか絶対作れるなあと思いました。

なのでインターンの最終課題としてLaravelでシフト管理アプリ作ろうと思います。
ちょっとグダグダすぎて非公開にしたいくらいだけど、終わりよければ全てよしということで頑張ります！！！！

インターンでの目標成果物がこの記事での目標成果物と全く一緒なので続きのような形で書いていきます


改めてサービス概要とかまとめたので[Notion](https://silly-notify-89d.notion.site/Mission6-f85959186db84adcbe3349ef72355ed3)で公開します




![スクリーンショット 2023-02-20 19.58.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/6f2982de-d916-7be7-41bf-204254ecc8e2.png)

トップページのイメージをFigmaで作りました。
デザイン楽しすぎて時間溶ける、、、

# 2023/2/21

最近Notionでメモを取るようになったのでこれからはNotionのメモ内容をコピペ＆一言みたいな感じで書いていきます



【今日やったこと】
- composerのインストール
- Laravelの環境構築
    
    　【エラー】
    
    ターミナルで’php artisan migrate’を入力したら
    
    **SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = laravel_task and table_name = migrations and table_type = 'BASE TABLE')**
    
    と表示された
    
    【解決方法】
    
    MAMPのポート番号が8889になってたので3306に変える
    
    MAMP再起動して実行可能になった
    
- migrationコマンドとかMVCモデル　流れの中で理解したい


Laravel思ってたより大変
Djangoある程度できたしフレームワークはδ大丈夫だろうと正直舐めてました

まあで覚えるってよりは実装しながら身につけいくのが理想ですね

# 2023/2/22

Laravelわからん

- Laravel Breezeのインストール→Laravelの認証機能を実装してくれるスターターキット
- ターミナルにnpm run devと入力したら
    
    sh: vite: command not found と表示された
    
    →npm updateaaでバージョン更新して解決
    
- [日本語ドキュメント](https://readouble.com/laravel/9.x/ja/validation-php.html)
- ターミナルは3つ表示
    
    ‘php artisan serve’と‘npm run dev’と書き込み用

# 2023/2/23

Laravelの講義続き見た

よくわからない

機能正式リリースされたNotion AIに日記の続きを書いてもらいました

"2/21の日記で、LaravelのmigrationコマンドやMVCモデルの流れを理解したいと書かれていましたが、Laravelについて理解するのは難しいかもしれません。参考になる学習資料として、PHP+MySQL(MariaDB)入門講座やPHPからLaravelまで サーバーサイドをとことんやってみよう【初心者から脱初心者へ】【わかりやすさ最重視】があります。また、個人開発ブログやアイデアを提供しているサイトもありますので、参考にしてみてください。"

こんな感じにまとめてくれました。「長くする」とかいろいろ精度高くてこれマジですごいなと思いました。月5000円までなら出せるレベル（日経電子版と同じくらい）

# 2023/2/24~2/26

予定パンパンだったので作業なしです

# 2023/2/27

MVCモデルの勉強をしました。
Laravelワカンネです

# 2023/2/28

Laravelの勉強
停滞気味

# 2023/3/1

tech-baseインターンの修了式で余韻に浸りすぎて何もしてません


記事書いたのでぜひ
[【超オススメ】TECH-BASEのプログラミングインターンに参加してみた](https://qiita.com/udonrm/items/bf6650435d9e4774f15f)

チーム優勝&MVPいただきました！素直に嬉しいです。
同じくらいのレベル感の学生エンジニアコミュニティとかないかなあ

# 2023/3/2
Laravel学習

コミュニティサイトとか探してた

いくつか良さげなのに入った

こういうのに積極的に参加したい

# 2023/3/3
UdemyのLaravel講座修了

1人で作れる気が全くしないデス


# 2023/3/4

Laravel完全に理解した（）

今日はトップページ作った
割とイメージ通りにできて満足
レスポンシブも対応させました

![スクリーンショット 2023-03-04 17.21.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/71441e65-cdac-0731-dfb8-975e9da1eb68.png)


# 2023/3/5

home/idex.blade.phpにアクセスできない

welcome.blade.phpに行っちゃう

なんか適当にサーバー再起動とかしてたら動いた　よくわからん

チーム作成機能追加

# 2023/3/6

ログイン画面の背景色変えたい

認証機能もろもろ

# 2023/3/7
laravel jetstreemのインストール

breeze今まで使ってたからぐちゃぐちゃになっちゃった

****[Laravel Jetstreamチーム版でユーザーの役割と権限を簡単に設定する](https://biz.addisteria.com/jetstream_teams/)****

これでやり直す

データベースの整理したい


# 2023/3/8

用件定義もっとちゃんと準備しておけばよかったー
準備不足感が否めない
guest.blade.phpにbackground-colorが適用されない

フロント後回しにしてとりあえず機能実装しよう

カレンダー全く埋め込めなくて詰み

# 2023/3/9

カレンダー登録できた


スケジュールの記入が反映されないのと,このページをdashbard.blade.phpに埋め込みたい

# 2023/3/10

**Attempt to read property "id" on null**

チームを削除したときに起こる→所属チームがなくなるからteamがnullになる？

よくわからんから作り直した
複製してバックアップとる

[https://chigusa-web.com/blog/fullcalendar/](https://chigusa-web.com/blog/fullcalendar/)で

**resources\js\calendar.jsnに書き込む1行目import '@fullcalendar/core/vdom';を消す**


# 2023/3/11
カレンダー埋め込んだらナビゲーションメニューが動かない

    FullCalendarとJetstreamの競合

    →calendar.jsの修正

```app.js
import "./bootstrap";

import Alpine from "alpinejs";
import focus from "@alpinejs/focus";
window.Alpine = Alpine;

Alpine.plugin(focus);

Alpine.start();
```
calendar.jsにimport "./calendar";を書いて

dashboard.blade.phpに@vite(['resources/css/app.css', 'resources/js/**calendar.js**'])を読み込む

navigation-menu.blade.phpにimport "./calendar";が読み込まれててバグってたっぽい


### 現時点でのやるべきこと

- [ ]  **カレンダーの編集削除機能追加**
- [ ]  **シフト追加(時間指定,ユーザーネーム自動付与)**
- [ ]  **チーム別にカレンダーを分ける**
- [ ]  **チームメンバー共通のカレンダーにする**
- [ ]  レスポンシブ
- [ ]  フロントのデザイン
- [ ]  日本語に変更
- [ ]  （チームメンバー一覧をヘッダーのシフト管理画面の横に表示）

時間指定のとこでぴえんになってます
データベースの接続とかからやり直さないといけなさそう

# 2023/3/12

FullCalendarの公式ドキュメント読み解いていく

カレンダーのタイトルにログイン中のユーザーネームを表示する→誰のシフトかをわかりやすくする

```dashboard.blade.php
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                @php
                $username = auth()->user()->name;
                @endphp
                @vite(['resources/css/app.css', 'resources/js/calendar.js'])
                <script>
                    var username = "{{ $username }}";
                </script>
                <div id='calendar'></div>
            </div>
```
dashboard.blade.phpに$usernameをログイン中のユーザーネームに指定する



```calendar.js
```php
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                @php
                $username = auth()->user()->name;
                @endphp
                @vite(['resources/css/app.css', 'resources/js/calendar.js'])
                <script>
                    var username = "{{ $username }}";
                </script>
                <div id='calendar'></div>
            </div>
```

# 2023/3/13

DB接続成功！

calendar.jsのarg.event.idはfullcalendarで生成されたidだからscheduleテーブルのidとは一致しない？

# 2023/3/14

scheduleテーブルにevent_idカラムを追加してシフトができるようにする→無理そう

本格的に詰んでる気がする

# 2023/3/15

DB接続と削除編集機能の実装終了

GPT-4があっさり解決してくれた

流れとかちゃんと理解する

teamsテーブルとschedulesテーブルを関連づける（RDBMS）

schedulesテーブルとteamsテーブルを関連づけて、schedulesテーブルにteamsテーブルのidカラムを呼びたい→できた

チーム別に一つずつのカレンダーを共有したい

今はチームを切り替えてもシフトの履歴が残ってる

**fetchInitialEvents関数でシフトをフィルタリングする**

**`ScheduleController.php`**の **get**メソッド内で、**`team_id`**をバリデーションに追加し、リクエストから取得したチーム ID を使用してシフトをフィルタリング

チームメンバー共通のカレンダー

mailtrap使って招待機能でチームに複数のメンバーを入れる

招待を受けてチームにジョインするとアカウントが招待送信側の方になっちゃうDB接続と削除編集機能の実装終了

GPT-4があっさり解決してくれた

流れとかちゃんと理解する

teamsテーブルとschedulesテーブルを関連づける（RDBMS）

schedulesテーブルとteamsテーブルを関連づけて、schedulesテーブルにteamsテーブルのidカラムを呼びたい→できた

チーム別に一つずつのカレンダーを共有したい

今はチームを切り替えてもシフトの履歴が残ってる

**fetchInitialEvents関数でシフトをフィルタリングする**

**`ScheduleController.php`**の **get**メソッド内で、**`team_id`**をバリデーションに追加し、リクエストから取得したチーム ID を使用してシフトをフィルタリング

チームメンバー共通のカレンダー

mailtrap使って招待機能でチームに複数のメンバーを入れる

招待を受けてチームにジョインするとアカウントが招待送信側の方になっちゃう

![スクリーンショット 2023-03-16 1.16.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/8baef0f2-d9d0-4fe4-34e9-763450b0741d.png)
自分の名前はちゃんと表示されてるのに、相手の名前はお互いにusersテーブルのidが表示されてる

# 2023/3/16

招待を受けてチームにジョインするとアカウントが招待送信側の方になっちゃう

→同じブラウザで複数のアカウントでログインするとセッションが混同されちゃう

→プライベートブライジングを使ったら解決できた

追加したシフトでtitleにusernameを表示させたいが、自分以外の全員のtitleがusersテーブルのidカラムになってしまう→chatGPT先生に解決してもらいました

シフトを登録したあとブラウザで再リロードしないと編集ができない

勉強会でアドバイスもらった→Git,人に聞く,自分の強みとプロダクトのアピールポイントの整理

打算的に行動してもいい

HR系とか良さそう

# 2023/3/17

シフトを登録したあとブラウザで再リロードしないと編集ができない

```calendar.js
select: function (arg) {
    axios
        .post("/schedule-add", {
            start_date: arg.start.valueOf(),
            end_date: arg.end.valueOf(),
            user_id: userid,
            team_id: currentTeamId,
        })
        .then((response) => {
            calendar.addEvent({
                id: response.data.id,
                title: username,
                start: arg.start,
                end: arg.end,
                allDay: arg.allDay,
                color: "#FFA500",
                extendedProps: {
                    user_id: userid, // ここでuser_idをextendedPropsに追加
                },
            });
        })
        .catch(() => {
            // バリデーションエラーなど
            alert("登録に失敗しました");
        });
},
```
`if (arg.event.extendedProps.user_id == userid) {`

新しいイベントに`user_id`が設定されるようになるから編集のifにかかるようになった

extendProps

> FullCalendarのイベントオブジェクト内にあるプロパティで、カスタムプロパティや追加情報を格納するために使用されます。FullCalendarのイベントオブジェクトは、イベントに関する情報（開始日、終了日、タイトルなど）を保持しますが、**`extendedProps`**を使うことで、それらの標準プロパティ以外の追加情報をイベントオブジェクトに格納することができます。
例えば、ユーザーIDやカスタムカラーなど、イベントに関連する他のデータを保存しておくために**`extendedProps`**を利用できます。この場合、**`extendedProps`**内に**`user_id`**を格納し、イベントの編集や削除が現在のユーザーによって許可されているかどうかを判断するために使用しています。**`extendedProps`**内のデータは、イベントに関連するコールバック関数（**`eventClick`**、**`eventDrop`**、**`eventResize`**など）内で**`arg.event.extendedProps`**を参照することでアクセスできます。
>

レスポンシブ

多分できてる

```app.css
@media (min-width: 521px) {
    /* ヘッダーセルのフォントサイズを小さくする */
    .fc {
        font-size: 12px;
    }

    /* 日付の表示形式を短くする */
    .fc .fc-col-header-cell-cushion {
        white-space: nowrap;
    }
}

@media (max-width: 520px) {
    /* ヘッダーセルのフォントサイズを小さくする */
    .fc {
        font-size: 11px;
    }

    /* 日付の表示形式を短くする */
    .fc .fc-col-header-cell-cushion {
        white-space: nowrap;
    }
}

@media (max-width: 480px) {
    /* ヘッダーセルのフォントサイズを小さくする */
    .fc {
        font-size: 12px;
    }

    /* 日付の表示形式を短くする */
    .fc .fc-col-header-cell-cushion {
        white-space: nowrap;
    }
}
@media (max-width: 400px) {
    /* ヘッダーセルのフォントサイズを小さくする */
    .fc {
        font-size: 9px;
    }

    /* 日付の表示形式を短くする */
    .fc .fc-col-header-cell-cushion {
        white-space: nowrap;
    }
}
```

# 2023/3/18

ひたすら日本語化とフロントいじってた

ちょっと前に書いたToDolistは今こんな感じ



- [x]  **カレンダーの編集削除機能追加**
- [x]  **入力シフトをscheduleテーブルに保存する**
- [x]  **シフト追加(時間指定,ユーザーネーム自動付与)**
- [x]  **チーム別にカレンダーを分ける**
- [x]  **チームメンバー共通のカレンダーにする**
- [x]  レスポンシブ
- [x]  日本語に変更
- [x]  フロントのデザイン
- [ ]  **デプロイ**

残りデプロイだけ！！！（歓喜）

# 2023/3/19
****[【Git】Laravel×Vue.jsアプリをXserverにデプロイする方法！500エラー解決](https://tech.amefure.com/web-git-laravel-vue-xserver)****

デプロイよくわかんないから勉強する

Gitにプッシュした
https://github.com/udonrm/shift-management-App

# 2023/3/20

****[XServerにSSH接続してLaravelプロジェクト(ないしデプロイ)を作成する手順](https://maasaablog.com/development/backend/php/laravel/2142/)****

- [x]  SSH接続

デプロイできない　びゃあああああああああああああああああああああああああああああああ


# 2023/3/21

### 

- ****[XSERVERにlaravelのwebアプリをgitからデプロイ](https://qiita.com/ren7087/items/654f2be6b34ba428405f)****

エックスサーバーにssh接続→gitクローン→.envとかいじってデータベース設計してみたいな流れ

またデプロイの機会あるだろうから時間ある時に復習してまとめる

初期ドメインで作ったから明日独自ドメインに移行したい

# 2023/3/22

独自ドメインとって移行した

シンボリックリンクを作成できた（サブドメインの設定方法）

****[Laravelを初めてエックスサーバーにデプロイする人のためのシンボリックリンク作成方法](https://biz.addisteria.com/laravel_project_deploy8/)****

ついに完成！！！！！！！！！！！！！！

割と精神論とか多めの日誌だったので技術的なことをまた後日改めて書いて別の記事にまとめたいと思います

あとユーザーテストしてもらったんですけどマウス操作で直感的に操作できるのがいいていう評価もらいました

とりあえず2ヶ月間にわたる（地獄の）開発日誌終了です！お疲れ様でした！！