lzx02 6 months ago
parent 660cdb0720
commit b09c5c4ad2

2
.idea/.gitignore vendored

@ -1,4 +1,4 @@
# 默认忽略的文件
# Default ignored files
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="Django default" uuid="4780d78e-bbdc-4708-aa57-23b7fa11976b">
<data-source source="LOCAL" name="Django default" uuid="3a0cb1a9-ffa1-40c6-9c58-1663dfce0708">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<imported>true</imported>

@ -2,10 +2,22 @@
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="django-ratelimit" />
<item index="1" class="java.lang.String" itemvalue="sorl-thumbnail" />
<item index="2" class="java.lang.String" itemvalue="django_chunked_upload" />
<item index="3" class="java.lang.String" itemvalue="ratelimit" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="server.myapp.admin.myapp" />
<option value="users.views.FeedbackView.*" />
</list>
</option>
</inspection_tool>

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

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/videoproject-master.iml" filepath="$PROJECT_DIR$/.idea/videoproject-master.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/videoproject-master-4ec34161fdb4c9d953372c1b3fe44fa0a66876ec.iml" filepath="$PROJECT_DIR$/.idea/videoproject-master-4ec34161fdb4c9d953372c1b3fe44fa0a66876ec.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/video.sql" dialect="MySQL" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -0,0 +1,34 @@
<?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="videoproject/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 (server)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/templates" />
</list>
</option>
</component>
</module>

@ -1 +1 @@
# 初始化

@ -1,5 +1,6 @@
from django.contrib import admin
from .models import *
# Register your models here.
admin.site.register(Comment)

@ -1,5 +1,6 @@
from django.apps import AppConfig
class CommentConfig(AppConfig):
name = 'comment'

@ -1,5 +1,6 @@
import datetime
from django.conf import settings
from django.db import models

@ -1,3 +1,4 @@
from django.test import TestCase
# Create your tests here.

