python3.doc_64
R e i - D r e a m
for Laravel
TOP > Python3 > Django(AJAX)
Guest
login

最終投稿日:2022年6月18日

Django(AJAX)
AJAX
内容は特に DJANGO というか JQUERY です。
【画面仕様】
    部のプルダウンを選択すると AJAX にて課のプルダウンの値が自動的に生成される。

ディレクトリ構造は以下
    [プロジェクト]
            |
            +---【apps】
            |       |
            |       +---【myajax】
            |                 |
            |                 +--- [urls.py]
            |                 +--- [models.py]
            |                 +--- [forms.py]
            |                 +--- [views.py]
            +---【config】
            |         |
            |         +---【settings】
            |         |           |
            |         |           +--- [base.py] ※設定ファイルは省略しています
            |         |           +--- [develop.py] ※設定ファイルは省略しています
            |         +--- [urls.py]
            +---【static】
            |         |
            |         +---【common】
            |                   |
            |                   +---【js】
            |                          |
            |                          +--- [jquery-1.7.js]
            |                          +--- [ajaxsend.js]
            +---【templates】
                        |
                        +---【layout】
                        |         |
                        |         +--- [jquery_base.html]
                        +---【myajax】
                                  |
                                  +--- [index.html]


● settings.py
    INSTALLED_APPS = [
        ~ 省略 ~
        'myajax.apps.MyajaxConfig'
    ]

● プロジェクトの urls.py
    urlpatterns = [
        url(r'^$', RedirectView.as_view(url='myajax/')),
        url(r'^myajax/', include('myajax.urls', namespace='myajax')),
    ]

● アプリの urls.py
    app_name = 'myajax'
    urlpatterns = [
        url(r'^$', RedirectView.as_view(url='index/')),
        url(r'^index/$', IndexView.as_view(), name='index'),
        url(r'^myajax/$', MyAjaxView.as_view(), name='myajax'),
    ]

● models.py
    from django.db import models
	#【部】のテーブル
    class SectionBu(models.Model):
        class Meta:
            db_table = 'section_bu'
            verbose_name = 'セクション部名'
        bname = models.CharField(max_length=15, unique=True)
        bname_k = models.CharField(max_length=20, unique=True)
        def __str__(self):
            return self.bname

	#【課】のテーブル
    class SectionKa(models.Model):
        class Meta:
            db_table = 'section_ka'
            verbose_name = 'セクション課名'
        bu = models.ForeignKey(SectionBu, to_field='id', on_delete=models.PROTECT)
        kname = models.CharField(max_length=15, unique=True)
        kname_k = models.CharField(max_length=20, unique=True)
        def __str__(self):
            return self.kname

    ※お約束のコマンドを叩いてテーブルを作成する
        python manage.py makemigrations
        python manage.py migrate

● forms.py
    from django import forms
    from .models import *
    class AjaxForm(forms.Form):
        option_bu = [ (row.id, row.bname) for row in SectionBu.objects.all()]
        option_bu.insert(0,(0,'---'))
        sec_bu = forms.ChoiceField(
            label = '部',
            widget = forms.Select(),
            choices = option_bu
        )
        sec_ka = forms.ChoiceField(
            label = '課',
            widget = forms.Select(),
        )

● views.py
    from django.shortcuts import render
    from django.http.response import HttpResponse
    from django.views.generic import View
    from . import forms
    from . import models
    from django.http import JsonResponse

    class IndexView(View):
        def get(self, request):
            form = forms.AjaxForm()
            d = {'form':form}
            return render(request, 'myajax/index.html', d)

    class MyAjaxView(View):
        def post(self, request):
			#AJAX 経由か確認できる
            if request.is_ajax():
                res = models.SectionKa.objects.all().filter(bu_id=request.POST['id_sec_bu'])
                kalist = []
                for row in res:
                    kalist.append([row.id, row.kname])
                ka = {'kalist':kalist}
				#JSON 形式で返却する
                return JsonResponse(ka)


● static/common/js/jquery-1.7.js
    どっかから落としてくる。。

● static/common/js/ajaxsend.js
    jQuery(document).ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    });

● templates/layout/jquery_base.html
    {% load static %}
    <html>
        <head>
            <title>{{my_title}}</title>
            <meta http-equiv="content-type" content="text/html; charset=utf-8">
            <script type="text/javascript" src="{% static 'common/js/jquery-1.7.js' %}"></script>
            <script type="text/javascript" src="{% static 'common/js/ajaxsend.js' %}"></script>
            {% block my_script %}{% endblock %}
        </head>
        <body>
            {% block my_body %}{% endblock %}
        </body>
    </html>

● templates/myajax/index.html
    {% extends 'layout/jquery_base.html' %}
    {% block my_script %}
        <SCRIPT>
            $(function() {
                $('#id_sec_bu').change(function(){
                    if($('#id_sec_bu').val() > 0){
                        $('#id_sec_ka > option').remove();
                        var param = {};
                        param.id_sec_bu = $('#id_sec_bu').val();
						//クロスドメインでの通信を可能とする(IE専用)
                        jQuery.support.cors = true;
                        $.ajax({
                            type    : 'POST',
                            url     : "{% url 'myajax:myajax' %}",
                            cache   : false,
							//非同期通信
                            async    : true,
                            data    : param,
                            success : function(data){
// data = {'kalist': [[4,'インフラ課'], [5,'アプリ1課'], [6,'アプリ2課']]}のJSON形式で受け取る
                                $('#id_sec_ka').append($('<option>').html('- 選択 -').val(0));
                                for(var i=0;i < data.kalist.length;i++){
                                    $('#id_sec_ka').append($('<option>')
					.html(data.kalist[i][1]).val(data.kalist[i][0]));
                                }
                            },
                            error : function(request,status,error){
                                alert('失敗。。');
                            }
                        });
                    }else{
                        $('#id_sec_ka > option').remove();
                    }
                });
                $('#id_sec_ka').change(function(){
                    alert($('#id_sec_ka').val());
                });
            });
        </SCRIPT>
    {% endblock %}

    {% block my_body %}
        {{form.as_p}}
    {% endblock %}


【メモ】
			
<AJAX の csrf_token 問題>
Django は AJAX であろうと POST 遷移に関してはセキュリティのため csrf_token トークンを必要とします。
自分のサイト内であれば {% csrf_token %} をテンプレートに設置して、その値を AJAX に付加すれば問題ありませんが、
他のサイトへ情報を公開している様な AJAX の場合は他者からアクセスを受け付けるので {% csrf_token %} なんで他者は設定しようがありません。
そんな時は JQUERY の AjaxSend メソッドを使えば良いらしい。
サンプルのファイル ajaxsend.js の中身が丸々ソースですが、単にこれを置いておくだけで AJAX の際に勝手にトークンを付与してくれるらしい。
正確には、XMLHttpRequestに対し、X-CSRFTokenヘッダの値にcsrftokenの値を付加しています。
本当にこれで他のサイトから通信出来るかは未確認です。
ログインしてコメントを残そう!!


きっぷる