iT邦幫忙

2022 iThome 鐵人賽

DAY 30
0
自我挑戰組

從0 到 50 初探 如何使用Django 架構出一個網站系列 第 30

Day- 30 Last Day! 網站建置- 如何做一個簡單的預約系統

  • 分享至 

  • xImage
  •  

前言

雖然說好D29要開始網站的建置,但其實最近忙於實驗,也沒有特別去規劃,所以打算做一個預約系統,我預想可以用它來幫我預約實驗或讓訪客可以直接看到有實驗的時段。在這篇會用比較沒有修飾的方式,先做出功能,之後部署可能會在Medium或其他地方陸續更新。
那我們就來迎接30天的最後一步!

網站架構

頁面:

  • 登入頁面(首頁)
  • 註冊頁面
  • 訪客頁面
  • 預約頁面
  • 預約完成頁面
  • 預約紀錄表頁面
  • 登出跳轉頁面

資料庫欄位:

  • 會員
    • 會員名稱
    • 會員email
    • 預約紀錄
    • 會員帳號

那其實在前幾天裡,就已經慢慢把頁面都建立起來了,今天我們就只要把他串起來即可

網站範例 - Django_project 內容

首頁(登入頁面)

這部分之前有講過了,不過還是把程式碼貼出來,這樣會比較清楚。

urls.py


from django.contrib import admin
from django.urls import path, include
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('reserve/',  include('Django_app.urls')),
    path('account/', include('django.contrib.auth.urls')),
    path('login/',views.login, name = 'login'),
    path('log_out',views.log_out, name= "log_out"),
    path('main_page', views.main_page, name = 'main_page'),
    path('sign_up/', views.SignUpView.as_view(), name = "sign_up")
]

views.py

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.views.generic import TemplateView, CreateView
from django.urls import reverse, reverse_lazy
from django.contrib import auth
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm

def login(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect('/main_page')
    username = request.POST.get('username')
    password = request.POST.get('password')
    user = auth.authenticate(username=username, password=password)
    if user is not None and user.is_active:
        auth.login(request, user)
        return HttpResponseRedirect('/main_page')
    else:
        return render(request, 'login.html', locals())

def main_page(request):
    return render(request, 'main_page.html')

def log_out(request):
    auth.logout(request)
    return HttpResponseRedirect('/main_page')

class SignUpView(CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy('login')
    template_name = 'sign_up.html'

Template

login.html

<html>
    <title>登入</title>
    </head>
    <body>
      <h1>實驗預約系統</h1><br>

    <div><form method="post" class="center">
          {% csrf_token %}
          <div><table class="center">
            <tr>
              <td width="16%" align="right">帳號:</td>
              <td width="84%"><input type="text" name="username" id="username"></td>
            </tr>
            <tr>
              <td width="16%" align="right">密碼:</td>
              <td width="84%"><input type="password" name="password" id = "password" ></td>
            </tr>
            <tr>
              <div><td><p><input type="submit" name="login" value="登入"></p></td></div>
              <div><td>
                <p>
                  <button type="button">
                    <a href= "{% url 'main_page' %}">訪客登入</a>
                  </button>
                </p>
              </td></div>
              <div><td><a href="{% url 'sign_up' %}">註冊</a></td></div>  

            </tr>
          </table></div>   
     </form></div>
</html>

log_out.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>你已經登出囉!</p>
    <a href= "{% url 'login' %}">回到登入頁面</a>
    
</body>
</html>

sign_up.html

<h1>註冊頁面<h1>
<form method = "POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type= "submit", value = "註冊">
</form>

main_page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>歡迎來到實驗預約系統!</h1>
    {% if request.user.is_authenticated %}
        <p>Hi~ {{request.user}} 您已經登入囉~!</p>
        <a href= "{% url 'Order_System:order_list' %}">查看目前預約狀態</a><br>
        <a href= "{% url 'Order_System:order' %}">預約</a><br>
        <a href= "{% url 'log_out' %}">登出</a>
        {% comment %} <a href= "{% url 'log_out' %}?next={{request.path}}">登出</a> {% endcomment %}
    {% else %}
        <p>您尚未登入唷~</p>
        <a href= "{% url 'login' %}">回到登入頁面</a><br>
        <a href= "{% url 'Order_System:order_list' %}">查看目前預約狀態</a>
        {% comment %} a href= "{% url 'login' %}?next={{request.path}}">回到登入頁面</a> {% endcomment %}
    {% endif %}
    
</body>
</html>

網站範例 - Django_app 內容

urls.py

from django.urls import path
from . import views
app_name = 'Order_System'
urlpatterns = [
    path('', views.OrderCreateView.as_view() , name = 'order'),
    path('finish/', views.FinishView.as_view() , name = 'finish'),
    path('orderlist/', views.OrderListView.as_view(), name = 'order_list'),
]

models.py

這裡有新增了一個外來鍵,要放的值是目前登入的使用者名稱,以這種方式可以區分不同帳號所預約的紀錄。
友善提醒:改完 model 要記得 migrate 唷!

from django.db import models
from datetime import datetime
from django.contrib.auth.models import User
from django.conf import settings
from django.utils import timezone
class account_info(models.Model):
    account_name = models.CharField(max_length= 10)
    account_email = models.EmailField()
    account_order = models.DateField(default = datetime.now())
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE,primary_key=True)

    class Meta:
        db_table = 'account'

views.py

為了去抓目前登入的使用者並傳給 model,所以這裡使用了一個 form_valid() 的方法
form_valid 是 Model form 提供了的一個方法,可以自動儲存model資料。
我們可以用這個方式讓我們的外來鍵可以存取目前的使用者名稱。

from django.views.generic import TemplateView, CreateView, ListView, DetailView, UpdateView, DeleteView
from .models import account_info
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.contrib.auth.models import User

class OrderCreateView(LoginRequiredMixin, CreateView):
    # template_name = "Django_app/account_info.html"
    login_url = "/login"
    model = account_info
    fields = ["account_name","account_email", "account_order"]
    success_url = reverse_lazy("Order_System:finish")
   
    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

class FinishView(TemplateView):
    template_name = "Django_app/finish.html"


class OrderListView(ListView):
    # model_list.html
    model = account_info
    #context_object_name = Order_list
    # queryset = account_info.objects.all()

Template

這裡的內容其實就是我們前天再講CBVs時所講的,也都幾乎沒有更改。

account_info_form.html 預約頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form method="POST">
        {% csrf_token %}
        {% if request.user.is_authenticated %}
        <p>Hi~ {{request.user}} 歡迎預約!</p>
        {{form.as_p}}
        {{created_by}}
        <input type = "submit" value = "預約">
        {% else %}
        <p>您尚未登入唷~</p>
        <a href= "{% url 'login' %}">回到登入頁面</a><br>
        <a href= "{% url 'Order_System:order_list' %}">查看目前預約狀態</a>
        {% endif %}
    </form>
    
</body>
</html>

account_info_list.html 預約紀錄表

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<h1>預約資料表</h1>
<body>
    <form method="POST">
        {% for data in object_list %}
            <li>預約人姓名:{{data.account_name}} 預約時間 {{data.account_order}} </li>
        {% endfor %}
    </form>
    
</body>
</html>

finish.py 預約完成跳轉頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>預約完成!</h1>
    <h2><a href = "{% url 'Order_System:order_list' %}">跳轉回紀錄頁面</h2>
</body>
</html>

呈現畫面

首頁(登入頁面)

https://ithelp.ithome.com.tw/upload/images/20221015/20150927cvjyy3hMnY.png

註冊頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927ydqRdC9krA.png

登入後主頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927IuUPY1pnPx.png

訪客登入後主頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927XGxBtgwJfO.png

預約頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927R8TqtYYoKt.png

預約完成頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927jho7rz9qog.png

預約紀錄表頁面

https://ithelp.ithome.com.tw/upload/images/20221015/20150927SaywBy2OOH.png

這就是簡單的一個小網站了,請包涵介面非常醜,而且其實還有更新、刪除、功能跳轉列表等等很多功能可以做,礙於時間不夠,希望自己之後可以再慢慢更新XD

完賽感言

因為是在每天實驗的情況下來做這次挑戰,所以其實覺得每天都不太夠用XD,因為自己其實也是一邊查找資料和寫文章,還好我一開始好像屯了約5天的份量XDD,直到發現想講的內容變多以及有新東西以前沒用過後,開始覺得有一點壓力,因為都要先閱讀官方文件或影片,每天都寫到時間快到才發稿。不過回顧這30天,真是又充實又好玩,對 Django 的使用也更加了解,希望看了我的文章的大家也能稍微獲得一些東西!
最後期許自己能夠持續的精進自己,自己希望能夠以後至少能一週更新一篇文章啦XD
也非常感謝看到這裡的你,未來有機會也一定會繼續挑戰鐵人賽的!!

參考資料&推薦閱讀

https://docs.djangoproject.com/en/4.1/topics/class-based-views/generic-editing/


上一篇
Day -29 - auth - Django內建的超好用註冊和登入
系列文
從0 到 50 初探 如何使用Django 架構出一個網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
arguskao
iT邦新手 3 級 ‧ 2023-07-26 15:37:16

如果別人也要預約這天,會出現已被預約嗎

我要留言

立即登入留言