1. 程式人生 > 實用技巧 >Django 專案分析後得到的某些結論

Django 專案分析後得到的某些結論

專案下的 urls 篇
urlpatterns = [ ] 其中主要是包含有各個 app 的路由
示例:

url(r'^users/', include('users.urls', namespace='users')),

url(r'^admin/', admin.site.urls),
settings 中的基礎知識
INSTALLED_APPS = [ ] 存放建立好的app名稱(app註冊)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes
', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users', '建立好的app名稱', ]
MIDDLEWARE = [] 中介軟體
TEMPLATES = [ ] 模板檔案 

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        
'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages
', ], }, }, ] 'DIRS'可以修改為 'DIRS': [os.path.join(BASE_DIR, 'templates')],
DATABASES  = { } 資料庫 配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '資料庫',
        'USER': '使用者名稱',
        'PASSWORD': '密碼',
        'CHARSET': '字符集',
        'HOST': 'IP地址',
        'PORT': '',
    }
}

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'webshop',
        'USER': 'root',
        'PASSWORD': 'root',
        'CHARSET': 'UTF-8',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}
設定中文

LANGUAGE_CODE = 'zh-hans'
時間顯示為北京時間

TIME_ZONE = 'Asia/Shanghai'
配置 static 靜態目錄

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'static'),
)

暫時還沒有接觸到的點(慎用)

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

# hash加密使用的鹽值
SALT_KEY = "Hello"

LOGIN_URL = '/users/login'

專案的 __init__ 檔案中新增的內容

import pymysql

pymysql.install_as_MySQLdb()

app 的urls(建立的.py檔案)

匯入 views 

from . import views

urlpatterns = [
    url(r'^login/$', views.user_login, name='user_login'),
    url(r'^register/$', views.register, name='register'),
]
使用 (?P<views 中的函式引數名稱>\d+) 獲取傳遞進來的引數給 views 中函式的引數

urlpatterns = [
    url(r'^(?P<s_id>\d+)/detail_store', views.detail_store, name='detail_store'),
    url(r'^(?P<s_id>\d+)/(?P<status>\d+)/status_store', views.status_store, name='status_store'),
]
urlpatterns = [
    url(r'^(?P<number>\d+)/(?P<goods_id>\d+)/shop_into/$', views.shop_into, name='shop_into'),
    url(r'^list_car/$', views.list_car, name='list_car'),
    url(r'^(?P<shopcar_id>\d+)/del_car/$', views.del_car, name='del_car'),
]
urlpatterns = [
    url(r'^order_confirm/$', views.order_confirm, name='order_confirm'),
    url(r'^order_pay/$', views.order_pay, name='order_pay'),
    url(r'^order_done/$', views.order_done, name='order_done'),
    url(r'^order_list/$', views.order_list, name='order_list'),
    url(r'^(?P<order_id>\d+)/order_desc/$', views.order_desc, name='order_desc'),

]
url(r'^路由地址/$', views.函式名, name='名稱'),

url(r'^(?P<函式引數名稱>\d+)/路徑名/$', views.函式名, name='名稱'),
關於路由系統,這裡只是寫出了最簡單的寫法,此處只是根據讀程式獲取到的部分知識

app 的 models,為 views 作基礎,views在獲取到urls中的請求後,會呼叫一些方法
建立主鍵 -> 1.11.14 自動建立 id 列 
在外來鍵關聯時,自動加上 _id 名稱
 
id = models.AutoField(primary_key=True)
建立字串 name 列 ,使用 models.CharField 

country = models.CharField(max_length=255, default='中國',verbose_name='城市')

area = models.CharField(max_length=50, verbose_name='收貨人縣/區/')
使用 bool 型別

資料欄位名稱 = models.BooleanField(default=False, verbose_name='xxx')

is_default = models.BooleanField(default=False, verbose_name='是否是預設地址')
int 型別 , 使用 models.IntegerField

age = models.IntegerField(default='20', verbose_name='使用者年齡')

status = models.IntegerField(default=0, verbose_name='店鋪狀態')

goods_count = models.IntegerField(verbose_name='購買數量')
image 圖片型別 使用 models.ImageField

變數名 = models.ImageField(upload_to='圖片路徑', default='圖片名', verbose_name='名稱')
變數名 = models.ImageField(upload_to='圖片路徑')


