Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Release on 2024-03-02 #14

Merged
merged 8 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions public/django-foreign-key-exception-catch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Djangoで削除時に外部キー制約によって例外が発生する問題の対処法
tags:
- "Programming"
- "Python"
- "django"
private: false
updated_at: ""
id: null
organization_url_name: null
slide: false
ignorePublish: false
---

Djangoで汎用View `django.views.generic.DeleteView` を用いた削除時に外部キー制約によってProtectedErrorの例外が発生するのをキャッチする方法を紹介します。

※ これは2020/02/05に個人ブログで公開した記事を移植したものです。

## PROTECT されている場合に削除しようとする場合の挙動

Djangoでは、モデルに外部キーを設定できます。モデルの第二引数では、参照先が削除等された場合の挙動が設定できます。

```py
class Comment(models.Model):
user = models.ForeignKey(User, models.PROTECT)
```

ここで、参照先を削除できなくする `models.PROTECT` という設定ができます。この設定をした場合、参照先は削除できなくなります。

そして、公式ドキュメントにはこのような記述があります。

> Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.

https://docs.djangoproject.com/ja/3.0/ref/models/fields/#arguments

削除を試みると、 ProtectedError例外が発生するという仕様です。例外ということは、誤って削除が試みられると500エラーとなってしまいます。

## 汎用 View でシンプルに実装したい

一方で、せっかくDjangoで実装するのですから、汎用Viewでリレーション確認などの記述無しでシンプルに削除したいですよね。そこで次のように構築したとします。

```py
class UserDeleteView(DeleteView):
model = User
success_url = reverse_lazy('user-list')
```

ここで先程示したように他のモデルからPROTECTされていた場合、UserDeleteViewはProtectedError例外エラー(500エラー)を返してしまいます。

## 例外をキャッチする

Viewでは例外をキャッチするのみの実装とします。

https://docs.djangoproject.com/ja/3.0/misc/design-philosophies/

ほとんど汎用View使う理由がないような感じはしますが、post関数を上書きします。

```py
class UserDeleteView(DeleteView):
model = User
success_url = reverse_lazy('user-list')

def post(self, request, *args, **kwargs):
try:
obj = self.get_object()
obj.delete()
except models.ProtectedError as e:
messages.error(request, f'「{obj}」は紐付けられているため削除できません。')
return redirect('user-list')
```

これで、ProtectedErrorが発生したら削除されず、フラッシュメッセージが表示されます。
62 changes: 62 additions & 0 deletions public/docker-eset-firewall-detected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: "DockerがESETの影響でファイルマウントできない場合の対処法"
tags:
- "Programming"
- "Docker"
- "Windows"
- "eset"
private: false
updated_at: ""
id: null
organization_url_name: null
slide: false
ignorePublish: false
---

DockerがESET Endpoint Protectionのファイアウォールの影響で「Firewall Detected」エラーが発生し、ファイル共有が一切できなくなる問題の対処方法を掲載しています。

※ これは2019-07-15に個人ブログで公開した記事を移植したものです。

## Docker でファイルマウントができない

Dockerでファイルのマウントが一切できない状態になりました。

Dockerを右クリック →「Settings」

![Dockerを右クリック→「Settings」](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/bfdb947a-9097-9f9e-311e-88d20f9bf492.png)

「Shared Drives」→「Shared」にチェック →「Apply」

![「Shared Drives」→「Shared」にチェック→「Apply」](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/cfc45a70-6ba1-9d57-6ba6-4128936a85d3.png)

「Docker needs to access your computer's filesystem」にファイルシステムへアクセスができるユーザー情報を入力。

