コマンドライン操作
バージョン確認
$ python -m django --version
プロジェクト作成
$ django-admin startproject mysite
$ cd mysite
開発用サーバー起動
$ python manage.py runserver
$ python manage.py runserver 8080 # ポート指定
アプリケーションを作る(Scaffoldのイメージ)
$ python manage.py startapp polls
マイグレーション
マイグレーションを実行する。
$ python manage.py migrate
$ python manage.py migrate --run-syncdb
モデルを有効にする
マイグレーションのSQLコマンドを生成する
$ python manage.py makemigrations polls
$ python manage.py sqlmigrate polls 0001
対話シェル
$ python manage.py shell
Model
モデル設定・設計
ForeignField
m.CASCADE
Relationships Related object reference Django: モデルフィールドリファレンスの一覧 <- 不完全 モデルフィールドリファレンス
on_delete
Django、on_delete
を使う(django2.0から必須)
models.CASCADE
models.PROTECT
models.SET_NULL
models.SET_DEFAULT
models.SET()
models.DO_NOTHING
AutoField
idに使われる。数字で、自動で1ずつ増える(?)。(参照:https://stackoverflow.com/a/6062240/8776028)
unique
ユニークさを保証するが、shellで試したとき重複するとエラーになってしまうため、使いにくいかも。 idを変更する目的ならいじる必要ない。
*
IDを文字列にする
class FooModel(m.Model):
id = m.CharField(max_length=100, unique=True, primary_key=True)
このようにidを書き換えればいい。
Overwrite save()
def save(self, *args, **kwargs):
# Before save
# ...
super(MyModel, self).save(*args, **kwargs)
# After save
# ...
Relationship
多対多関係(Many-to-many)
m.ManyToManyField(RelatedModel)
ManyToManyは.save()してから登録することに注意!
ManyToMany.throughを明示指定すれば任意のモデルをManyToManyのRelationとして使用できる(?)
Extra fields on many-to-many relationships
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
through Modelの要素でorder_by
するベストプラクティス何だろう
QuerySetの使い方?
Metaで記述する例
class ProfileAccount(models.Model):
pass
class Meta:
ordering = ('number',)
現状の方法ではunique_together
を用いる。これは将来depricatedとなる可能性があるため、他の方法があれば随時更新する。
class Hop(models.Model):
migration = models.ForeignKey('Migration')
host = models.ForeignKey(User, related_name='host_set')
class Meta:
unique_together = (("migration", "host"),)
多対一](https://docs.djangoproject.com/ja/2.0/topics/db/examples/many_to_one/)
一対一(one-to-one)
m.OneToOneField()
参照される方はsave済みである必要がある。
その他Model.pyを書くときのTips
定義前のモデルを参照
クラス名を文字列で書けば良い
モデル操作
モデルオブジェクトを作成するときの作法
f = FooModel(name='fooo')
f.save()
Player # <- Model
Player.objects.get(id=1)
Player.objects.filter(shard='ea')
一括作成 Bulk Create
Django https://docs.djangoproject.com/en/2.1/ref/models/querysets/#bulk-create
DRF https://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects
DRF ListSerializer https://www.django-rest-framework.org/api-guide/serializers/#listserializer
http://note.crohaco.net/2018/django-rest-framework-serializer/
クエリ
.filter()の中で使う、多分。
lte (less than or equal)など
lte
gte
Consider using the .exists method, for it issues a faster query to your database than if you try to retrieve all the user information with the .get method. And the code gets a little cleaner too
getよりfilter().exists()がいいらしい。
Using Django querysets effectively all()やiterator()についても記述がある。
ループの前にRelatedをあらかじめ取ってくる
select_related()
, prefetch_related("creative_set"):
統計分析
Aggregation
Django-Pandas
View
ディレクトリ設計
簡易
def index(request, ):
return HttpResponse("Hello world")
urlpatterns = [
path('', views.index, name='index'),
]
Method view ?で部分的にアップデートする方法
https://stackoverflow.com/a/4674127/8776028
def my_view(request, id):
instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
return redirect('next_view')
return render(request, 'my_template.html', {'form': form})
Class View
ListView, DetailView Generic detail views
CreateView, DeleteView, EditView, FormView クラスベースのビューでフォームを扱う
extra_context
は簡易に定義できるものの,urlパラメータを利用したオブジェクトを渡そうとするとselfが必要になる.そこで次のリンクを利用する.
https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/#adding-extra-context
Template
HTML
Form
Formクラスを使う。(使わなくてもいいかもしれないが) タグの編集がめんどくさい。
q = forms.CharField(label='search',
widget=forms.TextInput(attrs={'placeholder': 'Search'}))
値を取り出して使う方法 仮に使わなかった場合、どうやって値を取り出すのか不明。
if form.is_valid():
subject = form.cleaned_data['subject']
フォームのPOST先は自動で元のViewだが、actionで指定することもできるらしい? cf.
Submitボタンはないので普通に書いていいっぽい。 cf.
URL
DetailsViewなどを使いたい時、URLではpkまたはslugしか受け付けてもらえない。
cf. What is a slug in dnango モデルにslugを加える必要がありそう。
デバッグ
データベースをデバッグするときの一連の操作
mv db.sqlite3 db.sqlite3.bak
python manage.py migrate --run-syncdb
python manage.py shell
from vainlab.models import Player
from vainlab.vain_api import VainAPI
v = VainAPI()
v.player_matches('ea', 'Qiuqiu')
SQL文を確認する! reference
import logging
log = logging.getLogger('django.db.backends')
log.setLevel(logging.DEBUG)
log.addHandler(logging.StreamHandler())
デプロイ
WSGI
uWSGI
uwsgi これだっ。
static
$ python manage.py collectstatic
dhireクトリ構成
$ tree
.
├── db.sqlite3
├── gitshell
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── settings.cpython-36.pyc
│ │ ├── urls.cpython-36.pyc
│ │ └── wsgi.cpython-36.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── listter
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py