logo = models.ImageField(upload_to='static/images/logo', default='static/images/logo/goods-style1.png', verbose_name='商品型別圖示')

path = models.ImageField(upload_to='static/images/goods', default='static/images/goods/default.jpg', verbose_name='商品圖片')

goods_image = models.ImageField(upload_to='static/images/goods')

cover = models.ImageField(upload_to='static/images/store/', default='static/images/store/default.jpg', verbose_name='店鋪封面')

header = models.ImageField(upload_to='static/images/headers', default='static/images/headers/default.jpg', verbose_name='使用者頭像')
text 描述 使用 models.TextField
變數名 = models.TextField(verbose_name= '名稱')
變數名 = models.TextField(null=True, blank=True,verbose_name= '名稱')

intro = models.TextField(verbose_name='商品類別描述')

intro = models.TextField(null=True, blank=True, verbose_name='商品圖片描述')
float 浮點數型別,使用 models.FloatField
變數名 = models.FloatField(verbose_name='名稱')
變數名 = models.FloatField(default=0.00, verbose_name='名稱')

price = models.FloatField(verbose_name='商品價格')

allMoney = models.FloatField(default=0.00, verbose_name='總計')
datetime 使用 models.DateTimeField
變數名 = models.DateTimeField(auto_now_add=True, verbose_name='名稱')

openTime = models.DateTimeField(auto_now_add=True, verbose_name='開店時間')

注:可以新增 datetime.now 用來在建立時,指定當前時間
foreignkey 外來鍵 , 使用 models.ForeignKey

變數名 = models.ForeignKey(類名, null=True, blank=True, on_delete=models.CASCADE, verbose_name='名稱')

parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父級地址')
from app名稱.models import 類名

變數名 = models.ForeignKey(類名, on_delete=models.CASCADE, verbose_name='名稱')
注:類名可以是外部匯入或本models.py中建立的類名

from users.models import User

user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='地址所屬')
一個models 類可以存在兩個外來鍵

goodsStore = models.ForeignKey(類名, on_delete=models.CASCADE, verbose_name='名稱')
goodsType = models.ForeignKey(類名, on_delete=models.CASCADE, verbose_name='名稱')


from store.models import Store
goodsStore = models.ForeignKey(Store, on_delete=models.CASCADE, verbose_name='商品所屬店鋪')
goodsType = models.ForeignKey(GoodsType, on_delete=models.CASCADE, verbose_name='商品型別')
從 django.contrib.auth.models 匯入 User

from django.contrib.auth.models import User

user = models.ForeignKey(User, on_delete=models.CASCADE)
一對一 使用 models.OneToOneField
變數名 = models.OneToOneField(User, on_delete=models.CASCADE)

user = models.OneToOneField(User, on_delete=models.CASCADE)
在這裡補充一點,欄位還存在一對多和多對多

app 中的 views 
def 函式名(request):
    程式碼塊
    return 語句(是否存在引數)

def 函式名(request,引數(一個或多個)):
    程式碼塊
    return 語句(是否存在引數)

@裝飾器(一個或多個)
def 函式名(request):
    程式碼塊
    return 語句(是否存在引數)

@裝飾器(一個或多個)
def 函式名(request,引數(一個或多個)):
    程式碼塊
    return 語句(是否存在引數)
關於def 函式定義時,request 後面的引數
在進行路由分發時,使用 
url(r'^(?P<g_id>\d+)/goods_detail/$', views.goods_detail, name='goods_detail'),

進行 get 請求傳遞進來的引數會給 g_id ,因此在 goods_detail 函式中要設定一個引數名為 g_id 

def goods_detail(request, g_id):
    程式碼
注:有多少個?P<引數名> 就設定多少個引數,用來接收
程式碼塊中可以使用到很多知識,此處只是該專案使用到的基礎

request.method 
判斷進行的哪一種請求方式,GET還是POST

if request.method == 'GET':
    pass
elif request.method == 'POST':
    pass
else:
    pass
models.類名.objects.filter(表中欄位(user)=request.user)
filter 主要是用來過濾,使用了filter 之後還可以繼續使用 filter進行過濾

address_list = models.Address.objects.filter(user=request.user)

