学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | クラウドソーシングアプリの構築 | 39 | 配達依頼詳細ページ

↓↓クリックして頂けると励みになります。


38 | 配達依頼詳細表示】 << 【ホーム】 >> 【40 | 引き受けた配達依頼ページ


「crowdsource/urls.py」ファイルを編集します。


記述追加 【Desktop/crowdsource/crowdsource/urls.py】26行目

from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static

from core import views

from core.customer import views as customer_views
from core.courier import views as courier_views, apis as courier_apis

customer_urlpatters = [
    path('', customer_views.home, name="home"),
    path('profile/', customer_views.profile_page, name="profile"),
    path('payment_method/', customer_views.payment_method_page, name="payment_method"),
    path('create_job/', customer_views.create_job_page, name="create_job"),

    path('jobs/current/', customer_views.current_jobs_page, name="current_jobs"),
    path('jobs/archived/', customer_views.archived_jobs_page, name="archived_jobs"),
    path('jobs/<job_id>/', customer_views.job_page, name="job"),
]

courier_urlpatters = [
    path('', courier_views.home, name="home"),
    path('jobs/available/', courier_views.available_jobs_page, name="available_jobs"),
    path('jobs/available/<id>/', courier_views.available_job_page, name="available_job"),

    path('api/jobs/available/', courier_apis.available_jobs_api, name="available_jobs_api"),
]


urlpatterns = [
    path('admin/', admin.site.urls),
    path('oauth/', include('social_django.urls', namespace='social')),
    path('', views.home),

    path('sign-in/', auth_views.LoginView.as_view(template_name="sign_in.html")),
    path('sign-out/', auth_views.LogoutView.as_view(next_page="/")),
    path('sign-up/', views.sign_up),

    path('customer/', include((customer_urlpatters, 'customer'))),
    path('courier/', include((courier_urlpatters, 'courier'))),

]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)



「core/courier/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/courier/views.py】

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.conf import settings

from core.models import *

@login_required(login_url="/sign-in/?next=/courier/")
def home(request):
    return redirect(reverse('courier:available_jobs'))

@login_required(login_url="/sign-in/?next=/courier/")
def available_jobs_page(request):
    return render(request, 'courier/available_jobs.html', {
        "GOOGLE_MAP_API_KEY": settings.GOOGLE_MAP_API_KEY
    })

@login_required(login_url="/sign-in/?next=/courier/")
def available_job_page(request, id):
 
    job = Job.objects.filter(id=id, status=Job.PROCESSING_STATUS).last()

    if not job:
        return redirect(reverse('courier:available_jobs'))

    return render(request, 'courier/available_job.html', {
        "job": job
    })



「core/templates/courier」フォルダに「available_job.html」ファイルを新規作成します。


新規作成 【Desktop/crowdsource/core/templates/courier/available_job.html】

{% extends 'courier/base.html' %}

{% block head %}

<style>
  .header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 60px;
    display: flex;
    align-items: center;
    padding: 0 20px;
    background-color: #FFC106;
    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
  }
</style>

{% endblock %}

{% block content%}

<div class="header">
  <a href="{% url 'courier:available_jobs' %}" class="mr-2">
    <i class="fas fa-chevron-left text-dark"></i>
  </a>
  <h5 class="mt-1 mb-0">配達可能な仕事</h5>
</div>

{% endblock %}



「core/templates/courier/available_jobs.html」ファイルを編集します。


記述追加 【Desktop/crowdsource/core/templates/courier/available_jobs.html】62行目

{% extends 'courier/base.html' %}

{% block head %}
<script
  src="https://maps.googleapis.com/maps/api/js?key={{ GOOGLE_MAP_API_KEY }}&callback=initMap&libraries=places&v=weekly"
  defer></script>

<script>
  function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 13,
    center: { lat: 43.062087, lng: 141.354404 },
    });

    // Get available jobs via API
    fetch("{% url 'courier:available_jobs_api' %}")
      .then(response => response.json())
      .then(json => {
        // console.log(json);

        // Create a new viewpoint bound
        var bounds = new google.maps.LatLngBounds();

        for (let i = 0; i < json.jobs.length; i++) {
            const job = json.jobs[i];
            const position = { lat: job.pickup_lat, lng: job.pickup_lng };
            const marker = new google.maps.Marker({
                position,
                map,
            });

            // Increase the bounds to take this point
            bounds.extend(position);

            new google.maps.InfoWindow({
                content: "<small><b>" + job.name + "</b></small><br/><small>" + job.distance + " Km</small>"
            }).open(map, marker);

            // Click event for each job
            marker.addListener("click", () => {
                showJobDetails(job);
            });

            // Fit these bounds to the map
            map.fitBounds(bounds);

        }
      })
}

function showJobDetails(job) {
    $("#job-details").css("display", "block");
    $("#job-name").html(job.name);

    $("#job-photo").attr('src', "/media/" + job.photo);
    $("#pickup-address").html(job.pickup_address);
    $("#delivery-address").html(job.delivery_address);
    $("#duration").html(job.duration);
    $("#distance").html(job.distance);
    $("#price").html(job.price);

    $("#job-details").on("click", function () {
      window.location.href = "/courier/jobs/available/" + job.id + "/";
    })    

  }
</script>

<style>
    .gm-ui-hover-effect {
        display: none !important;
    }    

    #map {
      flex: 1;
    }

    small {
        font-size: 12px;
        line-height: 1.2rem;
    }

    .card {
        border: none;
    }

    #job-details {
        display: none;
    }    

  </style>

