angularとDRFでブログアプリ

# 完成像
1. APIから記事を取得
2. 記事のタイトルをリストで表示
3. 記事のタイトルをクリックしたら、内容を表示

# django部分
## djangoプロジェクトの作成
django,restframework,corsheadersはインストール済み。

```terminal:ターミナル
$ django-admin startproject django_blog
$ cd $_
$ python manage.py startapp blog
$ cd blog
$ touch urls.py
$ touch serializer.py
```

## 管理画面のユーザー作成

```terminal:ターミナル
$ python manage.py createsuperuser
```

## 設定に追記する

```python:settting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',#追加
    'rest_framework',#追加
    'corsheaders',#追加
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',#追加(場所は絶対ここ)
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

#末尾に追加
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
```

## modelsを定義

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

# Create your models here.
class Blog(models.Model):
    title = models.CharField(max_length=140, blank=False)
    text = models.CharField(max_length=1000, blank=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title
```

```terminal:ターミナル
$ python manage.py makemigrations
$ python manage.py migrate
```

```python:admin.py
from django.contrib import admin
from .models import Blog

# Register your models here.
@admin.register(Blog)
class Blog(admin.ModelAdmin):
    pass
```

## serializerの作成

```py:serializer.py
from rest_framework import serializers
from .models import Blog

class BlogSerializer(serializers.ModelSerializer):
    class Meta:
        model = Blog
        fields = ('id', 'title', 'text', 'created_at')
```

## viewの作成

```py:view.py
from django.shortcuts import render
from rest_framework import viewsets

from .models import Blog
from .serializer import BlogSerializer

# Create your views here.
class BlogViewSet(viewsets.ModelViewSet):
    queryset = Blog.objects.all()
    serializer_class = BlogSerializer
```

## urlsの作成

```py:blog/urls.py
from rest_framework import routers
from .views import BlogViewSet

router = routers.DefaultRouter()
router.register(r'blog', BlogViewSet)
```

```py:django_blog/urls.py
from django.contrib import admin
from django.urls import path, include

from blog.urls import router as blog_api_router

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(blog_api_router.urls)),
]
```
<img width="1412" alt="スクリーンショット 2020-02-08 15.39.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/aa1bc037-9697-d1e6-f97f-63eb26967d4e.png">

バックエンド完了。

# angular部分

## angularプロジェクトの作成

```terminal:ターミナル
$ ng new angular-blog
```

## welcomeページを削除

```html:app.component.html
<h1>BLOG</h1>
<router-outlet></router-outlet>
```

## コンポーネントとサービスの作成

```terminal:ターミナル
$ cd src/app
$ mkdir components
$ cd $_
$ ng g c list
$ ng g c detail
$ cd ..
$ mkdir services
$ cd $_
$ ng g s blog
```

## ルーティングの作成

```ts:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ListComponent } from './components/list/list.component';
import { DetailComponent } from './components/detail/detail.component';


const routes: Routes = [
  {path: '', component: ListComponent},
  {path: 'detail/:id', component: DetailComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

## モジュールのインストール

```ts:app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ListComponent } from './components/list/list.component';
import { DetailComponent } from './components/detail/detail.component';
import { BlogService } from './services/blog.service';

@NgModule({
  declarations: [
    AppComponent,
    ListComponent,
    DetailComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [BlogService],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

## インターフェイスの作成

```terminal:ターミナル
$ mkdir interfaces
$ cd $_
$ ng g i blog
```

```ts:blog.ts
export interface Blog {
    id: number;
    title: string;
    text: string;
}
```


## サービスの作成

```ts:blog.service.ts
import { Blog } from './../interfaces/blog';
import { Injectable } from '@angular/core';
import { HttpHeaders, HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable(
)
export class BlogService {
  blog: Blog[] = [];
  private Url = 'http://localhost:8000/api/blog/';
  private headers = new HttpHeaders({
    'Content-Type': 'application/json'
  });

  constructor(
    private http: HttpClient
  ) { }

  getAllBlog(): Observable<any>{
    return this.http.get(this.Url, {headers: this.headers});
  }
}
```

## リストコンポーネントを作成

```html:list.component.html
<div class="container">
<h1>List</h1>
    <ul class="">
        <li *ngFor="let blog of blogs" class="">
            <a routerLink="detail/{{blog.id}}">
                <span from="name">{{blog.title}}</span>
            </a>
        </li>
    </ul>
</div>
```

```ts:list.component.ts
import { BlogService } from './../../services/blog.service';
import { Blog } from './../../interfaces/blog';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {

  blogs: Blog[] = [];

  constructor(
    private blogService: BlogService
  ) { }

  ngOnInit() {
    this.blogService.getAllBlog().subscribe(
      blogs => this.blogs = blogs
    );
  }

}
```

<img width="649" alt="スクリーンショット 2020-02-08 17.22.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/7709ce30-54f6-34ee-8e6e-903fa4f0681e.png">



APIで取得した投稿をangularで表示することができた。


## detailコンポーネントの作成

```ts:blog.service.ts
  getBlog(id: number): Observable<Blog>{
    const url = `${this.Url}${id}`;
    return this.http.get<Blog>(url);
  }
```

```html:detail.component.html
<h1>Detail</h1>
<div *ngIf="blog">
    <h2>{{blog.title}}</h2>
    <p>{{blog.text}}</p>
</div>
<button [routerLink]="['']" routerLinkActive="router-link-active" >
    戻る
</button>
```

```ts:detail.component.ts
import { Blog } from './../../interfaces/blog';
import { BlogService } from './../../services/blog.service';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-detail',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.css']
})
export class DetailComponent implements OnInit {

  blog: Blog;

  constructor(
    private route: ActivatedRoute,
    private blogService: BlogService
  ) { }

  ngOnInit() {
    this.getBlog();
  }
  
  getBlog(): void{
    const id = +this.route.snapshot.paramMap.get('id');
    this.blogService.getBlog(id).subscribe(
      blog => this.blog = blog
      );
  }

}
```

<img width="400" alt="スクリーンショット 2020-02-09 2.06.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/e1d3a79f-75ec-120e-2a4a-985a1b0cb766.png">

urlのidを元にAPIのデータを探して詳細を表示することtができた。