嘿,欢迎您介绍另一篇文章,我将带您浏览一个令人兴奋的概念,这是电子商务网站和应用程序中最重要的一部分。
购物车或篮子至关重要,因为它允许客户选择他们想要购买的产品,类似于现实生活,我们使用手推车或篮子来容纳我们想要购买的各种物品。同样,我们实际上使用购物车实际完成了相同的任务。
本教程旨在引导您逐步构建此类购物车逻辑,同时利用Django和Django Rest框架的力量。毫无疑问,让我们深入研究吗?
项目设置
我们将首先导航到工作空间上的一个文件夹,在那里我们将创建项目文件夹。对我来说,那是桌面文件夹,因此请打开一个终端窗口并导航到该文件夹:
cd desktop
mkdir drf_shopping_cart && cd drf_shopping_cart
上面,我们将导航到计算机上的桌面文件夹中,然后创建一个称为drf_shopping_cart
的文件夹,然后还导航到其中。接下来,让我们发出以下命令,我很快就会解释:
virtualenv env
source env/bin/activate
pip install django djangorestframework pillow
在这里,我们正在创建一个虚拟环境,以将项目的依赖关系与系统宽的配置和设置隔离,然后我们激活它,最后安装我们的两个主要依赖项,即Django和DRF以及用于图像的第三个依赖关系枕头Python的处理。
借此来,请发出以下命令,我在一点点解释:
django-admin startproject mysite .
python manage.py startapp cart
因此,第一个命令用于创建一个新项目,然后使用startapp
命令在我们的项目中创建一个新应用。 cart
应用程序是我们将花费大量时间编写代码的地方。下一个至关重要的步骤是将我们新创建的cart
应用与DRF一起添加到settings.py
中的已安装应用程序列表,因此请继续添加:
INSTALLED_APPS = [
....
'cart',
'rest_framework',
]
设置模型
现在,如果您考虑一下,我们需要一个数据库表,该表将包含产品信息,例如名称,价格,Image E.T.C.我们可以通过使用Django模型来实现这一目标,以便我们将Python代码作为类编写,并且由于内置的Django Orm,它将被转换为SQL表。
前往cart/models.py
并添加以下代码:
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=150)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
is_available = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return str(self.name)
我们已经定义了一些表字段,但随时可以添加更多信息。为了确保我们的数据库已捕获,我们需要运行以下命令来同步应用更改:
python makemigrations && python manage.py migrate
此时我们的数据库准备就绪。
现在,因为我们将处理产品图像,我们需要添加更多设置,以免遇到错误和挫败感。首先打开mysite/settings.py
文件,然后在底部添加以下内容:
import os
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
我们正在设置MEDIA_ROOT
,这是通往目录的绝对路径,我们的应用程序将从
中提供图像
然后,我们将设置MEDIA_URL
,这是将处理媒体根部提供的图像的URL。
下一个打开mysite/urls.py
并添加以下代码:
#...
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
#...
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
在这一点上,我们准备移至下一章。
用产品填充数据库
现在,我们需要使用一些数据来填充数据库表的数据库表,这些数据可以用来测试购物车功能。
我们将需要创建一个端点,使我们能够创建和列出产品并实现这一目标,我们将创建一个序列化器类,以将复杂的数据类型转换为本机Python等效物,然后可以将其呈现为JSON。
接下来,我们将创建一个视图,该视图允许我们从数据库中写入并阅读。
在购物车文件夹中创建一个名为serializers.py
的文件,并添加以下代码:
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = "__all__"
下一个打开cart/views.py
并添加以下代码:
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from .serializers import ProductSerializer
from .models import Product
class ProductAPI(APIView):
"""
Single API to handle product operations
"""
serializer_class = ProductSerializer
def get(self, request, format=None):
qs = Product.objects.all()
return Response(
{"data": self.serializer_class(qs, many=True).data},
status=status.HTTP_200_OK
)
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
serializer.data,
status=status.HTTP_201_CREATED
)
我们创建了一个单个端点,它将允许我们执行GET
请求,以检索数据库中的所有产品和POST
请求,以将新产品保存到数据库中。
下一个打开mysite/urls.py
并添加以下代码:
#...
from cart.views import ProductAPI
urlpatterns = [
#...
path('products', ProductAPI.as_view(), name='products'),
]
#...
我们准备在数据库中添加新产品,因此可以通过:
旋转服务器
python manage.py runserver
访问http://localhost:8000/products并添加几个产品。
建造购物车
在这一点 购物车应在客户浏览网站之前暂时存储任何产品,直到下订单为止。
为此,我们将利用Django的会话框架来坚持购物车并将其保持在会话中,直到下订单或会话到期。
Django的会话框架支持匿名和用户会话,并且存储的数据在每个站点访问者中都是唯一的。当我们创建项目时,Django添加了一个会话中间件django.contrib.sessions.middleware.SessionMiddleware
,以管理项目中的所有会话。此中间件将当前的会话用作字典中的当前会话,因此我们可以通过调用request.session
访问它,并且可以序列化。
足够的文献,让我们编写一些代码:)。这是我们要做的:
- 创建一个手推车服务来处理购物车
- 创建一个调用购物车服务的API端点
- 测试每个购物车操作
如上所述,我们需要创建一项服务来放置购物车的逻辑。在购物车文件夹中创建一个名为service.py
的文件,并添加以下代码:
from decimal import Decimal
from django.conf import settings
from .serializers import ProductSerializer
from .models import Product
class Cart:
def __init__(self, request):
"""
initialize the cart
"""
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
# save an empty cart in session
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
def save(self):
self.session.modified = True
def add(self, product, quantity=1, overide_quantity=False):
"""
Add product to the cart or update its quantity
"""
product_id = str(product["id"])
if product_id not in self.cart:
self.cart[product_id] = {
"quantity": 0,
"price": str(product["price"])
}
if overide_quantity:
self.cart[product_id]["quantity"] = quantity
else:
self.cart[product_id]["quantity"] += quantity
self.save()
def remove(self, product):
"""
Remove a product from the cart
"""
product_id = str(product["id"])
if product_id in self.cart:
del self.cart[product_id]
self.save()
def __iter__(self):
"""
Loop through cart items and fetch the products from the database
"""
product_ids = self.cart.keys()
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
for product in products:
cart[str(product.id)]["product"] = ProductSerializer(product).data
for item in cart.values():
item["price"] = Decimal(item["price"])
item["total_price"] = item["price"] * item["quantity"]
yield item
def __len__(self):
"""
Count all items in the cart
"""
return sum(item["quantity"] for item in self.cart.values())
def get_total_price(self):
return sum(Decimal(item["price"]) * item["quantity"] for item in self.cart.values())
def clear(self):
# remove cart from session
del self.session[settings.CART_SESSION_ID]
self.save()
现在让我们浏览上面的代码,因为那里发生了很多事情。
我们定义了一个Cart
课程,使我们能够管理购物车。
__init__
方法是我们的构造函数,需要一个请求对象才能初始化购物车。我们还存储了当前的会话,使其可以访问购物车类的其他方法。如前所述,我们尝试从当前会话中获取购物车,如果缺少它,我们通过在会话中设置一个空词典来创建一个空购物。
add
方法是我们的下一个方法,用于将产品添加到购物车或更新其数量。它将product, quantity, override_quantity
作为参数。产品ID充当字典的关键,而数量和价格数字成为字典的价值。
save
方法简单地将会话标记为修改,因此Django知道会话更改并需要保存
remove
方法确实可以从购物车中取出给定的产品。它还调用保存方法来确保所有保存所有内容。
然后,我们定义了一种__iter__
方法,该方法使我们可以循环浏览购物车的项目并访问相关的产品对象。在这里,我们获取了购物车中存在的产品实例。我们将在我们看来使用它。
__len__
方法返回购物车中的总项目数。
get_total_price
方法计算购物车中物品的总成本。
最后但并非最不重要的一点是,clear
方法在调用save
方法之前删除整个字典中的卡车对象。
最后,我们将以下设置添加到mysite/settings.py
文件。
CART_SESSION_ID = 'cart
有了所有这些,我们的Cart
班准备好管理购物车。
创建购物车API视图
好吧,我们有一个Cart
类来管理购物车,我们现在需要创建API端点以列出,添加,更新,删除项目并清除购物车。
考虑到这一点,让我们创建视图。打开cart/views.py
并添加以下代码:
class CartAPI(APIView):
"""
Single API to handle cart operations
"""
def get(self, request, format=None):
cart = Cart(request)
return Response(
{"data": list(cart.__iter__()),
"cart_total_price": cart.get_total_price()},
status=status.HTTP_200_OK
)
def post(self, request, **kwargs):
cart = Cart(request)
if "remove" in request.data:
product = request.data["product"]
cart.remove(product)
elif "clear" in request.data:
cart.clear()
else:
product = request.data
cart.add(
product=product["product"],
quantity=product["quantity"],
overide_quantity=product["overide_quantity"] if "overide_quantity" in product else False
)
return Response(
{"message": "cart updated"},
status=status.HTTP_202_ACCEPTED)
那里发生了很多事情,所以让我们将其分解。我们是子类REST框架的Apiview,并定义了两种http
方法。
在get
方法中,我们发送了一个GET
请求并初始化一个购物车对象,然后我们调用其__iter__
方法,该方法将使我们归还生成器对象。然后,我们将内置的list
拨打,以获取一份列表,然后将其作为响应的一部分序列化。另外,我们正在通过致电get_total_price
来返回购物车总数。
在post
方法中,我们发送了一个POST
请求,然后初始化卡车传递的实例,然后我们检查请求有效载荷中是否存在一些东西。
我们检查有效载荷中是否有一个名为remove
的密钥,如果存在,则我们从有效载荷中调用了产品中的购物车的remove()
。
然后,我们检查有效载荷中是否有一个名为clear
的密钥,如果存在,则我们调用购物车的clear()
以将其从当前会话中删除。
如果我们没有这两个密钥,那么我们将通过产品中的购物车的add()
称为add()
,数量以及是否覆盖数量。
在一天结束时,我们还会回复带有消息和状态的响应,但我们可以做更多的事情。在测试逻辑之前,我们只有最后一步。
打开mysite/urls.py
并向它添加以下代码:
#...
from cart.views import CartAPI
urlpatterns = [
#...
path('cart', CartAPI.as_view(), name='cart'),
#...
]
#...
让我们测试购物车
确保服务器仍在运行。前往购物车的URL,即http://localhost:8000/cart。让我们用follwoing有效载荷进行帖子:
{
"product": {
"id": 1,
"name": "Macbook Pro",
"description": "Our most powerful laptops, MacBook Pros are supercharged by M1 and M2 chips. Featuring Magic Keyboard, Touch ID, and brilliant Retina display.",
"price": "1800.00",
"image": "/products/2023/08/30/sp809-mbp16touch-silver-2019.jpeg",
"is_available": true,
"created_at": "2023-08-30T11:58:54.476688Z",
"modified_at": "2023-08-30T11:58:54.476720Z"
},
"quantity": 5
}
现在,在Get请求时,我们应该看到以下屏幕以显示添加作用。
{
"product": {
"id": 1,
"name": "Macbook Pro",
"description": "Our most powerful laptops, MacBook Pros are supercharged by M1 and M2 chips. Featuring Magic Keyboard, Touch ID, and brilliant Retina display.",
"price": "1800.00",
"image": "/products/2023/08/30/sp809-mbp16touch-silver-2019.jpeg",
"is_available": true,
"created_at": "2023-08-30T11:58:54.476688Z",
"modified_at": "2023-08-30T11:58:54.476720Z"
},
"remove": true
}
和清除购物车,有效载荷将简单:
{
"clear": true
}
继续测试它们,看看您最终的结果:)
这是一个包装
是的,这是一个包裹!如果您到达教程的末尾,那么对您来说是一个很大的拥抱。感谢您抽出宝贵的时间阅读和关注,希望您学到了一两件事,可以帮助您进行编码之旅。
如果您有任何想法,问题等,请将它们放在下面。
我也在寻找我的下一个角色,因此,如果您的团队正在招聘或认识任何人,那么如果我得到推荐,我会很有责任。
我可以通过Twitter或我的linkedin或我的website提供,我的电子邮件是nicksonlangat95@gmail.com。
本教程中使用的代码可以是found here.
暂时再见,在下一个见到你。欢呼ð¥