對於使用了 filter 方法 的物件,可以使用 len 進行判斷,是否已經存在

sto = models.Store.objects.filter(name=name)
if len(sto) == 1:
return render(request, 'store/store_add.html', {"msg": "商鋪名稱已存在,請重新輸入"})
獲取 post 方式提交的資料
request.POST['名稱']

recv_name = request.POST['recv_name']

html 中資料如下,讓name的值於名稱相對應即可
<input type="text" name="recv_name" id="recv_name" autocomplete="off">

name = request.POST['name'].strip()
在進行獲取資料時,可以新增 strip 進行字串操作
對於 filter 獲取到的資料可以進行遍歷
address_list = models.Address.objects.filter(user=request.user)
並且遍歷的元素物件具有 save 方法 可以修改欄位
Address 是類名,user , is_default 是 Address 表中的欄位

from . import models

address_list = models.Address.objects.filter(user=request.user)
for addr in address_list:
    addr.is_default = False
    addr.save()

使用 __in 時,可以直接寫明在某一個變數中 [0,1]
stores = models.Store.objects.filter(user=request.user, status__in=[0, 1])
新增表的一行資料
括號中 = 前面的都是表中的欄位,後面是對應的值
使用 save 進行儲存

變數 = models.類名(欄位1 = 值1, 欄位2 = 值2, user=request.user)
變數 .save()


address = models.Address(recv_name=recv_name, recv_tel=recv_tel, province=province, city=city, area=area,
                                     street=street, desc=desc, is_default=True, user=request.user)

address.save()

goods = models.Goods(name=name, price=price, stock=stock, desc=desc, goodSize=goodSize, goodsType=goodsType,goodsStore=store )
goods.save()




id 自增列不用新增
在使用 filter 獲取資料後,使用 order_by 進行排序

from app名稱.models import 類名
變數名 = 類名.objects.filter(user=request.user).order_by('名稱')


shop_cars = ShopCar.objects.filter(user=request.user).order_by('-createTime')
在 filter 中使用 =
變數名 = 類名.objects.filter(欄位名=值)

goods_type1 = GoodsType.objects.filter(pk=1001)
在 filter 中使用 __in
變數名 = 類名.objects.filter(欄位名__in=值)
變數名 = 類名.objects.filter(欄位名__in=值)[:2]

goods1_list = Goods.objects.filter(goodsType__in=goods_type1_2)[:4]
在 filter 中使用 __isnull
變數名 = 類名.objects.filter(欄位名__isnull=True)


allGoodsType = GoodsType.objects.filter(parent__isnull=True)
檔案 files , 具體請查閱更多資料

變數名 = request.FILES['名稱']

path = request.FILES['path']

cover = request.FILES['cover']
cover 為 html 中的 name 值 <input name="cover" type="file" ... >
使用 .get 獲取資料

變數 = 類名.objects.get(欄位=變數或值)

store_id = request.POST['goodsStore']
store = Store.objects.get(pk=store_id)
是否帶有 models 主要看匯入包的方式
from . import models

type2 = request.POST['type2']
goodsType = models.GoodsType.objects.get(pk=type2)
利用獲取到的物件的欄位屬性進行賦值

變數 = models.Goods.objects.get(欄位名1=引數)
變數= goods.欄位名2
store = models.類名.objects.get(欄位名1=欄位名2)


goods = models.Goods.objects.get(pk=g_id)
goodsStore_id = goods.goodsStore_id
store = models.Store.objects.get(pk=goodsStore_id)

注:
欄位名根據實際需要進行修改
獲取所有資料 使用 all 
變數名 = models.類名.objects.all()

all_goods = models.Goods.objects.all()
獲取 GET 引數
變數名1 = request.GET['名稱']

parent_id = request.GET['parent_id']

進行查詢資料
變數名2 = models.類名.objects.filter(欄位=變數名1)

type2 = models.GoodsType.objects.filter(parent=parent_id)
使用 getlist 獲取多個數據

變數 = request.POST.getlist('名稱')

shopcar_id_list = request.POST.getlist('buy_goods_id')

進行查詢資料
變數2 = app名.models.類名.objects.filter(欄位名__in=變數)
shopcar_list
= shopcar.models.ShopCar.objects.filter(pk__in=shopcar_id_list)
關於欄位中 user=request.user 的理解
MyOrder 中的 user 是 User 的外來鍵,所以在使用時,要注意傳遞的屬性還是一整個物件

