main
syk1209wwz0306 9 months ago
parent b1a32edb5c
commit ae37929d06

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="MoviesRecommend/settings.py" />
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/../MoviesRecommend\templates" />
</list>
</option>
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.8 (MoviesRecommend) (2)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/MoviesRecommend.iml" filepath="$PROJECT_DIR$/.idea/MoviesRecommend.iml" />
</modules>
</component>
</project>

@ -0,0 +1,3 @@
import pymysql
pymysql.install_as_MySQLdb()

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MovieConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'movie'

@ -0,0 +1,16 @@
"""
ASGI config for MoviesRecommend project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MoviesRecommend.settings')
application = get_asgi_application()

@ -0,0 +1,118 @@
"""
Django settings for MoviesRecommend project.
Generated by 'django-admin startproject' using Django 4.2.13.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
import os
# 项目路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 项目秘钥
SECRET_KEY = 'bhml2023(140w8x3ktw=yzm0=@3h5wr=$$4s!g(s-^s7^@e5=kz'
# 调试模式
DEBUG = True
# 允许的主机
ALLOWED_HOSTS = []
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 注册app
INSTALLED_APPS = [
'django.contrib.admin', # 后台管理系统
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'movie' # 电影推荐系统
]
# 中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 主路由
ROOT_URLCONF = 'Movie_recommendation_system.urls'
# 模板文件配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'movie.context_processors.movie_user'
],
'builtins': ['django.templatetags.static']
},
},
]
WSGI_APPLICATION = 'Movie_recommendation_system.wsgi.application'
# 数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_movie_recommend',
'USER': 'root',
'PASSWORD': '120930',
'HOST': 'localhost',
'PORT': '3306'
}
}
# 密码验证
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# 国际化配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# 静态文件 (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']

@ -0,0 +1,26 @@
"""
URL configuration for MoviesRecommend project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from .views import index, star
urlpatterns = [
#path('admin/', admin.site.urls), # 后台管理系统
path('', index), # 首页
path('movie/', include('movie.urls')), # 电影推荐系统子路由
]

@ -0,0 +1,11 @@
from django.shortcuts import render
# 首页
def index(request):
return render(request, 'index.html')
# 打分
def star(request):
return render(request, 'movie/star.html')

@ -0,0 +1,16 @@
"""
WSGI config for MoviesRecommend project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MoviesRecommend.settings')
application = get_wsgi_application()

@ -0,0 +1,14 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Movie_recommendation_system.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"项目环境配置异常,请检查!"
) from exc
execute_from_command_line(sys.argv)

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MovieConfig(AppConfig):
name = 'movie'
verbose_name = "电影推荐系统"

@ -0,0 +1,14 @@
from .models import User
# 未登录返回空
def movie_user(request):
user_id = request.session.get('user_id')
context = {}
if user_id:
try:
user = User.objects.get(pk=user_id)
context['movie_user'] = user
except:
pass
return context

@ -0,0 +1,68 @@
from django import forms
from movie.models import User, Movie_rating
# 注册用的表单
class RegisterForm(forms.ModelForm):
password_repeat = forms.CharField(max_length=256)
def get_errors(self):
errors = self.errors.get_json_data()
errors_lst = []
for messages in errors.values():
for message_dict in messages:
for key, message in message_dict.items():
if key == 'message':
errors_lst.append(message)
return errors_lst
# 普通验证之后的最后一层验证
# 验证密码
def clean(self):
cleaned_data = super(RegisterForm, self).clean()
pwd = cleaned_data.get('password')
password_repeat = cleaned_data.get('password_repeat')
if pwd != password_repeat:
raise forms.ValidationError(message='两次密码输入不一致!')
return cleaned_data
class Meta:
model = User
fields = ['name', 'password', 'email']
# 登录的表单
class LoginForm(forms.ModelForm):
name = forms.CharField(max_length=128)
remember = forms.IntegerField(required=False)
class Meta:
model = User
fields = ['password']
def get_errors(self):
errors = self.errors.get_json_data()
errors_lst = []
for messages in errors.values():
for message_dict in messages:
for key, message in message_dict.items():
if key == 'message':
errors_lst.append(message)
return errors_lst
# 表单验证通过后再验证分数是否为0
class CommentForm(forms.ModelForm):
def clean(self):
cleaned_data = super(CommentForm, self).clean()
score = cleaned_data.get('score')
if score == 0:
raise forms.ValidationError(message='评分不能为空!')
else:
return cleaned_data
class Meta:
# 电影评分,只记录评分和评论
model = Movie_rating
fields = ['score', 'comment']

