【Django】Djangoを用いたWebサービス（プロジェクト投稿）

## はじめに
今記事は、[【Djangoを用いたWebサービス】](https://qiita.com/kelp-shi/items/b498f72c7033d4918237)の関連記事になります。
プロジェクト投稿の関する事項をまとめてみました。

## models
```python:models.py
from django.db import models

class ProjectTags(models.Model):
    Ptags = models.CharField('tag', max_length=100)

    def __str__(self):
        return self.Ptags

class PostProject(models.Model):
    PPtitle = models.CharField(max_length=50) #プロジェクトタイトル
    PPcontext = models.TextField(max_length=2000) #プロジェクトコンテキスト
    PPimg = models.ImageField(upload_to='static/images') #プロジェクトイメージ
    PPuser = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True, null=True) #投稿ユーザー
    PCworktag   = models.ManyToManyField(ProjectTags, verbose_name='tag') #プロジェクトタグ
    created_at = models.DateTimeField(auto_now_add=True,) #投稿時刻

    def __str__(self):
        return self.PPtitle
```
・Ptags     = プロジェクト用タグモデル
・PPtitle   = Post Project title
・PPimg     = Post Project Image
・PPuser    = Post Project User
・PPworktag = Post Project Work Tag
・created_at= 作成日時
 
最初にプロジェクト用のタグモデルを作成。
その後、PostProjectモデルを作成し、PCworktagにて、タグを指定します。

## views
```python:views.py
from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import PostProject

# プロジェクトリスト------------------
class ProjectList(ListView):
    model = PostProject
    template_name = 'common/projectlist.html'
    paginate_by = 20

    def get_queryset(self):
        return PostProject.objects.exclude()

# プロジェクト作成画面 ---------------
class ProjectCreateView(LoginRequiredMixin, CreateView):
    model = PostProject
    template_name = 'common/project.html'
    fields = ['PPtitle', 'PPcontext']
    success_url = reverse_lazy('teamupweb:index')

    def form_valid(self, form):
        form.instance.PPuser = self.request.user
        return super().form_valid(form)

# プロジェクト詳細画面 ---------------
def ProjectDetail(request, pk):
    detail = get_object_or_404(PostProject, pk=pk)
    return render(request, 'common/detail.html', {'detail': detail})

```
細かく分割して説明します。
### プロジェクトリスト
```python:ProjectList
class ProjectList(ListView):
    model = PostProject
    template_name = 'common/projectlist.html'
    paginate_by = 20

    def get_queryset(self):
        return PostProject.objects.exclude()
```
データを引っ張ってくるモデルと、表示するテンプレートを指定し、ページネーション数（1ページでの表示上限）を指定します。
最後にget_querysetメソッドで返されたインスタンスを受け取ります。

### プロジェクト作成画面
```python:ProjectCreateView
class ProjectCreateView(LoginRequiredMixin, CreateView):
    model = PostProject
    template_name = 'common/project.html'
    fields = ['PPtitle', 'PPcontext']
    success_url = reverse_lazy('teamupweb:index')

    def form_valid(self, form):
        form.instance.PPuser = self.request.user
        return super().form_valid(form)
```
先程と同じようにモデルとテンプレートを指定しています。
fields欄には入力したいフォーム。
form_validメソッドでは、現在ログインしているユーザーが投稿者であるとDBに保存するようにしています。

## forms
```python:forms.py
from django import forms
from .models import PostProject
from .models import CustomUser

class ProjectForm(forms.Form):
    PPtitle = forms.CharField(
        label='タイトル',
        max_length=200,
        required=True,
    )

    PPcontext = forms.CharField(
        label='Context',
        max_length=1000,
        required=True,
        widget=forms.TextInput()
    )
```
...特に書くこともありません。

## urls
```python:urls.py
from django.urls import path
from . import views
from .views import index, test, ProjectCreateView,ProjectList, ProjectDetail


app_name = 'teamupweb'

urlpatterns = [
    path('', index.as_view(), name='index'),
    path('projectList/', ProjectList.as_view(), name='projectlist'),
    path('postproject/', ProjectCreateView.as_view(), name='postproject'),
    path('Detail/<int:pk>/', views.ProjectDetail, name='detail'),
]
```
urls.pyも至って普通です。
Detailに関してはプライマリーキーを用いてインスタンスを指定したいので<int:pk>の記述を追加しました。