my_order = models.MyOrder(user=request.user, address=addr, total=total)

user = models.ForeignKey(User, on_delete=models.CASCADE)
使用 欄位_set 可以獲取到外來鍵的表的欄位,具體詳情請查閱更多資料

此處僅給出部分示例

for sc_id in shopcar_list:
    shopcart = shopcar.models.ShopCar.objects.get(pk=sc_id)
    order_item = models.MyOrderItem(goods_image=shopcart.goods.goodsimage_set.first().path,
                                    goods_name=shopcart.goods.name,
                                    goods_price=shopcart.goods.price,
                                    goods_count=shopcart.number,
                                    goods_money=shopcart.allMoney,
                                    my_order=my_order)
    order_item.save()
    total += shopcart.allMoney
my_order.total = total
my_order.save()
get 獲取寫法,比之前的更深入一些

@login_required
@require_GET
def shop_into(request, number, goods_id):
    goods = Goods.objects.get(pk=goods_id)
    user = request.user
    try:
        shop_car = models.ShopCar.objects.get(user=user, goods=goods)
        shop_car.number += int(number)
        shop_car.allMoney = shop_car.number*goods.price
        shop_car.save()
    except:
        shop_car = models.ShopCar(goods=goods, number=number, user=user)
        shop_car.allMoney = int(shop_car.number)*goods.price
        shop_car.save()
    return redirect(reverse('shopcar:list_car'))

在使用 get 方法時,其中的 = 左側依舊為欄位名,=右側的為get 獲取到的物件,user 為 request.user

goods = Goods.objects.get(pk=goods_id)
user = request.user
shop_car = models.ShopCar.objects.get(user=user, goods=goods)

request.user 擁有 id 屬性

使用 get 可以獲取到欄位進行參與表示式運算

shop_car.allMoney = shop_car.number*goods.price
刪除資料 使用 delete()
shopcar = models.ShopCar(pk=shopcar_id, user=user)
shopcar.delete()
使用 int 進行轉換

status = models.IntegerField(default=0, verbose_name='店鋪狀態')


store = models.Store.objects.get(id=s_id)
store.status = int(status)
獲取 session 使用 request.session

變數名 = request.session["名稱"]
示例:

if code.lower() != request.session["code"].lower():
    return render(request, "users/user_login.html", {"msg": "驗證碼錯誤!!"})
使用 authenticate

from django.contrib.auth import authenticate
user = authenticate(username=username, password=password1)

password1 = utils.encryption(password)

# 密碼加密
def encryption(key):
    pwd = hmac.new(key.encode('utf-8'), settings.SALT_KEY.encode('utf-8'), 'MD5')
    return pwd.hexdigest()

此時的 user 擁有 is_active 屬性,判斷是否登入狀態
if user is not None:
    if user.is_active:
        login(request, user)
        try:
            return redirect(next_url)
        except:
            return redirect("/")
    else:
        return render(request, "users/user_login.html", {"msg": "您的賬號已被鎖定,請聯絡管理員"})
else:
    return render(request, "users/user_login.html", {"msg": "使用者名稱或者密碼錯誤"})
匯入 User
from django.contrib.auth.models import User

user = User.objects.create_user(username=username, password=password)

user.save()
程式碼塊介紹之後,進行return返回
return render(request, 'templates 下的資料夾名稱/檔名.html', {'名稱': 值})


return render(request, 'address/address_add.html', {'address_list': address_list})

可以存在多個引數,goods 為在app目錄下templates 中的 goods 資料夾
return render(request, 'goods/goods_show.html', {'goods': goods, 'store': store, 'nums':nums})
return redirect(reverse('名稱1:值1', kwargs={'引數名': 值}))
html 中的資料
<a href="{% url '名稱1:值1' 空格 引數名 %}">內容</a>

store_id = request.POST['goodsStore']

return redirect(reverse('store:detail_store', kwargs={'s_id': store_id}))

在這裡 'store:detail_store' 為 反向解析

<a href="{% url 'store:detail_store' store.id %}">檢視詳情</a>
from django.core.serializers import serialize

