読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Angular4 + Django1.11 vol.7

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/ http://qiita.com/kura07/items/c9fa858870ad56dfec12

Handling 404 with Object Lookups

  • 指定したurlが無いときの、404 errorのページを設定する。

  • video-detail.component.ts を修正する。

ngOnInit() {
    this.routeSub = this.route.params.subscribe(params => {
        this.slug = params['slug']
        this.req = this._video.get(this.slug).subscribe(data=>{
          this.video = data as VideoItem
        }, error=>{ // subscribeがrrorの場合の内容をconsole.logに表示する
            console.log(error) //
        })
    })
}
  • 実際にerrorが出るpageにアクセスしてみると以下のようなerrorがconsoleに表示される。
eaders:t
ok:false
status:404
statusText:"Not Found"
type:2
url:"http://127.0.0.1:8000/api/videos/bound-method-videotitle-/"
_body:"{"detail":"Not found."}"
  • videos.service.ts にalertが出るように追記する。
private handleError(error:any, caught:any): any{
    console.log(error, caught)
    if (error.status == 404){ // statusが、404のときに、alertが表示されるように設定する
      alert("Oopps. Not found")
    }
}
  • さらに、errorがでたときには、video一覧に戻るようにrouterを設定する。設定するのは、video-detail.component.typescript.
import { ActivatedRoute, Router } from '@angular/router'; // Routerをimport
import { VideoItem } from '../videos/video';
import { VideoService } from '../videos/videos.service';
...
...
  constructor(private route: ActivatedRoute, private router: Router, private _video:VideoService) { }
  // constructorにprivate router: Routerで型定義する。

  ngOnInit() {
      this.routeSub = this.route.params.subscribe(params => {
          this.slug = params['slug']
          this.req = this._video.get(this.slug).subscribe(data=>{
            this.video = data as VideoItem
          }, error=>{
              console.log(error)
              this.router.navigate(['/videos']) // subscribeがerrorのときに、/videos にアクセスする。
          })
      })
  }
  • errorのときの処理をさらに修正する。
export class VideoDetailComponent implements OnInit, OnDestroy {
    private routeSub:any;
    private req:any;
    video: VideoItem;
    slug:string;
    error: Boolean; //errorの型定義をする
  constructor(private route: ActivatedRoute, private router: Router, private _video:VideoService) { }

  ngOnInit() {
      this.routeSub = this.route.params.subscribe(params => {
          this.slug = params['slug']
          this.req = this._video.get(this.slug).subscribe(data=>{
            this.video = data as VideoItem
          }, error=>{
              console.log(error)
              this.error = true; // errorがでたときには、errorをtrueにする。
              // this.router.navigate(['/videos'])
          })
      })
  }
}
  • video-detail.component.htmlに追記する。
<div *ngIf='!video && !error'>Loading</div>
<div *ngIf='error'>Error. Please try again.</div>

まとめ

  • errorは、subscribeのerror時の処理を使うと良さそう。

Angular4 + Django1.11 vol.6

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/ http://www.django-rest-framework.org/api-guide/generic-views/#listapiview http://qiita.com/kura07/items/c9fa858870ad56dfec12

Better Backend Queries

  • featuredのqueryをmodelsでやるようにする。
from django.db import models
from django.db.models.signals import pre_save
# Create your models here.

from .utils import unique_slug_generator

class VideoQuerySet(models.query.QuerySet): # models.query.QuerySetを継承した、VideoQuerySet classを作成する
    def featured(self): # featuredメソッドを追加する。
        return self.filter(featured=True) # featuredメソッドは、querysetにfeatured=Trueのfilterをかけて、その結果を返す。

class VideoManager(models.Manager): #models.Managerを継承したVideoManagerClassを作成する。
    def get_queryset(self): # get_querysetで、VideoQuerySetのinstanceを返すようにセットする。
        return VideoQuerySet(self, using=self._db)

    def featured(self):
        return self.get_queryset().featured() # featuredメソッドは、VideoQuerySetのfeaturedメソッドの値を返すメソッド。

