1. 程式人生 > >Django小型專案練習:模擬商場儲物櫃

Django小型專案練習:模擬商場儲物櫃

        學習Django一週時間了,決定寫一個簡單的東西出來,碰巧最近培訓班老師講MySQL,那就寫個儲存相關的吧,於是定計劃,做一個類似商場儲物櫃的小站點。商場超市都會有給顧客放東西的儲物櫃,點選“存包”就會生成隨機條形碼,然後開啟一個空櫃子(如果有的話),條形碼僅一次有效。我做的站點最終呈現如下:

1.兩個表單,分別用於查詢和插入資料,資料格式均為字串型別。

2.插入資料無限制,在文字框輸入要插入的資料後,點選“新增”按鈕就可以講資料插入資料庫。之後會得到一個16個字元的隨即字串,後面憑藉此字串才能獲得存入資料庫的資料。

3.查詢資料需要輸入驗證碼,這主要是防止有人暴力查詢。如上所述,存資料時生成的 key 僅僅能取出一次資料,重複使用無效。這是通過flag欄位控制的,插入一條資料時,flag預設為1,取出資料後,flag置為0,表示該行資料不可取。

資料庫結構如下:

--


這個小專案的實現也是在改來改去的過程中完成的,但是這裡就不描述這個過程了,而是從整體上看如何實現之。      

---環境---

OS:kubuntu 17.04

Python:2.7

Django:1.8

---

setp1:pip install --user virtualenv 安裝虛擬環境,虛擬環境中的Python包與作業系統上的Python包是隔離,雖然在我們這個專案中這不是必須的,但是有時候虛擬環境就會很有用,比如我們我們要使用不同版本的Django,就可以把他們放到不同的虛擬環境中了。

setp2:cd ~/my_python/ 進入~/my_python,然後執行 virtualenv my_env --python=python2.7 因為我的系統同時裝了Python3,所以這裡需要使用--python=python2.7指明需要使用哪個版本的python。執行後在~/my_python/下會出現 my_env 目錄。


step3:安裝MySQL-server或者MariaDB-Server,設定使用utf8字符集,skip-name-resolve=yes跳過名稱解析,建立使用者‘root’@‘127.0.0.1’,密碼root,監聽在127.0.0.1的3306埠上。create database mykey; 建立資料庫。

setp4:cd ~/my_python 後執行 . ./my_env/bin/activate 啟動指令碼進入虛擬環境,後續工作都是在該虛擬環境中做的。pip安裝的模組也是放置在虛擬環境中,這樣的話若是普通使用者通過pip安裝模組,就不需要使用sudo了。

               pip install Django==1.8  安裝Django    

               pip install pillow  安裝pillow模組,用於生成驗證碼圖片

               pip install MySQL-python 安裝MySQL驅動模組 

step5:下面建立專案和應用, cd ~/my_python/,執行django.py startproject mykey  然後看到~/my_python/下出現新目錄mykey,cd mykey 進入後執行 django.py startapp tools 建立名為tools的應用(一個目錄),這時候在 ~/my_python/mykey 下有2個目錄(mykey,tools)和1個指令碼檔案manage.py

====================== 下面開始寫程式 ========================

<--mykey下settings.py -->

新增剛剛建立的應用tools,同時把預設使用的資料庫從sqlite修改為MySQL,修改後如下:

  

<-- mykey下urls.py -->

urlpatterns = [
   url(r'^$', 'tools.views.index', name='home'),  //主頁
   url(r'^chk/', 'tools.views.itemchk', name='home'),  //點選“查詢”按鈕則提交表單至該url
   url(r'^add/', 'tools.views.itemadd', name='home'),  //點選“新增”按鈕則提交表單至該url
   url(r'^create_code_img/','tools.views.create_code_img',name='home'),  //點選驗證碼圖片時提交到該url
]

<-- tools下新建forms.py -->  表單生成
#coding:utf-8  
from django import forms
class ChkForm(forms.Form):
   a=forms.CharField(label="請輸入您要查詢的key")
class AddForm(forms.Form):
   a=forms.CharField(label="請輸入您要新增的info")

<-- tools下models.py -->  在資料庫mykey建立表,名字為 tools_mysecret
from django.db import models
# Create your models here.
class MySecret(models.Model):
   key=models.CharField(max_length=16)
   info=models.CharField(max_length=256)
   flag=models.BooleanField(default='True')
   def __unicode__(self):
       return self.info

<-- tools下新建rankey.py -->  用於生成16個字元的隨機數
import string
import random
KEY_LEN=16
def base_str():
   return (string.letters+string.digits)
def key_gen():
   keylist=[random.choice(base_str()) for i in range(KEY_LEN)]
   return("".join(keylist))

<-- tools下新建check_code.py --> 用於生成驗證碼圖片

