Open10
Django: ECサイト作成
テンプレリポジトリをcloneして、リネームして自分のgithub管理配下に置く。
- リモートリポジトリのURL変更
https://docs.github.com/ja/get-started/getting-started-with-git/managing-remote-repositories#changing-a-remote-repositorys-url
git remote set-url origin https://github.com/OWNER/REPOSITORY.git
- cloneしてきたリポジトリのリモート設定確認
git remote -v
- pushする。これでテンプレートのgit logを保持したままにできる。余談だが、リポジトリ管理は
ghq
xpeco
がとても楽なのでオススメ。 - 適切なブランチを切って、開発開始。の前にまずは開発環境を少し整える。
開発環境を整える。
- Docker コンテナ内に 、nvimで使うLanguage Serverを入れる。以下はあくまでsample。
Dockerfile
FROM python:3.12.5-slim
ENV PYTHONUNBUFFERED=1
WORKDIR /sample_django/
COPY . /sample_django/
# python-lsp-serverをインストール
RUN pip install --upgrade pip && \
pip install 'python-lsp-server[all]' && \
pip install -r requirements.txt
init.lua
local lspconfig = require("lspconfig")
lspconfig.pylsp.setup {
cmd = {
'docker',
'exec',
'-i',
project_name_to_container_name(),
'pylsp'
}
}
-
project_name_to_container_name()
にはよしなにコンテナ名を取ってくるロジックを考える必要がある。コンテナのデフォルト命名は規則があるので、そこをフックにしよう。 - 今回はDockerfileを弄る方法を取ってしまったが、本来チーム開発で自分の為の変更を加えることは御法度だと思うので別途方法は考える。
ファビコンにこんな苦しめられることある?
- ページのソース確認すると、画像自体は正しく配信されている。ということはstaticファイルの設定はちゃんとできているはず。
- キャッシュ吹き飛ばしてみてもダメ。
解決
-
" assets/favicon.ico"
のように、assetsの前に空白が入ってた。かなり初歩的。だがこれが発生した原因には一癖あって、formatterが「単語の前後に空白を挿入する」という悪さをしていた。 - 合間にvscode-html-language-serverの設定を見直してみよう。
- しかし、なぜ画像の配信(=URLが正しく変換されて解決されている)ができていたのだろうか。
created_at/ updated_atの実現
model.py
created_at = models.DateTimeField(
auto_now_add=True
)
updated_at = models.DateTimeField(
auto_now=True
)
商品一覧/詳細画面の仮実装
ER図
- 課題の要件だけでいうと、ProductとProductImageは一対一の関係で良いが、詳細画面で画像を複数にしたい要件が後から出てきた時を想定して、一つのProductは複数のProductImageを持つことができる一対多(ProductImageは必ず1つのProductに属する)にした。
ProductImage モデルの画像アップロード先のパスを動的に生成する
model.py
def product_image_path(instance, filename):
return f'ecsite/{instance.product.slug}/{filename}'
このようにして使う。
model.py
image = models.ImageField(upload_to=product_image_path)
- 引数instanceには「FileField(ImageFieldの継承元) が定義されているモデルのインスタンス」が入る。
- 公式ドキュメントにサンプルがあるので、参照するといいかも
slug(コードは主要な部分以外端折ってる)
model.py
from django.utils.text import slugify
class Product(models.Model):
slug = models.SlugField(unique=True, null=True, blank=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('ecsite:product_detail', kwargs={'slug': self.slug})
- save()をオーバーライドして、nameカラムからよしなにslug名を作成している。blank=Trueにしたのは、自動で生成する仕組みを確立したかったから(if not self.slugの条件を通したいから)。
- get_absolute_url()は以下のようにtemplateでパスの記載を簡略化するために書いた。
list.html
<a href="{{ product.get_absolute_url }}">..
select_related/prefetch_relatedについて書こうと思ったら、ガッツリN+1問題発生しとる・・予防できたと思ってたのに(この画像を載せたのはあくまで架空のサイトだから)
- よしよし。ちょっとまだよくわかってないところも多いので、まとめ中
- https://qiita.com/rkiyose/items/4bb1f31e43bad763e573
-
all()以外のメソッドを使ったら
prefetch_related
が機能しない。
これ濃厚だねえ。明日もう少し調査しよう。