tag:crieit.net,2005:https://crieit.net/tags/Django/feed 「Django」の記事 - Crieit Crieitでタグ「Django」に投稿された最近の記事 2021-11-23T01:20:11+09:00 https://crieit.net/tags/Django/feed tag:crieit.net,2005:PublicArticle/17774 2021-11-22T02:31:55+09:00 2021-11-23T01:20:11+09:00 https://crieit.net/posts/d5ca0b7ff1f49b32066b352d05c4d40b 匿名掲示板作ってみた <p>匿名掲示板を作り、アルファ版として公開してみました。<br /> Crieitユーザーの皆さんにもぜひご意見いただきたいです。</p> <p>            -‐ '´ ̄ ̄`ヽ、へ    /\<br />              / /" `ヽ ヽ   ̄  ̄ ̄ ̄   ><br />          //, '/     ヽハ  、 ヽ ̄  ̄>/<br />          〃 {<em>{⌒    ⌒リ| l │ i| / /<br />          レ!小l●    ● 从 |、i| / <br />           ヽ|l⊃ 、</em>,、<em>, ⊂⊃ |ノ│|___</em>__/<br />         /⌒ヽ<strong>|ヘ   ゝ._)   j /⌒i !<br />       \ /:::::| l>,、 __, イァ/  /│<br /> .        /:::::/| | ヾ:::|三/::{ヘ、</strong>∧ |<br />        `ヽ< | |  ヾ∨:::/ヾ:::彡' |</p> <p>その名も、「よろずネットワーク」です。<br /> 作った目的は、「世の中のトレンドがわかって」「自由でゆるくて」「ネットの面白かった時代を再現できるような」掲示板を作りたいと思ったことです。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.yorozu.network">よろずネットワーク</a></p> <p>ちなみに、よろずネットワークではAAを綺麗に投稿できます。<br /> <a href="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a810ec0487.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a810ec0487.png?mw=700" alt="image.png" /></a></p> <p>コメント欄はこんな感じです。<br /> <a href="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a81667ab12.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a81667ab12.png?mw=700" alt="image.png" /></a></p> <p>スレにはyoutube動画やニコニコ動画も貼り付けできます。<br /> <a href="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a818d09a67.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b211ec485fd073472cd23c247404335f619a818d09a67.png?mw=700" alt="image.png" /></a></p> <p><strong>技術スタック</strong><br /> サーバー:Conoha VPS(ubuntu 20.04LTS) ×複数<br /> DB: Mariadb on Conoha<br /> バックエンドAPI:Django Rest Framework<br /> フロントエンド: Quasar(Nuxtjsみたいなやつ) でSSR(PWAモード)<br /> ドメイン:google domain<br /> CI/CD:github actions</p> <p>毎日アバター画像が自動生成されたり、返信がくると通知が来たり、カテゴリごとに毎時ランキングを見られたりなど、掲示板として使いやすいものを意識して作ったので、是非遊びに来てみてください!</p> <p> <a target="_blank" rel="nofollow noopener" href="https://www.yorozu.network">よろずネットワーク</a></p> Y O tag:crieit.net,2005:PublicArticle/15904 2020-05-20T21:15:03+09:00 2020-05-22T12:33:21+09:00 https://crieit.net/posts/Django-5ec51f47951bb Djangoで開発を始める時にやっておくと良いこと <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <p>Djangoで開発を始める時にやっておいたほうが良いこと。<br /> 後々になると変更が難しくなるので、必ずではないのですが初期段階のうちに設定しておいた方が良いことがあります。<br /> <strong>「settings.pyが入っている設定ディレクトリ名の設定」</strong> と <strong>「拡張ユーザーモデル」</strong> を作っておくことです。</p> <p>他にも色々あるかもしれませんが、現段階での備忘録として。</p> <h3 id="この記事の対象者"><a href="#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%AF%BE%E8%B1%A1%E8%80%85">この記事の対象者</a></h3> <ul> <li>Djangoのチュートリアル的な教材を一通り終えたぐらいで、これからアプリ制作を始めようという人</li> <li>ディレクトリ構造やプロジェクト、アプリケーションについて基礎知識を整理しておきたい人</li> <li>ユーザーモデルをちょろっとカスタマイズしたいという人</li> </ul> <h2 id="(1)プロジェクト制作時に設定ディレクトリの名前を変更しておく"><a href="#%EF%BC%88%EF%BC%91%EF%BC%89%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%88%B6%E4%BD%9C%E6%99%82%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE%E5%90%8D%E5%89%8D%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F">(1)プロジェクト制作時に設定ディレクトリの名前を変更しておく</a></h2> <p>これは、プロジェクトのディレクトリ構造をわかりやすくするための措置です。<br /> 普通に<code>$ django-admin startproject myproject</code>なとしてプロジェクト制作を始めると、ベースディレクトリ名と設定ディレクトリ名が同じ名前(ここでは<code>myproject</code>)で作られるため区別がつきづらい、という弊害が起こってしまいます。</p> <p>どういうことかというと、このコマンドでプロジェクト制作を始めると、こんなディレクトリ構造になります。</p> <pre><code>myproject <- ベースディレクトリ |-- manage.py `-- myproject <- 設定ディレクトリ |-- __init__.py |-- settings.py |-- urls.py |-- manage.py `-- wsgi.py </code></pre> <p>プロジェクト名(ここでは<code>myproject</code>)と同じ名前のベースディレクトリがあり、その中に同名の設定ディレクトリができています。</p> <p>(ちなみに[現場で使える Django の教科書《基礎編》]の書籍の中では、区別がつきやすいよう<br /> - ベースディレクトリ=<code>django-admin startproject</code> で作られるプロジェクトのディレクトリ<br /> - 設定ディレクトリ=<code>settings.py</code>のあるディレクトリ<br /> と呼んでいるので、その呼び方に準じることにします)</p> <p>これだとわかりづらいので、設定ディレクトリの方の名前を変えてやる方法があります。</p> <p>プロジェクト作成時に、ベースディレクトリを任意の名前(プロジェクト名)で作成した後にベースディレクトリの下へ移動し、第一引数に設定ディレクトリ名(ここでは<code>config</code>)、第二引数に<code>.</code>を指定して<code>startproject</code>を実行します。</p> <pre><code>$ mkdir myproject(ここにプロジェクト名を入れます) $ cd myproject/ $ django-admin startproject config . </code></pre> <p>これを実行することで、ディレクトリ構造は</p> <pre><code>myproject <- ベースディレクトリ |-- manage.py `-- config <- 設定ディレクトリ *この名前が変わる |-- __init__.py |-- settings.py |-- urls.py |-- manage.py `-- wsgi.py </code></pre> <p>このようになり、わかりやすい構成になるわけです。</p> <h2 id="(2)ユーザーモデルを拡張しておく"><a href="#%EF%BC%88%EF%BC%92%EF%BC%89%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%A2%E3%83%87%E3%83%AB%E3%82%92%E6%8B%A1%E5%BC%B5%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F">(2)ユーザーモデルを拡張しておく</a></h2> <p>DjangoにはデフォルトでUserモデルが用意されており、簡単にログイン機能などが実装できるようになっています。<br /> それだけでとても便利なのですが、よりUserモデルを使いやすくするために、カスタマイズしたユーザーモデルを作っておくことが<a target="_blank" rel="nofollow noopener" href="https://docs.djangoproject.com/ja/2.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project">公式でも推奨</a>されているようです。</p> <p>Userモデルを拡張する主な方法は3種類あって、<br /> - 1.<code>AbstractBaseUser</code>を継承する<br /> - 2.<code>AbstractUser</code>を継承する<br /> - 3. 別モデルを作って<code>OneToOneField</code>で関連させる</p> <p>それぞれのやり方で長所短所があるのですが、<br /> 開発が進んでデータベースに既にデータがある場合は3のやり方が良さそうです。<br /> アプリ制作を始める最初の段階なら1か2推奨ですが、1は入門〜初心者には難しそうなので、初めは2のやり方で慣れるのが無難かなというところです。</p> <p>2の方法では、ユーザーモデルに独自のカラムを追加することができます。</p> <p>カスタムユーザーモデルの作り方は簡単これだけ。</p> <ol> <li><code>models.py</code>に記述</li> <li><code>settings.py</code>に<code>AUTH_USER_MODEL</code>を設定</li> <li>マイグレート</li> </ol> <h3>①<code>app/models.py</code>に記述(<code>app</code>はアプリケーションディレクトリ名が入る)</h3> <p>ここにカスタムユーザーモデルを定義します。(<code>AbstractUser</code>というモデルにユーザーモデルのベースとなる情報が定義されているので、それを継承して使う形になります)</p> <p>ここでテーブル名や、追加したいカラムを指定することができます。<br /> 例えば、<code>custome_user</code>というテーブルに外部キーを用いた<code>Calendar</code>というカラムを設定できます。</p> <pre><code>from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): class Meta(AbstractUser.Meta): db_table = 'custom_user' swappable = 'AUTH_USER_MODEL' calendar = models.ForeignKey(Calendar, verbose_name='アクティブカレンダー', on_delete=models.PROTECT, blank=True, null=True) </code></pre> <p>これは僕の実際のコードの例なので、ユーザーモデルに<code>Calendar</code>というモデルを紐づけていますが、例えばユーザーモデルに性別や年齢、メールアドレス、パスワードなどを持たせたいときには、ここでカラム指定してあげると良いかと思います。<br /> デフォルトのUserモデルにカラムを追加する形になるので、もともとあるカラムも残ります(Userモデルの詳細はMEMO参照)</p> <h3>②<code>config/settings.py</code>に<code>AUTH_USER_MODEL</code>を設定(<code>config</code>はプロジェクト作成時に作られる設定ディレクトリの名前)</h3> <p>ここに使用するカスタムユーザーモデルを定義します。「アプリ名.モデル名」のように記述します</p> <pre><code>AUTH_USER_MODEL = app.CustomUser </code></pre> <h3 id="③マイグレート"><a href="#%E2%91%A2%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%88">③マイグレート</a></h3> <p>モデルを変更したら定番のデータベースのマイグレート。</p> <pre><code>$ Python manage.py makemigrations $ Python manage.py migrate </code></pre> <h2 id="Django入門向けのいろいろ"><a href="#Django%E5%85%A5%E9%96%80%E5%90%91%E3%81%91%E3%81%AE%E3%81%84%E3%82%8D%E3%81%84%E3%82%8D">Django入門向けのいろいろ</a></h2> <h3 id="バージョンについて"><a href="#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">バージョンについて</a></h3> <p>どのバージョンを指定するかですが、<strong>LTS (Long-Term Support)</strong>(=長期間のセキュリティサポートがあるバージョンのこと)に該当するバージョンを採用すると間違いがなさそう。</p> <ul> <li>2.2 => 2022年4月までサポート</li> <li>1.11 => 2020年4月までサポート</li> </ul> <p>ちなみに2019年12月にDjango3系が出ているのですが、LTSに当たる3.2は2021年の4月にリリース予定とのこと。</p> <p>特に理由がなければ現時点で最新のLTSで始めておけば間違いがないのかな?という印象です。<br /> (もしデプロイ先が決まっているなら、そのサーバーが対応しているかなどは調査の必要があるのかも)</p> <h3 id="プロジェクトとアプリケーションについて"><a href="#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">プロジェクトとアプリケーションについて</a></h3> <p>Djangoには「プロジェクト」と「アプリケーション」という概念があるので、少し整理しておきます。</p> <p><strong>プロジェクト</strong><br /> WEBサービスの全体のプロジェクト<br /> <code>$ django-admin startproject myproject</code><br /> (<code>myproject</code>がプロジェクト名)のコマンドで作られる<br />  <br />  <br /> <strong>アプリケーション</strong><br /> 小さな機能のひとまとまり<br /> <code>python3 manage.py startapp myapp</code><br /> (<code>myapp</code>がアプリケーション名)のコマンドで作られる</p> <p>プロジェクトが大きな箱で、アプリケーションはその箱の中に機能ごとに分けて作られるイメージです。</p> <p>1つのWEBサービスを作る際に1つのプロジェクトを作り、小さなサービスならその中に1つのアプリケーションを作成して実装していきます。<br /> プロジェクトの規模が大きくなってくると、1つのプロジェクトに複数のアプリケーションを作って運用することもできます。</p> <ul> <li>アプリケーションは他のアプリケーションとなるべく依存しないように作るとよい</li> <li>プロジェクトにアプリケーションを次々と追加する形で機能を追加していくのが基本スタイル</li> </ul> <p>複数のアプリケーションを作る場合は、このように考慮するとメンテナンスがしやすそうですね。</p> <h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2> <p>一通りチュートリアル的な教材を終えた後は</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Django-%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%E3%80%8A%E5%9F%BA%E7%A4%8E%E7%B7%A8%E3%80%8B-%E6%A8%AA%E7%80%AC-%E6%98%8E%E4%BB%81/dp/4802094744">現場で使える Django の教科書《基礎編》</a></p> <p>こちらの本がとてもわかりやすく勉強が捗ります!</p> <p>基礎的なことが広く網羅されていて、知識の定着や理解のために良いです。つまみ食いしながら読んでもよし。<br /> 今回まとめたようなベストプラクティスな手法が多く掲載されていて、かなり重宝しております。</p> <h2 id="MEMO:デフォルトのUserモデルについて"><a href="#MEMO%EF%BC%9A%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AEUser%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">MEMO:デフォルトのUserモデルについて</a></h2> <p>参考までに、Django 2.1.7で確認したUserモデルのフィールドを記載。<br /> デフォルトのUserモデルはAbstractUserモデルを継承している形になるので、AbstractUserモデルのカラム名が、カスタムユーザーモデルを作った際にも引き継がれます。</p> <p><em><code>lib/django/contrib/auth/models.py</code></em></p> <pre><code class="python">class AbstractUser(AbstractBaseUser, PermissionsMixin): """ An abstract base class implementing a fully featured User model with admin-compliant permissions. Username and password are required. Other fields are optional. """ username_validator = UnicodeUsernameValidator() username = models.CharField( _('username'), max_length=150, unique=True, help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'), validators=[username_validator], error_messages={ 'unique': _("A user with that username already exists."), }, ) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=150, blank=True) email = models.EmailField(_('email address'), blank=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'), ) is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this user should be treated as active. ' 'Unselect this instead of deleting accounts.' ), ) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() EMAIL_FIELD = 'email' USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] class Meta: verbose_name = _('user') verbose_name_plural = _('users') abstract = True def clean(self): super().clean() self.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self): """ Return the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): """Return the short name for the user.""" return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs) class User(AbstractUser): """ Users within the Django authentication system are represented by this model. Username and password are required. Other fields are optional. """ class Meta(AbstractUser.Meta): swappable = 'AUTH_USER_MODEL' </code></pre> Massa tag:crieit.net,2005:PublicArticle/15563 2019-11-27T13:45:50+09:00 2019-11-27T13:45:50+09:00 https://crieit.net/posts/django-import-export-CSV django-import-exportで管理画面にCSVエクスポート機能を追加する <p>Djangoのadminサイト、調べてみるといろいろプラグインがあるらしい。</p> <p>管理画面のデータをCSVなどの形式でインポート/エクスポートしたくなったので、<br /> 調べてみたら<a target="_blank" rel="nofollow noopener" href="https://django-import-export.readthedocs.io/en/stable/index.html">django-import-export</a>で簡単にできた。その時の備忘録。</p> <h5 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h5> <p>まずはpipでインストール</p> <pre><code class="shell">$ pip install django-import-export </code></pre> <h5 id="設定"><a href="#%E8%A8%AD%E5%AE%9A">設定</a></h5> <p><code>import_export</code>をINSTALLED_APPSに追加</p> <pre><code class="python"># settings.py INSTALLED_APPS = ( ... 'import_export', ) </code></pre> <h5 id="admin.pyに追加"><a href="#admin.py%E3%81%AB%E8%BF%BD%E5%8A%A0">admin.pyに追加</a></h5> <p>対象のデータに対する設定を追加していく。</p> <p>サンプルのモデルはこんな感じ。</p> <pre><code class="python"># models.py class Book(models.Model): name = models.CharField('Book name', max_length=100) author = models.CharField('Book name', max_length=100) </code></pre> <p>django-import-exportの設定。</p> <p>対象とするモデルに対して<code>ModelResource</code>を継承したクラスを追加する。<br /> 設定関連はココに書いていくらしい。</p> <pre><code class="python"># admin.py from django.contrib import admin from import_export import resources from import_export.admin import ImportExportModelAdmin from .models import Book class BookResource(resources.ModelResource): # Modelに対するdjango-import-exportの設定 class Meta: model = Book @admin.register(Book) class BookAdmin(ImportExportModelAdmin): # ImportExportModelAdminを利用するようにする ordering = ['id'] list_display = ('id', 'title', 'author') # django-import-exportsの設定 resource_class = BookResource </code></pre> <p>最後に、ImportExportModelAdminを継承したAdminクラスを用意して、<br /> resource_classに<code>ModelResource</code>を継承したクラスを設定すればOK!</p> <p>すると、こんな感じにボタンが表示される。簡単(<em>´ω`</em>)</p> <p><img width="221" alt="スクリーンショット 2019-11-27 13.38.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/aaaac4b5-e0dd-97ff-6391-a57c9d27ad63.png"></p> <h4 id="小ネタ"><a href="#%E5%B0%8F%E3%83%8D%E3%82%BF">小ネタ</a></h4> <h5 id="Exportだけにする: Importを無効化"><a href="#Export%E3%81%A0%E3%81%91%E3%81%AB%E3%81%99%E3%82%8B%3A+Import%E3%82%92%E7%84%A1%E5%8A%B9%E5%8C%96">Exportだけにする: Importを無効化</a></h5> <p>インポートは別にいらないなと思ったので、無効化してみた。<br /> <code>ExportMixin</code>だけにするといいらしい。</p> <pre><code class="python"># ... 略 from import_export.admin import ExportMixin @admin.register(Book) class BookAdmin(ExportMixin, admin.ModelAdmin): # ExportMixinをadmin.ModelAdminに追加すればOK ordering = ['id'] list_display = ('id', 'title', 'author') # django-import-exportsの設定 resource_class = BookResource </code></pre> <h5 id="Exportできるフォーマットを指定する"><a href="#Export%E3%81%A7%E3%81%8D%E3%82%8B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B">Exportできるフォーマットを指定する</a></h5> <p>デフォルトだとJSONとかYMLとかいろいろ選べるけどCSVだけでいいので、<br /> 選択できる部分を絞ってみた。formatsを指定すればOK</p> <pre><code class="python"># ... 略 from import_export.formats import base_formats @admin.register(Book) class BookAdmin(ImportExportModelAdmin): ordering = ['id'] list_display = ('id', 'title', 'author') # django-import-exportsの設定 resource_class = BookResource formats = [base_formats.CSV] # formatsで指定できる </code></pre> <p>以上!!</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p> <h1 id="参考にしたサイト様"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E6%A7%98">参考にしたサイト様</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://django-import-export.readthedocs.io/en/stable/index.html#">Django import / export — django-import-export 1.2.0 documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/29252500/django-import-export-only-export">Django import-export: only export - Stack Overflow</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/45930421/how-to-have-only-csv-xls-xlsx-options-in-django-import-export">How to have only CSV, XLS, XLSX options in django-import-export? - Stack Overflow</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15538 2019-11-11T10:57:24+09:00 2019-11-11T10:57:24+09:00 https://crieit.net/posts/Oracle-Django-Nginx-uWSGI Oracle無料ティアでDjango+Nginx+uWSGIでサーバを立ててみる <p>Oracle Cloudで常時無料サービスが開始されたので使ってみた。<br /> 構成は、Django+nginx+uWSGI+Oracle Database+Oracle Linux</p> <p>以下の3つの環境を作ってみたので、その時の備忘録。</p> <ul> <li>ローカルの開発環境</li> <li>ローカルでDockerを使った開発環境</li> <li>コンピュート・インスタンスでの本番環境</li> </ul> <p>とりあえず、Djangoの雛形アプリにアクセスできるまでの簡易なので、<br /> SSL対応などは省いてます。</p> <h3 id="Oracle Cloudの常時無料サービス(無料ティア)について"><a href="#Oracle+Cloud%E3%81%AE%E5%B8%B8%E6%99%82%E7%84%A1%E6%96%99%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%28%E7%84%A1%E6%96%99%E3%83%86%E3%82%A3%E3%82%A2%29%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">Oracle Cloudの常時無料サービス(無料ティア)について</a></h3> <p>新しく常時無料で利用できるようになったサービスたち。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/jp/cloud/free/">Oracle Cloud無償ティア | オラクル | Oracle 日本</a></p> <p>利用できるのは、以下のようなもの。</p> <ul> <li>データベース ... 20GBを2つまで</li> <li>コンピュート ... 仮想マシン。1/8 OCPU・1GBを2つまで</li> <li>ストレージ ... 合計100GBの2つのブロック・ボリューム。10GBのオブジェクト・ストレージ</li> </ul> <p>ほかにもロードバランサや監視・通知などある。</p> <p>仮想マシンもデータベースも1アカウントにつき2つまでなので、<br /> 1サービスであれば、ステージング環境と本番環境を用意できそう。</p> <hr /> <h3 id="とりあえずDBを作ってみる"><a href="#%E3%81%A8%E3%82%8A%E3%81%82%E3%81%88%E3%81%9ADB%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">とりあえずDBを作ってみる</a></h3> <p>トップ画面から。</p> <p><img width="1367" alt="oracle_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/dde42040-2f99-5a2a-4824-5894bd4ce59d.png"></p> <p>名前とAdminのパスワードを設定する。<br /> Always FreeもONにしておく。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/ce050658-f517-7338-ef93-cd0d07893e16.png" alt="oracle_2.png" /></p> <p>「Autonomous Databaseの作成」をクリックすると、プロビジョンがはじまる。<br /> プロビジョンが終わるとこんな感じに。</p> <p><img width="1436" alt="スクリーンショット 2019-11-10 15.59.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/0df9b110-5004-76cd-f942-10780d1c1e39.png"></p> <h5 id="WebブラウザでDBにアクセスしてみる"><a href="#Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7DB%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">WebブラウザでDBにアクセスしてみる</a></h5> <p>SQL Developer Webからアクセスできる。</p> <p>「DB接続」>「アプリケーション接続」>「SQL Developer Web」にある。<br /> 「アクセスURL」をコピーして、ブラウザに貼り付け。</p> <p><img width="742" alt="oracle_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8795616a-9ab4-87a2-cc78-460e9680f30d.png"></p> <p>ログイン画面が表示されるので、DBを作ったときのパスワードを入力。<br /> アカウントは「admin」</p> <p><img width="490" alt="スクリーンショット 2019-11-10 16.00.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/003a489d-23f3-3f50-4cff-a49f674fe002.png"></p> <p>ログインできるとこんな感じ</p> <p><img width="843" alt="スクリーンショット 2019-11-10 16.01.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/485c6462-de41-ad35-6829-33292cce2129.png"></p> <hr /> <h3 id="ローカルの開発環境を作ってみる"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">ローカルの開発環境を作ってみる</a></h3> <p>とりあえず、開発用にローカル環境で<code>python manage.py runserver</code>できるようにする。<br /> ローカルの環境はmacOS Mojave(10.14.6)</p> <h4 id="まずは、Djangoの雛形を作成する"><a href="#%E3%81%BE%E3%81%9A%E3%81%AF%E3%80%81Django%E3%81%AE%E9%9B%9B%E5%BD%A2%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">まずは、Djangoの雛形を作成する</a></h4> <pre><code class="shell"># pythonのバージョンは3.7.3 $ python3 -V Python 3.7.3 # ディレクトリの作成 $ mkdir sample $ cd sample/ # 仮想環境の作成 $ python3 -m venv venv $ source venv/bin/activate # djangoのインストール $ pip install --upgrade pip $ pip install django # djangoプロジェクトの作成 $ django-admin startproject myproject $ cd myproject $ python manage.py migrate # 起動 $ python manage.py runserver </code></pre> <p>これでとりあえず、デフォルトのデータベース(SQLite)で立ち上がるとこまで完成。</p> <p><img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/e2a487cd-a318-d09c-e9f3-899f598eee09.png" /></p> <h4 id="ローカルでOracleDBを使えるようにする"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7OracleDB%E3%82%92%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B">ローカルでOracleDBを使えるようにする</a></h4> <h5 id="Oracle Instant Clientのインストール"><a href="#Oracle+Instant+Client%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Oracle Instant Clientのインストール</a></h5> <p>OracleDBを使うためには、Oracle Instant Clientが必要なので、<br /> 以下からダウンロードしてインストールする。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/downloads.html">Oracle Instant Client Downloads</a></p> <p>Macだったので、「<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html">Instant Client for macOS (Intel x86)</a>」の「Basic Light Package」を選択</p> <pre><code class="sh">## インストールするディレクトリを作成 $ sudo mkdir -p /opt/oracle ## インストールしたファイルを展開 $ sudo unzip ~/Downloads/instantclient-basiclite-macos.x64-19.3.0.0.0dbru.zip -d /opt/oracle ## ライブラリを参照できるように${HOME}/libにリンクを追加 $ mkdir ~/lib $ ls -s /opt/oracle/instantclient_19_3/libclntsh.dylib ~/lib/ $ cp /opt/oracle/instantclient_19_3/lib* ~/lib/ </code></pre> <h5 id="環境変数にインストールした場所を設定"><a href="#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AB%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%9F%E5%A0%B4%E6%89%80%E3%82%92%E8%A8%AD%E5%AE%9A">環境変数にインストールした場所を設定</a></h5> <pre><code class="shell">echo "export ORACLE_HOME=/opt/oracle/instantclient_19_3" >> ~/.bashrc source ~/.bashrc </code></pre> <h5 id="認証情報の配置"><a href="#%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E3%81%AE%E9%85%8D%E7%BD%AE">認証情報の配置</a></h5> <p>Oracle Cloudの「Autonomous Database」>「Autonomous Databaseの詳細」にある<br /> 「DB接続」からウォレットをダウンロードしてくる。</p> <p><img width="753" alt="oracle_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/6b23b62d-623d-2fad-ea3b-a95c11d4d605.png"></p> <p>ファイル名は「<code>Wallet_<データベース名>.zip</code>」。<br /> 今回はデータベース名が<code>sample</code>なので、<code>Wallet_sample.zip</code>となる。</p> <pre><code class="shell">## 認証ファイルを配置するディレクトリを作成 $ mkdir -p /opt/oracle/instantclient_19_3/network/admin ## ダウンロードしたウォレットを展開して配置 $ sudo unzip ~/Downloads/Wallet_sample.zip -d ${ORACLE_HOME}/network/admin Archive: ~/Downloads/Wallet_sample.zip inflating: /opt/oracle/instantclient_19_3/network/admin/cwallet.sso inflating: /opt/oracle/instantclient_19_3/network/admin/tnsnames.ora inflating: /opt/oracle/instantclient_19_3/network/admin/truststore.jks inflating: /opt/oracle/instantclient_19_3/network/admin/ojdbc.properties inflating: /opt/oracle/instantclient_19_3/network/admin/sqlnet.ora inflating: /opt/oracle/instantclient_19_3/network/admin/ewallet.p12 inflating: /opt/oracle/instantclient_19_3/network/admin/keystore.jks </code></pre> <h5 id="cx_Oracle(pythonライブラリ)のインストール"><a href="#cx_Oracle%28python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%29%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">cx_Oracle(pythonライブラリ)のインストール</a></h5> <p>Oracle Databaseのpythonライブラリをインストールする</p> <pre><code>$ pip install cx_Oracle </code></pre> <h5 id="settings.pyの設定"><a href="#settings.py%E3%81%AE%E8%A8%AD%E5%AE%9A">settings.pyの設定</a></h5> <p>settings.pyをOracleように変更。<br /> <code>NAME</code>には、TNS名のどれかを指定する。</p> <p><img width="753" alt="oracle_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/6b23b62d-623d-2fad-ea3b-a95c11d4d605.png"></p> <p>今回は一番上の<code>sample_HIGH</code>を選択。</p> <pre><code class="python">DATABASES = { 'default': { 'ENGINE': 'django.db.backends.oracle', 'NAME': 'sample_HIGH', 'USER': 'admin', 'PASSWORD': '<DB作成時に入力したパスワード>', } } </code></pre> <p>マイグレーションをもう一度実行してみて、接続できるか確認。</p> <pre><code class="shell">$ python manage.py migrate </code></pre> <p>マイグレーションが成功すると、Webブラウザ上のSQL Developerでも確認できる。</p> <p><img width="926" alt="スクリーンショット 2019-11-10 16.35.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/53393a83-0772-2f8e-9814-6d2ddbe203bd.png"></p> <p>これで、とりあえず、開発できるようになった(<em>´ω`</em>)</p> <hr /> <h3 id="ローカルでDockerを使った開発環境を作ってみる"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7Docker%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">ローカルでDockerを使った開発環境を作ってみる</a></h3> <p>実際にデプロイする際は、NginxとuWSGIを利用するので、<br /> それを試せる環境をDockerで構築する。</p> <h4 id="Django側の変更"><a href="#Django%E5%81%B4%E3%81%AE%E5%A4%89%E6%9B%B4">Django側の変更</a></h4> <p>nginx+uWSGIで動かすために、いくつか変更。</p> <h5 id="1. STATIC_ROOTとALLOWED_HOSTS設定"><a href="#1.+STATIC_ROOT%E3%81%A8ALLOWED_HOSTS%E8%A8%AD%E5%AE%9A">1. STATIC_ROOTとALLOWED_HOSTS設定</a></h5> <p>settings.pyを以下の感じに変更。<br /> ログファイルも出るように変更。</p> <pre><code class="diff">-ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["127.0.0.1"] ... STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, "static/") +# for logging +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + + 'formatters': { + 'standard': { + 'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", + 'datefmt': "%d/%b/%Y %H:%M:%S" + }, + }, + 'handlers': { + 'file': { + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': 'django.log', + 'maxBytes': 50000, + 'backupCount': 2, + 'formatter': 'standard', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['file'], + 'level': 'DEBUG', + 'propagate': True, + }, + }, +} </code></pre> <h5 id="2. staticディレクトリを作成&amp;配置"><a href="#2.+static%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%26amp%3B%E9%85%8D%E7%BD%AE">2. staticディレクトリを作成&配置</a></h5> <p>manage.pyと同じ場所に作成し、<br /> django-adminのcssとかを配置</p> <pre><code class="shell">$ mkdir static $ python manage.py collectstatic </code></pre> <h4 id="Docker用の資材を配置"><a href="#Docker%E7%94%A8%E3%81%AE%E8%B3%87%E6%9D%90%E3%82%92%E9%85%8D%E7%BD%AE">Docker用の資材を配置</a></h4> <pre><code class="shell"># Docker用の資材の配置場所を作成 $ mkdir docker # 資格情報の配置 $ mkdir docker/wallet $ unzip ~/Downloads/Wallet_sample.zip -d docker/wallet/ Archive: ~/Downloads/Wallet_sample.zip inflating: wallet/cwallet.sso inflating: wallet/tnsnames.ora inflating: wallet/truststore.jks inflating: wallet/ojdbc.properties inflating: wallet/sqlnet.ora inflating: wallet/ewallet.p12 inflating: wallet/keystore.jks # NginxやuWSGIの設定ファイルは以下に配置 $ mkdir docker/conf $ touch docker/conf/requirements.txt $ touch docker/conf/myproject_nginx.conf $ touch docker/conf/myproject_uwsgi.ini $ touch docker/conf/uwsgi.service # Dockerfireとdocker-compose.ymlを配置 $ touch docker/Dockerfile $ touch docker-compose.yml </code></pre> <p>ディレクトリ的にはこんな感じ。</p> <pre><code>. ├── docker/ │   ├── conf/ │   │   ├── myproject_nginx.conf │   │   ├── myproject_uwsgi.ini │   │   └── uwsgi.service │   ├── wallet │   │   ├── ... │   │   └── tnsnames.ora │   ├── Dockerfile │   └── requirements.txt ├── myproject/ │   ├── myproject/ │   │   ├── settings.py │   │   └── wsgi.py │   ├── static/ │   └── manage.py ├── venv/ └── docker-compose.yml </code></pre> <p>各ファイルの中身は以下の感じ。</p> <h5 id="docker-compose.yml"><a href="#docker-compose.yml">docker-compose.yml</a></h5> <pre><code class="yml">version: '2' services: web: build: "./docker" volumes: # djangoアプリを/var/www配下にマウント - ./myproject:/var/www/myproject ports: # 80および8000ポートを開けておく - "80:80" - "8000:8000" # systemctlを使うので特権を有効にしておく privileged: true command: /sbin/init </code></pre> <h5 id="docker/Dockerfile"><a href="#docker%2FDockerfile">docker/Dockerfile</a></h5> <pre><code class="dockerfile"># Oracle Cloud Infrastructureでも # OracleLinuxを使うのでoraclelinuxのイメージを使う FROM oraclelinux:7 ### ENV ENV ORACLE_HOME "/usr/lib/oracle/18.3" ### INSTALL ORACLE DATABASE # oracle-instantclientを利用するために、2つリポジトリを有効化 RUN yum install -y oracle-release-el7 oracle-softwarecollection-release-el7 RUN yum install -y oracle-instantclient18.3-basiclite RUN echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf RUN mkdir -p ${ORACLE_HOME}/network/admin COPY wallet/* ${ORACLE_HOME}/network/admin/ ### INSTALL PYTHON # python3-develを利用するために、ol7_optional_latestを有効化 RUN yum-config-manager --enable ol7_optional_latest RUN yum install -y python3 python3-devel gcc ### CREATE VIRTUAL ENV RUN mkdir /var/www/ RUN mkdir /var/www/myproject WORKDIR /var/www/ RUN python3 -m venv venv # 作成した仮想環境(venv)にactivateする ENV PATH="/var/www/venv/bin:$PATH" COPY requirements.txt /var/www/ RUN pip install -r requirements.txt #### INSTALL NGINX RUN yum install -y nginx COPY conf/myproject_nginx.conf /etc/nginx/conf.d/ RUN systemctl enable nginx RUN chown -R nginx.nginx /var/www RUN chmod 755 /var/www ### SETUP uWSGI Emperor mode RUN mkdir /etc/uwsgi RUN mkdir /etc/uwsgi/vassals COPY conf/myproject_uwsgi.ini /etc/uwsgi/vassals # uWSGIのログディレクトリを作成 RUN mkdir /var/log/uwsgi RUN chown -R nginx:nginx /var/log/uwsgi # uWSGIをサービスに登録 COPY conf/uwsgi.service /etc/systemd/system/ RUN systemctl enable uwsgi </code></pre> <h5 id="docker/conf/requirements.txt"><a href="#docker%2Fconf%2Frequirements.txt">docker/conf/requirements.txt</a></h5> <pre><code class="txt">Django==2.2.7 cx-Oracle==7.2.3 uWSGI==2.0.18 </code></pre> <h5 id="docker/conf/myproject_nginx.conf"><a href="#docker%2Fconf%2Fmyproject_nginx.conf">docker/conf/myproject_nginx.conf</a></h5> <pre><code class="nginx"># the upstream component nginx needs to connect to upstream django { # myproject_uwsgi.iniで設定したsocketファイルを指定 # unix://<socketファイルのパス> server unix:///var/www/myproject.sock; } # configuration of the server server { listen 80; # IPアドレスを指定。ローカルなので、127.0.0.1を設定 server_name 127.0.0.1; charset utf-8; # Django static location /static { alias /var/www/myproject/static; } # Finally, send all non-media requests to the Django server. location / { include uwsgi_params; uwsgi_pass django; } } </code></pre> <h5 id="docker/conf/myproject_uwsgi.ini"><a href="#docker%2Fconf%2Fmyproject_uwsgi.ini">docker/conf/myproject_uwsgi.ini</a></h5> <pre><code class="ini">[uwsgi] # Djangoプロジェクトのパスを指定 chdir = /var/www/myproject # Djangoプロジェクトのwsgi.pyを指定 module = myproject.wsgi # venvのパスを指定 home = /var/www/venv # process-related settings: master master = true # maximum number of worker processes processes = 10 # socketファイルののパス socket = /var/www/myproject.sock # socketファイルのユーザと権限を設定 chown-socket = nginx:nginx chmod-socket = 666 # clear environment on exit vacuum = true # logfile logto = /var/log/uwsgi/%n.log </code></pre> <h5 id="docker/conf/uwsgi.service"><a href="#docker%2Fconf%2Fuwsgi.service">docker/conf/uwsgi.service</a></h5> <pre><code>[Unit] Description=uWSGI Emperor After=syslog.target [Service] User=nginx Group=nginx # 環境変数の設定 Environment="ORACLE_HOME=/usr/lib/oracle/18.3" Environment="LD_LIBRARY_PAT=${ORACLE_HOME}/client64/lib:$LD_LIBRARY_PATH" Environment="PATH=$PATH:${ORACLE_HOME}/client64/lib" # EmperorモードでuWSGIを実行。venvにあるuwsgiを使う ExecStart=/var/www/venv/bin/uwsgi --master --emperor /etc/uwsgi/vassals --die-on-term --uid nginx --gid nginx --logto /var/log/uwsgi/emperor.log Restart=always KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all [Install] WantedBy=multi-user.target </code></pre> <h4 id="Dockerを起動"><a href="#Docker%E3%82%92%E8%B5%B7%E5%8B%95">Dockerを起動</a></h4> <pre><code class="shell"># dockerを立ち上げ $ docker-compose up -d </code></pre> <p>これでうまくビルドされて立ち上がれば、<br /> <code>http://127.0.0.1</code>にアクセスできる。</p> <p><code>myproject_nginx.conf</code>の<code>server_name</code>で、<code>127.0.0.1</code>を指定しているので、<br /> <code>http://127.0.0.1</code>じゃないとDjangoアプリにアクセスできないので注意。</p> <p><code>http://localhost</code>だと、<code>myproject_nginx.conf</code>の設定が適用されず、<br /> nginxのデフォルトページが表示される。</p> <h5 id="よく使うログインとか停止とかはこんな感じ。"><a href="#%E3%82%88%E3%81%8F%E4%BD%BF%E3%81%86%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%8B%E5%81%9C%E6%AD%A2%E3%81%A8%E3%81%8B%E3%81%AF%E3%81%93%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98%E3%80%82">よく使うログインとか停止とかはこんな感じ。</a></h5> <pre><code class="shell"># コンテナにログイン $ docker-compose exec web /bin/bash # 停止 $ docker-compose stop # 削除 $ docker-compose rm # Dockerfile ビルド $ docker-compose build # Dockerfile ビルド(キャッシュなし) $ docker-compose build --no-cache # コンテナをせんぶ削除 $ docker rm `docker ps -a -q` </code></pre> <h5 id="うまくいかないときにみるところ"><a href="#%E3%81%86%E3%81%BE%E3%81%8F%E3%81%84%E3%81%8B%E3%81%AA%E3%81%84%E3%81%A8%E3%81%8D%E3%81%AB%E3%81%BF%E3%82%8B%E3%81%A8%E3%81%93%E3%82%8D">うまくいかないときにみるところ</a></h5> <p>以下の場所にログファイルが出力されるので見てみる。</p> <ul> <li><code>/var/log/messages</code> ... systemdのログ</li> <li><code>/var/log/nginx/error.log</code> ... nginxのエラーログ</li> <li><code>/var/log/uwsgi/emperor.log</code> ... uWSGI Emperorのログ</li> <li><code>/var/log/uwsgi/myproject_uwsgi.log</code> ... myproject_uwsgi.iniのログ</li> <li><code>/var/www/myproject/django.log</code> ... Djangoプロジェクトのログ</li> </ul> <p>あとは、「パスが正しいか」「権限、オーナーが正しいか」などを見てみるといいかも。</p> <hr /> <h3 id="コンピュート・インスタンスで公開してみる"><a href="#%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%83%88%E3%83%BB%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%A7%E5%85%AC%E9%96%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">コンピュート・インスタンスで公開してみる</a></h3> <h4 id="仮想インスタンスの作成"><a href="#%E4%BB%AE%E6%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">仮想インスタンスの作成</a></h4> <p>ここから選択。</p> <p><img width="1367" alt="oracle_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/58f5c6f6-a84b-435e-eadf-96a795fe8ba8.png"></p> <p>こんな感じで入力。<br /> 「<strong>パブリックIPアドレスの割当</strong>」を選択しておく。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/71e54b71-dad2-9b33-3120-73ef26aae734.png" alt="oracle_6.png" /></p> <p>ちゃんと「パブリックIPアドレスの割当」を選択していると、<br /> ここにIPアドレスが表示される</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/2a714a85-2389-506d-4a8c-9197fb9ca208.png" alt="oracle_7.png" /></p> <p>デフォルトのユーザは<code>opc</code>なので、<br /> こんな感じで、sshでログインできる。</p> <pre><code class="shell">$ ssh opc@<IPアドレス> </code></pre> <h4 id="セキュリティルールを設定"><a href="#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E8%A8%AD%E5%AE%9A">セキュリティルールを設定</a></h4> <p>HTTP(ポート80)でアクセスできるようにセキュリティルールを設定する<br /> ただ、セキュリティルールを設定する場所は少しわかりにくい。。</p> <p>仮想インスタンスの詳細にアクセスして、<br /> 「仮想クラウド・ネットワーク」を選択</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8c83e806-cb22-481f-a7c4-1903c7766685.png" alt="oracle_8.png" /></p> <p>左下に「ネットワーク・セキュリティ・グループ」を選択。<br /> 「ネットワーク・セキュリティ・グループの作成」を選択すると、追加できるようになる。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/107254d4-5c9f-155d-5fb2-f9ba13c9d621.png" alt="oracle_9.png" /></p> <p>「名前」と「コンパートメント」に作成を設定</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/4464efc9-a245-3858-707c-811f12a166d9.png" alt="oracle_10.png" /></p> <p>ルールの追加を以下のように設定して、「作成」をクリック</p> <p><img width="1404" alt="oracle_11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/f604553d-7ea4-925d-944b-2410bd920e91.png"></p> <p>これで作成できたので、仮想インスタンスの詳細にもどって、<br /> 「ネットワーク・セキュリティ・グループ」の「編集」を選択</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8c96405c-539f-9197-40b0-782c30b85079.png" alt="oracle_12.png" /></p> <p>さっき作ったセキュリティグループを設定</p> <p><img width="783" alt="スクリーンショット 2019-11-11 0.19.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/12823048-83d2-1278-68a6-dcd45dace136.png"></p> <h4 id="環境構築"><a href="#%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89">環境構築</a></h4> <p>Dockerfileでやったような感じで、<br /> Django+nginx+uWSGIな環境を構築してく。</p> <p>DockerイメージのOracleLinuxとは違い、</p> <ol> <li>リポジトリが最初から有効化されている</li> <li>SELinuxが有効化されている</li> </ol> <p>という感じなので、ちょっと変更が必要。</p> <h5 id="資材を仮想インスタンスに送る"><a href="#%E8%B3%87%E6%9D%90%E3%82%92%E4%BB%AE%E6%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AB%E9%80%81%E3%82%8B">資材を仮想インスタンスに送る</a></h5> <p>Dockerのときに使った資材を仮想インスタンスに送る。</p> <pre><code class="shell">$ scp -r docker opc@<IPアドレス>:~/ $ scp -r myproject/ opc@<IPアドレス>:~/ </code></pre> <p>送信したら、ログインして確認。</p> <pre><code class="shell">$ ssh opc@<IPアドレス> $ pwd /home/opc $ ls docker myproject </code></pre> <p>ログイン後のディレクトリ構成はこんな感じ</p> <pre><code>/home/opc ├── docker/ │   ├── conf/ │   │   ├── myproject_nginx.conf │   │   ├── myproject_uwsgi.ini │   │   └── uwsgi.service │   ├── wallet │   │   ├── ... │   │   └── tnsnames.ora │   ├── Dockerfile │   └── requirements.txt ├── myproject/ │   ├── myproject/ │   │   ├── settings.py │   │   └── wsgi.py │   ├── static/ │   └── manage.py ├── venv/ └── docker-compose.yml </code></pre> <h5 id="設定ファイルの変更"><a href="#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%A4%89%E6%9B%B4">設定ファイルの変更</a></h5> <p>IPアドレスと<code>127.0.0.1</code>にしていたので変更する。</p> <h6 id="~/docker/conf/myproject_nginx.conf"><a href="#%7E%2Fdocker%2Fconf%2Fmyproject_nginx.conf">~/docker/conf/myproject_nginx.conf</a></h6> <pre><code class="diff"> server { - server_name 127.0.0.1; + server_name <IPアドレス>; } </code></pre> <h6 id="~/myproject/myproject/settings.py"><a href="#%7E%2Fmyproject%2Fmyproject%2Fsettings.py">~/myproject/myproject/settings.py</a></h6> <pre><code class="diff">-ALLOWED_HOSTS = ["127.0.0.1"] +ALLOWED_HOSTS = ["<IPアドレス>"] </code></pre> <h5 id="環境構築の実施"><a href="#%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%AE%E5%AE%9F%E6%96%BD">環境構築の実施</a></h5> <pre><code class="shell">$ sudo -s ### INSTALL ORACLE DATABASE $ yum install -y oracle-instantclient18.3-basiclite $ echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf $ mkdir -p /usr/lib/oracle/18.3/network/admin $ /home/opc/docker/wallet/* /usr/lib/oracle/18.3/network/admin/ ### INSTALL PYTHON $ yum install -y python3 python3-devel gcc ### CREATE VIRTUAL ENV $ mkdir /var/www/ $ cp -r /home/opc/myproject /var/www $ cd /var/www/ $ python3 -m venv venv # 作成した仮想環境(venv)にactivateする $ source venv/bin/activate $ pip install -r /home/opc/docker/requirements.txt #### INSTALL NGINX $ yum install -y nginx $ cp /home/opc/docker/conf/myproject_nginx.conf /etc/nginx/conf.d/ $ systemctl enable nginx $ chown -R nginx.nginx /var/www # $ chmod 755 /var/www ### SETUP uWSGI Emperor mode $ mkdir -p /etc/uwsgi/vassals $ cp /home/opc/docker/conf/myproject_uwsgi.ini /etc/uwsgi/vassals # uWSGIのログディレクトリを作成 $ mkdir /var/log/uwsgi $ chown -R nginx:nginx /var/log/uwsgi # uWSGIをサービスに登録 $ cp /home/opc/docker/conf/uwsgi.service /etc/systemd/system/ $ systemctl enable uwsgi ##### ここから仮想インスタンス独自の設定 ### Firewallの設定 # httpを追加する $ firewall-cmd --permanent --add-service=http # firewallを再起動して変更を反映 $ systemctl restart firewalld.service ### SELinuxの設定 $ restorecon -RF /var/www ### サービスの起動 $ systemctl restart nginx $ systemctl restart uwsgi </code></pre> <p>一度、<code>http://<IPアドレス></code>にアクセスして確認してみる。<br /> エラーページが出ていたら、以下を実行</p> <pre><code class="shell"># 監査ログを確認 $ cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx # ポリシーファイルを作成 $ cat /var/log/audit/audit.log | audit2allow -M nginx # ポリシーファイルを適用 $ semodule -i nginx.pp </code></pre> <p>これで、<code>http://<IPアドレス></code>にアクセスして、<br /> Djangoの画面が表示されて、django-adminの画面が操作できればOK</p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>とりあえず、ローカルとインスタンス上の環境が作れたので、<br /> 色々することはできそう(<em>´ω`</em>)</p> <p>SSL対応、権限周りなど、本番としては足りないところがあるので、<br /> そのあたりは他の記事を参照ください〜ヽ(=´▽`=)ノ</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p> <h1 id="参考にしたサイトさま"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E3%81%95%E3%81%BE">参考にしたサイトさま</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://docs.djangoproject.com/ja/2.2/ref/databases/#oracle-notes">データベース | Django ドキュメント | Django</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://oracle.github.io/python-cx_Oracle/">cx_Oracle - Python Interface for Oracle Database</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html">cx_Oracle 7 Installation — cx_Oracle 7.3.0-dev documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html#ic_osx_inst">Instant Client for macOS (Intel x86)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://oracle.github.io/odpi/doc/installation.html#macos">ODPI-C Installation — ODPI-C v3.2.2</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://shase428.hatenablog.jp/entry/2018/01/31/201543">Macでsqlplus使えるようにするメモ - ビットの海</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/oracle/python-cx_Oracle/issues/56">trouble running Oracle_cx on macOS · Issue #56 · oracle/python-cx_Oracle</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.oracle.com/cd/E83857_01/iaas/compute-iaas-cloud/stcsg/accessing-oracle-linux-instance-using-ssh.html#GUID-D313B1A1-FB67-42C7-A7CC-958656A5207F">SSHを使用したOracle Linuxインスタンスへのアクセス</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://cloudii.atomitech.jp/entry/20190417/1555464532">コンピュート・インスタンスに予約済パブリックIPを付与する - Cloudii blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/chi9rin/items/af532d0dd9237cc65741#selinux-%E3%81%AE%E5%8B%95%E4%BD%9C%E3%83%A2%E3%83%BC%E3%83%89">SELinux を使おう.使ってくれ. - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://serverfault.com/questions/413397/how-to-set-environment-variable-in-systemd-service">arch linux - How to set environment variable in systemd service? - Server Fault</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/cof123/items/6c9d4b01f0057a9a8de0">EC2にnginx+uwsgi+python でHello World - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/takahirono7/items/fd6f9239f0f88eb65a7c">uwsgiのsystemd化(pyenv環境) - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/yasunori/items/64606e63b36b396cf695#%E3%83%AD%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%86%E3%83%BC%E3%83%88%E3%81%A7%E3%83%AD%E3%82%B0%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A6%8B%E5%A4%B1%E3%82%8F%E3%81%AA%E3%81%84">ちゃんと運用するときのuWSGI設定メモ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.saintsouth.net/blog/setup-django-app-with-uwsgi-and-nginx/#toc-9">Nginx に uWSGI + Django アプリ を組み込む | SaintSouth.NET</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/5t111111/items/e170fead91261621b054#uwsgi-emperor">Ubuntu 12.04でpyenvを利用して速攻でPython3.4 + Nginx + uWSGI + FlaskなWebアプリケーション実行環境を作る - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.mathpython.com/ja/django-nginx-conf/">nginxでDjangoを使うときの設定ファイル:クライアント、nginx、uwsgiの流れを整理しよう - MathPython</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html">Setting up Django and your web server with uWSGI and nginx — uWSGI 2.0 documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://pythonspeed.com/articles/activate-virtualenv-dockerfile/">Elegantly activating a virtualenv in a Dockerfile</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/hana_shin/items/bd9ba363ba06882e1fab">firewall-cmdコマンドの使い方 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/yakumo/items/8ac195337414aabd39c0">Oracle Cloud で Compute にWebサーバーを立てたメモ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e">venv: Python 仮想環境管理 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="http://blog.higty.xyz/archives/242/">SELinux + Nginx ポリシー設定 - URAGAMI</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.blog.umentu.work/centos7nginx-selinux%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%83%9B%E3%83%BC%E3%83%A0%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E9%85%8D%E4%B8%8B%E3%81%AEweb%E3%82%B3%E3%83%B3%E3%83%86/">[CentOS7][Nginx] SELinuxを設定しホームディレクトリ配下のWebコンテンツを公開を許可 | from umentu import stupid</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae#%E5%81%9C%E6%AD%A2%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AE%E7%A2%BA%E8%AA%8D">Dockerイメージとコンテナの削除方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/gold-kou/items/44860fbda1a34a001fc1#rm">いまさらDockerに入門したので分かりやすくまとめます - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/okhrn/items/d8580e66546d166f489a">Dockerネットワーク設定 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa">Docker Compose - docker-compose.yml リファレンス - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae">Dockerイメージとコンテナの削除方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/prgseek/items/e557a371d7bd1f57b9b1#-docker-composeyml">Docker Compose で複数コンテナ構築&管理 - Qiita</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/14616 2018-12-01T14:27:52+09:00 2018-12-01T14:27:52+09:00 https://crieit.net/posts/4 ニュースをランダムにガチャで読める「ガチャっとニュース」を4時間でリリースした話【個人開発】 <p><a target="_blank" rel="nofollow noopener" href="https://twitter.com/jyouj__">じぇい</a>です!こんにちは。</p> <p>ニュースをガチャすることで、ニュースをランダムに読める「<a target="_blank" rel="nofollow noopener" href="https://gachat-news.herokuapp.com/">ガチャっとニュース</a>」をリリースしました!</p> <p><a target="_blank" rel="nofollow noopener" href="https://gachat-news.herokuapp.com/">https://gachat-news.herokuapp.com/</a></p> <blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">【拡散希望】ニュースをランダムにガチャして見れる「ガチャっとニュース」をリリースしました㊗️情報の偏りが問題になるこの世の中でランダムにニュースを見れたなら、偏りも減るのでは?と思って作りました楽しめるようにガチャ風にニュースが出るようになってます<a target="_blank" rel="nofollow noopener" href="https://t.co/95AlF0d9Tr">https://t.co/95AlF0d9Tr</a></p>— じぇい👨‍💻 (@jyouj__) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/jyouj__/status/1068155029582864384?ref_src=twsrc%5Etfw">November 29, 2018</a></blockquote> <p>ぜひいろんな人に触ってもらいたいのでリツイートしてもらえると泣いて喜びます:stuck_out_tongue_closed_eyes:</p> <h2 id="作った背景"><a href="#%E4%BD%9C%E3%81%A3%E3%81%9F%E8%83%8C%E6%99%AF">作った背景</a></h2> <p>上のツイートにも書いてあるように、情報の偏りを無くそうと思いました。ただランダムにニュースを閲覧できるようにしても面白くないので、ガチャというエンターテイメント性を入れました。</p> <p>ガチャしてニュースを読むという新たなアプローチ方法です!</p> <h2 id="製作期間"><a href="#%E8%A3%BD%E4%BD%9C%E6%9C%9F%E9%96%93">製作期間</a></h2> <p>水曜日3時間、木曜日1時間の計4時間で完成させました。</p> <p>水曜日にメインの機能であるNewsAPIでニュースをランダムで取得するコードや大まかなサイトのレイアウトを作成しました。</p> <p>木曜日はTwiiterでシェアされる画像の設定や細かいレイアウトを作成しました。</p> <h2 id="ガチャっとニュースってどんなサービス?"><a href="#%E3%82%AC%E3%83%81%E3%83%A3%E3%81%A3%E3%81%A8%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%E3%81%A3%E3%81%A6%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%EF%BC%9F">ガチャっとニュースってどんなサービス?</a></h2> <p>「ガチャっと」というボタンを押すとランダムでニュースが一つガチャされます。</p> <p><img width="1252" alt="スクリーンショット 2018-11-30 18.31.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/c6babb97-62cc-50e8-dd48-1f6e18aa3082.png"></p> <p><img width="1248" alt="スクリーンショット 2018-11-30 18.32.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/5706c062-30ca-867d-2faf-0a6ac3a1c63d.png"></p> <p>1ページで完結している、シンプルなサービスです。</p> <p>もちろんスマホ対応してます。</p> <p><img width="321" alt="スクリーンショット 2018-11-30 18.35.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/f01547b4-ae28-bfaf-c91f-d67a7aa9837f.png"></p> <p><img width="314" alt="スクリーンショット 2018-11-30 18.35.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/a44e31fc-26e5-b19d-116c-142d2f6c178e.png"></p> <h2 id="使ったもの"><a href="#%E4%BD%BF%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">使ったもの</a></h2> <ul> <li><p>Django</p> <ul> <li>使い慣れているから、サクッとできる</li> <li>Flaskとかでもよかったかも</li> </ul></li> <li><p>Bulma</p> <ul> <li>1ページだけだけどレイアウトはそれなりには整えたかった</li> <li>サクッとCSS適用できて便利</li> <li>モーダルウィンドウやボタン、画像サイズの部分で活躍しました</li> </ul></li> <li><p>jQuery</p> <ul> <li>モーダルウィンドウの表示の部分で活用しました</li> <li>小さな機能ならjQueryで十分</li> </ul></li> <li><p>News API</p> <ul> <li>国別、カテゴリー別など様々なニュースを取得できるAPI</li> <li>newsapi-pythonというパッケージがあってよかった</li> <li>最新のニュースを常に取得できるのもいい!</li> </ul></li> </ul> <p>NewsAPIについては僕自身が使い方をブログに記事書いてます(笑)</p> <p><a target="_blank" rel="nofollow noopener" href="https://jyouj.hatenablog.com/entry/2018/11/26/222639">[Django]NewsAPIを使ってニュースサイトを作ってみる</a><br /> <a target="_blank" rel="nofollow noopener" href="https://jyouj.hatenablog.com/entry/2018/11/27/214832">[Django]NewsAPIを使って色々なニュースを取り出してみよう</a></p> <ul> <li><p>Github</p> <ul> <li>使わない選択肢がなかった</li> </ul></li> <li><p>Heroku</p> <ul> <li>とりあえず無料のを使った</li> <li>サーバーの知識なくてもOKなのありがたい</li> </ul></li> </ul> <h2 id="最後に"><a href="#%E6%9C%80%E5%BE%8C%E3%81%AB">最後に</a></h2> <p>今回で二つ目のサービスのリリースとなります。個人で色々開発する上のメリットは思い立ったらすぐ形にできたり、自分の気分の乗るときに作れるところだと思います。</p> <p>まだまだ開発するぞ!</p> <p>Qiitaにいいねくれたら舞って喜びます:sunglasses:</p> <p>お読みいただきありがとうございました!</p> じぇい👨‍💻Hundread運営&Punizm開発中 tag:crieit.net,2005:PublicArticle/14592 2018-11-03T22:40:22+09:00 2018-11-16T16:49:04+09:00 https://crieit.net/posts/Hundread 【個人開発】リレー式小説投稿サービス"Hundread"をリリースしました! <p>じぇい(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/jyouj__">@jyouj__</a>)です!</p> <p>一週間ちょっとでリレー式小説投稿サービス"<a target="_blank" rel="nofollow noopener" href="https://hundread.fun/">Hundread</a>(ハンドレッド)"をリリースしました!</p> <p>このサービスはもともと6月に行われたStartup Weekend Okayamaにて発表し、優勝したものです。</p> <p>その後、別のサービスの開発で全然作れていなかったのですが、急に作りたくなってきてデザインを考え直し、急遽一週間ちょっとで作りリリースすることができました!</p> <blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">リレー式小説サービス"Hundread"をリリースしました!!Hundreadは自分が投稿した小説をツイッターにシェアして続きを他の人に書いてもらうことができます!もちろん、他の人の小説の続きを書くこともできちゃいます!ぜひ、使って拡散してください!<a target="_blank" rel="nofollow noopener" href="https://t.co/qEbytWUukM">https://t.co/qEbytWUukM</a></p>— じぇい👨‍💻Punizm作ってます (@jyouj__) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/jyouj__/status/1057652433797570562?ref_src=twsrc%5Etfw">October 31, 2018</a></blockquote> <p>個人開発ではあるものの、様々な方にDMでわからないことを教えていただき無事リリースしました。本当にありがとうございます。</p> <h1 id="どんなサービスなの?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AA%E3%81%AE%EF%BC%9F">どんなサービスなの?</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://hundread.fun/">Hundread</a>は</p> <p>小説を投稿してツイッターで共有するとそのツイートを見た誰かがその続きを書いてくれる小説投稿サービスです。</p> <p>もちろん他のユーザーの小説や文章の続きも書くことができます。</p> <h3 id="ログイン画面"><a href="#%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%BB%E9%9D%A2">ログイン画面</a></h3> <p><img width="1242" alt="スクリーンショット 2018-11-01 22.08.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/9767151f-d0d3-01b5-ca7c-cc9f06a3f242.png"><br /> <img width="1247" alt="スクリーンショット 2018-11-01 22.08.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/e9943f02-a63b-9b3d-c649-81a8a96391d8.png"></p> <h3 id="トップページ"><a href="#%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8">トップページ</a></h3> <p><img width="1247" alt="スクリーンショット 2018-11-01 22.09.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/825c32a8-da0c-5347-ecf7-c6485ce40879.png"></p> <p>このサービスは質問箱のようなサービスのようにツイッターでのコミュニケーションの方法の一つになればと思っています。</p> <p>次から次に小説をリレーで回すことでこの人はこんなことを書くのか!という新たな気づきを、新しいコミュニケーションの形を、楽しんでみてください!</p> <h3 id="モバイルにも対応"><a href="#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%82%E5%AF%BE%E5%BF%9C">モバイルにも対応</a></h3> <p><img width="439" alt="スクリーンショット 2018-11-01 22.20.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/449d51fe-faca-8a28-c7ee-48a83e6f32f7.png"><br /> <img width="416" alt="スクリーンショット 2018-11-01 22.20.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/45860f71-248f-cdb3-7281-5600f84744ae.png"></p> <h1 id="使ったもの"><a href="#%E4%BD%BF%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">使ったもの</a></h1> <p>・<a target="_blank" rel="nofollow noopener" href="https://www.djangoproject.com/">Django</a><br />  Pythonのフレームワーク。一番なれてる。</p> <p>・<a target="_blank" rel="nofollow noopener" href="https://bulma.io/">Bulma</a><br />  CSSのフレームワーク。モバイル対応も簡単でデザインもいい感じにできるので、これに頼りきりでした。</p> <p>・<a target="_blank" rel="nofollow noopener" href="https://developer.twitter.com/">Twitter API</a><br />  Twitterアカウントでログインできるようにしました。</p> <p>・<a target="_blank" rel="nofollow noopener" href="https://fontawesome.com/">fontawesome</a><br />  とにかく便利</p> <p>・Github<br />  使うよね:sunglasses:</p> <p>・Heroku<br />  インフラ関連の知識がないので助かりました。hobbyプランにすると独自ドメインでもSSLになるのでとにかくありがたい。ただ、staticfileの扱いでハマってしまった。。。</p> <h1 id="助けられた記事"><a href="#%E5%8A%A9%E3%81%91%E3%82%89%E3%82%8C%E3%81%9F%E8%A8%98%E4%BA%8B">助けられた記事</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://torina.top/detail/337/">https://torina.top/detail/337/</a><br />  DetailViewとCreateViewの組み合わせを参考にさせていただきました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/okoppe8/items/76cdb202eb15aab566d1">https://qiita.com/okoppe8/items/76cdb202eb15aab566d1</a><br />  Herokuでのデプロイの時に参考にさせていただきました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://blog.mktia.com/how-to-use-environment-variables-on-heroku/">https://blog.mktia.com/how-to-use-environment-variables-on-heroku/</a><br />  Herokuで環境変数の設定をする際に参考にさせていただきました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kenjikatooo/items/07c3d911210a4ca96781">https://qiita.com/kenjikatooo/items/07c3d911210a4ca96781</a><br />  Herokuで独自ドメインを設定する際に参考にさせていただきました。</p> <p>また、困っているDjango関連の質問を<a target="_blank" rel="nofollow noopener" href="https://groups.google.com/forum/m/#!forum/django-ja">Django-ja</a>というグループにして、助けてもらいました。</p> <h1 id="最後に"><a href="#%E6%9C%80%E5%BE%8C%E3%81%AB">最後に</a></h1> <p>僕は新しい文化を創造することを常に追求してます。</p> <p>是非とも<a target="_blank" rel="nofollow noopener" href="https://hundread.fun/">Hundread</a>を遊んで、拡散してください!</p> <p>ちなみに......</p> <p>Hundreadというサービス名は</p> <p>手(Hund)で書き、読む(read)</p> <p>と</p> <p>100の英単語であるHundred</p> <p>をかけた造語です笑</p> <p>お読みいただきありがとうございます!</p> じぇい👨‍💻Hundread運営&Punizm開発中 tag:crieit.net,2005:PublicArticle/14288 2016-11-26T02:25:46+09:00 2018-10-24T16:13:50+09:00 https://crieit.net/posts/Angular2-Django Angular2アプリを全部無料で公開してみる-Django編 <p>Angular2で開発したアプリケーションを完全に無料で公開できる方法を考えてみた。</p> <h3 id="要件"><a href="#%E8%A6%81%E4%BB%B6">要件</a></h3> <p>上から順に重要度が高い。</p> <ul> <li>Angular2</li> <li>Angular2のサーバーサイドレンダリング対応</li> <li>そこそこのDB容量</li> <li>なるべく無料枠が大きいところ</li> <li>開発しやすさ</li> </ul> <h3 id="考察"><a href="#%E8%80%83%E5%AF%9F">考察</a></h3> <p>まず、Angular2をサーバーサイドレンダリングしようと思うと、node.jsでサーバーを動作させることが必要となる。<br /> これは色々調べてみると、恐らく速度や無料枠を比較するとherokuがベストかと思う。<br /> 2016年現在は無料で停止なしで稼働できる。</p> <p>上記は確定っぽいのでDB側を考えてみる。</p> <p>容量の無料枠で一番大きいのは恐らくAmazon DynamoDBの25GB。</p> <p>様々な言語のSDKがあるのでどのサーバーでも行けると思う。<br /> Angular2からも直接行けるが接続情報が筒抜けになるし、直接DB接続だと複数の処理を1リクエストにまとめたりができないので、<br /> 費用が発生する可能性が高くなる。<br /> やはり一度サーバーを経由したいところ。</p> <p>Angular2 → Amazon lambda → Amazon DynamoDB</p> <p>というのもなかなか良さそう。<br /> ただし認証によってアクセスできる処理をきっちり整理する必要がある。<br /> こちらはまた今後確認してみたい。</p> <p>(追記)<br /> 調べてみたらcognito + lambda + DynamoDBを使用する必要がありそう。<br /> ちょっとこれはめんどそうだしcognitoは未認証ユーザーという概念があるが、<br /> もしそれも課金計算に含めるなら費用が発生する可能性は高くなりそう。</p> <h3 id="構成"><a href="#%E6%A7%8B%E6%88%90">構成</a></h3> <p>今回は総合的なバランスを考えて下記を試してみた。</p> <p>Angular2 → GAE (Python + Django) + Datastore</p> <ul> <li>直接APIサーバーにアクセスするだけなのでサーバーを分けない場合とアクセス時間が変わらない。</li> <li>Datastoreが1GB(?)無料なのでそこそこ。</li> <li>Djangaeを使うとDjangoのモデルそのままでDatastoreにアクセスできるので、<br /> この環境用の特別なプログラムで開発をする必要がない。</li> <li>pythonはpython, python3, pip, pip3と分けてインストールされたり切り替えたりができたりするので、<br /> python2しか使えないGAEでもローカルの開発環境を汚さずに開発しやすい。</li> <li>pythonはリモートで本番のDjango用のコマンドを実行できるのでマイグレーションなども簡単。</li> </ul> <h3 id="Angular2側"><a href="#Angular2%E5%81%B4">Angular2側</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/angular/universal-starter">GitHub - angular/universal-starter: Angular 2 Universal starter kit by @AngularClass</a></p> <p>ng newしないで、上記をそのままcloneして改造していくのがいい。<br /> デフォルトのコマンドでherokuでそのまま動くし、<br /> Visual Studio Codeでもデバッグできる。</p> <p>必要であればangular-cliで新規作成したプロジェクトから必要なファイルだけコピーしてくると良いと思う。</p> <h3 id="GAE側"><a href="#GAE%E5%81%B4">GAE側</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/ottoyiu/django-cors-headers">GitHub - ottoyiu/django-cors-headers: Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)</a></p> <p>別サーバーなのでこれをいれておけば動く。<br /> いちいち全部のResponseにヘッダーを指定する必要はない。</p> <p>接続や設定などはGAEの特別な仕様などがあり最初はつまずくが、<br /> 解決すればあとは普通と同じように開発ができる。</p> <p>チュートリアルで操作させられるが、どうもGithubと連携できる開発環境みたいなのもあるようだ。</p> <h3 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3> <p>たいしてアクセスやデータ量の無いアプリケーションは、こんな感じで無料でなるべく開発しやすい環境を模索すると面白そうだ。</p> <p>APIサーバー側は、さくらレンタルなど安いサーバーを別途持っていればそれをそのまま使うのも簡単だ。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14297 2016-08-09T01:11:30+09:00 2018-10-26T12:48:25+09:00 https://crieit.net/posts/Twitter-5 Twitterを作る 第5回 フォロー <p>引き続き他のユーザーをフォローする部分を進める。</p> <h3 id="モデル"><a href="#%E3%83%A2%E3%83%87%E3%83%AB">モデル</a></h3> <pre><code class="python">class Follow(models.Model): """フォロー""" user = models.ForeignKey(User, verbose_name='ユーザー', related_name='follows') target = models.ForeignKey(User, verbose_name='フォローユーザー', related_name='followers') created = models.DateTimeField(auto_now_add=True) </code></pre> <p>モデル定義はこれだけ。<br /> view側ではこれの一覧をjsonで返したり、<br /> あとは追加削除するだけで特筆することもない。</p> <h3 id="フォローボタン"><a href="#%E3%83%95%E3%82%A9%E3%83%AD%E3%83%BC%E3%83%9C%E3%82%BF%E3%83%B3">フォローボタン</a></h3> <p>ボタンはコンポーネント化し、画面のどこに配置しても同じように動作するようにする。<br /> 今回も実際に画面右のおすすめユーザーの一覧に表示したものと、<br /> そこのユーザー名をクリックして他ユーザーのプロフィール画面に表示されるものは同じもの。</p> <pre><code class="javascript"><MainFollowButton user={this.props.user} follows={this.props.follows} onFollowsUpdated={this.props.onFollowsUpdated} /> </code></pre> <p>userでターゲットユーザーを指定。<br /> followsは現在のフォロー一覧配列で、<br /> ボタンを押して追加、削除するとこの配列から新たな配列を作り、<br /> onFollowsUpdatedコールバックを呼び出して親にsetStateしてもらうことで適切に画面上が更新される。</p> <h3 id="自分のタイムラインの修正"><a href="#%E8%87%AA%E5%88%86%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AE%E4%BF%AE%E6%AD%A3">自分のタイムラインの修正</a></h3> <p>フォロー機能ができたので、自分のタイムラインにはフォローしている人の投稿も表示する必要がある。<br /> 取得するPostのfilterをユーザー指定からin指定に変更するだけ。</p> <h3 id="今後"><a href="#%E4%BB%8A%E5%BE%8C">今後</a></h3> <ul> <li>検索(MeCabで解析したワードやハッシュタグで検索)</li> <li>ユーザープロフィールの変更</li> <li>非ログイン状態でもアクセスできる箇所の調整</li> <li>OAuth導入によるAPIの作成</li> <li>切りが良いので一旦休載</li> </ul> <p>Dumitter</p> <p><a target="_blank" rel="nofollow noopener" href="https://alphabrend.sakura.ne.jp/dumitter/">https://alphabrend.sakura.ne.jp/dumitter/</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14298 2016-08-05T19:44:47+09:00 2018-11-16T16:55:11+09:00 https://crieit.net/posts/Bash-on-Ubuntu-on-Windows-Django Bash on Ubuntu on WindowsでDjango <p>Windows10のアニバーサリーアップデートにて<br /> Bash on Ubuntu on Windowsが使用できるようになった。<br /> 結構色々普通にちゃんと動くみたいなので、Djangoを動かしてみた。</p> <h3 id="python"><a href="#python">python</a></h3> <p>最初からpython2もpython3も入っているらしい。</p> <pre><code class="bash"># python3 --version Python 3.4.3 </code></pre> <h3 id="pip"><a href="#pip">pip</a></h3> <p>pip3を入れる。</p> <pre><code class="bash"># apt-get install python3-pip </code></pre> <h3 id="virtualenv"><a href="#virtualenv">virtualenv</a></h3> <p>virtualenvをいれる。</p> <pre><code class="bash"># pip3 install virtualenv </code></pre> <h3 id="仮想環境作成"><a href="#%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83%E4%BD%9C%E6%88%90">仮想環境作成</a></h3> <pre><code class="bash"># virtualenv test # cd test # source bin/activate (test) pip install Django=1.10 (test) django-admin startproject testprj (test) cd testprj (test) ./manage.py startapp testapp (test) ./manage.py runserver </code></pre> <p>これで表示されたURLにブラウザでアクセスすると普通に表示される。<br /> Bash on Ubuntu on Windowsすごい。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14300 2016-08-02T01:10:31+09:00 2018-10-02T20:26:50+09:00 https://crieit.net/posts/Twitter-3 Twitterを作る 第3回 投稿 <p>投稿機能の作成を進めた。実際の画面は下記のような感じでTwitterと構成は同じような形にしてある。<br /> 各パーツはmaterial-ui。すごく便利。</p> <p><a href="https://crieit.now.sh/upload_images/da575d4c4b83e987cb4d4a2e6c7b4ca25b0d18af5a469.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/da575d4c4b83e987cb4d4a2e6c7b4ca25b0d18af5a469.png?mw=700" alt="" /></a></p> <p>投稿ボタンを押すと下記のようなウィンドウが出てくる。</p> <p><a href="https://crieit.now.sh/upload_images/e7f029e271fc33d32e17cb59b545e8045b0d18b008f01.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/e7f029e271fc33d32e17cb59b545e8045b0d18b008f01.png?mw=700" alt="" /></a></p> <h3 id="モデルの作成"><a href="#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">モデルの作成</a></h3> <p>モデルは下記のような感じになった。</p> <pre><code class="python">class Post(models.Model): """投稿""" user = models.ForeignKey(User, verbose_name='ユーザー', related_name='posts') repost = models.ForeignKey( "Post", verbose_name='リポスト', related_name='reposts', null=True ) citing = models.ForeignKey( "Post", verbose_name='引用', related_name='citings', null=True ) thread = models.ForeignKey( "Post", verbose_name='コメント先', related_name='comments', null=True ) body = models.CharField('内容', max_length=140) image = models.ImageField(upload_to='posts/') created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) deleted = models.BooleanField('削除済', default=False) def __str__(self): if len(self.body) > 10: return str(self.body)[:10] + '...' return self.body class PostWord(models.Model): """単語""" post = models.ForeignKey(Post, verbose_name='投稿', related_name='post_words') word = models.CharField('単語', max_length=64) created = models.DateTimeField(auto_now_add=True) def __str__(self): return self.word class PostTag(models.Model): """タグ""" post = models.ForeignKey(Post, verbose_name='投稿', related_name='post_tags') name = models.CharField('タグ', max_length=64) created = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name </code></pre> <p>投稿フォームから投稿が行われると、Postとして保存される。<br /> この時にハッシュタグは正規表現で解析してPostTagとして保存する。</p> <p>あとはPostWordに投稿で使用されている単語などを保存してトレンド等に使う必要があると思うが、<br /> MeCabの準備などが必要だったりして面倒なのでとりあえず後回し。<br /> まずは大まかな流れを優先する。</p> <h3 id="投稿一覧"><a href="#%E6%8A%95%E7%A8%BF%E4%B8%80%E8%A6%A7">投稿一覧</a></h3> <p>jsonで読み込んでsetStateするだけで勝手に表示してくれる。<br /> 各投稿はmaterial-uiのcardそのまま。</p> <p>下にスクロールすると次の50件を読み込んで表示。<br /> 本家はガンガンスクロールできるのでレスポンスの良さや調整の努力がうかがえる。</p> <p>jsonについて、エンティティから自動で変換も試したが、<br /> リレーション部分を含ませることができなかったのと、<br /> よくよく考えると最終的には他人の投稿も含まれるのでセキュリティな問題を考えて、<br /> json用の辞書インスタンスの作成は手動で代入して作ることにした。</p> <h3 id="投稿"><a href="#%E6%8A%95%E7%A8%BF">投稿</a></h3> <p>投稿すると現在の一覧よりも最新の投稿がjsonで返ってくるので既存の配列にマージするだけ。</p> <h3 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3> <p>次はReactのComponentの構成考察や、あとはフォロー機能を作らないと何も進まなそうだ。<br /> djangoのview側はデータ登録したり取得したりしてjsonを返すだけで何も特筆することがない。</p> <p>Dumitter</p> <p><a target="_blank" rel="nofollow noopener" href="https://alphabrend.sakura.ne.jp/dumitter/">https://alphabrend.sakura.ne.jp/dumitter/</a></p> <p><a href="https://crieit.net/posts/Twitter-4">Twitterを作る 第4回 コンポーネント構成考察</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14302 2016-07-24T21:26:15+09:00 2018-10-17T19:37:08+09:00 https://crieit.net/posts/Twitter-2 Twitterを作る 第2回 認証 <p>まずはユーザー登録。これがなければ何も話が進まない。<br /> ひとまず下記の第3回までを見てさくっと動作確認とユーザーテーブル作成まで行う。</p> <p><a target="_blank" rel="nofollow noopener" href="http://qiita.com/kaki_k/items/511611cadac1d0c69c54">Python Django入門 (1)</a></p> <p><a target="_blank" rel="nofollow noopener" href="http://qiita.com/kaki_k/items/7b178ad39394a031b50d">Python Django入門 (3)</a></p> <h3 id="ログイン前トップページ"><a href="#%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E5%89%8D%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8">ログイン前トップページ</a></h3> <p>material-uiでさくっと作成。Twitterのトップ画面を見ると今回必要そうなコンテンツはこれだけ。<br /> アカウント作成でsignupページヘ。</p> <p><a href="https://crieit.now.sh/upload_images/25c52bd03d41a78fe11eb47d165881035b0d18b4692e5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/25c52bd03d41a78fe11eb47d165881035b0d18b4692e5.png?mw=700" alt="" /></a></p> <h3 id="ユーザー登録ページ"><a href="#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E7%99%BB%E9%8C%B2%E3%83%9A%E3%83%BC%E3%82%B8">ユーザー登録ページ</a></h3> <p><a href="https://crieit.now.sh/upload_images/a519923405e2c9c1623e609656c0258d5b0d18b5e439f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a519923405e2c9c1623e609656c0258d5b0d18b5e439f.png?mw=700" alt="" /></a></p> <p>こちらも同様にぱぱっと作成。<br /> このページはユーザー登録とログインのサーバーへの通信が必要なのだが、<br /> そのままだとCSRFでエラーになるのでensure_csrf_cookieを設定している。<br /> また、後述するconfigライブラリを作成している。</p> <p>ちなみにログインを押すとモーダルが出てくる。</p> <p><a href="https://crieit.now.sh/upload_images/b521711f76f0a2b601d366c86199d9075b0d18b68a7b1.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b521711f76f0a2b601d366c86199d9075b0d18b68a7b1.png?mw=700" alt="" /></a></p> <h3 id="configライブラリ"><a href="#config%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA">configライブラリ</a></h3> <p>全体の共通機能として下記のようなファイルを作成した。</p> <p>app/lib/config.js</p> <pre><code class="javascript">const config = { defaultHeaders: { "X-CSRFToken": getCookie('csrftoken'), "Accept": "application/json", }, url: (url) => { if (url.charAt(0) === '/') { url = url.substr(1); } return '/dumitter/' + url; }, } module.exports = config; </code></pre> <p>現在さくらサーバーのそのままのURL(SSL)なので、<br /> 今後独自ドメインを使う場合全箇所の修正は大変になるためurl補正メソッドを作成。<br /> (最初から独自ドメインなら絶対パスで良いのだが)</p> <p>また、ajaxの際にCSRFのトークンを送信するため、共通のデフォルトヘッダを定義している。<br /> (getCookieは検索すれば出てくる)</p> <h3 id="バリデーション &amp; 登録処理"><a href="#%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3+%26amp%3B+%E7%99%BB%E9%8C%B2%E5%87%A6%E7%90%86">バリデーション & 登録処理</a></h3> <p>postするとjsonを返却するアクション。<br /> resultがtrueなら成功でログイン済みなのでトップページへリダイレクト。<br /> falseならjsonに各フィールド名のエラーメッセージが入っているのでmaterial-uiのTextFieldのerrorTextにセット。</p> <p>バリデーションの処理は全部python側でやっている。<br /> js側でもいいかと思ったのだが、パスワードの細かいバリデーションがdjango側に入っているのでそちらに統一した。<br /> (設定ファイルで細かいパスワードのバリデーション方法を指定することができる)</p> <p>本当はもっとちゃんとした書き方がありそうだが、この処理はここだけだしいいかと思いバリデーションもベタ書き。</p> <pre><code class="python">from django.http.response import JsonResponse from django.contrib.auth import authenticate, login as authLogin from django.contrib.auth.models import User from django.core.validators import validate_email from django.contrib.auth.password_validation import validate_password from django.db import IntegrityError from django.core.exceptions import ValidationError import re def create(request): errors = {} if re.match(r'^[\da-zA-Z_]+$', request.POST['name']) is None: errors['name'] = '半角英数字で入力して下さい。' try: validate_email(request.POST['email']) except ValidationError as e: errors['email'] = e.messages try: validate_password(request.POST['password']) except ValidationError as e: errors['password'] = e.messages if len(errors) == 0: try: user = User.objects.create_user( username=request.POST['name'], email=request.POST['email'], ) except IntegrityError as e: if 'email' in str(e): errors['email'] = 'そのメールアドレスは既に使用されています。' elif 'name' in str(e): errors['name'] = 'そのユーザー名は既に使用されています。' if len(errors) != 0: errors['result'] = False return JsonResponse(errors) user.set_password(request.POST['password']) user.save() return login(request) def login(request): authed = authenticate( username=request.POST['name'], password=request.POST['password'], ) result = {'result': True} if authed is not None: authLogin(request, authed) else: result['result'] = False return JsonResponse(result) </code></pre> <p>新規登録後は自動的にログインするが、通常のログインのプログラムと全く同じだったので関数を流用している。</p> <p>ログイン後はトップページにリダイレクトするが、<br /> ここではログインの場合別のテンプレートを表示するようにしている。</p> <pre><code class="python">def index(request): if request.user.is_authenticated(): template = 'main.html' else: template = 'index.html' return render(request, template) </code></pre> <h3 id="React側"><a href="#React%E5%81%B4">React側</a></h3> <p>多分邪道かも知れないが下記のようなことを行っている。</p> <pre><code class="javascript">const element = document.getElementById('auth-regist'); if (element != undefined) { ReactDOM.render(<AuthRegist />, element); } </code></pre> <p>認証側はこれ以上ページを作るつもりはないので適当。<br /> 認証後はルーティングを使いたい。</p> <p>これで認証が完成したので次は投稿を作っていく予定。</p> <p><a target="_blank" rel="nofollow noopener" href="https://alphabrend.sakura.ne.jp/dumitter/">https://alphabrend.sakura.ne.jp/dumitter/</a></p> <p><a href="https://crieit.net/posts/Twitter-3">Twitterを作る 第3回 投稿</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14303 2016-07-24T07:47:26+09:00 2018-10-30T14:17:36+09:00 https://crieit.net/posts/Twitter-1 Twitterを作る 第1回 概要 <p>これからTwitterを作って行くところを少しずつ公開していきたいと思う。<br /> 下記のような環境で作成していく。</p> <h3 id="Django"><a href="#Django">Django</a></h3> <p>Djangoはpythonのフレームワーク。<br /> 慣れているCakePHPの方が早いが面白くないのでDjangoを練習しつつ作成。<br /> (python3.5 + Django1.9.7)</p> <p>ちなみにtwitterはRuby on RailsからJavaVMに移行していっている様で、pythonとは何の関係もなさそう。<br /> ただ、Instagramはdjangoで作成されているらしい。<br /> また、pythonはGoogleでよく利用されているし、良い言語であることは間違いなさそう。</p> <p>実際に、使ってみてまだちょっとしか経っていないがかなり好きになってきている。<br /> ひとまず現状の理由としては下記のようなものがあげられる。</p> <h4 id="管理画面が勝手に作られる"><a href="#%E7%AE%A1%E7%90%86%E7%94%BB%E9%9D%A2%E3%81%8C%E5%8B%9D%E6%89%8B%E3%81%AB%E4%BD%9C%E3%82%89%E3%82%8C%E3%82%8B">管理画面が勝手に作られる</a></h4> <p>adminページがあり、DBやモデルの作成が進んで行くと勝手に管理画面が作られていく。<br /> 仕様の細かい案件等では使いづらいかもしれないが、<br /> こうやって一人で勝手に作っていったり要件のゆるい案件では非常に役立つし無駄な工数削減になる。</p> <h4 id="情報が見つかりやすい"><a href="#%E6%83%85%E5%A0%B1%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%84">情報が見つかりやすい</a></h4> <p>公式のドキュメントにはわりと欲しい情報が載っているし、<br /> 検索すればそこそこすぐに情報が見つかりハマりにくい気がする。<br /> もしかすると英語前提かも知れないがプログラムなのであまり関係ないだろう。</p> <h4 id="進化してきている"><a href="#%E9%80%B2%E5%8C%96%E3%81%97%E3%81%A6%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B">進化してきている</a></h4> <p>何かやりたいことがある時、古い情報が見つかると、「面倒だな…」と思うことがあるが、<br /> 最新の情報をよくよく見ていると結構洗練されていたりする。<br /> 最新のWEB開発が好きな人は結構ハマるのではないかと思う。</p> <h4 id="面倒な部分"><a href="#%E9%9D%A2%E5%80%92%E3%81%AA%E9%83%A8%E5%88%86">面倒な部分</a></h4> <p>慣れていないと環境構築が結構面倒かもしれない。<br /> 今のところWindowsでMySQLに接続する方法が分かっていなかったりする。<br /> (サーバーにあげて動作確認している)</p> <h3 id="React + webpack + superagent + material-ui"><a href="#React+%2B+webpack+%2B+superagent+%2B+material-ui">React + webpack + superagent + material-ui</a></h3> <p>Twitterは基本的にSPAっぽいので、基本的にjavascriptで作成し、サーバー側はAPIとして動かしていく必要がある。<br /> そうなるとReactかAngular2になってくると思うが、今回はちょっと型管理が面倒なのでReactを選んだ。</p> <p>サーバーとの通信はsuperagentを利用し、webpackでビルドする。<br /> とりあえず、webpackで1ファイルになってくれるのはやはり非常に楽。<br /> 多くのストレスを軽減してくれる。</p> <p>UIはmaterial-uiを使用する。<br /> よく出来ていて、今回の様なアプリケーションの場合はすごく使いやすい。</p> <h3 id="アプリ名"><a href="#%E3%82%A2%E3%83%97%E3%83%AA%E5%90%8D">アプリ名</a></h3> <p>Djangoで作成するdummyのtwitterなのでDumitterとする。</p> <h3 id="方針"><a href="#%E6%96%B9%E9%87%9D">方針</a></h3> <p>可能な限り似せる。ただしすぐできる範囲。面倒なことは一切やらない。<br /> (ほぼmaterial-uiそのまま)</p> <p>あと記事の方針としてはなるべく進めていく状況や難しい箇所の説明を入れたいので、<br /> 他で調べれば出てくるような細かい技術は解説しない予定。<br /> あくまで娯楽であり教材ではない。</p> <h3 id="公開場所"><a href="#%E5%85%AC%E9%96%8B%E5%A0%B4%E6%89%80">公開場所</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://alphabrend.sakura.ne.jp/dumitter/">https://alphabrend.sakura.ne.jp/dumitter/</a><br /> (さくらレンタルで無理やり動かしてるので非常に重いです)</p> <p>次回から実際に開発状況を公開していく予定。</p> <p><a href="https://crieit.net/posts/Twitter-2">Twitterを作る 第2回 認証</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14304 2016-07-19T04:14:38+09:00 2018-10-27T16:34:52+09:00 https://crieit.net/posts/django さくらのレンタルスタンダードにdjangoを入れて公開 <p>さくらの共用レンタルのスタンダードでのdjango公開方法のメモ。<br /> 環境としては下記の通り。</p> <ul> <li>python3.5</li> <li>django1.9.7</li> <li>virtualenv</li> <li>MySQL接続</li> </ul> <h3 id="python3.5のインストール"><a href="#python3.5%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">python3.5のインストール</a></h3> <p>ネットで調べてインストール。<br /> .cshrcを見ると下記を追記していた。</p> <ul> <li>pathにpython/binフォルダの追加</li> <li>setenv PTYHON にpython/libフォルダの指定</li> </ul> <h3 id="仮想環境"><a href="#%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83">仮想環境</a></h3> <p>作成(非公開フォルダで良い)と切り替え</p> <pre><code class="csh">virtualenv myenv cd myenv source bin/activate.csh </code></pre> <p>抜けるときはdeactivate</p> <h3 id="django &amp; MySQL関連のインストール"><a href="#django+%26amp%3B+MySQL%E9%96%A2%E9%80%A3%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">django & MySQL関連のインストール</a></h3> <pre><code class="csh">pip install django==1.9.7 pip install PyMySQL pip install mysqlclient </code></pre> <p>manage.pyに下記追加</p> <pre><code class="python">import pymysql pymysql.install_as_MySQLdb() </code></pre> <p>あとはcreatesuperuser等。<br /> 詳しくは分からないがPyMySQLとmysqlclient両方を追加しないと上手くいかなかった。</p> <h3 id="公開"><a href="#%E5%85%AC%E9%96%8B">公開</a></h3> <p>公開フォルダにはdjango.cgiを設置するのだが、python3で動作するものを使う必要があるので下記を使用。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/chibiegg/django-cgi/blob/master/django-python3.cgi">django-cgi/django-python3.cgi at master · chibiegg/django-cgi · GitHub</a></p> <p>中身は下記を設定。<br /> 1行名は仮想環境のbin/pythonのパス。<br /> sys.path.appendをしろ、というところに下記を追記。</p> <pre><code class="python">sys.path.append('仮想環境パス/lib/python3.5/site-packages') sys.path.append("仮想環境パス/プロジェクト名") </code></pre> <p>末尾あたりに</p> <pre><code class="python">os.environ['DJANGO_SETTINGS_MODULE'] = 'プロジェクト名.settings' </code></pre> <p>あとは.htaccessも設置。<br /> (RewriteBaseは適宜指定)</p> <pre><code class="sh">RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ django.cgi/$1 [QSA,L] </code></pre> <p>とりあえず上記でアクセスできるようになるのだが、<br /> adminにアクセスしてみるとcss等が正しく反映されていない。</p> <p>ローカル環境のrunserverと違い、staticが正しく表示されないので、<br /> collectstaticを利用しファイルを公開フォルダにコピーする必要がある。<br /> まずsettings.pyに下記を設定。(バーチャルホストを使わない例)</p> <pre><code class="python">STATIC_ROOT = '/home/username/www/myapp/static' STATIC_URL = '/myapp/static/' </code></pre> <p>この状態で下記を実行でコピーされる。</p> <pre><code class="csh">python manage.py collectstatic </code></pre> <p>これで公開までの一通りの準備が完了。<br /> (この先の諸々も問題なく動作するかは不明)</p> だら@Crieit開発者