firebase functionsにデプロイした関数をテストするたびに
firebase deploy –only functions
を実行し、デプロイが完了するまで待つのは大変時間がかかるので、基本的には
firebase emulators:start
でローカル環境で実行する。
データベース接続処理などを行う場合、一般的にはfirebaseの環境変数に
firebase functions:config:set database_password=”*****”
等でコンソールから保存した内容をコード上で
functions.config().database_passwordといった具合で参照するが、これは本番環境でしか使用できない。
したがってエミュレーターでローカルでテストしたい場合には別途.envファイルをfunctionsフォルダ内に作成してテスト環境用に別のコードで.envを参照していたが、画期的な方法があったのでメモ
firebase functions:config:get > .runtimeconfig.json
上記コマンドを実行することで、firebase functionsに保存していた環境変数がローカルのカレントディレクトリに.runtimeconfig.jsonというファイルで保存される。
そしてfirebase emulators:start –import=.runtimeconfig.jsonでエミュレーターを実行することにより、本番環境と同じコードで環境変数を参照することができる。
“https://androidpublisher.googleapis.com/androidpublisher/v3/applications”エンドポイントを使用して、ユーザーが購入したサブスクリプションの期限を調べようとしたら、
{
"message": "The current user has insufficient permissions to perform the requested operation.", "domain": "androidpublisher", "reason": "permissionDenied" }
が発生し続けた。
GCPやPlay console上でもサービスアカウントに必要な権限は全て付与したつもりでいたが、原因がわかったのでメモ
原因はこのサービスアカウントを設定するよりも先にアプリ内課金アイテム(今回の場合は定期購入)をプレイストア上で作成してしまっていたこと。
この場合は何でもいいのでアイテムに変更を加えないといけないらしい。適当に名前など一部情報を変更して更新したところ、permissionDeniedが解消され、無事必要なデータをGoogle Develope APIを通して取得できた。
open -a Simulator
いままでxcodeを開いて、メニューからシミュレーターを起動していたが直接Simulatorを起動できたので備忘録。
emulator -avd Pixel_6a
Pixel_6aはインストール済みのエミュレーター名
インストール済みのエミュレーターは以下のコマンドで確認
adb devices
adbコマンドがインストールされていない場合はAndroid Studio SDKのパスが通っているか確認
通常は
/Users/AndroidSDK/platform-tools
等のPATHを通す
Flutterでプロジェクトを作成
flutter create --platforms=android,ios my_project
XCodeでios/Runner.xcworkspaceを開きProduct>Archiveを実行しStore Connectにアップロード
Store Connectで色々設定して審査
カレンダー拡張機能には、異なるカレンダー形式の間で変換を簡単にする関数などが含まれています。
これは、紀元前4713年1月1日から始まる日数をカウントするユリウス日数を基にしています。
注: カレンダー形式を変換するには、まずユリウス日数に変換してから、選択したカレンダーに変換する必要があります。
注: ユリウス日数はユリウス暦とは異なります!
カレンダー関数を使用するには、PHPを –enable-calendar でコンパイルする必要があります。
Windows版のPHPには、この拡張機能のサポートが組み込まれています。
関数 | 説明 |
---|---|
cal_days_in_month() |
指定された年とカレンダーの月の日数を返します |
cal_from_jd() |
ユリウス日数を指定されたカレンダーの日付に変換します |
cal_info() |
指定されたカレンダーに関する情報を返します |
cal_to_jd() |
指定されたカレンダーの日付をユリウス日数に変換します |
easter_date() |
指定された年の復活祭のUnixタイムスタンプを返します |
easter_days() |
指定された年の復活祭の日付が3月21日から何日後にあるかを返します |
frenchtojd() |
フランス共和暦の日付をユリウス日数に変換します |
gregoriantojd() |
グレゴリオ暦の日付をユリウス日数に変換します |
jddayofweek() |
曜日を返します |
jdmonthname() |
月の名前を返します |
jdtofrench() |
ユリウス日数をフランス共和暦の日付に変換します |
jdtogregorian() |
ユリウス日数をグレゴリオ暦の日付に変換します |
jdtojewish() |
ユリウス日数をユダヤ暦の日付に変換します |
jdtojulian() |
ユリウス日数をユリウス暦の日付に変換します |
jdtounix() |
ユリウス日数をUnixタイムスタンプに変換します |
jewishtojd() |
ユダヤ暦の日付をユリウス日数に変換します |
juliantojd() |
ユリウス暦の日付をユリウス日数に変換します |
unixtojd() |
Unixタイムスタンプをユリウス日数に変換します |
以下はPHPのカレンダー関数を使用した例です。
<?php
echo cal_days_in_month(CAL_GREGORIAN, 2, 2020); // 2020年2月の月の日数
?>
<?php
$jd = 2458849; // ユリウス日数
$gregorian = cal_from_jd($jd, CAL_GREGORIAN);
print_r($gregorian); // グレゴリオ暦の日付
?>
SQL SELECT DISTINCT文は、重複しない異なる値のみを返すために使用されます。
Customersテーブルから異なるすべての国を選択します:
SELECT DISTINCT Country FROM Customers;
テーブル内の列はしばしば多くの重複する値を含むことがありますが、異なる(重複しない)値のみをリストしたい場合があります。
SELECT DISTINCT column1, column2, ...
FROM table_name;
以下は例で使用されるCustomersテーブルからの一部です:
CustomerID | CustomerName | ContactName | Address | City | PostalCode | Country |
---|---|---|---|---|---|---|
1 | Alfreds Futterkiste | Maria Anders | Obere Str. 57 | Berlin | 12209 | Germany |
2 | Ana Trujillo Emparedados y helados | Ana Trujillo | Avda. de la Constitución 2222 | México D.F. | 05021 | Mexico |
3 | Antonio Moreno Taquería | Antonio Moreno | Mataderos 2312 | México D.F. | 05023 | Mexico |
4 | Around the Horn | Thomas Hardy | 120 Hanover Sq. | London | WA1 1DP | UK |
5 | Berglunds snabbköp | Christina Berglund | Berguvsvägen 8 | Luleå | S-958 22 | Sweden |
DISTINCTキーワードを省略すると、SQL文はCustomersテーブルのすべてのレコードから「Country」値を返します:
SELECT Country FROM Customers;
DISTINCTキーワードをCOUNT関数で使用することで、異なる国の数を返すことができます。
SELECT COUNT(DISTINCT Country) FROM Customers;
注:COUNT(DISTINCT column_name)はMicrosoft Accessデータベースではサポートされていません。
MS Access用の回避策はこちらです:
SELECT Count(*) AS DistinctCountries
FROM (SELECT DISTINCT Country FROM Customers);
GoogleサーチコンソールでURLがインデックス登録されているか確認してみた結果、
「ページはインデックスに登録されていません: 重複しています。ユーザーにより、正規ページとして選択されていません」と表示され、インデックス登録されていなかった場合、Googleによって指定したURLが正規のページと判断されなかったということになります。
正規のページとは、以下の2つのURLが存在した場合、かつ同じページ(構造やコンテンツが同一)を示している場合、Googleはどちらか一つのURLを優先し、その優先されたページが正規ページとなります。
Googleは自動で正確な情報、かつ有益と判断した方を正規ページとして扱うとありますが、必ずしもそれが管理者にとってふさわしい結果であるとは限りません。
そんな場合に管理者が明示的に特定のURLを正規ページとしてマークし、Googleに伝える方法を紹介します。
例えばhttps://example.com/dresses/green-dressesというURLを正規ページにしたいとします。しかし何らかの方法でこのページにたどり着くURLが複数個ある場合、以下の手順でこのURLを正規ページに指定することができます。
<link rel="canonical" href="https://example.com/dresses/green-dresses" />
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.example.com/dresses/green-dresses">
以上です。
私の経験ではユーザーが指定した正規ページが100%Googleによって正規ページとして扱われるわけではありませんでしたが、明示的に正規ページを指定することにより、インデックス登録される可能性が少しは上がります。
Djangoで作成したモデルをobjects.filter()メソッド等で抽出した場合、
‘django.db.models.query.QuerySet’型のオブジェクトが返されます。
このQuerySetはテンプレート内でもviews.pyの中でもリストの用にして扱うことができます。
別々の条件でQuerySetを生成したけれど、一つのQuerySetとしてまとめて扱いたいという場合に複数のQuerySetを一つのQuerySetに結合する方法を解説します。
結論から言うと、unionメソッドを使うことで複数のQuerySetを結合することができます。以下ではunionメソッドの使い方を解説していきます。
今回はnameとpriceをフィールドにもつProductというモデルを利用していきます。
Productは既に5つ用意してあり、それぞれをProduct.objects.all()で取得した結果をテンプレートから出力した結果が以下のようになっています。
all_products = Product.objects.all()
</table>
<hr>
<h2>Queryset_2</h2>
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in Queryset_2%}
<tr>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
それではさっそくunionの使い方を説明していきます。
まずは結合する前のQuerySetが必要なので、Productモデルからpriceが300のものと500のものをそれぞれfilter()メソッドで抽出していきます。
それぞれをqueryset_1、queryset_2という変数に代入しておき、それらをunionでまとめたものをqueryset_3とします。
以下のコードで上記のことを行っています。
views.py
from django.shortcuts import render
from .models import Product
# Create your views here.
def result(request):
all_products = Product.objects.all()
queryset_1 = Product.objects.filter(price=300)
queryset_2 = Product.objects.filter(price=500)
queryset_3 = queryset_1.union(queryset_2)
context = {
'all_products': all_products,
'queryset_1': queryset_1,
'queryset_2': queryset_2,
'queryset_3': queryset_3,
}
return render(request, 'result.html', context)
result.html
<h2>全商品</h2>
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in all_products%}
<tr>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr>
<h2>Queryset_1</h2>
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in queryset_1%}
<tr>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr>
<h2>Queryset_2</h2>
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in Queryset_2%}
<tr>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr>
<h2>Queryset_3(Queryset_1 + Queryset_2)</h2>
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
{% for product in queryset_3%}
<tr>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
出力結果
queryset_1.union(queryset_2)という構文で二つのQuerySetを一つにまとめることができます。
以下書籍を参考にしました。
最近Amazonのアソシエイトリンクを生成するためのProduct Advertisin API、通称PA-APIが5.0にアップデートされ、さまざまな機能が追加された。
その中の一つであるScratchpadはブラウザ上で簡単にAPIの動作を確認できるツールで、取得したい情報をブラウザ上で選択するだけで出力結果とコードを表示してくれる強力なツール。
今回はそのScratchpadについて基本的な使い方を紹介していこうと思う。
ScratchpadはPA-APIにリクエストを送信し、結果を取得することができるツールであり、同時にいくつかのプログラミング言語でのサンプルコードも返してくれる。そのためPA-APIがどのように動作するのかを手軽に確認することができ、サンプルコードを自身のプロジェクトにそのまま組み込むこともできるため、コーディングの手間も大幅に省くことができる強力なツールである。
なお、使用するためにはPA-APIのアクセスキーとシークレットキーを事前に取得しておく必要がある。
それでは早速Scratchpadの使い方を説明していく。下記手順に沿って進めていけばAmazon上の商品を特定のキーワードで検索したり、特定の商品の情報を取得することができる。APIのアクセスキーとシークレットキーは取得済みと仮定して進める。
まずはScratchpadを開いてみよう。https://webservices.amazon.com/paapi5/scratchpad/index.htmlから開くと下記のような画面が表示される。
次に左のSelect Option内のGetBrowseNodesをクリックする。
すると上画像のセクションが表示されるので、順に入力していく。
Marketplaceは日本のアマゾンの商品を紹介する場合はwww.amazon.co.jpを選択する。
Partner TypeはAssociatesを選択。
Partner Tagはアソシエイトセントラルにログインした際に右上に表示されるアソシエイトIDを入力すればよい。
Access KeyとSecret Keyは事前に取得しておいたものを入力。取得していない場合はアソシエイトセントラルのツール>Product Advertisin API>認証キーの管理より認証情報の追加をクリックして取得することができる。
上記の内容の入力が済んだらあとは商品情報を取得するだけである。
Select OptionのItem内にGetValiations、GetItems、SearchItemsの3つがあるので、まずは特定の商品情報を取得するGetItemsの使い方を説明する。
GetItemsをクリックするとリクエストパラメーターを入力するセクションが現れるので、必要に応じて入力しよう。ItemIdsはASINのことで、一度に最大10個指定することができる。つまり1度のリクエストで最大10個の商品情報を取得することができる。Amazon PAAPIはリクエスト数に何らかの制限があるので、なるべく多くの商品情報を取得するためには同時に商品を指定するコードを組むように工夫する必要がある。
今回は使い方の確認なので、一つのASINを指定する。ASINはAmazon上の商品すべてに紐づけられた固有のIDで、商品ページ内に記述されている。例えばこのモバイルバッテリーであれば登録情報に記されたB019GNUT0CがASINである。
これを先ほどのItemIdsに入力する。
次にResourcesを選択する。Resourcesとは指定した商品のどの情報を取得したいかを指定するものである。商品名、生産者名、セールスランキング、画像URLなど、Amazon上にあるデータは大体取得できるようになっている。Select Allを選択することでとりあえずすべての情報を取得することができる。
個人的には情報の抽出については自身のプロジェクト内のコードで行えばいいと思っているので、わざわざここでフィルタリングする意味はないような気もするが、もしかしたら必要な情報のみを指定することでレスポンスとして受け取るデータ容量を削減し、ごくわずかではあるが処理速度が上がるかもしれない。
ここではひとまずSelect Allを選択する。
以上二つが必須パラメーターなので、あとは実行すれば指定した商品の情報がすべて取得される。
Add a new parameterには商品の状態を指定するConditionや、販売元を指定するMerchantなどがあるので、必要に応じて追加すると良い。
必須項目の入力が完了した状態でRun Requestボタンをクリックすると、さっそく指定した内容でリクエストが送信され、結果が表示される。HTMLとして表示された状態や、JSON、サンプルコードなどが即座に表示されるので、そのまま自分のプロジェクトに組み込むこともできる。
上ではASINを指定して商品情報を取得したが、Amazonを普通に利用しているときのようにキーワードなどから商品を検索して、その情報を取得することもできる。
Select OptionのSearchItemsを選択する。
例のごとくリクエストパラメーターを入力する欄が現れるので、必要に応じて入力しよう。
操作方法に関しては上記で説明したGetItemsと同じなので、よく使われるパラメーターについてのみ簡単に説明する。
Keywords:検索したい商品のキーワードを指定する。(例:モバイルバッテリー
Resources:GetItemsと同じく、検索した商品のどんな情報が欲しいかを指定。決まってない場合はSelect Allにしておけば問題ない。
SearchIndex:商品のカテゴリを指定する。国によってカテゴリを指定するSearchIndexが異なるため、日本用のSearchIndexを調べて指定する必要がある。日本のSearchIndexは次のURLから確認できる。https://webservices.amazon.com/paapi5/documentation/locale-reference/japan.html
例えば検索する商品のカテゴリをスポーツ用品に絞りたい場合はSportsAndOutdoorsを指定する。
Add new parameterよりそのほかの条件も追加できるが、この三つが一番基本的でありよく使われるのではないだろうか。
そのほかのものについては需要がありそうであれば今後記事にする。