@ -2,6 +2,7 @@ from django.urls import path
from . import views
app_name = 'comment'
urlpatterns = [
path('submit_comment/<int:pk>',views.submit_comment, name='submit_comment'),

@ -10,6 +10,7 @@ from video.forms import CommentForm
from video.models import Video
@ratelimit(key='ip', rate='2/m')
def submit_comment(request,pk):
"""

@ -9,7 +9,9 @@ from django.utils.html import strip_tags
from django.views.generic import View
def get_page_list(paginator, page):
"""
分页逻辑
if 页数>=10:
@ -36,10 +38,8 @@ def get_page_list(paginator, page):
return page_list
def ajax_required(f):
"""Not a mixin, but a nice decorator to validate than a request is AJAX"""
def wrap(request, *args, **kwargs):
if not request.is_ajax():
return HttpResponseBadRequest()
@ -50,7 +50,6 @@ def ajax_required(f):
wrap.__name__ = f.__name__
return wrap
def send_html_email(subject, html_message, to_list):
plain_message = strip_tags(html_message)
from_email = settings.EMAIL_HOST_USER
@ -58,6 +57,7 @@ def send_html_email(subject, html_message, to_list):
def send_email(subject, content, to_list):
"""
Example:
subject = 'test subject'
@ -71,7 +71,7 @@ def send_email(subject, content, to_list):
# do not forget set password
print("--> is sending email")
send_mass_mail((message,))
except smtplib.SMTPException:
except smtplib.SMTPException :
print("--> send fail")
return HttpResponse("fail")
else:
@ -92,7 +92,6 @@ class AdminUserRequiredMixin(View):
"""
管理员拦截器
"""
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_staff:
return redirect('myadmin:login')
@ -104,9 +103,9 @@ class SuperUserRequiredMixin(View):
"""
超级用户拦截器
"""
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_superuser:
return HttpResponse('无权限')
return super().dispatch(request, *args, **kwargs)

@ -2,8 +2,8 @@
import os
import sys
if __name__ == '__main__':
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'videoproject.settings')
try:
from django.core.management import execute_from_command_line

@ -1,2 +1,3 @@
from django.contrib import admin

@ -1,6 +1,7 @@
from django.apps import AppConfig
class MyadminConfig(AppConfig):
name = 'myadmin'

@ -2,6 +2,7 @@ from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import ValidationError
from users.models import User
from video.models import Video, Classification

@ -1,6 +1,7 @@
from chunked_upload.models import ChunkedUpload
from django.db import models
# Create your models here.
class MyChunkedUpload(ChunkedUpload):
pass

@ -1,3 +1,4 @@
from django.test import TestCase
# Create your tests here.

@ -1,6 +1,7 @@
from django.urls import path
from . import views
app_name = 'myadmin'
urlpatterns = [
path('login/', views.login, name='login'),

@ -1,6 +1,7 @@
import logging
import smtplib
import datetime
from chunked_upload.views import ChunkedUploadView, ChunkedUploadCompleteView
from django.conf import settings

@ -199,10 +199,3 @@ body {
line-height:34px;
color:#000;
}
.del {
width:100px;
height: 40px;
position: absolute;
right: 40px;
}

@ -3,7 +3,6 @@ $(function () {
// 写入csrf
$.getScript("/static/js/csrftoken.js");
// 点赞
$("#like").click(function(){
var video_id = $("#like").attr("video-id");

@ -44,11 +44,10 @@ $("#chunked_upload").fileupload({
console.log('file size --> ' + fileSize);
console.log('type --> ' + type);
// 若想限制大小,解开注释即可
// if(fileSize > 10000000000){
// alert('文件太大了请上传10000M以内的文件');
// return;
// }
if(fileSize > 100000000){
alert('文件太大了请上传100M以内的文件');
return;
}
if(!type.startsWith("video/")){
alert('视频格式不正确');

@ -17,7 +17,6 @@
</div>
<div class="middle aligned content">
<a class="header" href="{% url 'video:detail' item.pk %}">{{ item.title }}</a>
<a class="del" onclick="uncollect({{item.id}})">取消收藏</a>
</div>
</div>
{% empty %}
@ -30,52 +29,4 @@
{% endblock content %}
{% block javascript %}
<script>
// 写入csrf
$.getScript("/static/js/csrftoken.js");
function uncollect(id) {
var x;
var r=confirm("确定删除?");
if (r==true){
console.log('click ok');
}
else{
return;
}
$.ajax({
url: '/video/collect/',
data: {
video_id: id,
'csrf_token': csrftoken
},
type: 'POST',
dataType: 'json',
success: function (data) {
var code = data.code
if(code == 0){
alert('删除成功')
window.location.reload()
}else{
var msg = data.msg
alert(msg)
}
},
error: function(data){
alert("收藏失败")
}
});
}
</script>
<script src="{% static 'js/detail.js' %}"></script>
{% endblock javascript %}

@ -17,7 +17,6 @@
</div>
<div class="middle aligned content">
<a class="header" href="{% url 'video:detail' item.pk %}">{{ item.title }}</a>
<a class="del" onclick="unlike({{item.id}})">取消喜欢</a>
</div>
</div>
{% empty %}
@ -32,50 +31,3 @@
{% endblock content %}
{% block javascript %}
<script>
// 写入csrf
$.getScript("/static/js/csrftoken.js");
function unlike(id) {
var x;
var r=confirm("确定删除?");
if (r==true){
console.log('click ok');
}
else{
return;
}
$.ajax({
url: '/video/like/',
data: {
video_id: id,
'csrf_token': csrftoken
},
type: 'POST',
dataType: 'json',
success: function (data) {
var code = data.code
if(code == 0){
alert('删除成功')
window.location.reload()
}else{
var msg = data.msg
alert(msg)
}
},
error: function(data){
alert("收藏失败")
}
});
}
</script>
<script src="{% static 'js/detail.js' %}"></script>
{% endblock javascript %}

@ -2,7 +2,6 @@
<a target="_blank" href="https://promotion.aliyun.com/ntms/act/enterprise-discount.html?userCode=3bcjya8p">
<img src="{% static 'img/img_ad_banner.jpg' %}">
</a>

@ -5,6 +5,65 @@
<link rel="stylesheet" href="{% static 'css/dropload.css' %}">
{% endblock css %}
{% block content %}
<div class="ui unstackable two column grid">
<div class=" ten wide column">
<video class="video" autoplay="autoplay" controls="controls" controlslist="nodownload"
disablePictureInPicture>
<source src="{{video.file.url}}" type="video/mp4">
<!-- <source src="https://www.runoob.com/try/demo_source/movie.mp4" type="video/mp4">-->
</video>
<div class="video-info">
<div class="video-title">{{ video.title }}</div>
<div class="video-view-count">{{ video.view_count }}次观看</div>
<div class="video-view-operation">
{{video.desc}}
</div>
<div class="extra content video-view-operation">
<span class="left floated like">
<i class="like {% user_liked_class video user %} icon cursor" id="like"
video-id="{{ video.id }}"></i>
<span id="like-count">{{ video.count_likers }}</span>
</span>
<span class="right floated star">
<i class="bookmark {% user_collected_class video user %} icon cursor" id="star"
video-id="{{ video.id }}"></i>
<span id="collect-count">{{ video.count_collecters }}</span>
</span>
</div>
<div class="ui divider"></div>
</div>
<div class="ui comments">
{% if user.is_authenticated %}
<form class="ui reply form" id="comment_form" method="post"
action="{% url 'comment:submit_comment' video.pk %}">
{% csrf_token %}
<div class="field">
{{form.content}}
<input type="hidden" value="{{ video.id }}" name="video_id">
</div>
<button class="ui primary button" type="submit">
添加评论
</button>
<div class="ui info message n">
<div class="item" id="comment-result"></div>
</div>
</form>
{% else %}
<div class="ui ignored info attached message">
<p>登录后即可评论 &nbsp;&nbsp;&nbsp;<a href="{% url 'users:login' %}?next={{ request.path }}">马上登录</a></p>
</div>
{% endif %}
<h3 class="ui dividing header" id="id_comment_label">评论</h3>
<div class="comment-list"></div>
</div>
</div>
<div class="six wide column">
{% include "video/recommend.html" %}
{% include "video/ad.html" %}
</div>
</div>
{% endblock content %}
{% block javascript %}

@ -1,5 +1,6 @@
from django.contrib import admin
# Register your models here.
from .models import User
admin.site.register(User)

@ -1,3 +1,4 @@
from django.apps import AppConfig

@ -3,6 +3,7 @@ from django.db import models
class User(AbstractUser):
GENDER_CHOICES = (
('M', ''),

@ -1,3 +1,4 @@
from django.test import TestCase
# Create your tests here.

@ -1,6 +1,7 @@
from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
path('login/', views.login, name='login'),

@ -8,15 +8,146 @@ from django.shortcuts import *
from django.views import generic
from ratelimit.decorators import ratelimit
from .models import Feedback
from .forms import ProfileForm, SignUpForm, UserLoginForm, ChangePwdForm, SubscribeForm, FeedbackForm
User = get_user_model()
def login(request):
# 功能待开发,请期待
if request.method == 'POST':
next = request.POST.get('next', '/')
form = UserLoginForm(request=request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
auth_login(request, user)
# return redirect('home')
return redirect(next)
else:
print(form.errors)
else:
next = request.GET.get('next', '/')
form = UserLoginForm()
print(next)
return render(request, 'registration/login.html', {'form': form, 'next':next})
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password1 = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password1)
auth_login(request, user)
return redirect('home')
else:
print(form.errors)
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
def logout(request):
auth_logout(request)
return redirect('home')
def change_password(request):
if request.method == 'POST':
form = ChangePwdForm(request.user, request.POST)
if form.is_valid():
user = form.save(commit=False)
if not user.is_staff and not user.is_superuser:
user.save()
update_session_auth_hash(request, user) # 更新session 非常重要!
messages.success(request, '修改成功')
return redirect('users:change_password')
else:
messages.warning(request, '无权修改管理员密码')
return redirect('users:change_password')
else:
print(form.errors)
else:
form = ChangePwdForm(request.user)
return render(request, 'registration/change_password.html', {
'form': form
})
class ProfileView(LoginRequiredMixin,AuthorRequiredMixin, generic.UpdateView):
model = User
form_class = ProfileForm
template_name = 'users/profile.html'
def get_success_url(self):
messages.success(self.request, "保存成功")
return reverse('users:profile', kwargs={'pk': self.request.user.pk})
class SubscribeView(LoginRequiredMixin,AuthorRequiredMixin, generic.UpdateView):
model = User
form_class = SubscribeForm
template_name = 'users/subscribe.html'
def get_success_url(self):
messages.success(self.request, "保存成功")
return reverse('users:subscribe', kwargs={'pk': self.request.user.pk})
class FeedbackView(LoginRequiredMixin, generic.CreateView):
model = Feedback
form_class = FeedbackForm
template_name = 'users/feedback.html'
@ratelimit(key='ip', rate='2/m')
def post(self, request, *args, **kwargs):
was_limited = getattr(request, 'limited', False)
if was_limited:
messages.warning(self.request, "操作太频繁了请1分钟后再试")
return render(request, 'users/feedback.html', {'form': FeedbackForm()})
return super().post(request, *args, **kwargs)
def get_success_url(self):
messages.success(self.request, "提交成功")
return reverse('users:feedback')
class CollectListView(generic.ListView):
model = User
template_name = 'users/collect_videos.html'
context_object_name = 'video_list'
paginate_by = 10
def get_context_data(self, *, object_list=None, **kwargs):
context = super(CollectListView, self).get_context_data(**kwargs)
paginator = context.get('paginator')
page = context.get('page_obj')
page_list = get_page_list(paginator, page)
context['page_list'] = page_list
return context
def get_queryset(self):
user = get_object_or_404(User, pk=self.kwargs.get('pk'))
videos = user.collected_videos.all()
return videos
class LikeListView(generic.ListView):
model = User
template_name = 'users/like_videos.html'
context_object_name = 'video_list'
paginate_by = 10
def get_context_data(self, *, object_list=None, **kwargs):
context = super(LikeListView, self).get_context_data(**kwargs)
paginator = context.get('paginator')
page = context.get('page_obj')
page_list = get_page_list(paginator, page)
context['page_list'] = page_list
return context
def get_queryset(self):
user = get_object_or_404(User, pk=self.kwargs.get('pk'))

@ -3,6 +3,7 @@
chdir = /var/www/videoproject
module = videoproject.wsgi
master = true
processes = 2
#socket = /run/uwsgi/video-conf.sock
@ -15,5 +16,3 @@ gid = www-data
vacuum = true
daemonize = %(chdir)/uwsgi.log
#

@ -1,6 +1,7 @@
from django.contrib import admin
from .models import *
# Register your models here.)
admin.site.register(Classification)
admin.site.register(Video)

@ -1,5 +1,6 @@
from django.apps import AppConfig
class VideoConfig(AppConfig):
name = 'video'

@ -1,6 +1,7 @@
from django import forms
from comment.models import Comment
class CommentForm(forms.ModelForm):
content = forms.CharField(error_messages={'required': '不能为空',},
widget=forms.Textarea(attrs = {'placeholder': '请输入评论内容' })

@ -5,6 +5,7 @@ from django.db import models
from django.dispatch import receiver
class VideoQuerySet(models.query.QuerySet):
def get_count(self):

@ -1,3 +1,4 @@
from django.test import TestCase
# Create your tests here.

@ -1,6 +1,7 @@
from django.urls import path
from . import views
app_name = 'video'
urlpatterns = [
path('index', views.IndexView.as_view(), name='index'),

@ -3,6 +3,7 @@ from django.shortcuts import get_object_or_404
from django.views import generic
from django.views.decorators.http import require_http_methods
from helpers import get_page_list, ajax_required
from .forms import CommentForm
from .models import Video, Classification
@ -56,9 +57,45 @@ class SearchListView(generic.ListView):
return context
class VideoDetailView(generic.DetailView):
model = Video
template_name = 'video/detail.html'
def get_object(self, queryset=None):
obj = super().get_object()
obj.increase_view_count()
return obj
def get_context_data(self, **kwargs):
context = super(VideoDetailView, self).get_context_data(**kwargs)
form = CommentForm()
recommend_list = Video.objects.get_recommend_list()
context['form'] = form
context['recommend_list'] = recommend_list
return context
@ajax_required
@require_http_methods(["POST"])
def like(request):
if not request.user.is_authenticated:
return JsonResponse({"code": 1, "msg": "请先登录"})
video_id = request.POST['video_id']
video = Video.objects.get(pk=video_id)
user = request.user
video.switch_like(user)
return JsonResponse({"code": 0, "likes": video.count_likers(), "user_liked": video.user_liked(user)})
@ajax_required
@require_http_methods(["POST"])
def collect(request):
if not request.user.is_authenticated:
return JsonResponse({"code": 1, "msg": "请先登录"})
video_id = request.POST['video_id']
video = Video.objects.get(pk=video_id)
user = request.user
video.switch_collect(user)
return JsonResponse({"code": 0, "collects": video.count_collecters(), "user_collected": video.user_collected(user)})

@ -1,4 +1,5 @@
import pymysql
pymysql.install_as_MySQLdb()
print("===============install pymysql==============")

@ -71,7 +71,7 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'upload').replace('\\', '/')
MEDIA_URL = '/upload/'
# 上传视频最大尺寸
CHUNKED_UPLOAD_MAX_BYTES = 10000000000
CHUNKED_UPLOAD_MAX_BYTES = 100000000
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
@ -98,6 +98,7 @@ TEMPLATES = [
},
]
WSGI_APPLICATION = 'videoproject.wsgi.application'
# Database

@ -1,5 +1,6 @@
""" URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:

@ -1,6 +1,7 @@
"""
WSGI config for dj_demo_one project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see

Loading…
Cancel
Save