@ -0,0 +1,102 @@
# Generated by Django 3.2.16 on 2023-11-26 06:06
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Genre',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
options={
'db_table': 'Genre',
},
),
migrations.CreateModel(
name='Movie',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=256, verbose_name='电影名')),
('imdb_id', models.IntegerField()),
('time', models.CharField(blank=True, max_length=256)),
('release_time', models.CharField(blank=True, max_length=256)),
('intro', models.TextField(blank=True)),
('director', models.CharField(blank=True, max_length=256)),
('writers', models.CharField(blank=True, max_length=256)),
('actors', models.CharField(blank=True, max_length=512)),
('genre', models.ManyToManyField(to='movie.Genre')),
],
options={
'db_table': 'Movie',
},
),
migrations.CreateModel(
name='Movie_rating',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('score', models.FloatField()),
('comment', models.TextField(blank=True)),
('movie', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='movie.movie')),
],
options={
'db_table': 'Movie_rating',
},
),
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, unique=True)),
('password', models.CharField(max_length=256)),
('email', models.EmailField(max_length=254, unique=True)),
('rating_movies', models.ManyToManyField(through='movie.Movie_rating', to='movie.Movie')),
],
options={
'db_table': 'User',
},
),
migrations.CreateModel(
name='Movie_similarity',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('similarity', models.FloatField()),
('movie_source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_source', to='movie.movie')),
('movie_target', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_target', to='movie.movie')),
],
options={
'ordering': ['-similarity'],
},
),
migrations.AddField(
model_name='movie_rating',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='movie.user'),
),
migrations.CreateModel(
name='Movie_hot',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('rating_number', models.IntegerField()),
('movie', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='movie.movie')),
],
options={
'db_table': 'Movie_hot',
'ordering': ['-rating_number'],
},
),
migrations.AddField(
model_name='movie',
name='movie_similarity',
field=models.ManyToManyField(through='movie.Movie_similarity', to='movie.Movie'),
),
]

@ -0,0 +1,127 @@
from django.db import models
from django.db.models import Avg
# 分类信息表
class Genre(models.Model):
name = models.CharField(max_length=100, verbose_name="类型")
class Meta:
db_table = 'Genre'
verbose_name = '电影类型'
verbose_name_plural = '电影类型'
def __str__(self):
return self.name
# 电影信息表
class Movie(models.Model):
name = models.CharField(max_length=256, verbose_name="电影名")
imdb_id = models.IntegerField(verbose_name="imdb_id")
time = models.CharField(max_length=256, blank=True, verbose_name="时长")
genre = models.ManyToManyField(Genre, verbose_name="类型")
release_time = models.CharField(max_length=256, blank=True, verbose_name="发行时间")
intro = models.TextField(blank=True, verbose_name="简介")
director = models.CharField(max_length=256, blank=True, verbose_name="导演")
writers = models.CharField(max_length=256, blank=True, verbose_name="编剧")
actors = models.CharField(max_length=512, blank=True, verbose_name="演员")
# 电影和电影之间的相似度,A和B的相似度与B和A的相似度是一致的所以symmetrical设置为True
movie_similarity = models.ManyToManyField("self", through="Movie_similarity", symmetrical=False,
verbose_name="相似电影")
class Meta:
db_table = 'Movie'
verbose_name = '电影信息'
verbose_name_plural = '电影信息'
def __str__(self):
return self.name
# 获取平均分的方法
def get_score(self):
result_dct = self.movie_rating_set.aggregate(Avg('score')) # 格式 {'score__avg': 3.125}
try:
result = round(result_dct['score__avg'], 1) # 只保留一位小数
except TypeError:
return 0
else:
return result
# 获取用户的打分情况
def get_user_score(self, user):
return self.movie_rating_set.filter(user=user).values('score')
# 整数平均分
def get_score_int_range(self):
return range(int(self.get_score()))
# 获取分类列表
def get_genre(self):
genre_dct = self.genre.all().values('name')
genre_lst = []
for dct in genre_dct.values():
genre_lst.append(dct['name'])
return genre_lst
# 获取电影的相识度
def get_similarity(self, k=5):
# 默认获取5部最相似的电影的id
similarity_movies = self.movie_similarity.all()[:k]
return similarity_movies
# 电影相似度
class Movie_similarity(models.Model):
movie_source = models.ForeignKey(Movie, related_name='movie_source', on_delete=models.CASCADE, verbose_name="来源电影")
movie_target = models.ForeignKey(Movie, related_name='movie_target', on_delete=models.CASCADE, verbose_name="目标电影")
similarity = models.FloatField(verbose_name="相似度")
class Meta:
# 按照相似度降序排序
verbose_name = '电影相似度'
verbose_name_plural = '电影相似度'
# 用户信息表
class User(models.Model):
name = models.CharField(max_length=128, unique=True, verbose_name="用户名")
password = models.CharField(max_length=256, verbose_name="密码")
email = models.EmailField(unique=True, verbose_name="邮箱")
rating_movies = models.ManyToManyField(Movie, through="Movie_rating")
def __str__(self):
return "<USER:( name: {:},password: {:},email: {:} )>".format(self.name, self.password, self.email)
class Meta:
db_table = 'User'
verbose_name = '用户信息'
verbose_name_plural = '用户信息'
# 电影评分信息表
class Movie_rating(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, unique=False, verbose_name="用户")
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, unique=False, verbose_name="电影")
score = models.FloatField(verbose_name="分数")
comment = models.TextField(blank=True, verbose_name="评论")
class Meta:
db_table = 'Movie_rating'
verbose_name = '电影评分信息'
verbose_name_plural = '电影评分信息'
# 最热门的一百部电影
class Movie_hot(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, verbose_name="电影名")
rating_number = models.IntegerField(verbose_name="评分人数")
class Meta:
db_table = 'Movie_hot'
verbose_name = '最热电影'
verbose_name_plural = '最热电影'
# python manage.py makemigrations
# python manage.py migrate

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

@ -0,0 +1,24 @@
Musical
War
Crime
Romance
Fantasy
Drama
Music
Sci-Fi
Action
Comedy
Biography
Family
Horror
Short
Documentary
Film-Noir
Animation
Adventure
News
Mystery
Sport
History
Thriller
Western

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save