Django构建的物品协同过滤电影推荐系统有哪些特点?
- 内容介绍
- 文章标签
- 相关推荐
本文共计3133个文字,预计阅读时间需要13分钟。
1. 创建项目+Python版本:3.7.8,MySQL版本:5.7.28
2.创建虚拟环境
3.在D盘下创建文件夹my_work,并在其中创建文件夹pro和venv
4.在文件夹venv中打开cmd,执行以下命令创建虚拟环境:`python -m venv venv`
一、搭建项目
python版本: 3.7.8.
mysql版本:5.7.28.
1、创建虚拟环境
在d盘下创建一个文件夹my_work,然后在里面创建两个文件夹:pro和venv。
win+R输入cmd进入文件夹venv,然后执行以下命令创建虚拟环境:
python -m venv movie_manager激活虚拟环境:
cd movie_manager cd Scripts activate升级pip:
pip install --upgrade pip导入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/ pip install beautifulsoup4==4.9.3 -i pypi.mirrors.ustc.edu.cn/simple/然后进入pro目录
cd .. cd .. cd .. cd pro2、创建项目
执行命令:
django-admin startproject movie_manager3、创建子应用
切换到项目根目录:
cd movie_manager创建子应用
python manage.py startapp movie自此项目创建完成。
二、settings.py配置
1、创建数据库
使用MySQL可视化工具(比如Navicat)创建一个数据库movie_manager,
字符集选择utf8mb4:
2、PyCharm打开项目
使用PyCharm打开项目:file->open.
在项目根目录下创建以下文件夹:
imgs、log、media、static、template。
其中media中再创建一个文件夹movie_cover存放电影封面。
设置template,选中template->右键->Make Directory as- >Template Folder.
3、配置项目虚拟环境
4、允许所有网站访问
在movie_manager\settings.py中做修改:
ALLOWED_HOSTS = ['*']5、添加子应用
在movie_manager\settings.py中的INSTALLED_APPS加入子应用movie,如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'xadmin', 'crispy_forms', 'movie' ]6、添加template目录
在movie_manager\settings.py中的TEMPLATES中DIRS改为:
'DIRS': [os.path.join(BASE_DIR, 'template')],7、使用mysql数据库
把在movie_manager\settings.py中的DATABASES注释掉,改为:
ip = '127.0.0.1' DATABASE_NAME = 'movie_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、使用中文
把movie_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、配置静态文件路由
把movie_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数据表
1、电影数据获取
从豆瓣电影top250获取数据
2、创建表
在movie\models.py中创建用户、类型表、电影表、评分表、收藏表、点赞表、评论表:
from django.db import models # 用户表 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 Types(models.Model): name = models.CharField(max_length=32, verbose_name='类型') intro = models.TextField(blank=True, null=True, verbose_name='简介') class Meta: db_table = 'types' verbose_name = '类型' verbose_name_plural = '类型' def __str__(self): return self.name # 电影表 class Movies(models.Model): title = models.CharField(verbose_name='电影名', max_length=128) director = models.CharField(verbose_name='导演', max_length=128, null=True, blank=True) writers = models.CharField(verbose_name='编剧', max_length=128, null=True, blank=True) actors = models.TextField(verbose_name='主演', null=True, blank=True) movie_type = models.ManyToManyField(Types, verbose_name='类型', blank=True) region = models.CharField(verbose_name='制片国家/地区', max_length=128, null=True, blank=True) language = models.CharField(verbose_name='语言', max_length=128, null=True, blank=True) detail_url = models.TextField(verbose_name='详情链接', null=True, blank=True) watch_url = models.TextField(verbose_name='观看链接', null=True, blank=True) screen_time = models.TextField(verbose_name='上映日期', null=True, blank=True) running_time = models.CharField(verbose_name='片长', max_length=255, null=True, blank=True) other_name = models.CharField(verbose_name='又名', max_length=255, null=True, blank=True) pic = models.FileField(verbose_name='封面图片', max_length=64, upload_to='movie_cover') score = models.FloatField(verbose_name='豆瓣评分', default=0) intro = models.TextField(verbose_name='简介', null=True, blank=True) look_num = models.IntegerField(default=0, verbose_name='浏览人数') like_num = models.IntegerField(default=0, verbose_name='点赞人数') collect_num = models.IntegerField(default=0, verbose_name='收藏人数') rate_num = models.IntegerField(default=0, verbose_name='评分人数') class Meta: db_table = 'movie' verbose_name = '电影' verbose_name_plural = '电影' def __str__(self): return self.title # 用户评分表 class RateMovie(models.Model): movie = models.ForeignKey(Movies, related_name='rate_movie', 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') score = models.FloatField(verbose_name='评分') create_time = models.DateTimeField(verbose_name='添加时间', auto_now_add=True) class Meta: db_table = 'rate_movie' verbose_name = '评分表' verbose_name_plural = '评分表' # 用户收藏表 class CollectMovie(models.Model): movie = models.ForeignKey(Movies, on_delete=models.CASCADE, related_name='collect_movie', blank=True, null=True, verbose_name='电影id' ) user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name='用户id') create_time = models.DateTimeField(verbose_name='收藏时间', auto_now_add=True) class Meta: db_table = 'collect_movie' verbose_name = '电影收藏表' verbose_name_plural = '电影收藏表' # 用户点赞表 class LikeMovie(models.Model): movie = models.ForeignKey( Movies, on_delete=models.CASCADE, related_name='like_movie', blank=True, null=True, verbose_name='电影id') user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name='用户id') create_time = models.DateTimeField(verbose_name='点赞时间', auto_now_add=True) class Meta: db_table = 'like_movie' verbose_name = '电影点赞表' verbose_name_plural = '电影点赞表' # 用户评论表 class CommentMovie(models.Model): movie = models.ForeignKey(Movies, 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') 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='点赞用户id列表') is_show = models.BooleanField(default=True, verbose_name='是否显示') class Meta: db_table = 'comment_movie' verbose_name = '电影评论表' verbose_name_plural = '电影评论表'四、urls.py路由配置
1、修改movie_manager\urls.py
在movie文件夹下创建一个urls.py,并在movie_manager\urls.py分配路由。
其中movie_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('movie.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、修改movie\urls.py
先改为:
from django.urls import path, re_path from movie import views urlpatterns = [ ]后期会添加各种路由。
3、数据迁移
在pycharm左下角的Terminal里执行数据迁移命令
python manage.py makemigrations python manage.py migrate4、创建缓存表
python manage.py createcachetable5、收集静态文件
先把movie_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执行成功后,把movie_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS把movie_manager\urls.py改为:
"""movie_manager URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: docs.djangoproject.com/en/3.0/topics/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'] # 要显示的字段 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-users' # 左侧小图标 list_editable = ['name', 'address'] # 可编辑字段 # 类型管理 class TypesAdmin(object): search_fields = ['name'] # 检索字段 list_display = ['id', 'name', 'intro'] list_filter = ['name'] ordering = ('id',) model_icon = 'fa fa-tags' # 左侧小图标 # 电影管理 class MovieAdmin(object): search_fields = ['title', 'director', 'actors'] # 检索字段 list_display = ['id', 'show_pic', 'title', 'director', 'screen_time', 'show_intro', 'movie_type', 'score','look_num', 'like_num', 'collect_num', 'rate_num'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-book' # 左侧小图标 list_editable = ['title', 'director', 'intro', 'running_time'] # 可编辑字段 style_fields = {'movie_type': 'm2m_transfer'} # 控制字段的显示样式 filter_horizontal = ('movie_type', ) # 水平选择编辑多对多字段 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 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 = '描述' # 电影评分管理 class RateAdmin(object): search_fields = ['movie__title', 'user__name', 'score'] # 检索字段 list_display = ['movie', 'user', 'score', 'create_time'] # 要显示的字段 list_filter = ['score', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影点赞管理 class LikeAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['movie', 'user', 'create_time'] # 要显示的字段 list_filter = ['create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影收藏管理 class CollectAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['movie', 'user', 'create_time'] # 要显示的字段 list_filter = ['create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影评论管理 class CommentAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['user', 'movie', 'show_content', 'like_num', 'is_show', 'create_time'] # 要显示的字段 list_filter = ['movie', 'is_show', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', '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(Types, TypesAdmin) xadmin.site.register(Movies, MovieAdmin) xadmin.site.register(RateMovie, RateAdmin) xadmin.site.register(LikeMovie, LikeAdmin) xadmin.site.register(CollectMovie, CollectAdmin) xadmin.site.register(CommentMovie, CommentAdmin)2、修改movie\apps.py
代码改为如下:
from django.apps import AppConfig class MovieConfig(AppConfig): name = 'movie' verbose_name = "电影推荐系统"3、修改movie\__init__.py
代码改为:
default_app_config = 'movie.apps.MovieConfig'4、浏览器登录
浏览器访问127.0.0.1:8000/xadmin/
输入账号:root
输入密码:movie-root
本文共计3133个文字,预计阅读时间需要13分钟。
1. 创建项目+Python版本:3.7.8,MySQL版本:5.7.28
2.创建虚拟环境
3.在D盘下创建文件夹my_work,并在其中创建文件夹pro和venv
4.在文件夹venv中打开cmd,执行以下命令创建虚拟环境:`python -m venv venv`
一、搭建项目
python版本: 3.7.8.
mysql版本:5.7.28.
1、创建虚拟环境
在d盘下创建一个文件夹my_work,然后在里面创建两个文件夹:pro和venv。
win+R输入cmd进入文件夹venv,然后执行以下命令创建虚拟环境:
python -m venv movie_manager激活虚拟环境:
cd movie_manager cd Scripts activate升级pip:
pip install --upgrade pip导入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/ pip install beautifulsoup4==4.9.3 -i pypi.mirrors.ustc.edu.cn/simple/然后进入pro目录
cd .. cd .. cd .. cd pro2、创建项目
执行命令:
django-admin startproject movie_manager3、创建子应用
切换到项目根目录:
cd movie_manager创建子应用
python manage.py startapp movie自此项目创建完成。
二、settings.py配置
1、创建数据库
使用MySQL可视化工具(比如Navicat)创建一个数据库movie_manager,
字符集选择utf8mb4:
2、PyCharm打开项目
使用PyCharm打开项目:file->open.
在项目根目录下创建以下文件夹:
imgs、log、media、static、template。
其中media中再创建一个文件夹movie_cover存放电影封面。
设置template,选中template->右键->Make Directory as- >Template Folder.
3、配置项目虚拟环境
4、允许所有网站访问
在movie_manager\settings.py中做修改:
ALLOWED_HOSTS = ['*']5、添加子应用
在movie_manager\settings.py中的INSTALLED_APPS加入子应用movie,如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'xadmin', 'crispy_forms', 'movie' ]6、添加template目录
在movie_manager\settings.py中的TEMPLATES中DIRS改为:
'DIRS': [os.path.join(BASE_DIR, 'template')],7、使用mysql数据库
把在movie_manager\settings.py中的DATABASES注释掉,改为:
ip = '127.0.0.1' DATABASE_NAME = 'movie_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、使用中文
把movie_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、配置静态文件路由
把movie_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数据表
1、电影数据获取
从豆瓣电影top250获取数据
2、创建表
在movie\models.py中创建用户、类型表、电影表、评分表、收藏表、点赞表、评论表:
from django.db import models # 用户表 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 Types(models.Model): name = models.CharField(max_length=32, verbose_name='类型') intro = models.TextField(blank=True, null=True, verbose_name='简介') class Meta: db_table = 'types' verbose_name = '类型' verbose_name_plural = '类型' def __str__(self): return self.name # 电影表 class Movies(models.Model): title = models.CharField(verbose_name='电影名', max_length=128) director = models.CharField(verbose_name='导演', max_length=128, null=True, blank=True) writers = models.CharField(verbose_name='编剧', max_length=128, null=True, blank=True) actors = models.TextField(verbose_name='主演', null=True, blank=True) movie_type = models.ManyToManyField(Types, verbose_name='类型', blank=True) region = models.CharField(verbose_name='制片国家/地区', max_length=128, null=True, blank=True) language = models.CharField(verbose_name='语言', max_length=128, null=True, blank=True) detail_url = models.TextField(verbose_name='详情链接', null=True, blank=True) watch_url = models.TextField(verbose_name='观看链接', null=True, blank=True) screen_time = models.TextField(verbose_name='上映日期', null=True, blank=True) running_time = models.CharField(verbose_name='片长', max_length=255, null=True, blank=True) other_name = models.CharField(verbose_name='又名', max_length=255, null=True, blank=True) pic = models.FileField(verbose_name='封面图片', max_length=64, upload_to='movie_cover') score = models.FloatField(verbose_name='豆瓣评分', default=0) intro = models.TextField(verbose_name='简介', null=True, blank=True) look_num = models.IntegerField(default=0, verbose_name='浏览人数') like_num = models.IntegerField(default=0, verbose_name='点赞人数') collect_num = models.IntegerField(default=0, verbose_name='收藏人数') rate_num = models.IntegerField(default=0, verbose_name='评分人数') class Meta: db_table = 'movie' verbose_name = '电影' verbose_name_plural = '电影' def __str__(self): return self.title # 用户评分表 class RateMovie(models.Model): movie = models.ForeignKey(Movies, related_name='rate_movie', 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') score = models.FloatField(verbose_name='评分') create_time = models.DateTimeField(verbose_name='添加时间', auto_now_add=True) class Meta: db_table = 'rate_movie' verbose_name = '评分表' verbose_name_plural = '评分表' # 用户收藏表 class CollectMovie(models.Model): movie = models.ForeignKey(Movies, on_delete=models.CASCADE, related_name='collect_movie', blank=True, null=True, verbose_name='电影id' ) user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name='用户id') create_time = models.DateTimeField(verbose_name='收藏时间', auto_now_add=True) class Meta: db_table = 'collect_movie' verbose_name = '电影收藏表' verbose_name_plural = '电影收藏表' # 用户点赞表 class LikeMovie(models.Model): movie = models.ForeignKey( Movies, on_delete=models.CASCADE, related_name='like_movie', blank=True, null=True, verbose_name='电影id') user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, verbose_name='用户id') create_time = models.DateTimeField(verbose_name='点赞时间', auto_now_add=True) class Meta: db_table = 'like_movie' verbose_name = '电影点赞表' verbose_name_plural = '电影点赞表' # 用户评论表 class CommentMovie(models.Model): movie = models.ForeignKey(Movies, 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') 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='点赞用户id列表') is_show = models.BooleanField(default=True, verbose_name='是否显示') class Meta: db_table = 'comment_movie' verbose_name = '电影评论表' verbose_name_plural = '电影评论表'四、urls.py路由配置
1、修改movie_manager\urls.py
在movie文件夹下创建一个urls.py,并在movie_manager\urls.py分配路由。
其中movie_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('movie.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、修改movie\urls.py
先改为:
from django.urls import path, re_path from movie import views urlpatterns = [ ]后期会添加各种路由。
3、数据迁移
在pycharm左下角的Terminal里执行数据迁移命令
python manage.py makemigrations python manage.py migrate4、创建缓存表
python manage.py createcachetable5、收集静态文件
先把movie_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执行成功后,把movie_manager\settings.py中的静态文件路由改为:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # STATIC_ROOT = os.path.join(BASE_DIR, 'static') # 收集静态文件时打开,然后关闭STATICFILES_DIRS把movie_manager\urls.py改为:
"""movie_manager URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: docs.djangoproject.com/en/3.0/topics/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'] # 要显示的字段 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-users' # 左侧小图标 list_editable = ['name', 'address'] # 可编辑字段 # 类型管理 class TypesAdmin(object): search_fields = ['name'] # 检索字段 list_display = ['id', 'name', 'intro'] list_filter = ['name'] ordering = ('id',) model_icon = 'fa fa-tags' # 左侧小图标 # 电影管理 class MovieAdmin(object): search_fields = ['title', 'director', 'actors'] # 检索字段 list_display = ['id', 'show_pic', 'title', 'director', 'screen_time', 'show_intro', 'movie_type', 'score','look_num', 'like_num', 'collect_num', 'rate_num'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 model_icon = 'fa fa-book' # 左侧小图标 list_editable = ['title', 'director', 'intro', 'running_time'] # 可编辑字段 style_fields = {'movie_type': 'm2m_transfer'} # 控制字段的显示样式 filter_horizontal = ('movie_type', ) # 水平选择编辑多对多字段 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 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 = '描述' # 电影评分管理 class RateAdmin(object): search_fields = ['movie__title', 'user__name', 'score'] # 检索字段 list_display = ['movie', 'user', 'score', 'create_time'] # 要显示的字段 list_filter = ['score', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影点赞管理 class LikeAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['movie', 'user', 'create_time'] # 要显示的字段 list_filter = ['create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影收藏管理 class CollectAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['movie', 'user', 'create_time'] # 要显示的字段 list_filter = ['create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', 'user') # 设置显示外键字段 # 电影评论管理 class CommentAdmin(object): search_fields = ['movie__title', 'user__name'] # 检索字段 list_display = ['user', 'movie', 'show_content', 'like_num', 'is_show', 'create_time'] # 要显示的字段 list_filter = ['movie', 'is_show', 'create_time'] # 分组过滤的字段 ordering = ('id',) # 设置默认排序字段,负号表示降序排序 list_per_page = 30 # 默认每页显示多少条记录,默认是100条 list_editable = [] # 可编辑字段 fk_fields = ('movie', '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(Types, TypesAdmin) xadmin.site.register(Movies, MovieAdmin) xadmin.site.register(RateMovie, RateAdmin) xadmin.site.register(LikeMovie, LikeAdmin) xadmin.site.register(CollectMovie, CollectAdmin) xadmin.site.register(CommentMovie, CommentAdmin)2、修改movie\apps.py
代码改为如下:
from django.apps import AppConfig class MovieConfig(AppConfig): name = 'movie' verbose_name = "电影推荐系统"3、修改movie\__init__.py
代码改为:
default_app_config = 'movie.apps.MovieConfig'4、浏览器登录
浏览器访问127.0.0.1:8000/xadmin/
输入账号:root
输入密码:movie-root