![「Docker needs to access your computer's filesystem」にファイルシステムへアクセスができるユーザー情報を入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/ba76d1f2-1df4-8fe3-3eb6-587eb7a10fc3.png)

「Firewall detected」エラーが発生。

![「Firewall detected」エラーが発生](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/e2fa131d-f1f9-ec63-777c-f1c68b60f968.png)

## ファイアウォールの解除方法

PCに入っていた「ESET Endpoint Protection」のファイアウォール機能が原因でした。

「ESET Endpoint Protection」を起動し、「設定」→「ネットワーク」をクリックします。

![ESET Endpoint Protection のメイン画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/ded8bae3-f1e7-41e4-cb3f-e07d148413b1.png)

再度Dockerを操作して「Firewall detected」エラーを発生させた後、「トラブルシューティングウィザード」をクリックします。

![トラブルシューティングウィザード を選択する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/a4b20cae-e662-cb67-1554-1fdf47115d1a.png)

「ネットワーク保護トラブルシューティング」のIPアドレス「10.0.75.2」を探し出し、「ブロック解除」をクリックします。あまりにも数が多く見つからない場合は「最後の5分」をします。

![ネットワーク保護トラブルシューティング を開き、フィルターを「最後の5分」と選択し、10.0.75.2をブロック解除する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/59ca6aed-b4c4-3a0c-1f05-ecac7c0d6aeb.png)

「以前にブロックされた通信と類似した通信は許可されます」と表示されるので「完了」をクリックします。

![以前にブロックされた通信と類似した通信は許可されます ダイアログが表示されるので「完了」をクリックする](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/919f5f7f-3c30-79e0-4f0a-360097972e4b.png)

再度「Shared」にチェックして、「Apply」をクリックするとマウントが可能になります。できない場合は「Reset Credentials」をクリックするか、再起動してみてください。

![Docker の Shared Drives でオフ→オンする](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/7b0afa3f-8ca6-59b9-70f4-bf8e362cb337.png)
77 changes: 77 additions & 0 deletions public/vagrant-apache-failure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: "Vagrant で Apache が自動起動しない場合の対処法"
tags:
- "Programming"
- "Vagrant"
- "Laravel"
- "VirtualBox"
- "Apache"
private: false
updated_at: ""
id: null
organization_url_name: null
slide: false
ignorePublish: false
---

Vagrant + VirtualBoxでApacheを動かすと、 `DocumentRoot is not a directory, or is not readable` で自動起動せずに強制終了してしまい、手動でのサービス再起動が必要になってしまいます。Apacheを強制終了しないようにする方法を紹介します。

※ これは2020-02-11に個人ブログで公開した記事を移植したものです。

## 強制終了してしまう

仕事でLaravelを使ったWebサイトをVirtualBoxで構築(指定されたので...)していたところ、 `vagrant up` してもApacheが自動起動せずに強制終了してしまう現象に遭遇しました。

ログには次のように残っています。

```sh
Main PID: 1021 (code=exited, status=1/FAILURE)
systemd[1]: Starting The Apache HTTP Server...
httpd[1021]: AH00526: Syntax error on line 5 of /etc/httpd/conf/httpd.conf:
httpd[1021]: DocumentRoot '/var/www/public' is not a directory, or is not readable
systemd[1]: httpd.service: main process exited, code=exited, status=1/FAILURE
kill[1455]: kill: cannot find process ""
systemd[1]: httpd.service: control process exited, code=exited status=1
systemd[1]: Failed to start The Apache HTTP Server.
systemd[1]: Unit httpd.service entered failed state.
systemd[1]: httpd.service failed.
```

Apacheから、DocumentRootが読めないというエラーになっています。

`DocumentRoot '/var/www/public' is not a directory, or is not readable`

しかし、この後にサービスの再起動をすると強制終了せずに動作します。

## 原因

原因は、Vagrantによるマウントが完了する前にApacheが起動してしまい、DocumentRootのシンボリックリンクが読めないため発生しています。

## 対処方法

かなり対処療法ですが、VagrantFileによるマウントの記述の後にApacheを再起動することで対処します。

CentOS 7系の場合はマウントの記述の後に下記を追加します。

```rb
config.vm.provision :shell, run: "always", :inline => <<-EOT
sudo systemctl restart httpd.service
EOT
```

その他は下記を追加します。

```rb
config.vm.provision :shell, run: "always", :inline => <<-EOT
sudo service httpd restart
EOT
```

以上で、マウント後にApacheが自動再起動されます。

ちなみに、`vagrant up` 時にApacheの再起動をした際のログが次のように残ります。

```sh
==> default: Running provisioner: shell...
default: Running: inline script
```
112 changes: 112 additions & 0 deletions public/vagrant-laravel-slow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
title: "Vagrant(VirtualBox)でディスクアクセスが遅い問題の対処法"
tags:
- "Programming"
- "PHP"
- "Laravel"
- "Vagrant"
- "Windows"
private: false
updated_at: ""
id: null
organization_url_name: null
slide: false
ignorePublish: false
---

Windows + Vagrant + VirtualBoxでLaravelを動かすと、ローディングにかなりの時間がかかって仕事が進まなかったという問題の対処方法を紹介します。NFSを使用する方法です。

※ これは2020-02-01に個人ブログで公開した記事を移植したものです。

## Virtual Box の共有フォルダ機能は遅い

ホスト側とゲスト側でプログラムファイルなどを共有するためにVirtualBoxには共有フォルダ機能が存在しますが、デフォルトの共有方法を用いるとかなり遅くなります。

仕事でLaravelを使ったWebサイトをVirtualBoxで構築していたところ、Windows環境やMac環境でも1ページ読み込むのに5秒ほどかかり、まともに仕事ができない状態になってしまいました。

![Laravelのデバッグツールのスクリーンショット、Bootingに1.15s、Appに1.03sかかっている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/ac106095-9e40-a975-fd51-e0da5d775443.png)

デフォルトのファイル共有機能は、比較的安定性は高く、多くのOSで使用できるのですが、メモリキャッシュなどの機能を使用していないため、ディスクアクセスは遅い欠点があります。

一方、Laravelは大量の依存ファイルを読み込むのでディスクアクセスが大量に発生します。そのため表示が遅くなります。

## 対処方法

Dockerなどの仮想化技術が使用できるツールに切り替えができるのであれば、切り替えるのをおすすめします(ちなみにDocker ToolBoxはVirtualBoxを使用するので意味ありません...)。それができない場合は、NFSでマウントする機能を使用します。

仕組みは公式ドキュメントをご確認ください。

https://www.vagrantup.com/docs/synced-folders/nfs

## Windows の場合はプラグインが必要

公式ドキュメントには次の記載があり、Windowsホストでは使えないと書いてあります。

> Windows users: NFS folders do not work on Windows hosts. Vagrant will ignore your request for NFS synced folders on Windows.

ところが、なんとWindowsでNFS機能を使用できるプラグイン(`vagrant-winnfsd`)がコミュニティに存在します!素晴らしすぎて感謝してもしきれません。

https://github.com/winnfsd/vagrant-winnfsd

ホスト側がWindowsの場合は下記コマンドでプラグインを先にインストールしておいてください。

```bash
vagrant plugin install vagrant-winnfsd
```

## NFS に変更する方法

NFSに変更するにはVagrantFileの共有ディレクトリの設定にあたる部分を変更する必要があります。

先ほどの公式ドキュメントに記載されていた通り、`type: "nfs"` を追加するだけで使用できます。

例えば次のように設定します。

```rb
config.vm.synced_folder ".", "/var/www/src", type: "nfs"
```

尚、private_networkが必要です。IPは例ですが、静的IPアドレスだとトラブルがすくないです(.1はホスト側で予約されていますので.2以上にする必要があります)。

```rb
config.vm.network :private_network, ip: "192.168.2.2"
```

(とくにMac)ファイアウォールに引っかかりやすいので、うまく動作しない場合はファイアウォールの設定をご確認ください。

## CSS や JavaScript が壊れてしまう場合

環境の組み合わせによっては、sendfileの影響でCSSやJavaScriptが壊れてしまう場合があります。その場合の対処方法はこちらをご確認ください。

https://bicstone.me/enablesendfile-js-broken/

## シンボリックリンクが動作しない場合

Laravelでは、シンボリックリンクを貼らないといけない機能(ファイルストレージ)があります。

https://readouble.com/laravel/6.x/ja/filesystem.html

ホストがWindowsの環境では、なぜかシンボリックリンクが壊れてしまい利用できませんでした。

```bash
$ ls -l storage
lrwxrwxrwx 1 root root 0 Dec 24 02:12 storage -> ../../storage/app/public
```

```bash
$ cd storage
cd: no such file or directory: storage
```

vagrant-winnfsdプラグインの影響なのか、Windowsの影響なのかわかってはいません。

私は、Publicディレクトリのみ、標準の共有ファイルに設定しました。次のようなイメージです。

```rb
config.vm.synced\_folder ".", "/var/www/src", type: "nfs", rsync\_\_exclude: "./public"
config.vm.synced\_folder "./public", "/var/www/src/public"
```

これで、高速化しつつ、ファイルストレージも使用できる環境になりました。それでもLaravelは遅いですけどね…。

![Larabelのデバッグツールスクリーンショット Bootingが304ms、Appが195ms](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/f8b436be-bb5d-cbce-abf6-d180c29942d0.png)