#coding:utf-8
import random
from PIL import Image,ImageDraw,ImageFont,ImageFilter
_letter_cases="abcdefghjkmnpqrstuvwxy"
_upper_cases=_letter_cases.upper()
_numbers=''.join(map(str,range(3,10)))
init_chars=''.join((_letter_cases,_upper_cases,_numbers))

def create_validate_code(size=(120,30),
chars=init_chars,
img_type="png",
mode="RGB",
bg_color=(255,255,255),
fg_color=(255,0,255),
font_size=18,
font_type="Hack-Bold.ttf",
length=4,
draw_lines=True,
n_line=(1,2),
draw_points=True,
point_chance=2):
   width,height=size
   img=Image.new(mode,size,bg_color)
   draw=ImageDraw.Draw(img)

   def get_chars():
       return random.sample(chars,length)
   def create_lines():
       line_num=random.randint(*n_line)
       for i in range(line_num):
           begin=(random.randint(0,size[0]),random.randint(0,size[1]))
      end=(random.randint(0,size[0]),random.randint(0,size[1]))
           draw.line([begin,end],fill=(0,0,0))
   def create_points():
       chance=min(100,max(0,int(point_chance)))
       for w in range(width):
           for h in range(height):
               tmp=random.randint(0,100)
               if tmp>100-chance:
                   draw.point((w,h),fill=(0,0,0))
   def create_strs():
       c_chars=get_chars()
       strs=' %s ' % ' '.join(c_chars)
       font=ImageFont.truetype(font_type,font_size)
       font_width,font_height=font.getsize(strs)
       draw.text(((width-font_width)/3,(height-font_height)/3),strs,font=font,fill=fg_color)
       return ''.join(c_chars)

   if draw_lines:
       create_lines()
   if draw_points:
       create_points()
   strs=create_strs()

   params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
              1 - float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
    ]
   img=img.transform(size,Image.PERSPECTIVE,params)
   img=img.filter(ImageFilter.EDGE_ENHANCE_MORE)
   return img,strs

<-- tools下views.py --> 
#coding:utf-8
from io import BytesIO
from django.shortcuts import render
from django.http import HttpResponse
from django.db.models.query import *

from .forms import ChkForm,AddForm
from .models import MySecret
from .rankey import key_gen
from .check_code import *

def index(request):
   chk_form=ChkForm()
   add_form=AddForm()
   return render(request,'index.html',{'form1':chk_form,'form2':add_form})
def itemchk(request):
   if request.method == 'POST':
       chk_form=ChkForm(request.POST)
       if chk_form.is_valid():
           a=chk_form.cleaned_data['a']
           post_check_code=request.POST.get('check_code')
           session_check_code=request.session['check_code']
           if post_check_code.lower()==session_check_code.lower():
               try:     
                   secitem=MySecret.objects.get(key=a)
                   if secitem.flag==1:
                       MySecret.objects.filter(key=a).update(flag=0)  
                       return HttpResponse(unicode(secitem.info))
                   else:    
                       return HttpResponse(str('該key已取出'))  
               except MySecret.DoesNotExist:
                   return HttpResponse(str('該key不存在'))  
           else:   
       return HttpResponse(str('驗證碼錯誤'))
       else:
           return HttpResponse(str('key不能為空'))

def itemadd(request):
   if request.method == 'POST':
       add_form=AddForm(request.POST)
       if add_form.is_valid():
           a=add_form.cleaned_data['a']
           mykey=key_gen()
          # b=add_form.cleaned_data['b']
          # MySecret.objects.create(key=a,info=b)
           MySecret.objects.create(key=mykey,info=a)
           return HttpResponse(str('請牢記您的key:'+mykey))
def create_code_img(request):
   f=BytesIO()
   img,code=create_validate_code()
   request.session['check_code']=code
   img.save(f,'png')
   return HttpResponse(f.getvalue(),content_type="image/png")

==========

cd ~/my_python/mykey/tools,建立templates目錄 mkdir templates

cd templates 建立index.html 內容如下:

<-- index.html -->

<form action='/chk/' method='post'>

{% csrf_token %}
{{ form1 }}

<div class="row">
   <div class="col-xs-7">
       <input type="text" class="form-control" name="check_code" id="check_code" placeholder="請輸入驗證碼">
   </div>   
   <div class="col-xs-5">
       <img id="check_code_img" src="/create_code_img/" onclick="javascript:window.location.reload();"/>
   </div>   
</div>

<input type="submit" value="查詢">
</form>

<form action='/add/' method='post'>
{% csrf_token %}
{{ form2 }}
<input type="submit" value="新增">
</form>

結下來連線資料庫建立表

cd ~/my_python/mykey/

./manage.py makemigrations

./manage.py migrate

./manage.py runserver  執行webserver,通過瀏覽器訪問 127.0.0.1:8000