class Video(models.Model):
    name = models.CharField(max_length=220)
    slug = models.SlugField(unique=True, blank=True)
    embed = models.CharField(max_length=120, help_text='Youtube Embed Code', null=True, blank=True)
    featured = models.BooleanField(default=False)
    timestamp = models.DateTimeField(auto_now_add=True)

    objects = VideoManager() # objectsには、VideoManagerのinstanceを代入する。

    def __str__(self):
        return self.name

    def title(self):
        return self.name


def video_pre_save_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)


pre_save.connect(video_pre_save_receiver, sender=Video)
  • views.pyを以下のように修正する。
class VideoFeatured(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.filter(name__icontains=query).featured()
        else:
          qs = Video.objects.featured()
        return qs
  • 次はsearchメソッドを追記する。まずは、models.pyにsearchメソッドを追加する。
from django.db.models import Q
...
class VideoQuerySet(models.query.QuerySet):
    def featured(self):
        return self.filter(featured=True)

    def search(self, query):
        return self.get_queryset().filter(
            Q(name__icontains=query) |
            Q(slug__icontains=query) |
            Q(embed__icontains=query)
        )


class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self.model, using=self._db)

    def featured(self):
        return self.get_queryset().featured()

    def search(self, query):
        return self.get_queryset().search(query)
  • views.pyに追記する。
class VideoList(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
        #   qs = Video.objects.filter(name__icontains=query)
          qs = Video.objects.search(query)
        else:
          qs = Video.objects.all()
        return qs

class VideoFeatured(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.featured().search(query)
        else:
          qs = Video.objects.featured()
        return qs
  • activeフィールドも追加して、最終的にmodels.pyは以下のようになった。
from django.db import models
from django.db.models import Q
from django.db.models.signals import pre_save
# Create your models here.

from .utils import unique_slug_generator

class VideoQuerySet(models.query.QuerySet):
    def active(self):
        return self.filter(active=True)

    def featured(self):
        return self.filter(featured=True)

    def search(self, query):
        return self.get_queryset().filter(
            Q(name__icontains=query) |
            Q(slug__icontains=query) |
            Q(embed__icontains=query)
        )


class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self, using=self._db)

    def all(self):
        return self.get_queryset().active()

    def featured(self):
        return self.get_queryset().featured().active()

    def search(self, query):
        return self.get_queryset().search(query).active()


class Video(models.Model):
    name            = models.CharField(max_length=220)
    slug            = models.SlugField(unique=True, blank=True)
    embed           = models.CharField(max_length=120, help_text='Youtube Embed Code', null=True, blank=True)
    active          = models.BooleanField(default=True)
    featured        = models.BooleanField(default=False)
    timestamp       = models.DateTimeField(auto_now_add=True)

    objects = VideoManager()

    def __str__(self):
        return self.name

    def title(self):
        return self.name


def video_pre_save_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)


pre_save.connect(video_pre_save_receiver, sender=Video)
  • error 発生! _metaがmanagerにはないとのこと。どうもquerysetの箇所を以下のように修正する必要があるようだ。
class VideoManager(models.Manager):
    def get_queryset(self):
        return VideoQuerySet(self.model, using=self._db)

まとめ

  • VideoManager と、VideoQuerySetをsetで使うと、better queryを作成できる。こちらの方がrobustのようだ。確かに、queryは、modelで完結させたほうが、わかりやすい気がする。

Angular4 + Django1.11 vol.5

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/ http://www.django-rest-framework.org/api-guide/generic-views/#listapiview http://qiita.com/kura07/items/c9fa858870ad56dfec12

Integrate Django API with Angular

  • videos.service.ts のendpointを、django rest_framework のapiのurlに変更する。
const endpoint = '/api/videos/'
  • お〜〜表示された!すげー!

Detail View

  • detail viewを作成するために、まずは api/views.pyに、RetrieveAPIViewを追加する。
from django.contrib.auth.models import User

from rest_framework import generics
from rest_framework.permissions import IsAdminUser

from videos.models import Video
from .serializers import VideoSerializer

