假設(shè)我們有個(gè)電商網(wǎng)站,一個(gè)基本的流程就是用戶下單,然后進(jìn)入購(gòu)物車cart, 然后進(jìn)入checkout。 假設(shè)我們有如下比較簡(jiǎn)單的Data Structure:

1.針對(duì)這個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)build data model:
models.py in the 'store' app
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(
User, null=True, blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=False)
image = models.ImageField(null=True, blank=True)
def __str__(self):
return self.name
@property
def imageURL(self):
try:
url = self.image.url
except:
url = ""
return url
class Order(models.Model):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False, null=True, blank=False)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
@property
def get_cart_total(self):
orderitems = self.orderitem_set.all()
total = sum([item.get_total for item in orderitems])
return total
@property
def get_cart_items_quantity(self):
orderitems = self.orderitem_set.all()
total = sum([item.quantity for item in orderitems])
return total
class OrderItem(models.Model):
product = models.ForeignKey(
Product, on_delete=models.SET_NULL, null=True, blank=True)
order = models.ForeignKey(
Order, on_delete=models.SET_NULL, null=True, blank=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.product.name)
@property
def get_total(self):
total = self.product.price * self.quantity
return total
class ShippingAddress(models.Model):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True, blank=True)
order = models.ForeignKey(
Order, on_delete=models.SET_NULL, null=True, blank=True)
address = models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
注意下其中的image這個(gè)需要安裝pillow
pipenv install pillow
2.model需要進(jìn)行makingmigrations這樣就會(huì)創(chuàng)建Customer, Order...這些不同的models
python manage.py makingmigrations
然后進(jìn)行migrate
python manage.py migrate
這樣就算把Data Structure建立好了,如果DB有實(shí)際的數(shù)據(jù)的話,一個(gè)簡(jiǎn)單的訪問(wèn)數(shù)據(jù)的方式就是Order.objects.all()或者Product.objects.all()
3. 把這些model加到admin后臺(tái)以準(zhǔn)備手動(dòng)添加數(shù)據(jù):
admin.py
from django.contrib import admin
# Register your models here.
from .models import *
admin.site.register(Customer)
admin.site.register(Product)
admin.site.register(Order)
admin.site.register(OrderItem)
admin.site.register(ShippingAddress)
4. 創(chuàng)建超級(jí)用戶來(lái)手動(dòng)添加數(shù)據(jù)
python manage.py createsuperuser
127.0.0.1:8000/admin 就可以訪問(wèn)了
4.1 手動(dòng)添加product, customer, order, orderitem等數(shù)據(jù)
4.2 為了給商品動(dòng)態(tài)添加圖片
采用在后臺(tái)上傳圖片的方式而不是直接在項(xiàng)目的images文件中直接添加圖片。 那么上傳的圖片你需要告訴項(xiàng)目存在項(xiàng)目的什么地方,所以需要在settings中添加:
MEDIA_URL = '/images/'
MEDIA_ROOT = os.path.join(BASE_DIR, "static/images")
然后再urls.py中添加:
from django.conf.urls.static import static
from django.conf import settings
....
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
這樣后臺(tái)upload image到對(duì)應(yīng)的product時(shí)候,系統(tǒng)會(huì)自動(dòng)將圖片添加到static/images下
5. 把添加的數(shù)據(jù)反映到網(wǎng)頁(yè)上,需要修改views.py和對(duì)應(yīng)xxx.html:
注意其中Order.objects.get_or_create(customer=customer, complete=False)的使用是根據(jù)目前還沒(méi)有結(jié)賬的該登錄用戶的信息query這個(gè)用戶的order的中item有哪些,如果沒(méi)有order就創(chuàng)建order.
items = order.orderitem_set.all() 表示用這個(gè)order去拿到所有order下的items,因?yàn)榻⒛P偷臅r(shí)候就是一個(gè)order(parent)對(duì)應(yīng)多個(gè)items(child with model 'OrderItem'), 所以這個(gè)方法其實(shí)是 parentmodel.lowercasesofchildmodel_set.all()
from django.shortcuts import render
from .models import *
# Create your views here.
def store(request):
products = Product.objects.all()
context = {"products": products}
return render(request, 'store/store.html', context)
def cart(request):
# user has logged in:
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(
customer=customer, complete=False)
items = order.orderitem_set.all()
# user has not logged in:
else:
items = []
order = {'get_cart_total': 0, 'get_cart_items_quantity': 0}
context = {"items": items, "order_of_this_transaction": order}
print("context:")
print(context)
return render(request, 'store/cart.html', context)
def checkout(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(
customer=customer, complete=False)
items = order.orderitem_set.all()
else:
items = []
order = {'get_cart_total': 0, 'get_cart_items_quantity': 0}
context = {"items": items, "order_of_this_transaction": order}
return render(request, 'store/checkout.html', context)
把這些拿到的值拿去render對(duì)應(yīng)html文件的方式就是用
context = {a_key_belonging_to_some_model: value},
然后傳入context, html文件取這些值的方式就是{{a_key_belonging_to_some_model.xxx}},比如item對(duì)應(yīng)的model就是orderitem, 里面有成員quantity, 所以直接item.quantity就可以拿到這個(gè)物品的數(shù)量。orderitem有外鍵product, 而product這個(gè)model有成員name,所以item.product.name可以拿到這個(gè)item對(duì)應(yīng)的product的name.
item.get_total的用法其實(shí)是在models.py里面用了python的property decorator, 關(guān)于為什么要用property decorator,這里有篇不錯(cuò)的文章做了解釋.
比如下面就是在cart.html中的render出數(shù)據(jù)的一段代碼:
{% for item in items %}
<div class="row cart-row align-items-center">
<div class="col-lg-3">
<img class="row-image" src="{{item.product.imageURL}}" alt="" />
</div>
<div class="col-lg-3 table-content">{{item.product.name}}</div>
<div class="col-lg-2 table-content">
SEK {{item.product.price|floatformat:2}}
</div>
<div class="col-lg-2 table-content quantity-container">
<div class="quantity">
<img
src="{% static 'images/up-arrow.png' %}"
alt=""
class="chg-quantity"
/>
<img
src="{% static 'images/down-arrow.png' %}"
alt=""
class="chg-quantity"
/>
</div>
<p class="quantity">
{{item.quantity}}
</p>
</div>
<div class="col-lg-2 table-content">
<span>SEK {{ item.get_total }}</span>
</div>
</div>
{% endfor %}
</div>