项目简介:
Hello 今天和同学们分享一个Python推荐系统的项目,校园外卖推荐系统,下面先直接介绍一下这个项目的大概实现功能和相关涉及技术吧~
📖Python校园外卖推荐系统
📖首页模块:展示全部外卖数据,用户可以点击查看外卖详情,搜索外卖,也可以通过分类标签查看外卖,以及展示用户最近购买下单过的商品.
📖 热门模块:根据用户收藏和下单的数量位指标来评选展示热门的商品,同时用户可以搜索外卖,查看最近下单过的外卖数据.
📖 推荐模块:根据用户收藏和下单以及浏览等参数作为指标依据,结合协同过滤算法个性化给用户推荐可能喜欢的商品,并支持用户搜索和分类查询.
📖 购物车模块:展示用户购物车的外卖数据,添加了哪些外卖以及数量,并展示总金额,用户再次页面进行支付.
📖 订单模块:展示用户所有下单的数据(时间,外卖,数量以及金额)
📖 今日数据:可视化出现外卖的字段数据,给用户友好清晰展示外卖的详细数据,为用户下单和选择提供友好的选择和参考~
📖 管理员模块:管理员可以对用户数据,外卖数据,用户购物车数据,用户订单数据,热门数据,推荐数据进行综合管理.
📖 涉及技术:Python,Django,MySQL,协同过滤,前端.
项目核心代码:
数据库设计:
from django.db import models
# Create your models here.
import uuid
from django.db import models
from django.contrib.auth.models import User
class UserInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='用户',related_name='userInfo')
class_name = models.CharField(max_length=50, verbose_name='班级') # 增加班级字段
grade = models.CharField(max_length=50, verbose_name='年级') # 增加年级字段
phone = models.CharField(max_length=11, verbose_name='电话')
address = models.CharField(max_length=255, verbose_name='地址')
def __str__(self):
return self.user.username
class Meta:
verbose_name = '用户信息'
verbose_name_plural = '用户信息'
class Category(models.Model):
name = models.CharField(max_length=100, unique=True, verbose_name='分类名称')
def __str__(self):
return self.name
class Meta:
verbose_name = '分类'
verbose_name_plural = '分类'
class Product(models.Model):
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='products',
verbose_name='分类'
)
name = models.CharField(max_length=255, verbose_name='名称')
price = models.DecimalField(
max_digits=10,
decimal_places=2,
verbose_name='价格'
)
stock = models.IntegerField(verbose_name='库存')
image = models.ImageField(
upload_to='products/',
blank=True,
null=True,
verbose_name='封面'
)
description = models.TextField(
blank=True,
null=True,
verbose_name='描述'
)
view_count = models.IntegerField(verbose_name='浏览量',default=0)
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建日期')
def __str__(self):
return self.name
class Meta:
verbose_name = '产品'
verbose_name_plural = '产品'
class Favorite(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='favorites',
verbose_name='用户'
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
related_name='favorited_by',
verbose_name='产品'
)
date_added = models.DateTimeField(auto_now_add=True, verbose_name='添加日期')
def __str__(self):
return f'{self.user.username} - {self.product.name}'
class Meta:
verbose_name = '用户收藏'
verbose_name_plural = '用户收藏'
unique_together = ('user', 'product') # 确保每个用户只能收藏同一个产品一次
class CartItem(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
verbose_name='用户'
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
verbose_name='产品'
)
quantity = models.IntegerField(default=1, verbose_name='数量')
def __str__(self):
return f"{self.quantity} of {self.product.name}"
def get_total_price(self):
return self.quantity * self.product.price
class Meta:
verbose_name = '购物车项'
verbose_name_plural = '购物车项'
#商品评分
class Product_score(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey('Product', on_delete=models.CASCADE)
score = models.IntegerField('热度', null=True,default=0)
def __str__(self):
return f'用户 {self.user.username} 对 {self.product.name} 的评分:{self.score}'
class Meta:
verbose_name = '商品评分'
verbose_name_plural = '商品评分'
# 订单
class Order(models.Model):
# 定义订单状态的选项
ORDER_STATUS_CHOICES = (
('未支付', '未支付'),
('已支付', '已支付'),
('已发货', '已发货'),
('已完成', '已完成'),
('已取消', '已取消'),
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
verbose_name='用户'
)
date_ordered = models.DateTimeField(
auto_now_add=True,
verbose_name='下单日期'
)
status = models.CharField(
max_length=10,
choices=ORDER_STATUS_CHOICES,
default='未支付',
verbose_name='订单状态'
)
transaction_id = models.CharField(
max_length=100,
default=uuid.uuid4(),
blank=True,
verbose_name='交易ID'
)
def __str__(self):
return f"订单 {self.id} 用户 {self.user.username}"
def get_total_cost(self):
return sum(item.get_total_price() for item in self.orderitem.all())
class Meta:
verbose_name = '订单'
verbose_name_plural = '订单'
class OrderItem(models.Model):
order = models.ForeignKey(
Order,
on_delete=models.CASCADE,
related_name='orderitem',
verbose_name='订单'
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
verbose_name='产品'
)
quantity = models.IntegerField(
default=1,
verbose_name='数量'
)
date_added = models.DateTimeField(
auto_now_add=True,
verbose_name='添加日期'
)
def __str__(self):
return f"{self.quantity} of {self.product.name}"
def get_total_price(self):
return self.quantity * self.product.price
class Meta:
verbose_name = '订单项'
verbose_name_plural = '订单项'
路由设置:
urlpatterns = [
path('admin/', admin.site.urls),
path('', account.login, name='login'),
path('index/', account.index, name='index'),
path('login/', account.login, name='login'),
path('logout/', account.logout, name='logout'),
path('register/', account.register, name='register'),
re_path('media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
path('profile/update/', account.profile_update, name='profile_update'),
path('password/change/', account.change_password, name='password_change'),
path('product/detail/<int:pk>/', index.product_detail, name='product_detail'),
path('cart/', index.cart, name='cart'),
path('order/success/<int:order_id>/',index.order_success, name='order_success'),
path('order/fail/',index.order_fail, name='order_fail'),
path('unorder/success/<int:order_id>/', index.unorder_success, name='unorder_success'),
path('order/process_payment/<int:order_id>/', index.process_payment, name='process_payment'),
path('orders/', index.order_list, name='order_list'),
path('orders/<int:order_id>/', index.order_detail, name='order_detail'),
path('toggle_favorite/<int:product_id>/', index.toggle_favorite, name='toggle_favorite'),
path('product/hot/', index.hot_products, name='hot'),
path('product/recommend/', recommd.recommend, name='recommend'),
path('today/chart/', chart.today_chart, name='today_chart'),
path('echart1/', chart.top_viewed_products, name='echart1'),
path('echart2/', chart.order_rank, name='echart2'),
path('echart3/', chart.favorite_rank, name='echart3'),
path('echart4/', chart.daily_order_volume, name='echart4'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
后端代码:
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Q, Sum
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from app.forms import CartAddForm
from app.models import Category, Product, CartItem, Order, OrderItem, Favorite, Product_score
# 产品详情页
@login_required
def product_detail(request, pk):
product = get_object_or_404(Product, pk=pk)
# 检测用户是否收藏
is_favorited = Favorite.objects.filter(user=request.user, product=product).exists()
# 提交购物车
if request.method == 'POST':
form = CartAddForm(request.POST)
if form.is_valid():
quantity = form.cleaned_data['quantity']
# 创建或更新购物车项
if request.user.is_authenticated:
cart_item, created = CartItem.objects.get_or_create(user=request.user, product=product)
cart_item.quantity = quantity
cart_item.save()
# 商品评分 加 3
product_score, score_created = Product_score.objects.get_or_create(user=request.user,product=product)
product_score.score += 3
product_score.save()
return redirect('cart')
else:
# 如果用户未登录,处理逻辑可能不同,例如使用 session 或 cookie
pass
return redirect('product_detail', pk=product.pk)
else:
form = CartAddForm()
# 浏览量 +1
product.view_count += 1
product.save()
# 商品评分+1
product_score, score_created = Product_score.objects.get_or_create(user=request.user, product=product)
product_score.score += 1
product_score.save()
return render(request, 'product_detail.html', {'product': product, 'form': form,'is_favorited':is_favorited})
# 购物车
@login_required
def cart(request):
cart_items = CartItem.objects.filter(user=request.user)
if request.method == 'POST':
if 'cart_items' in request.POST:
cart_item_ids = request.POST.getlist('cart_items')
order = Order(user=request.user)
order.save()
for cart_id in cart_item_ids:
try:
cart_item = CartItem.objects.get(id=cart_id)
quantity = request.POST.get(f'quantity_{cart_item.id}')
# 如果库存不足
if cart_item.product.stock < int(quantity):
return redirect(reverse('order_success', args=[order.id])) # 重定向到订单失败页面
# 创建订单
OrderItem.objects.create(
order=order,
product=cart_item.product,
quantity=quantity,
)
# 清楚购物车栏
cart_item.delete()
# 更新库存
cart_item.product.stock -= int(quantity)
cart_item.product.save()
except OrderItem.DoesNotExist:
pass # 如果项不存在,则忽略
return redirect(reverse('order_success', args=[order.id])) # 重定向到订单成功页面
elif 'update' in request.POST:
# 更新购物车
for cart_item in cart_items:
quantity = request.POST.get(f'quantity_{cart_item.id}')
cart_item.quantity = int(quantity) if quantity else 1
cart_item.save()
return redirect('cart')
elif 'delete' in request.POST:
# 获取所有被选中的项的 ID
cart_item_ids = request.POST.getlist('delete')
for cart_item_id in cart_item_ids:
try:
cart_item = CartItem.objects.get(id=cart_item_id)
cart_item.delete()
except CartItem.DoesNotExist:
pass # 如果项不存在,则忽略
return redirect('cart')
else:
cart_items = CartItem.objects.filter(user=request.user)
total = sum(item.product.price * item.quantity for item in cart_items)
context = {
'cart_items': cart_items,
'total': total,
}
return render(request, 'cart.html', context)
# 提交订单
@login_required
# 提交订单成功
def order_success(request,order_id):
# 假设订单成功后,返回订单成功页面
order = Order.objects.get(id=order_id)
context = {'order': order,'total_cost':order.get_total_cost(),'title':'您的订单已经提交成功','flag':'order'}
return render(request, 'order_success.html', context)
# 订单失败
@login_required
# 提交订单成功
def order_fail(request):
# 假设订单成功后,返回订单成功页面
context = {'title':'订单创建失败,请检查库存'}
return render(request, 'order_fail.html',context)
@login_required
# 取消订单成功
def unorder_success(request,order_id):
# 假设订单成功后,返回订单成功页面
order = Order.objects.get(id=order_id)
order.status = '已取消'
order.save()
context = {'order': order,'total_cost':order.get_total_cost(),'title':'您的订单已经取消成功','flag':'unorder'}
return render(request, 'order_success.html', context)
@login_required
# 支付成功
def process_payment(request, order_id):
# 这里添加支付逻辑,比如调用支付网关
# 以下代码仅为示例,实际项目中需要替换为真实的支付逻辑
try:
order = Order.objects.get(id=order_id)
# 假设支付成功后,设置订单为完成状态
order.status = '已支付'
order.save()
# 商品评分+4
for item in order.orderitem.all():
product_score, score_created = Product_score.objects.get_or_create(user=request.user, product=item.product)
if score_created:
product_score.score += 4
product_score.save()
return render(request, 'pay_success.html',{'order':order})
except:
return HttpResponse("支付处理错误", status=400)
@login_required
# 我的订单
def order_list(request):
orders = Order.objects.filter(user=request.user)
context = {
'orders': orders,
}
return render(request, 'order_list.html', context)
@login_required
# 订单详情
def order_detail(request, order_id):
order = Order.objects.get(user=request.user, id=order_id)
context = {
'order': order,
}
return render(request, 'order_detail.html', context)
# 收藏
@login_required
def toggle_favorite(request, product_id):
product = get_object_or_404(Product, id=product_id)
# 这里添加你的逻辑来切换收藏状态
# 例如,如果有一个 Favorite 模型来存储收藏的商品
favorite, created = Favorite.objects.get_or_create(user=request.user, product=product)
product_score , score_created= Product_score.objects.get_or_create(user=request.user, product=product)
if not created:
product_score.score -= 2
product_score.save()
favorite.delete()
else:
# 给商品收藏加2分
product_score.score += 2
product_score.save()
favorite.save()
is_favorited = Favorite.objects.filter(user=request.user, product=product).exists()
return JsonResponse({'isFavorited': is_favorited})
@login_required
# 热门
def hot_products(request):
# 计算每个商品的总热度
product_scores = Product_score.objects.filter(score__gt=0).values('product').annotate(total_score=Sum('score'))
# 获取总热度排名前十的商品
top_10_hot_products = product_scores.order_by('-total_score')[:10]
# 获取热门商品的ID列表
hot_product_ids = [item['product'] for item in top_10_hot_products]
# 获取最近购买的商品,这里假设我们只取最新的5个订单的商品
recent_items = OrderItem.objects.filter(
Q(product_id__in=hot_product_ids) &
Q(order__user=request.user)
).select_related('product').order_by('-date_added')[:5]
products = Product.objects.filter(id__in=[item.product.id for item in recent_items])
# 自己最近购买商品 以及热度
recent_products = products.annotate(total_score=Sum('product_score__score')).order_by('-total_score')
query = request.GET.get('q')
# 如果没有查询参数,只按照category_id排序
products = Product.objects.filter(
id__in=hot_product_ids
).order_by('category_id').annotate(total_score=Sum('product_score__score'))
if query:
products = Product.objects.filter(
Q(id__in=hot_product_ids) &
Q(name__icontains=query)
).order_by('category_id').annotate(total_score=Sum('product_score__score'))
categories = Category.objects.all()
# 如果有分类选择,过滤商品
category_id = request.GET.get('category')
selected_category = None # 记录选中的分类
if category_id:
try:
selected_category = Category.objects.get(id=category_id)
products = products.filter(
Q(id__in=hot_product_ids) & Q(category=selected_category))
except Category.DoesNotExist:
products = Product.objects.none()
# 按照热度排序
products = products.order_by('-total_score')
# 分页
paginator = Paginator(products, 6) # 每页显示10个商品
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'categories': categories,
'products': page_obj,
'selected_category': selected_category,
'recent_products': recent_products,
}
return render(request, 'hot_products.html', context)
推荐算法:
import os
from math import *
import time
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db.models import Q
from django.http import JsonResponse
from django.shortcuts import render, redirect
from app import models
from app.models import Product_score, Product, User, OrderItem, Category
def getdata():#获取数据
alldata=Product_score.objects.values_list('user','product','score')
data={}
# for i in alldata:
# if not i[0] in data.keys():
# data[i[0]]={i[1]:i[2]}
# else:
# data[i[0]][i[1]]=i[2]
for user, product, score in alldata:
if user not in data:
data[user] = {}
data[user][product] = score
return data
#计算用户相似度
def Euclid(user1,user2):#尤几里得距离也就是欧式距离
#取出两个用户都查看过的的职位
data=getdata()
print('data',data)
user1_data = data.get(user1, {})
user2_data = data.get(user2, {})
#默认距离,相似度越大距离越短
distance=0
#遍历找出相同职位
for key in user1_data.keys():
if key in user2_data.keys():
distance+=pow(float(user1_data[key])-float(user2_data[key]),2)
return 1/(1+sqrt(distance))
#计算某用户和其他用户相似度的比对
def top_simliar(user):
res=[]
data=getdata()
for userid in data.keys():
#首先排除当前用户
if not userid==user:
simliar=Euclid(user,userid)
res.append((userid,simliar))
res.sort(key=lambda val:val[1],reverse=True)
return res,data
def recommend(request):#给用户推荐职位方法
# id =request.session.get('user').get('id')
#print(top_simliar(id))
user = request.user
res,data=top_simliar(user.id)
print('res+data',res,data)
workid={}
try:
for i in range(5):
top_user=res[i][0]
#print(top_user)
#print(data[top_user])
workid.update(data[top_user])
except:
pass
#print(workid)
recommend_list=[]
workid=sorted(workid.items(),key=lambda x:x[1],reverse=True)[:10]#给列表按打分排序,取出前十个推荐
for i in workid:
recommend_list.append(i[0])
if len(recommend_list) == 0:
product_scores = Product_score.objects.values_list('product', flat=True)
recommend_list = list(product_scores)
print(recommend_list)
products= Product.objects.filter(id__in=recommend_list)
# 获取最近购买的商品,这里假设我们只取最新的5个订单的商品
recent_items = OrderItem.objects.filter(
Q(product_id__in=recommend_list) &
Q(order__user=request.user)
).select_related('product').order_by('-date_added')[:5]
recent_products = Product.objects.filter(id__in=[item.product.id for item in recent_items])
if products:
query = request.GET.get('q')
if query:
products = products.filter(name__icontains=query)
categories = Category.objects.all()
# 如果有分类选择,过滤商品
category_id = request.GET.get('category')
selected_category = None # 记录选中的分类
if category_id:
try:
selected_category = Category.objects.get(id=category_id)
products = products.filter(
Q(id__in=recommend_list) & Q(category=selected_category))
except Category.DoesNotExist:
products = Product.objects.none()
paginator = Paginator(products, 10)
page = request.GET.get('page')
try:
page_obj = paginator.page(page)
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
print(page_obj)
context = {
'recent_products':recent_products,
'categories': categories,
'products': page_obj,
'selected_category': selected_category,
}
return render(request,'recommend.html',context)
return render(request, 'recommend.html')
项目截图:




项目最后:
需要该项目的同学可以私信我哦,或者添加我下方名片或者我简介信息获取哦~
支持Python项目的答疑和指导~
1523

被折叠的 条评论
为什么被折叠?



