リクエスト元のIPアドレスから、アクセスしている国を特定する必要があり、Django で実現する方法を調べたところ、Geolocation with GeoIP2 | Django ドキュメント | Djangoいうライブラリを使えば実現できそうに思いました。

ユースケースとして、Web API でリクエスト元のIPアドレスから 地域を推定したかったので、GeoIP2 と、djangorestframework を使ってWeb API を書いてみました。
事前準備として実施したこと、作ったAPIについて記載します。


前提

OS の情報と、Django、djangorestframework の Version 情報 は以下の通りです。

  • OS の Version

    cat /etc/redhat-release
    CentOS Linux release 7.8.2003 (Core)
    

  • DjangoのVersion

    pip list | grep Django                  
    Django                     1.11.20
    

  • djangorestframeworkのVersion

    pip list | grep djangorestframework
    djangorestframework        3.9.2
    


CentOS 7 に、geoipupdateインストールして、GeoIP2のデータベースを自動更新する

Django の GeoIP2動かすには、IP Geolocation and Online Fraud Prevention | MaxMindデータベースファイルが必要になります。
これは、毎週火曜日に更新されるのですが、自動更新を可能にするgeoipupdateいうライブラリがあり、Web API を書く前に、自動更新の設定をします。
インストール、設定方法は以下の記事が参考になりました。
CentOS 7のGeoIP Free Databaseの更新 ← RootLinks Co., Ltd.

  • インストール

    yum -y install geoipupdate    
    
    Version 2.5.0 がインストールされました。
    geoipupdate -V
    geoipupdate 2.5.0
    

  • GeoIP.confの編集
    データベースの更新には、アカウント情報とライセンスキーが必要になります。
    ライセンスキーは、GeoLite2 Sign Up | MaxMindアカウントを作ると発行できるようになります。
    ちなみに、データベースのダウンロードにも、アカウント登録が必要です。
    CentOS 7 だと、/etc/GeoIP.confファイルは配置されています。
    AccuntIDLicenseKey払い出された情報を設定します。

    # Enter your account ID and license key below. These are available from
    # https://www.maxmind.com/en/my_license_key. If you are only using free                                                                                                                
    # GeoLite databases, you may leave the 0 values.
    AccountID YOUR_ACCOUNT_IDYOUR_ACCOUNT_ID
    LicenseKey YOUR_LICENSE_KEY
    
    # Enter the edition IDs of the databases you would like to update.
    # Multiple edition IDs are separated by spaces.
    EditionIDs GeoLite2-Country GeoLite2-City
    

  • ライセンスキー発行時の注意点
    ライセンスキー発行時に、geoipupdate使用するか否かのチェックボックスがあり、チェックしないと、geoipupdate では使用できないキーになります。
    Image from Gyazo CentOS 7 のyum でインストールできるgeoipupdateVesion が2.5.0 なので 3.1.1以下を選択しています。この設定ですと、ライセンスキーはハッシュ形式で保存されないため、安全性が低くなる旨の警告がこの後のページで出力されます。私は気にしませんでしたが、気にされる方は yum でのインストールではなく、ソースからビルドをかけるなど実施したほうが良いかもしれません。

  • ディレクトリ作成

    /bin/geoipupdate
    
    実行したところ、
    /usr/share/GeoIP does not exist
    
    出力されました。
    データベースの格納先がないので、ディレクトリを作成します。
    mkdir /usr/share/GeoIP
    

  • スケジュール実行
    参考記事と同様に、木曜日に実行するように設定しました。

    0 12 * * 4 /bin/geoipupdate # GeoIP Update
    

以上で、データベースの自動更新の設定は完了です。


djangorestframework で Web API を建てる

djangorestframework で リクエスト送信元のIPアドレスを元に、都市の情報を返す Web API を作成します。

  • geoip2 のインストール
    StackOverFlow の記事で、Django 1.11 の場合、Version指定してインストールしていたので、それを参考にバージョン指定しています。

    pip install geoip2==2.9.0
    

  • settings.pyの編集
    GEOIP_PATH追加します。GEOIP_COUNTRY と、GEOIP_CITYありますが、デフォルト設定で問題ないので、記載しませんでした。

    ##################
    # GEOIP SETTINGS 
    ##################
    GEOIP_PATH='/usr/share/GeoIP'
    

  • urls.pyの編集

    import apis
        url("^geoip/$",apis.geoip, name="geoip")
    

  • apis.py
    @api_viewデコレータで、関数APIを作りました。

    from rest_framework.decorators import api_view
    from django.contrib.gis.geoip2 import GeoIP2
    from rest_framework.response import Response
    
    @api_view(['GET'])                                                                                                                                                                     
    def geoip(request):
        g = GeoIP2()
        client_addr = request.META.get('REMOTE_ADDR')
        city = g.city(client_addr)
        return Response(city)
    


追記. django-geoip2-extras を使う

template で、国コードで制御したい画面項目がある場合は、django-geoip2-extras · PyPI使うのが良いかと思います。
tempalteタグで使用するまでの手順を記載します。

  • インストール

    pip install django-geoip2-extras     
    

  • settings.py に geoip2_extras.middleware.GeoIP2Middleware追加

    MIDDLEWARE = (
        ...,
        'django.contrib.sessions.middleware.SessionMiddleware',
        'geoip2_extras.middleware.GeoIP2Middleware',
        ...
    )
    

これで、request.geo_data以下の情報が設定されるようになります。

  • ip_address
  • city
  • postal_code
  • region
  • country_code
  • country_name
  • latitude
  • longitude
  • is_unknown

  • templateで使う
    Django のtemplate内では以下のように使用できます。

    {% if request.geo_data is None or request.geo_data.country_code == "JP" %}
    <div class="blog-item">
        <!-- blog本文下の広告 -->
        <ins class="adsbygoogle"
                style="display:block"
                data-ad-client="{{ settings.CLEAN_BLOG_GOOGLE_ADS_CLIENT_ID }}"
                data-ad-slot="{{ settings.CLEAN_BLOG_GOOGLE_ADS_SLOT_ID }}"
                data-ad-format="auto"></ins>
        <hr>
    </div>
    {% endif %}
    

  • 注意点
    template内で使用する際の注意点を記載します。

    • Cacheの設定の確認 Django の Cache の設定によっては、templateの評価が行われず、requestごとに判定されない場合があります。
      Django’s cache framework | Django ドキュメント | Djangotemplateに対するCache設定についての記載があります。

    • django.core.context_processors.request を有効にする。
      template 内で request にオブジェクトにアクセスするには、Django.core.context_processors.request TEMPLATE_CONTEXT_PROCESSORS登録する必要があります。


参考

以下、参考にした記事になります。

以上です。

コメント