假设我们有个电商网站,一个基本的流程就是用户下单,然后进入购物车cart, 然后进入checkout。 假设我们有如下比较简单的Data Structure:
1.针对这个数据结构来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这个需要安装pillow
pipenv install pillow
2.model需要进行makingmigrations这样就会创建Customer, Order...这些不同的models
python manage.py makingmigrations
然后进行migrate
python manage.py migrate
这样就算把Data Structure建立好了,如果DB有实际的数据的话,一个简单的访问数据的方式就是Order.objects.all()或者Product.objects.all()
3. 把这些model加到admin后台以准备手动添加数据:
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. 创建超级用户来手动添加数据
python manage.py createsuperuser
127.0.0.1:8000/admin 就可以访问了
4.1 手动添加product, customer, order, orderitem等数据
4.2 为了给商品动态添加图片
采用在后台上传图片的方式而不是直接在项目的images文件中直接添加图片。 那么上传的图片你需要告诉项目存在项目的什么地方,所以需要在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)
这样后台upload image到对应的product时候,系统会自动将图片添加到static/images下
5. 把添加的数据反映到网页上,需要修改views.py和对应xxx.html:
注意其中Order.objects.get_or_create(customer=customer, complete=False)的使用是根据目前还没有结账的该登录用户的信息query这个用户的order的中item有哪些,如果没有order就创建order.
items = order.orderitem_set.all() 表示用这个order去拿到所有order下的items,因为建立模型的时候就是一个order(parent)对应多个items(child with model 'OrderItem'), 所以这个方法其实是 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对应html文件的方式就是用
context = {a_key_belonging_to_some_model: value}
,
然后传入context, html文件取这些值的方式就是{{a_key_belonging_to_some_model.xxx}}
,比如item对应的model就是orderitem, 里面有成员quantity, 所以直接item.quantity就可以拿到这个物品的数量。orderitem有外键product, 而product这个model有成员name,所以item.product.name可以拿到这个item对应的product的name.
item.get_total的用法其实是在models.py里面用了python的property decorator, 关于为什么要用property decorator,这里有篇不错的文章做了解释.
比如下面就是在cart.html中的render出数据的一段代码:
{% for item in items %}
{{item.product.name}}
SEK {{item.product.price|floatformat:2}}
{{item.quantity}}
SEK {{ item.get_total }}
{% endfor %}