Twetterなどで使われているタグ付け機能を作ってみようと思い作成してみました。
とりあえず機能として成り立てばいいかなと思い作成したので、改善点などがあればコメント等で教えていただけたら嬉しいです。
タグ付け機能をつけるモデル
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Notes(models.Model):
title = models.CharField(max_length=255)
content = models.CharField(max_length=500)
tags = models.ManyToManyField(Tag)
favorites = models.ManyToManyField(Users, blank=True, related_name='favorite_notes')
user = models.ForeignKey('accounts.Users', on_delete=models.CASCADE)
タグ付け機能を行うモデルとして、「Tag」と「Notes」を定義しました。
「Tag」モデルはタグを保存するためのモデルになっており、「Notes」モデルのtags
フィールドで多対多で紐付いています。
アプリの機能としてはノートをタグにより分類する感じになります。
フォームの作成
class CreateNoteForm(forms.ModelForm):
title = forms.CharField(label='タイトル')
tags = forms.CharField(label='タグ') # タグを入力するためのフィールド
content = forms.CharField(label='あらすじ', widget=forms.Textarea())
class Meta:
model = Notes
fields = ('title', 'content') # Notesモデルにタグ自体を保存しないので除く
フォームにタグ入力するためのフィールドを作成するためにtags
を定義してますが、Notes
モデルには保存しないのでfields
でtag
は指定しません。
ビューの作成
ビューの関数内でタグの保存の処理などを行います。
def create_note(request):
create_note_form = forms.CreateNoteForm(request.POST or None)
if create_note_form.is_valid():
note = create_note_form.save(commit=False) # save(commit=False)で保存せずにインスタンスを受け取る
note.user = request.user # Notesはユーザーモデルとも紐付いているのでユーザーを指定
note.save() # タグ以外のフィールドを保存
tags = create_note_form.cleaned_data['tags'] # tagsフィールドに入力された値を取得
tag_list = tags.split() # 入力された値をsplitで半角スペースごとに区切る
for tag in tag_list:
tag = tag.lower() # 区切られた値をlowerで小文字にする
if Tag.objects.filter(name=tag).exists(): # existでタグが既にあるか判定(ある:True,ない:False)
add_tag = Tag.objects.filter(name=tag).first() # 存在する場合はタグを取得
note.tags.add(add_tag) # addでタグを追加
else:
add_tag = Tag.objects.create(name=tag) # 存在しない場合タグを新しく作成
note.tags.add(add_tag)
return render(request, 'note/create_note.html', context={
'create_note_form': create_note_form,
})
note.save()
でタグ以外のフィールドを先に保存し、その後にタグを紐付けていきます。
cleaned_data['tags']
でtagsフィールドに入力された値を取得し、tags
に代入しています。
タグは半角スペースで区切って入力するので、tags
で受け取った値をsplit
で半角スペースごとに区切りtag_list
にリスト型で代入。
for
文でタグを一つずつ取得し、lower
で小文字に変換しています。同じ文字列でも別のデータとして扱われてしまうので今回は小文字に統一させます。(Python,python, PYTHONなどが別々に保存され統一性がなくなる)
if Tag.objects.filter(name=tag).exists():
でタグが既に存在するか判定します。同じ文字列が複数ある場合でも統一性がなくなってしまいます。
タグが存在する場合、add_tag = Tag.objects.filter(name=tag).first()
でタグを取得。
タグが存在しない場合、add_tag = Tag.objects.create(name=tag)
でタグを新規作成。
note.tags.add(add_tag)
により関連付ける事ができる。