class VideoList(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

class VideoDetail(generics.RetrieveAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []
  • 次に、urls.pyにdetail viewのurlを追加する。
from django.conf.urls import url

from .views import VideoList, VideoDetail

urlpatterns = [
    url(r'^$', VideoList.as_view(), name='list'),
    url(r'^(?P<slug>[\w-]+)/$', VideoDetail.as_view()),
]
# ここでは、slugからvideoDetailをgetするようにセットしてある
  • http://127.0.0.1:8000/api/videos/bound-method-videotitle-of-video-new-title/ にアクセスしてみる。。。error発生!
AssertionError at /api/videos/bound-method-videotitle-of-video-new-title/
Expected view VideoDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
  • lookup_fieldのセットが必要ぽいので、セットする。
class VideoDetail(generics.RetrieveAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    lookup_field            = "slug"
    permission_classes      = []
    authentication_classes  = []
  • これだけで修正完了(^^)すごい!

  • VideoDetail用のVideoDetailSerializerも作成する。

class VideoDetailSerializer(serializers.ModelSerializer):
    image       = serializers.SerializerMethodField()
    is_promo    = serializers.SerializerMethodField()
    class Meta:
        model = Video
        fields = [
            'name',
            'slug',
            'embed',
            'featured',
            'image',
            'is_promo'
            ]

    def get_image(self,obj):
        return "/static/ang/assets/images/nature/4.jpg"

    def get_is_promo(self,obj):
        return False
  • VideoDetailに、serializer_class=VideoDetailSerializerを、セットすれば完了。

  • videos.service.tsのget(slug)メソッドを修正する。

get(slug){
  return this.http.get(endpoint + slug + "/") // endpoint + slug + "/"に設定する。
          .map(response=>response.json())
          .catch(this.handleError)
    // return this.http.get(endpoint)
    //         .map(response=>{
    //                let data = response.json().filter(item=>{
    //                                 if (item.slug == slug) {
    //                                     return item
    //                                 }
    //                             })
    //                if (data.length == 1){
    //                    return data[0]
    //                }
    //                return {}
    //          })
    //         .catch(this.handleError)
}
  • これで、get methodは、django rest_frameworkのVideoDetailからJSONデータをゲットして、表示させるというロジックになる。

Backend API Search

  • backendのdjangoに、Search後のqueryを出力する機能をつける。
class VideoList(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.filter(name__icontains=query)
        else:
          qs = Video.objects.all()      
        return qs
  • http://127.0.0.1:8000/api/videos/?q=newになどのようにアクセスして、検索結果が表示されればOK(^^)

  • videos.service.ts のsearch(query)メソッドのendpointを修正する。以下のように予想した。

search(query){
  return this.http.get(endpoint + "?q=" + query)
          .map(response=>response.json())
          .catch(this.handleError)
        }
  • 上記でも動く気がするんだけど、動画内では以下のように記載していた。
search(query){
  let querystring = `?q=${query}`
  return this.http.get(endpoint + querystring)
          .map(response=>response.json())
          .catch(this.handleError)
  // return this.http.get(endpoint)
  //           .map(response=>{
  //                  let data = []
  //                  let req = response.json().filter(item=>{
  //                                 if (item.name.indexOf(query) >=0) {
  //                                      data.push(item)
  //                                 }
  //                             })
  //
  //                  return data
  //            })
  //           .catch(this.handleError)

}
  • videos.service.tsは以下の通りに全体を修正したある。
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';


// const endpoint = '/static/ang/assets/json/videos.json' // http://www.yourdomain.com/api/videos/
const endpoint = '/api/videos/'

@Injectable()
export class VideoService {
  constructor(private http: Http) { }

  list(){
      return this.http.get(endpoint)
              .map(response=>response.json())
              .catch(this.handleError)
  }
  get(slug){
    return this.http.get(endpoint + slug + "/")
            .map(response=>response.json())
            .catch(this.handleError)
  }

  search(query){
    let querystring = `?q=${query}`
    return this.http.get(endpoint + querystring)
            .map(response=>response.json())
            .catch(this.handleError)
  }

  private handleError(error:any, caught:any): any{
      console.log(error, caught)
  }

}
  • home.component.ts の、featuredされたitemのみを表示するという機能もbackendに移行させる。
ngOnInit() {
    this.req = this._video.featured().subscribe(data=>{
        //console.log(data.json())
        //this.homeImageList
        this.homeImageList = data as [VideoItem]
        // data.filter(item=>{
        //     if(item.featured){
        //       let dataItem = item
        //         this.homeImageList.push(dataItem)
        //     }
        // })
        // this.homeImageList = data.json();
     })
}
  • featuredメソッドは、まだ定義されていないので、videos.service.tsに追加する。
featured(){
    return this.http.get(endpoint + "featured/")
            .map(response=>response.json())
            .catch(this.handleError)
}
  • backendのdjangoに、featured のurlを作成していないので、設定する。
lass VideoFeatured(generics.ListAPIView):
    queryset                = Video.objects.all()
    serializer_class        = VideoSerializer
    permission_classes      = []
    authentication_classes  = []

    def get_queryset(self):
        query = self.request.GET.get("q")
        if query:
          qs = Video.objects.filter(name__icontains=query).filter(featured=True)
        else:
          qs = Video.objects.filter(featured=True)
        return qs
  • urls.py に、featured viewのurlをセットする。
from django.conf.urls import url

from .views import VideoList, VideoDetail, VideoFeatured

urlpatterns = [
    url(r'^$', VideoList.as_view(), name='list'),
    url(r'^featured/$', VideoFeatured.as_view(), name='featured'),
    url(r'^(?P<slug>[\w-]+)/$', VideoDetail.as_view()),
]
  • http://127.0.0.1:8000/api/videos/featured/にアクセスして、rest_framework viewが表示されればOK(^^)

まとめ

  • endpointから必要なデータを取得して、client側では加工しないほうが、シンプルな実装ができそうだな。frontendとbackendを分けるメリットはこのへんにあるのか。

  • let querystring = ?q=${query} については、ちゃんと意味を調べないとな。。とりあえず、バッククオートは、複数行のコメントをするときに便利らしい。あと${変数}の表現が使える。

  • あと、${変数}で、+などの演算子を使わずに、文字列をつなげることができるらしい。なので、let querystring = `?q=${query}は、let querystring = '"?q=" + queryと同じはず。でも書いてみて思ったけどたしかに文字列をつなげるときは、${}のほうが使いやすいそう(^^)

  • このqiitaの記事がわかりやすかったです! http://qiita.com/kura07/items/c9fa858870ad56dfec12

  • はじめから、apiを使う仕様で作成したほうが楽そうだなぁ(^^)

Angular4 + Django1.11 vol.3

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/ https://www.codingforentrepreneurs.com/blog/random-string-generator-in-python/ https://www.codingforentrepreneurs.com/blog/a-unique-slug-generator-for-django/

Videos Django App

  • ng buildを起動した状態にしておく。
ng build --prod --output-path /Users/yassy/Desktop/djangular4/backend/src/static/ang/ --watch --output-hashing none
  • deploy.shに上記のコマンドを記載しておく。

  • 現在の仕様では、video.service.tsが、videos.jsonからデータを取得しているが、これをdjangoのデータベースから直接持ってくるように設定したい。

  • まず、videos appを作成する。$ python manage.py startapp videos

  • videos の modelを作成する。

from django.db import models

# Create your models here.

class Video(models.Model):
    name = models.CharField(max_length=220)
    slug = models.SlugField(unique=True, blank=True)
    embed = models.CharField(max_length=120, null=True, blank=True)
    featured = models.BooleanField(default=False)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

'''
     "name": "Welcome",
     "slug": "item-1",
     "embed": "1hyjLD7pk10",
     "image": "/static/ang/assets/images/nature/4.jpg",
     "featured": true
    },
'''

Auto Generate Slug

import random
import string
from django.utils.text import slugify


def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))

'''
random_string_generator is located here:
http://joincfe.com/blog/random-string-generator-in-python/
'''

def unique_slug_generator(instance, new_slug=None):
    if new_slug is not None:
        slug = new_slug
    else:
        slug = slugify(instance.title)

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(slug=slug).exists()
    if qs_exists:
        new_slug = "{slug}-{randstr}".format(
                    slug=slug,
                    randstr=random_string_generator(size=4)
                )
        return unique_slug_generator(instance, new_slug=new_slug)
    return slug
    ```

* 最終的にvideos/modelssは以下のように修正

from django.db import models from django.db.models.signals import pre_save

Create your models here.

from .utils import unique_slug_generator

class Video(models.Model): name = models.CharField(max_length=220) slug = models.SlugField(unique=True, blank=True) embed = models.CharField(max_length=120, help_text=‘Youtube Embed Code’, null=True, blank=True) featured = models.BooleanField(default=False) timestamp = models.DateTimeField(auto_now_add=True)

def __str__(self):
    return self.name

def title(self):
    return self.name

def video_pre_save_receiver(sender, instance, *args, **kwargs): if not instance.slug: instance.slug = unique_slug_generator(instance)

pre_save.connect(video_pre_save_receiver, sender=Video)

Angular4 + Django1.11 vol.2

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/

ng build to Django Static

  • $ ng build --prod で、production versionのbuildを実行する。(結果、bundle.jsが作成される)

  • buildしたファイルの出力先をdjangoのstaciファイル内にする。

$ ng build --prod --output-path /Users/yassy/Desktop/djangular4/backend/src/static/ang --watch --output-hashing none

// --output-path で出力先を指定
// --watchで、変更があったら自動でbuildするモードに切り替えられる
// --output-hashing none で、build時に作成されるhashをなくすことができる。
  • deploy.sh ファイルを作成する。deployのときに実行するコマンドを記載する。
ng build --prod --output-path /Users/yassy/Desktop/djangular4/backend/src/static/ang --watch --output-hashing none

Django render Angular

  • static/ang/index.htmlをang_home.htmlにコピペする。さらに、load staticで、django templateで、staticfileを読み込むようにする。
{% load static %}
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Srvup</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
      <!-- index.html -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link href="{% static 'ang/styles.bundle.css' %}" rel="stylesheet"/></head>
<body>
  <app-root>Loading...</app-root>
  <script type="text/javascript" src="{% static 'ang/inline.bundle.js' %}"></script>
  <script type="text/javascript" src="{% static 'ang/polyfills.bundle.js' %}"></script>
  <script type="text/javascript" src="{% static 'ang/vendor.bundle.js' %}"></script>
  <script type="text/javascript" src="{% static 'ang/main.bundle.js' %}"></script>
</body>
</html>
  • 無事表示された!しかし、image ファイルなどが読み込まれていない。。。ang/assets/videos.jsonの中のpathがdjangoと一致してないのが原因ぽい。なので、そのimage のpathを修正する。
    {
     "name": "Welcome",
     "slug": "item-1",
     "embed": "1hyjLD7pk10",
     "image": "/static/ang/assets/images/nature/4.jpg",
     "featured": true
    }
    ...
  • 次に、vides.service.ts内のendpoint(videos.jsonにアクセスするpath)も修正する。
const endpoint = '/static/ang/assets/json/videos.json'
  • http://127.0.0.1:8000/にアクセスしてみる。。。error!というか画像が表示されない。。。原因は、videos.jsonをbuildあとのファイル(angフォルダ以下のファイル)を修正していたため、buildが実行されるたびに、上書きされていたためだった(^^; なので、client/assets/json/videos.jsonの方のpathを修正して再度buildする。

  • 無事表示された(^^)

  • home.component.tsの、defaultImageのpathも修正する。

videoListDefaultImage = '/static/ang/assets/images/videos/1.jpg'

まとめ

  • angularアプリと、djangoアプリは別物と考える。
  • angularアプリ作成→build→deployという流れだが、django backendに使うときは、angularアプリ作成→build output→outputしたファイルを、djangoに静的ファイルとして扱わせる という流れになるのか。
  • build –watch にしておくことで、常にtranscompile + outputされる。そのため、基本的に、django側にoutputされたファイルを修正ではなく、angularアプリの方のファイルを修正する(djangoは、angularアプリからoutputされるファイルを扱うという役割)

Angular4 + Django1.11 vol.1

参考サイト

https://www.codingforentrepreneurs.com/projects/angular-django/

Getting Started Angular4+Django

  • djangular4というフォルダを作成する。さらに、djangular4/client, djangular4/backend というサイトをそれぞれ作成する。

  • clientフォルダに、joincfe/github のtry-angular-v4をgit cloneしてくる。

$ git clone https://github.com/codingforentrepreneurs/Try-Angular-v4.git .
// ここのピリオドがポイント

$ npm install
// package.jsonに記載があるmoduleをinstallする。

$ ng serve
// angularのコードをtranscompileして、localserverを起動する。

$ rm -rf .git
// gitのrepositoryを削除する
  • djangoの環境を作成する。
$ pyenv virtualenv djangular4 // 仮想環境を作成する
$ pip install django djangorestframework // django djangorestframework をpip installする

A Django URL Catch-all

  • django startprojectで、新しいprojectを開始する。$ django-admin.py startproject tryangular .

  • settings.pyにstaticfileの設定を追記する。

STATIC_URL = '/static/'

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static-root')

STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static')
]
  • urls.pyにangularで表示するurlをcatchするための設定をする。
from django.conf.urls import url
from django.contrib import admin
from django.views.generic.base import TemplateView #template viewをimportする

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^.*', TemplateView.as_view(template_name="ang_home.html"), name='home'), #
]
  • templatesフォルダを作成して、その中にang_home.htmlを作成する。
<h1>Hello Django!</h1>
  • またsettings.pyにtemplatesのフォルダの場所を指定する。
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
  • http://127.0.0.1:8000/でも、http://127.0.0.1:8000/dddでも、表示されるページが、ang_home.htmlになっていればOK。

  • 今後は、個別に表示したいurlがある場合は、(adminのように)、r'^.*'より上に書く。

まとめ

  • これで一通りの準備は完了ぽい。
  • .(ピリオド)を使うのがポイントだったな。

Angular4入門_Vol.20

参考サイト

https://www.codingforentrepreneurs.com/projects/try-angular-v4/

ngBuild and Deploy to Heroku

  • packageが完成したら、$ ng build --prod で、deploy用に、bundle.jsを作成する。prodオプションは、minファイルにするためか。bundle.jsには、typescriptファイルを役割ごとにまとめて、javascriptにtrans compileしたコードが記載されている。

  • $ ng build --prod --output-path /Users/username/Desktop/try_angular4/ngSrvupTest というコマンドでpathを指定して、ファイルを出力する。

  • さらに、$ ng build --prod --output-path /Users/username/Desktop/try_angular4/ngSrvupTest --watchで、watchもできる。

  • $ ng build --prod --output-path /Users/yassy/Desktop/try_angular4/ngSrvupTest/public/ というように、publicにしておいたほうがデプロイのときに楽ぽい。

  • ngSrvupTest フォルダに、Procfileを作成する。

web: node index.js
  • package.jsonを作成する(requirements.txtみたいなもんかな)
{
  "name": "try-angular-4",
  "version": "1.0.0",
  "main": "index.js",
  "engines": {
    "node": "5.9.1"
  },
  "dependencies": {
    "ejs": "2.4.1",
    "express": "4.13.3",
    "path": "0.12.7",
    "mongoose": "4.9.3",
    "body-parser": "1.17.1",
    "compression": "1.6.2"
  }
}
  • index.jsを作成する。
var express = require('express');
var path = require('path');
var app = express();

const port = process.env.PORT || '5000';

app.set('port', port);
app.use(express.static(__dirname + '/public')); // staticファイルの置き場所?
app.get('/[^\.]+$', function(req, res){
    res.set('Content-Type', 'text/html')
        .sendFile(path.join(__dirname, '/public/index.html'))
});

app.listen(app.get('port'), function(){
    console.log("Node app is running at localhost:" + app.get('port'))
});
  • $ node index.jsを実行してみる。。。error! express確認できないとのこと。

  • $ npm installで、package.jsonから必要なpackageをinstallする。

  • $ node index.js再度実行する。。。localhost:5000にアクセスしたところ無事表示された(^^)

  • .gitignoreファイルを作成する。

node_modules
.DS_Store
  • herokuにデプロイするために、git repositoryをlocalに作成する。
$git init
$git add --all
$git commit -m "initial commit"
  • herokuのrepositoryを作成する。
$ heroku create tryangular4
Creating ⬢ tryangular4yassy... done
https://tryangular4.herokuapp.com/ | https://git.heroku.com/tryangular4.git
  • $ git push heroku master で、deployする。。。デプロイ成功!上記で作成されたurlにアクセスすると、デプロイされているか確認できる(^^)