{% endblock %}

{% block content %}

<div class="d-flex flex-column h-100" style="padding-bottom: 60px">
    <div id="map"></div>  

    <div id="job-details" class="card">
        <div class="card-body p-2">
          <div class="media">
            <img id="job-photo" class="rounded-lg mr-3" width="50px" height="50px">
            <div class="media-body">
              <b id="job-name"></b>
              <div class="d-flex">
                <div class="flex-grow-1 mr-2">
    
                  <small class="text-success">
                    <i class="fas fa-car"></i> <span id="distance"></span> km
                    <i class="far fa-clock ml-2"></i> <span id="duration"></span></small>
    
                  <div class="d-flex align-items-center mt-2">
                    <i class="fas fa-map-marker-alt"></i>
                    <small id="pickup-address" class="text-secondary ml-2"></small>
                  </div>
    
                  <div class="d-flex align-items-center mt-2">
                    <i class="fas fa-flag-checkered"></i>
                    <small id="delivery-address" class="text-secondary ml-2"></small>
                  </div>
    
                </div>
                <h3 id="price"></h3></div>
            </div>
          </div>
        </div>
    </div>    
</div>



{% include 'courier/bottom_tabs.html' %}

{% endblock %}



ブラウザを確認します。
マーカーをクリックして表示される詳細をクリックすると、配達依頼詳細ページにジャンプできるようになりました。
http://127.0.0.1:8000/courier/jobs/available/

配達依頼詳細をクリック
配達依頼詳細をクリック
配達依頼詳細ページにジャンプ
配達依頼詳細ページにジャンプ



配達依頼詳細ページの内容を更新します。


「core/templates/courier/available_job.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/courier/available_job.html】

{% extends 'courier/base.html' %}
{% load static %}

{% block head %}

<style>
  .header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 60px;
    display: flex;
    align-items: center;
    padding: 0 20px;
    background-color: #6f00be;
    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
  }
</style>

{% endblock %}

{% block content%}

<div class="header">
  <a href="{% url 'courier:available_jobs' %}" class="mr-2">
    <i class="fas fa-chevron-left text-light"></i>
  </a>
  <h5 class="mt-1 mb-0 text-light">利用可能な配達依頼</h5>
</div>

<div class="container-fluid" style="padding-top: 80px">
    <div class="media">
      <img src="{{ job.photo.url }}" class="rounded-lg mr-3" width="100" height="100">
      <div class="media-body">
        <h4>{{ job.name }}</h4>
        <span>サイズ:{{ job.get_size_display }}</span><br />
        <span>数量:{{ job.quantity }}</span><br />
        <span>{{ job.price }}円</span>
      </div>
    </div>
    <hr />
  
    <div class="d-flex align-items-center text-secondary mb-3">
      <i class="fas fa-map-marker-alt"></i>
      <span class="ml-2">{{ job.pickup_address }}</span>
    </div>
  
    <div class="d-flex align-items-center text-secondary mb-2">
      <i class="fas fa-flag-checkered"></i>
      <span class="ml-2">{{ job.delivery_address }}</span>
    </div>
    <hr />
  
    <b class="text-secondary">配達依頼人</b>
    <div class="media align-items-center mt-2">
      <img
        src="{% if job.customer.avatar %}{{ job.customer.avatar.url }}{% else %}{% static 'img/avatar.png' %}{% endif %}"
        class="rounded-circle mr-3" width="60" height="60">
      <div class="media-body">
        <h5 class="text-danger">{{ job.customer.user.get_full_name }}</h5>
        <span>{{ job.customer.phone_number }}</span>
      </div>
    </div>
    <hr />
  
    <form method="POST">
      {% csrf_token %}
      <button class="btn btn-danger btn-block">配達依頼を受ける</button>
    </form>
  
  </div>

{% endblock %}



ブラウザを確認します。

配達依頼詳細ページ更新
配達依頼詳細ページ更新



「配達依頼を受ける」ボタンを実装します。


「core/courier/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/courier/views.py】26行目

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.conf import settings

from core.models import *

@login_required(login_url="/sign-in/?next=/courier/")
def home(request):
    return redirect(reverse('courier:available_jobs'))

@login_required(login_url="/sign-in/?next=/courier/")
def available_jobs_page(request):
    return render(request, 'courier/available_jobs.html', {
        "GOOGLE_MAP_API_KEY": settings.GOOGLE_MAP_API_KEY
    })

@login_required(login_url="/sign-in/?next=/courier/")
def available_job_page(request, id):
 
    job = Job.objects.filter(id=id, status=Job.PROCESSING_STATUS).last()

    if not job:
        return redirect(reverse('courier:available_jobs'))

    if request.method == 'POST':
        job.courier = request.user.courier
        job.status = Job.PICKING_STATUS
        job.save()

        return redirect(reverse('courier:available_jobs'))    

    return render(request, 'courier/available_job.html', {
        "job": job
    })



「配達依頼を受ける」ボタンを押すとhttp://127.0.0.1:8000/courier/jobs/available/ページにジャンプし、ステータスが「Picking」になるようになりました。

ステータス更新
ステータス更新


↓↓クリックして頂けると励みになります。


38 | 配達依頼詳細表示】 << 【ホーム】 >> 【40 | 引き受けた配達依頼ページ