基于Django框架的图书推荐系统源码下载方法有哪些?
- 内容介绍
- 文章标签
- 相关推荐
本文共计4851个文字,预计阅读时间需要20分钟。
Python 解释器版本为 3.7.8。创建虚拟环境,在 D 盘下创建一个文件夹 my_work,并在其中创建两个子文件夹:book_manager 和 venv。在 Win + R 输入 cmd 进入文件夹 venv,执行以下命令创建虚拟环境:
python -m venv venv
python解释器版本使用3.7.8。
1、创建虚拟环境
在d盘下创建一个文件夹my_work,然后在里面创建两个文件夹:book_manager和venv。
win+R输入cmd进入文件夹venv,然后执行以下命令创建虚拟环境:
python -m venv book_manager激活虚拟环境:
cd book_manager cd Scripts activate然后进入pro目录
cd .. cd .. cd .. cd pro2、创建项目
执行命令:
django-admin startproject book_manager3、创建子应用
切换到项目根目录:
cd book_manager导入django:
pip install Django==3.0.7 -i pypi.mirrors.ustc.edu.cn/simple/ pip install PyMySQL==0.9.2 -i pypi.mirrors.ustc.edu.cn/simple/ pip install xadmin-django==3.0.2 -i pypi.mirrors.ustc.edu.cn/simple/ pip install mysqlclient==2.0.1 -i pypi.mirrors.ustc.edu.cn/simple/创建子应用
python manage.py startapp book自此项目创建完成。
二、settings.py配置
1、创建数据库
使用MySQL可视化工具创建一个数据库book_manager。
2、PyCharm打开项目
使用PyCharm打开项目:file->open.
在项目根目录下创建以下文件夹:
static、media、imgs、log。
其中media中再创建一个文件夹book_cover存放书籍封面。
template,选中template->右键->Make Directory as- >Template Folder.
3、配置项目虚拟环境
4、允许所有网站访问
在book_manager\settings.py中做修改:
ALLOWED_HOSTS = ['*']5、添加子应用
在book_manager\settings.py中的INSTALLED_APPS加入子应用book,如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'xadmin', 'crispy_forms', 'book' ]6、添加template目录
在book_manager\settings.py中的TEMPLATES中DIRS改为:
'DIRS': [os.path.join(BASE_DIR, 'templates')],7、使用mysql数据库
把在book_manager\settings.py中的DATABASES注释掉,改为:
ip = '127.0.0.1' DATABASE_NAME = 'book_manager' # mysql数据库名称 DATABASE_USER = 'root' # mysql数据库用户名 DATABASE_PASS = 'ldc-root' # mysql数据库密码 DATABASE_HOST = ip # mysql数据库IP DATABASE_PORT = 3306 # mysql数据库端口 # 配置数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改数据库为MySQL,并进行配置 'NAME': DATABASE_NAME, # 'USER': DATABASE_USER, # 用户名 'PASSWORD': DATABASE_PASS, # 密码 'HOST': DATABASE_HOST, 'PORT': DATABASE_PORT, 'OPTIONS': {'charset': 'utf8mb4', } } }8、使用中文
把book_manager\settings.py的LANGUAGE_CODE、TIME_ZONE和USE_TZ改为:
LANGUAGE_CODE = 'zh-hans' # 使用中国时区 TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False9、配置静态文件路由
把book_manager\settings.py的STATIC_URL改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_USER_ICON = os.path.join(BASE_DIR, 'media/user_icon')三、models.py数据表
在book\models.py中创建用户、标签表、书籍表、购书清单车、评分表、收藏表、点赞表、评论表:
from django.db import models # Create your models here. class User(models.Model): username = models.CharField(max_length=32, unique=True, verbose_name="账号") password = models.CharField(max_length=32, verbose_name="密码") phone = models.CharField(max_length=32, verbose_name="手机号码") name = models.CharField(max_length=32, verbose_name="名字", unique=True) address = models.CharField(max_length=32, verbose_name="地址") email = models.EmailField(verbose_name="邮箱") class Meta: db_table = 'user' verbose_name_plural = "用户" verbose_name = "用户" def __str__(self): return self.name class Tags(models.Model): name = models.CharField(max_length=32, verbose_name="标签") intro = models.TextField(blank=True, null=True, verbose_name='简介') class Meta: db_table = 'tags' verbose_name = "标签" verbose_name_plural = "标签" def __str__(self): return self.name class Book(models.Model): tags = models.ForeignKey( Tags, on_delete=models.CASCADE, verbose_name="标签", related_name="tags", blank=True, null=True, ) title = models.CharField(verbose_name="书名", max_length=32) author = models.CharField(verbose_name="作者", max_length=32) published_time = models.DateField(blank=True, null=True, verbose_name='出版时间') intro = models.TextField(verbose_name="描述") pic = models.FileField(verbose_name="封面图片", max_length=64, upload_to='book_cover') collect_num = models.IntegerField(verbose_name="收藏人数", default=0) rate_num = models.IntegerField(verbose_name="评分人数", default=0) like_num = models.IntegerField(verbose_name="点赞人数", default=0) look_num = models.IntegerField(verbose_name="浏览量", default=0) is_show = models.BooleanField(default=True, verbose_name="是否显示") create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') is_purchase = models.BooleanField(default=False, verbose_name='是否可购买') price = models.FloatField(default=66.66, verbose_name="单价") inventory = models.IntegerField(verbose_name="库存", default=9999, blank=True, null=True) purchase_num = models.IntegerField(verbose_name="销售数量", default=0, blank=True, null=True) class Meta: db_table = 'book' verbose_name = "图书" verbose_name_plural = "图书" def __str__(self): return self.title class PurchaseList(models.Model): # 购书清单 book = models.ForeignKey(Book, related_name='purchase_book', on_delete=models.CASCADE, blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id") order_code = models.CharField(max_length=20, unique=True, verbose_name='订单号') create_time = models.DateTimeField(verbose_name="下单时间", auto_now_add=True) price = models.FloatField(default=66.66, verbose_name="单价") purchase_num = models.IntegerField(verbose_name="购买数量", default=1) all_price = models.FloatField(default=66.66, verbose_name="总价") phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="手机号") address = models.TextField(blank=True, null=True, verbose_name="地址") order_status = models.CharField(max_length=10, default='0', choices=( ('0', '待支付'), ('1', '已支付'), ('2', '待收货'), ('3', '已收货'), ), verbose_name='订单状态') pay_time = models.DateTimeField(blank=True, null=True, verbose_name="支付时间") received_time = models.DateTimeField(blank=True, null=True, verbose_name="收货时间") class Meta: db_table = 'purchase_list' verbose_name = "购书清单" verbose_name_plural = verbose_name class RateBook(models.Model): book = models.ForeignKey(Book, related_name='rate_book', on_delete=models.CASCADE, blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id") mark = models.FloatField(verbose_name="评分") create_time = models.DateTimeField(verbose_name="添加时间", auto_now_add=True) class Meta: db_table = 'rate_book' verbose_name = "评分信息" verbose_name_plural = verbose_name class CollectBook(models.Model): book = models.ForeignKey( Book, on_delete=models.CASCADE, related_name='collect_book', blank=True, null=True, verbose_name="图书id" ) user = models.ForeignKey( User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id", ) is_delete = models.BooleanField(default=False, verbose_name='是否取消') create_time = models.DateTimeField(verbose_name="收藏时间", auto_now_add=True) class Meta: db_table = 'collect_book' verbose_name = "图书收藏" verbose_name_plural = verbose_name class LikeBook(models.Model): book = models.ForeignKey( Book, on_delete=models.CASCADE, related_name='like_book', blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id", ) is_delete = models.BooleanField(default=False, verbose_name='是否删除') create_time = models.DateTimeField(verbose_name="点赞时间", auto_now_add=True) class Meta: db_table = 'like_book' verbose_name = "图书点赞" verbose_name_plural = verbose_name class CommentBook(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户") book = models.ForeignKey(Book, on_delete=models.CASCADE, blank=True, null=True, verbose_name="书籍") content = models.TextField(verbose_name="内容") create_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True) like_num = models.IntegerField(verbose_name="点赞数", default=0) like_users = models.TextField(null=True,blank=True, default=None,verbose_name="点赞用户") is_show = models.BooleanField(default=True, verbose_name='是否显示') class Meta: db_table = 'comment_book' verbose_name = "图书评论" verbose_name_plural = verbose_name四、urls.py路由配置
1、修改book_manager\urls.py
在book下创建一个urls.py,并让book_manager\urls.py分配路由,
其中book_manager\urls.py改为:
import xadmin from django.urls import path, re_path, include from django.views.generic import RedirectView from django.views.static import serve from django.conf import settings urlpatterns = [ path('xadmin/', xadmin.site.urls), path("", include("book.urls")), # favicon.cio re_path(r'^favicon\.ico$', RedirectView.as_view(url=r'media/favicon.ico')), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), # re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATICFILES_DIRS}), # 收集静态文件时关闭 path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}), # 收集静态文件时打开,然后关闭STATICFILES_DIRS ]2、修改book\urls.py
先改为:
from django.urls import path, re_path from book import views urlpatterns = [ ]后期会添加各种路由。
3、数据迁移
在pycharm左下角的Terminal里执行数据迁移命令
python manage.py makemigrations python manage.py migrate4、创建缓存表
python manage.py createcachetable5、收集静态文件
先把book_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' # STATICFILES_DIRS = [ # os.path.join(BASE_DIR, 'static'), # ] STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS然后执行:
python manage.py collectstatic执行成功后,把book_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS把book_manager\urls.py改为:
import xadmin from django.urls import path, re_path, include from django.views.generic import RedirectView from django.views.static import serve from django.conf import settings urlpatterns = [ path('xadmin/', xadmin.site.urls), path("", include("book.urls")), # favicon.cio re_path(r'^favicon\.ico$', RedirectView.as_view(url=r'media/favicon.ico')), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATICFILES_DIRS}), # 收集静态文件时关闭 # path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}), # 收集静态文件时打开,然后关闭STATICFILES_DIRS ]6、创建后台管理员
python manage.py createsuperuser 设置账号为 root 邮箱为 1@qq.com 密码为 book-root五、导入基础数据
把根目录下的book.sql在mysql可视化工具中执行即可。
六、核心代码
1、static创建文件夹
在static目录下创建三个文件夹image、css、js和fonts用来存放前端需要使用到的文件。
2、base.html前端框架
在目录templates下创建前端页面框架base.html,代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta fontawesome.dashgame.com/ 图标字体网站 # 基础设置 class BaseSetting(object): enable_themes = True # 使用主题 use_bootswatch = True # 全局设置 class GlobalSettings(object): site_title = '图书管理系统' # 标题 site_footer = mark_safe(settings.SITE_FOOTER) # 页尾 site_url = '/' menu_style = 'accordion' # 设置左侧菜单 折叠样式 # 用户管理 class UserAdmin(object): search_fields = ['username', 'phone', 'name'] # 检索字段 list_display = ['id', 'username', 'phone', 'name', 'address', 'email'] # 要显示的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-users' # 左侧小图标 list_editable = ['name', 'address'] # 可编辑字段 # 标签管理 class TagsAdmin(object): search_fields = ['name'] # 检索字段 list_display = ['id', 'name', 'show_intro'] list_filter = ['name'] ordering = ('id',) model_icon = 'fa fa-tags' # 左侧小图标 def show_intro(self, obj): # 显示简介 if not obj.intro: return mark_safe('') if len(obj.intro) < 20: return mark_safe(obj.intro) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text_len = len(obj.intro) // 4 short_text = obj.intro[:short_text_len] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.intro text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % (short_id, detail_id, short_id, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) show_intro.short_description = '描述' # 书籍管理 class BookAdmin(object): search_fields = ['title', 'author', 'intro'] # 检索字段 list_display = ['id', 'show_pic', 'title', 'author', 'published_time', 'show_intro', 'tags', 'look_num', 'like_num', 'collect_num', 'rate_num', 'show_avg_mark', 'is_show', 'is_purchase', 'price', 'inventory', 'purchase_num'] # 要显示的字段 list_filter = ['create_time', 'published_time', 'tags', 'is_show'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-book' # 左侧小图标 list_editable = ['title', 'author', 'intro', 'published_time', 'is_show', 'is_purchase'] # 可编辑字段 style_fields = {'tags': 'm2m_transfer', 'prizes': 'm2m_transfer'} # 控制字段的显示样式 filter_horizontal = ('tags', 'prizes') # 水平选择编辑多对多字段 def show_pic(self, obj): # 显示书籍封面 if obj.pic.name: text = """ <style type="text/css"> #div1 img{ cursor: pointer; transition: all 0.6s; } #div1 img:hover{ transform: scale(2); } </style> <div id="div1"> <img src="%s" style="width:50px;"/> </div> """ % (self.request.build_absolute_uri('/') + 'media/' + obj.pic.name) return mark_safe(text) return '' def show_intro(self, obj): # 显示简介 if not obj.intro: return mark_safe('') if len(obj.intro) < 20: return mark_safe(obj.intro) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text = obj.intro[:len(obj.intro) // 4] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.intro text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s" title="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % ( short_id, detail_id, short_id, detail_text, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) def show_avg_mark(self, obj): return obj.avg_mark def save_models(self): flag = self.org_obj is None and 'create' or 'change' if flag == 'create': if self.new_obj.pic.name: self.new_obj.pic.name = f"{self.new_obj.title}.{self.new_obj.pic.name.split('.')[1]}" if flag == 'change' and 'pic' in self.change_message(): if self.org_obj.pic.name: self.org_obj.pic.name = f"{self.org_obj.title}.{self.org_obj.pic.name.split('.')[1]}" super().save_models() show_pic.short_description = '封面' show_intro.short_description = '描述' show_avg_mark.short_description = '评分' # 书籍购买管理 class PurchaseListAdmin(object): search_fields = ['book__title', 'user__name'] # 要显示的字段 list_display = ['book', 'user', 'purchase_num', 'all_price', 'phone', 'address', 'order_status', 'pay_time', 'received_time'] # 检索字段 list_filter = ['order_status', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = ['order_status', 'received_time'] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍评分管理 class RateAdmin(object): search_fields = ['book__title', 'user__name', 'mark'] # 检索字段 list_display = ['book', 'user', 'mark', 'create_time'] # 要显示的字段 list_filter = ['mark', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍点赞管理 class LikeBookAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['book', 'user', 'is_delete', 'create_time'] # 要显示的字段 list_filter = ['is_delete', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍收藏管理 class CollectBookAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['book', 'user', 'is_delete', 'create_time'] # 要显示的字段 list_filter = ['is_delete', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍评论管理 class CommentAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['user', 'book', 'show_content', 'like_num', 'is_show', 'create_time'] # 要显示的字段 list_filter = ['book', 'is_show', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 def show_content(self, obj): # 显示评论内容 if not obj.content: return mark_safe('') if len(obj.content) < 20: return mark_safe(obj.content) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text = obj.content[:len(obj.content) // 4] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.content text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % (short_id, detail_id, short_id, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) show_content.short_description = '评论内容' xadmin.site.register(views.CommAdminView, GlobalSettings) xadmin.site.register(views.BaseAdminView, BaseSetting) xadmin.site.register(User, UserAdmin) xadmin.site.register(Tags, TagsAdmin) xadmin.site.register(Book, BookAdmin) xadmin.site.register(PurchaseList, PurchaseListAdmin) xadmin.site.register(RateBook, RateAdmin) xadmin.site.register(LikeBook, CollectBookAdmin) xadmin.site.register(CollectBook, CollectBookAdmin) xadmin.site.register(CommentBook, CommentAdmin)2、修改book\apps.py
代码改为如下:
from django.apps import AppConfig class BookConfig(AppConfig): name = 'book' verbose_name = "图书推荐系统"3、修改book\__init__.py
代码改为:
default_app_config = 'book.apps.BookConfig'4、浏览器登录
浏览器访问127.0.0.1:8000/xadmin/
输入账号:root
输入密码:book-root
八、部署到服务器
1、前期工作
部署到ubuntu服务器,把项目放到home目录下,创建数据库book_manager。
在服务器/home/venv/目录下创建一个虚拟环境book_manager:
cd .. cd home/venv/ python3 -m venv book_manager激活虚拟环境:
source book_manager/bin/activate更新pip:
pip install --upgrade pip退回项目根目录:
cd .. cd book_manager批量安装第三方库:
pip install -r requirements.txt -i pypi.tuna.tsinghua.edu.cn/simple数据迁移:
python manage.py migrate创建缓存表:
python manage.py createcachetable创建后台管理员
python manage.py createsuperuser 设置账号为 root 邮箱为 1@qq.com 密码为 book-root数据库图形化工具执行books.sql
2、配置uwsgi.ini
uwsgi.ini内容如下:
[uwsgi] # 使用nginx连接时 使用 socket=0.0.0.0:8101 # 直接作为web服务器使用 #http=127.0.0.1:8101 # 配置工程目录 chdir=/home/book_manager # 配置项目的wsgi目录。相对于工程目录 wsgi-file=book_manager/wsgi.py virtualenv =/home/venv/book_manager #配置进程,线程信息 listen=1024 processes=2 threads=4 enable-threads=True master=True pidfile=uwsgi.pid daemonize=uwsgi.log #django项目修改完文件后自动重启 py-autoreload=1把uwsgi.ini放到根目录下。
导入uwsgi:
pip install uwsgi启动uwsgi:
uwsgi --ini uwsgi.ini查看是否启动成功:
netstat -lnp|grep uwsgi若出现类似:
tcp 0 0 0.0.0.0:8101 0.0.0.0:* LISTEN 927/uwsgi则说明启动成功
2、配置nginx
创建一个book_manager_nginx文件,内容如下:
#设定虚拟主机配置 server { #侦听80端口 listen 80; #listen 443 ssl; #定义使用 www.nginx.cn访问 #ssl on; server_name xxx.xxx.com; #server_name xxx.xxx.xxx.xxx; #定义服务器的默认网站根目录位置 root /home/book_manager; #ssl_session_timeout 5m; #ssl_certificate /etc/nginx/cert/xxx.pem; #ssl_certificate_key /etc/nginx/cert/xxx.key; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl_prefer_server_ciphers on; #设定本虚拟主机的访问日志 #access_log logs/nginx.access.log main; #默认请求 location / { #倒入了uwsgi的配置 include uwsgi_params; client_max_body_size 50m; #连接uwsgi的超时时间 # uwsgi_connect_timeout 30; #设定了uwsig服务器位置 uwsgi_pass 127.0.0.1:8101; } location /static{ alias /home/book_manager/static; } location /media { alias /home/book_manager/media; } }文件放到/etc/nginx/sites-available下面。
然后通过以下命令映射到/etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/book_manager_nginx /etc/nginx/sites-enabled/book_manager_nginxnginx重启:
nginx -s reload在浏览器中访问网站就可以看到书籍了。
[uwsgi] # 使用nginx连接时 使用 socket=0.0.0.0:8101 # 直接作为web服务器使用 #http=127.0.0.1:8101 # 配置工程目录 chdir=/home/book_manager # 配置项目的wsgi目录。相对于工程目录 wsgi-file=book_manager/wsgi.py virtualenv =/home/venv/book_manager #配置进程,线程信息 listen=1024 processes=2 threads=4 enable-threads=True master=True pidfile=uwsgi.pid daemonize=uwsgi.log #django项目修改完文件后自动重启 py-autoreload=1把uwsgi.ini放到根目录下。
导入uwsgi:
pip install uwsgi启动uwsgi:
uwsgi --ini uwsgi.ini查看是否启动成功:
netstat -lnp|grep uwsgi若出现类似:
tcp 0 0 0.0.0.0:8101 0.0.0.0:* LISTEN 927/uwsgi则说明启动成功
2、配置nginx
创建一个book_manager_nginx文件,内容如下:
#设定虚拟主机配置 server { #侦听80端口 listen 80; #listen 443 ssl; #定义使用 www.nginx.cn访问 #ssl on; server_name xxx.xxx.com; #server_name xxx.xxx.xxx.xxx; #定义服务器的默认网站根目录位置 root /home/book_manager; #ssl_session_timeout 5m; #ssl_certificate /etc/nginx/cert/xxx.pem; #ssl_certificate_key /etc/nginx/cert/xxx.key; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl_prefer_server_ciphers on; #设定本虚拟主机的访问日志 #access_log logs/nginx.access.log main; #默认请求 location / { #倒入了uwsgi的配置 include uwsgi_params; client_max_body_size 50m; #连接uwsgi的超时时间 # uwsgi_connect_timeout 30; #设定了uwsig服务器位置 uwsgi_pass 127.0.0.1:8101; } location /static{ alias /home/book_manager/static; } location /media { alias /home/book_manager/media; } }文件放到/etc/nginx/sites-available下面。
然后通过以下命令映射到/etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/book_manager_nginx /etc/nginx/sites-enabled/book_manager_nginxnginx重启:
nginx -s reload在浏览器中访问网站就可以看到书籍了。
后记
为了让大家能够轻松学编程,我创建了一个公众号,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。!
公众号
关注我,我们一起成长~~
本文共计4851个文字,预计阅读时间需要20分钟。
Python 解释器版本为 3.7.8。创建虚拟环境,在 D 盘下创建一个文件夹 my_work,并在其中创建两个子文件夹:book_manager 和 venv。在 Win + R 输入 cmd 进入文件夹 venv,执行以下命令创建虚拟环境:
python -m venv venv
python解释器版本使用3.7.8。
1、创建虚拟环境
在d盘下创建一个文件夹my_work,然后在里面创建两个文件夹:book_manager和venv。
win+R输入cmd进入文件夹venv,然后执行以下命令创建虚拟环境:
python -m venv book_manager激活虚拟环境:
cd book_manager cd Scripts activate然后进入pro目录
cd .. cd .. cd .. cd pro2、创建项目
执行命令:
django-admin startproject book_manager3、创建子应用
切换到项目根目录:
cd book_manager导入django:
pip install Django==3.0.7 -i pypi.mirrors.ustc.edu.cn/simple/ pip install PyMySQL==0.9.2 -i pypi.mirrors.ustc.edu.cn/simple/ pip install xadmin-django==3.0.2 -i pypi.mirrors.ustc.edu.cn/simple/ pip install mysqlclient==2.0.1 -i pypi.mirrors.ustc.edu.cn/simple/创建子应用
python manage.py startapp book自此项目创建完成。
二、settings.py配置
1、创建数据库
使用MySQL可视化工具创建一个数据库book_manager。
2、PyCharm打开项目
使用PyCharm打开项目:file->open.
在项目根目录下创建以下文件夹:
static、media、imgs、log。
其中media中再创建一个文件夹book_cover存放书籍封面。
template,选中template->右键->Make Directory as- >Template Folder.
3、配置项目虚拟环境
4、允许所有网站访问
在book_manager\settings.py中做修改:
ALLOWED_HOSTS = ['*']5、添加子应用
在book_manager\settings.py中的INSTALLED_APPS加入子应用book,如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'xadmin', 'crispy_forms', 'book' ]6、添加template目录
在book_manager\settings.py中的TEMPLATES中DIRS改为:
'DIRS': [os.path.join(BASE_DIR, 'templates')],7、使用mysql数据库
把在book_manager\settings.py中的DATABASES注释掉,改为:
ip = '127.0.0.1' DATABASE_NAME = 'book_manager' # mysql数据库名称 DATABASE_USER = 'root' # mysql数据库用户名 DATABASE_PASS = 'ldc-root' # mysql数据库密码 DATABASE_HOST = ip # mysql数据库IP DATABASE_PORT = 3306 # mysql数据库端口 # 配置数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改数据库为MySQL,并进行配置 'NAME': DATABASE_NAME, # 'USER': DATABASE_USER, # 用户名 'PASSWORD': DATABASE_PASS, # 密码 'HOST': DATABASE_HOST, 'PORT': DATABASE_PORT, 'OPTIONS': {'charset': 'utf8mb4', } } }8、使用中文
把book_manager\settings.py的LANGUAGE_CODE、TIME_ZONE和USE_TZ改为:
LANGUAGE_CODE = 'zh-hans' # 使用中国时区 TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False9、配置静态文件路由
把book_manager\settings.py的STATIC_URL改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_USER_ICON = os.path.join(BASE_DIR, 'media/user_icon')三、models.py数据表
在book\models.py中创建用户、标签表、书籍表、购书清单车、评分表、收藏表、点赞表、评论表:
from django.db import models # Create your models here. class User(models.Model): username = models.CharField(max_length=32, unique=True, verbose_name="账号") password = models.CharField(max_length=32, verbose_name="密码") phone = models.CharField(max_length=32, verbose_name="手机号码") name = models.CharField(max_length=32, verbose_name="名字", unique=True) address = models.CharField(max_length=32, verbose_name="地址") email = models.EmailField(verbose_name="邮箱") class Meta: db_table = 'user' verbose_name_plural = "用户" verbose_name = "用户" def __str__(self): return self.name class Tags(models.Model): name = models.CharField(max_length=32, verbose_name="标签") intro = models.TextField(blank=True, null=True, verbose_name='简介') class Meta: db_table = 'tags' verbose_name = "标签" verbose_name_plural = "标签" def __str__(self): return self.name class Book(models.Model): tags = models.ForeignKey( Tags, on_delete=models.CASCADE, verbose_name="标签", related_name="tags", blank=True, null=True, ) title = models.CharField(verbose_name="书名", max_length=32) author = models.CharField(verbose_name="作者", max_length=32) published_time = models.DateField(blank=True, null=True, verbose_name='出版时间') intro = models.TextField(verbose_name="描述") pic = models.FileField(verbose_name="封面图片", max_length=64, upload_to='book_cover') collect_num = models.IntegerField(verbose_name="收藏人数", default=0) rate_num = models.IntegerField(verbose_name="评分人数", default=0) like_num = models.IntegerField(verbose_name="点赞人数", default=0) look_num = models.IntegerField(verbose_name="浏览量", default=0) is_show = models.BooleanField(default=True, verbose_name="是否显示") create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') is_purchase = models.BooleanField(default=False, verbose_name='是否可购买') price = models.FloatField(default=66.66, verbose_name="单价") inventory = models.IntegerField(verbose_name="库存", default=9999, blank=True, null=True) purchase_num = models.IntegerField(verbose_name="销售数量", default=0, blank=True, null=True) class Meta: db_table = 'book' verbose_name = "图书" verbose_name_plural = "图书" def __str__(self): return self.title class PurchaseList(models.Model): # 购书清单 book = models.ForeignKey(Book, related_name='purchase_book', on_delete=models.CASCADE, blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id") order_code = models.CharField(max_length=20, unique=True, verbose_name='订单号') create_time = models.DateTimeField(verbose_name="下单时间", auto_now_add=True) price = models.FloatField(default=66.66, verbose_name="单价") purchase_num = models.IntegerField(verbose_name="购买数量", default=1) all_price = models.FloatField(default=66.66, verbose_name="总价") phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="手机号") address = models.TextField(blank=True, null=True, verbose_name="地址") order_status = models.CharField(max_length=10, default='0', choices=( ('0', '待支付'), ('1', '已支付'), ('2', '待收货'), ('3', '已收货'), ), verbose_name='订单状态') pay_time = models.DateTimeField(blank=True, null=True, verbose_name="支付时间") received_time = models.DateTimeField(blank=True, null=True, verbose_name="收货时间") class Meta: db_table = 'purchase_list' verbose_name = "购书清单" verbose_name_plural = verbose_name class RateBook(models.Model): book = models.ForeignKey(Book, related_name='rate_book', on_delete=models.CASCADE, blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id") mark = models.FloatField(verbose_name="评分") create_time = models.DateTimeField(verbose_name="添加时间", auto_now_add=True) class Meta: db_table = 'rate_book' verbose_name = "评分信息" verbose_name_plural = verbose_name class CollectBook(models.Model): book = models.ForeignKey( Book, on_delete=models.CASCADE, related_name='collect_book', blank=True, null=True, verbose_name="图书id" ) user = models.ForeignKey( User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id", ) is_delete = models.BooleanField(default=False, verbose_name='是否取消') create_time = models.DateTimeField(verbose_name="收藏时间", auto_now_add=True) class Meta: db_table = 'collect_book' verbose_name = "图书收藏" verbose_name_plural = verbose_name class LikeBook(models.Model): book = models.ForeignKey( Book, on_delete=models.CASCADE, related_name='like_book', blank=True, null=True, verbose_name="图书id") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户id", ) is_delete = models.BooleanField(default=False, verbose_name='是否删除') create_time = models.DateTimeField(verbose_name="点赞时间", auto_now_add=True) class Meta: db_table = 'like_book' verbose_name = "图书点赞" verbose_name_plural = verbose_name class CommentBook(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name="用户") book = models.ForeignKey(Book, on_delete=models.CASCADE, blank=True, null=True, verbose_name="书籍") content = models.TextField(verbose_name="内容") create_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True) like_num = models.IntegerField(verbose_name="点赞数", default=0) like_users = models.TextField(null=True,blank=True, default=None,verbose_name="点赞用户") is_show = models.BooleanField(default=True, verbose_name='是否显示') class Meta: db_table = 'comment_book' verbose_name = "图书评论" verbose_name_plural = verbose_name四、urls.py路由配置
1、修改book_manager\urls.py
在book下创建一个urls.py,并让book_manager\urls.py分配路由,
其中book_manager\urls.py改为:
import xadmin from django.urls import path, re_path, include from django.views.generic import RedirectView from django.views.static import serve from django.conf import settings urlpatterns = [ path('xadmin/', xadmin.site.urls), path("", include("book.urls")), # favicon.cio re_path(r'^favicon\.ico$', RedirectView.as_view(url=r'media/favicon.ico')), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), # re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATICFILES_DIRS}), # 收集静态文件时关闭 path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}), # 收集静态文件时打开,然后关闭STATICFILES_DIRS ]2、修改book\urls.py
先改为:
from django.urls import path, re_path from book import views urlpatterns = [ ]后期会添加各种路由。
3、数据迁移
在pycharm左下角的Terminal里执行数据迁移命令
python manage.py makemigrations python manage.py migrate4、创建缓存表
python manage.py createcachetable5、收集静态文件
先把book_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' # STATICFILES_DIRS = [ # os.path.join(BASE_DIR, 'static'), # ] STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS然后执行:
python manage.py collectstatic执行成功后,把book_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS把book_manager\urls.py改为:
import xadmin from django.urls import path, re_path, include from django.views.generic import RedirectView from django.views.static import serve from django.conf import settings urlpatterns = [ path('xadmin/', xadmin.site.urls), path("", include("book.urls")), # favicon.cio re_path(r'^favicon\.ico$', RedirectView.as_view(url=r'media/favicon.ico')), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATICFILES_DIRS}), # 收集静态文件时关闭 # path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}), # 收集静态文件时打开,然后关闭STATICFILES_DIRS ]6、创建后台管理员
python manage.py createsuperuser 设置账号为 root 邮箱为 1@qq.com 密码为 book-root五、导入基础数据
把根目录下的book.sql在mysql可视化工具中执行即可。
六、核心代码
1、static创建文件夹
在static目录下创建三个文件夹image、css、js和fonts用来存放前端需要使用到的文件。
2、base.html前端框架
在目录templates下创建前端页面框架base.html,代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta fontawesome.dashgame.com/ 图标字体网站 # 基础设置 class BaseSetting(object): enable_themes = True # 使用主题 use_bootswatch = True # 全局设置 class GlobalSettings(object): site_title = '图书管理系统' # 标题 site_footer = mark_safe(settings.SITE_FOOTER) # 页尾 site_url = '/' menu_style = 'accordion' # 设置左侧菜单 折叠样式 # 用户管理 class UserAdmin(object): search_fields = ['username', 'phone', 'name'] # 检索字段 list_display = ['id', 'username', 'phone', 'name', 'address', 'email'] # 要显示的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-users' # 左侧小图标 list_editable = ['name', 'address'] # 可编辑字段 # 标签管理 class TagsAdmin(object): search_fields = ['name'] # 检索字段 list_display = ['id', 'name', 'show_intro'] list_filter = ['name'] ordering = ('id',) model_icon = 'fa fa-tags' # 左侧小图标 def show_intro(self, obj): # 显示简介 if not obj.intro: return mark_safe('') if len(obj.intro) < 20: return mark_safe(obj.intro) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text_len = len(obj.intro) // 4 short_text = obj.intro[:short_text_len] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.intro text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % (short_id, detail_id, short_id, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) show_intro.short_description = '描述' # 书籍管理 class BookAdmin(object): search_fields = ['title', 'author', 'intro'] # 检索字段 list_display = ['id', 'show_pic', 'title', 'author', 'published_time', 'show_intro', 'tags', 'look_num', 'like_num', 'collect_num', 'rate_num', 'show_avg_mark', 'is_show', 'is_purchase', 'price', 'inventory', 'purchase_num'] # 要显示的字段 list_filter = ['create_time', 'published_time', 'tags', 'is_show'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-book' # 左侧小图标 list_editable = ['title', 'author', 'intro', 'published_time', 'is_show', 'is_purchase'] # 可编辑字段 style_fields = {'tags': 'm2m_transfer', 'prizes': 'm2m_transfer'} # 控制字段的显示样式 filter_horizontal = ('tags', 'prizes') # 水平选择编辑多对多字段 def show_pic(self, obj): # 显示书籍封面 if obj.pic.name: text = """ <style type="text/css"> #div1 img{ cursor: pointer; transition: all 0.6s; } #div1 img:hover{ transform: scale(2); } </style> <div id="div1"> <img src="%s" style="width:50px;"/> </div> """ % (self.request.build_absolute_uri('/') + 'media/' + obj.pic.name) return mark_safe(text) return '' def show_intro(self, obj): # 显示简介 if not obj.intro: return mark_safe('') if len(obj.intro) < 20: return mark_safe(obj.intro) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text = obj.intro[:len(obj.intro) // 4] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.intro text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s" title="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % ( short_id, detail_id, short_id, detail_text, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) def show_avg_mark(self, obj): return obj.avg_mark def save_models(self): flag = self.org_obj is None and 'create' or 'change' if flag == 'create': if self.new_obj.pic.name: self.new_obj.pic.name = f"{self.new_obj.title}.{self.new_obj.pic.name.split('.')[1]}" if flag == 'change' and 'pic' in self.change_message(): if self.org_obj.pic.name: self.org_obj.pic.name = f"{self.org_obj.title}.{self.org_obj.pic.name.split('.')[1]}" super().save_models() show_pic.short_description = '封面' show_intro.short_description = '描述' show_avg_mark.short_description = '评分' # 书籍购买管理 class PurchaseListAdmin(object): search_fields = ['book__title', 'user__name'] # 要显示的字段 list_display = ['book', 'user', 'purchase_num', 'all_price', 'phone', 'address', 'order_status', 'pay_time', 'received_time'] # 检索字段 list_filter = ['order_status', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = ['order_status', 'received_time'] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍评分管理 class RateAdmin(object): search_fields = ['book__title', 'user__name', 'mark'] # 检索字段 list_display = ['book', 'user', 'mark', 'create_time'] # 要显示的字段 list_filter = ['mark', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍点赞管理 class LikeBookAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['book', 'user', 'is_delete', 'create_time'] # 要显示的字段 list_filter = ['is_delete', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍收藏管理 class CollectBookAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['book', 'user', 'is_delete', 'create_time'] # 要显示的字段 list_filter = ['is_delete', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 # 书籍评论管理 class CommentAdmin(object): search_fields = ['book__title', 'user__name'] # 检索字段 list_display = ['user', 'book', 'show_content', 'like_num', 'is_show', 'create_time'] # 要显示的字段 list_filter = ['book', 'is_show', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('book', 'user') # 设置显示外键字段 def show_content(self, obj): # 显示评论内容 if not obj.content: return mark_safe('') if len(obj.content) < 20: return mark_safe(obj.content) short_id = f'{obj._meta.db_table}_short_text_{obj.id}' short_text = obj.content[:len(obj.content) // 4] + '......' detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}' detail_text = obj.content text = """<style type="text/css"> #%s,%s {padding:10px;border:1px solid green;} </style> <script type="text/javascript"> function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){ var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj; var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj; var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj; var openTip = oOpenTip || ""; var shutTip = oShutTip || ""; if(targetObj.style.display!="none"){ if(shutAble) return; targetObj.style.display="none"; shortObj.style.display="block"; if(openTip && shutTip){ sourceObj.innerHTML = shutTip; } } else { targetObj.style.display="block"; shortObj.style.display="none"; if(openTip && shutTip){ sourceObj.innerHTML = openTip; } } } </script> <p id="%s">%s</p> <p><a rel="nofollow" href="###" onclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p> <p id="%s" style="display:none"> %s </p> """ % (short_id, detail_id, short_id, short_text, detail_id, short_id, detail_id, detail_text) return mark_safe(text) show_content.short_description = '评论内容' xadmin.site.register(views.CommAdminView, GlobalSettings) xadmin.site.register(views.BaseAdminView, BaseSetting) xadmin.site.register(User, UserAdmin) xadmin.site.register(Tags, TagsAdmin) xadmin.site.register(Book, BookAdmin) xadmin.site.register(PurchaseList, PurchaseListAdmin) xadmin.site.register(RateBook, RateAdmin) xadmin.site.register(LikeBook, CollectBookAdmin) xadmin.site.register(CollectBook, CollectBookAdmin) xadmin.site.register(CommentBook, CommentAdmin)2、修改book\apps.py
代码改为如下:
from django.apps import AppConfig class BookConfig(AppConfig): name = 'book' verbose_name = "图书推荐系统"3、修改book\__init__.py
代码改为:
default_app_config = 'book.apps.BookConfig'4、浏览器登录
浏览器访问127.0.0.1:8000/xadmin/
输入账号:root
输入密码:book-root
八、部署到服务器
1、前期工作
部署到ubuntu服务器,把项目放到home目录下,创建数据库book_manager。
在服务器/home/venv/目录下创建一个虚拟环境book_manager:
cd .. cd home/venv/ python3 -m venv book_manager激活虚拟环境:
source book_manager/bin/activate更新pip:
pip install --upgrade pip退回项目根目录:
cd .. cd book_manager批量安装第三方库:
pip install -r requirements.txt -i pypi.tuna.tsinghua.edu.cn/simple数据迁移:
python manage.py migrate创建缓存表:
python manage.py createcachetable创建后台管理员
python manage.py createsuperuser 设置账号为 root 邮箱为 1@qq.com 密码为 book-root数据库图形化工具执行books.sql
2、配置uwsgi.ini
uwsgi.ini内容如下:
[uwsgi] # 使用nginx连接时 使用 socket=0.0.0.0:8101 # 直接作为web服务器使用 #http=127.0.0.1:8101 # 配置工程目录 chdir=/home/book_manager # 配置项目的wsgi目录。相对于工程目录 wsgi-file=book_manager/wsgi.py virtualenv =/home/venv/book_manager #配置进程,线程信息 listen=1024 processes=2 threads=4 enable-threads=True master=True pidfile=uwsgi.pid daemonize=uwsgi.log #django项目修改完文件后自动重启 py-autoreload=1把uwsgi.ini放到根目录下。
导入uwsgi:
pip install uwsgi启动uwsgi:
uwsgi --ini uwsgi.ini查看是否启动成功:
netstat -lnp|grep uwsgi若出现类似:
tcp 0 0 0.0.0.0:8101 0.0.0.0:* LISTEN 927/uwsgi则说明启动成功
2、配置nginx
创建一个book_manager_nginx文件,内容如下:
#设定虚拟主机配置 server { #侦听80端口 listen 80; #listen 443 ssl; #定义使用 www.nginx.cn访问 #ssl on; server_name xxx.xxx.com; #server_name xxx.xxx.xxx.xxx; #定义服务器的默认网站根目录位置 root /home/book_manager; #ssl_session_timeout 5m; #ssl_certificate /etc/nginx/cert/xxx.pem; #ssl_certificate_key /etc/nginx/cert/xxx.key; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl_prefer_server_ciphers on; #设定本虚拟主机的访问日志 #access_log logs/nginx.access.log main; #默认请求 location / { #倒入了uwsgi的配置 include uwsgi_params; client_max_body_size 50m; #连接uwsgi的超时时间 # uwsgi_connect_timeout 30; #设定了uwsig服务器位置 uwsgi_pass 127.0.0.1:8101; } location /static{ alias /home/book_manager/static; } location /media { alias /home/book_manager/media; } }文件放到/etc/nginx/sites-available下面。
然后通过以下命令映射到/etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/book_manager_nginx /etc/nginx/sites-enabled/book_manager_nginxnginx重启:
nginx -s reload在浏览器中访问网站就可以看到书籍了。
[uwsgi] # 使用nginx连接时 使用 socket=0.0.0.0:8101 # 直接作为web服务器使用 #http=127.0.0.1:8101 # 配置工程目录 chdir=/home/book_manager # 配置项目的wsgi目录。相对于工程目录 wsgi-file=book_manager/wsgi.py virtualenv =/home/venv/book_manager #配置进程,线程信息 listen=1024 processes=2 threads=4 enable-threads=True master=True pidfile=uwsgi.pid daemonize=uwsgi.log #django项目修改完文件后自动重启 py-autoreload=1把uwsgi.ini放到根目录下。
导入uwsgi:
pip install uwsgi启动uwsgi:
uwsgi --ini uwsgi.ini查看是否启动成功:
netstat -lnp|grep uwsgi若出现类似:
tcp 0 0 0.0.0.0:8101 0.0.0.0:* LISTEN 927/uwsgi则说明启动成功
2、配置nginx
创建一个book_manager_nginx文件,内容如下:
#设定虚拟主机配置 server { #侦听80端口 listen 80; #listen 443 ssl; #定义使用 www.nginx.cn访问 #ssl on; server_name xxx.xxx.com; #server_name xxx.xxx.xxx.xxx; #定义服务器的默认网站根目录位置 root /home/book_manager; #ssl_session_timeout 5m; #ssl_certificate /etc/nginx/cert/xxx.pem; #ssl_certificate_key /etc/nginx/cert/xxx.key; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl_prefer_server_ciphers on; #设定本虚拟主机的访问日志 #access_log logs/nginx.access.log main; #默认请求 location / { #倒入了uwsgi的配置 include uwsgi_params; client_max_body_size 50m; #连接uwsgi的超时时间 # uwsgi_connect_timeout 30; #设定了uwsig服务器位置 uwsgi_pass 127.0.0.1:8101; } location /static{ alias /home/book_manager/static; } location /media { alias /home/book_manager/media; } }文件放到/etc/nginx/sites-available下面。
然后通过以下命令映射到/etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/book_manager_nginx /etc/nginx/sites-enabled/book_manager_nginxnginx重启:
nginx -s reload在浏览器中访问网站就可以看到书籍了。
后记
为了让大家能够轻松学编程,我创建了一个公众号,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。!
公众号
关注我,我们一起成长~~