type1 = models.GoodsType.objects.filter(parent=parent_id)
return HttpResponse(serialize('json', type1))
#轉換成json型別的字串
return redirect(reverse('shopcar:list_car'))


<a href="{% url 'shopcar:list_car'%}" style="border: none;color: #00b7ee;width: 100px;height: 40px" >返回購物車</a>
from io import BytesIO

def code(request):
    img, msg = utils.create_code()
    f = BytesIO()
    img.save(f, "PNG")
    # 將驗證碼的值儲存到session
    request.session["code"] = msg
    return HttpResponse(f.getvalue(), "image/png")

utils.py 檔案,自己建立,如果需要可以複製貼上
import hmac
import string
import random
from PIL import Image, ImageDraw, ImageFont
from django.conf import settings



# 密碼加密
def encryption(key):
    pwd = hmac.new(key.encode('utf-8'), settings.SALT_KEY.encode('utf-8'), 'MD5')
    return pwd.hexdigest()


# 驗證碼
def getRandomChar(count=4):
    # 生成隨機字串
    # string模組包含各種字串,以下為小寫字母加數字
    ran = string.ascii_lowercase + string.ascii_uppercase + string.digits
    char = ''
    for i in range(count):
        char += random.choice(ran)
    return char


# 返回一個隨機的RGB顏色
def getRandomColor():
    return random.randint(50, 150), random.randint(50, 150), random.randint(50, 150)


def create_code():
    # 建立圖片,模式,大小,背景色
    img = Image.new('RGB', (120, 30), (255, 255, 255))
    # 建立畫布
    draw = ImageDraw.Draw(img)
    # 設定字型
    font = ImageFont.truetype('ARIALUNI.TTF', 25)

    code = getRandomChar()
    # 將生成的字元畫在畫布上
    for t in range(4):
        draw.text((25*t+7, 0), code[t], getRandomColor(), font)

    # 生成干擾點 增加識別的難度
    for _ in range(random.randint(99, 110)):
        # 位置,顏色
        draw.point((random.randint(0, 120), random.randint(0, 30)), fill=getRandomColor())
    # 生成干擾線 增加識別的難度
    for _ in range(random.randint(8, 15)):
        begin = random.randint(0, 120), random.randint(0, 50)
        end = random.randint(0, 120), random.randint(0, 50)
        draw.line([begin, end], fill=getRandomColor())

    # 使用模糊濾鏡使圖片模糊
    # img = img.filter(ImageFilter.BLUR)
    return img, code

HTML 檔案
此處只例舉一些基本語句,具體用法請查閱相關資料
{% block 名稱 %}{% endblock %}
進行繼承模板
{% extends '名稱.html' %}
{% csrf_token %}

伺服器返回頁面的同時向前端返回一串隨機字元

post提交時伺服器會驗證這串字元來確保使用者是在服務端返回的表單頁面中提交的資料
<tbody>
{% for addr in address_list %}
<tr>
    <td>{{addr.欄位1}}</td>
    <td>{{addr.欄位2}}</td>
    <td>{{addr.欄位3}}</td>
    <td>
        {% if addr.is_default %}
        預設地址
        {% endif %}
    </td>
</tr>
{% empty %}
<tr>提示資訊</tr>
{% endfor %}
</tbody>
{% if request.user.username %}
    html 語句
{% else %}
    html 語句
{% endif %}
{{request.user.userinfo.nickname}}
<form action="{%url 'orders:order_done' %}" method="post">
<input type="hidden" name="sc" value="{{sc.id}}">
<span>{{shopcar.number}}</span>
下單時間:{{order.order_time|date:'Y-m-d G:i:s'}}<br>
{% if store.status == 0 %}
<span style="font-size: 16px">店鋪狀態:正在營業</span>
{% elif store.status == 1 %}
<span style="font-size: 16px">店鋪休息</span>
{% endif %}
{{goods.desc|truncatechars:22}}
擷取前22個字元
{% for t in type1 %}
<option value="{{t.id}}" >{{t.name}}</option>
{% endfor %}

html 下還有很多的用法,此處僅列舉出了這些

django 專案獲取連結
連結:https://pan.baidu.com/s/1oWcHHbSR0JHmqr9qCzZGwA 提取碼:Hany

2020-07-24