diff --git a/article/views.py b/article/views.py index c1c9fa2..8646e53 100644 --- a/article/views.py +++ b/article/views.py @@ -417,8 +417,9 @@ class ArticleLikeToggleView(APIView): like, created = ArticleLike.objects.get_or_create(user=request.user, article=article) if not created: like.delete() - article.likes = max(0, article.likes - 1) - article.save(update_fields=['likes']) + Article.objects.filter(pk=pk).update(likes=F("likes") - 1) + article.refresh_from_db() + article.likes = max(0, article.likes) return create_standardized_response( data={'liked': False, 'likes_count': article.likes}, code=ResponseCode.SUCCESS @@ -498,8 +499,9 @@ class ArticleCommentLikeToggleView(APIView): like, created = ArticleCommentLike.objects.get_or_create(user=request.user, comment=comment) if not created: like.delete() - comment.likes = max(0, comment.likes - 1) - comment.save(update_fields=['likes']) + ArticleComment.objects.filter(pk=pk).update(likes=F("likes") - 1) + comment.refresh_from_db() + comment.likes = max(0, comment.likes) return create_standardized_response( data={'liked': False, 'likes_count': comment.likes}, code=ResponseCode.SUCCESS @@ -626,4 +628,4 @@ class ArticleToggleTopView(APIView): data={'is_top': article.is_top}, code=ResponseCode.SUCCESS, message='置顶状态已更新' - ) + ) \ No newline at end of file diff --git a/chunyu_project/settings.py b/chunyu_project/settings.py index ddf15d9..1ff4a72 100644 --- a/chunyu_project/settings.py +++ b/chunyu_project/settings.py @@ -21,7 +21,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-j+-psq=m++l7hup73k1eg+wm-b&2_)!+_^o=6(=xc$1px*kqt@' +SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'django-insecure-dev-only-key-change-in-production') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = os.environ.get('DJANGO_DEBUG', 'True') == 'True' @@ -66,7 +66,7 @@ CORS_ALLOWED_ORIGINS = [ ] CORS_ALLOW_ALL_ORIGINS = False -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',') CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_HEADERS = [ @@ -127,7 +127,7 @@ EMAIL_HOST = 'smtp.qq.com' EMAIL_PORT = 465 EMAIL_USE_SSL = True EMAIL_HOST_USER = 'cs10086086@qq.com' -EMAIL_HOST_PASSWORD = 'ldzpymytsinkfjhb' +EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '') EMAIL_USE_TLS = False AUTH_USER_MODEL = 'user.FUser' @@ -173,7 +173,7 @@ DATABASES = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'chunyu_project', 'USER': 'root', - 'PASSWORD': 'mysql_NpyMCS', + 'PASSWORD': os.environ.get('MYSQL_PASSWORD', ''), 'HOST': '192.168.5.7', 'PORT': '3306', 'OPTIONS': { @@ -189,7 +189,7 @@ DATABASES = { REDIS_HOST = '192.168.5.7' REDIS_PORT = 6379 REDIS_DB = 0 -REDIS_PASSWORD = 'jhkdjhkjdhsIUTYURTU_sx86Jf' +REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD', '') SESSION_DB = 1 CELERY_BROKER_DB = 2 CELERY_RESULT_BACKEND_DB = 2 diff --git a/learn/views.py b/learn/views.py index 7caf30e..c788930 100644 --- a/learn/views.py +++ b/learn/views.py @@ -500,10 +500,14 @@ class CDNStaticFileView(APIView): ) if not os.path.exists(file_path): raise Http404 - response = FileResponse(open(file_path, 'rb'), content_type='text/markdown; charset=utf-8') - response['Cache-Control'] = 'max-age=86400' - return response - + fh = open(file_path, "rb") + try: + response = FileResponse(fh, content_type="text/markdown; charset=utf-8") + response["Cache-Control"] = "max-age=86400" + return response + except Exception: + fh.close() + raise class CourseFavoriteToggleView(APIView): permission_classes = [IsAuthenticated] @@ -745,7 +749,10 @@ class MyProgressView(APIView): 'last_studied_at': read.completed_at, } course_map[course_id]['completed_chapters'] += 1 - if read.completed_at > course_map[course_id]['last_studied_at']: + if read.completed_at and ( + not course_map[course_id]['last_studied_at'] or + read.completed_at > course_map[course_id]['last_studied_at'] + ): course_map[course_id]['last_studied_at'] = read.completed_at courses = [] @@ -765,4 +772,4 @@ class MyProgressView(APIView): 'total_courses': len(courses), 'total_completed': total_completed, } - ) + ) \ No newline at end of file diff --git a/search/views.py b/search/views.py index d1595cc..22c6324 100644 --- a/search/views.py +++ b/search/views.py @@ -67,8 +67,8 @@ class GlobalSearchView(APIView): for article in articles: cover_url = '' - if article.cover and hasattr(article.cover, 'url'): - cover_url = request.build_absolute_uri(article.cover.url) + if article.cover_image and hasattr(article.cover_image, 'url'): + cover_url = request.build_absolute_uri(article.cover_image.url) excerpt = article.excerpt or '' if not excerpt and article.content: @@ -91,21 +91,16 @@ class GlobalSearchView(APIView): ).order_by('-created_at')[:100] for tool in tools: - cover_url = '' - if tool.icon and hasattr(tool.icon, 'url'): - cover_url = request.build_absolute_uri(tool.icon.url) - results.append({ 'id': tool.id, 'type': '工具', 'title': tool.name, 'desc': tool.description or '', - 'cover': cover_url, - 'views': tool.views or 0, - 'likes': tool.likes or 0, + 'cover': '', + 'views': tool.usage_count or 0, + 'likes': 0, 'url': f'/use?tool={tool.id}', }) - if content_type == 'all' or content_type == 'course': courses = Course.objects.filter( Q(title__icontains=q) | Q(description__icontains=q) @@ -113,8 +108,8 @@ class GlobalSearchView(APIView): for course in courses: cover_url = '' - if course.cover and hasattr(course.cover, 'url'): - cover_url = request.build_absolute_uri(course.cover.url) + if course.cover_image and hasattr(course.cover_image, 'url'): + cover_url = request.build_absolute_uri(course.cover_image.url) results.append({ 'id': course.id, @@ -122,9 +117,8 @@ class GlobalSearchView(APIView): 'title': course.title, 'desc': course.description or '', 'cover': cover_url, - 'views': course.views or 0, - 'likes': course.likes or 0, - 'url': f'/courses/{course.id}', + 'views': 0, + 'likes': 0, }) if content_type == 'all' or content_type == 'api': @@ -236,4 +230,4 @@ class HotKeywordsView(APIView): 'Vue3', 'Python', ] - return create_standardized_response(data=hot_keywords, code=ResponseCode.SUCCESS) + return create_standardized_response(data=hot_keywords, code=ResponseCode.SUCCESS) \ No newline at end of file diff --git a/user/views/user.py b/user/views/user.py index dc14620..5a830cc 100644 --- a/user/views/user.py +++ b/user/views/user.py @@ -17,7 +17,7 @@ from django.core.cache import caches default_cache = caches['default'] session_cache = caches['session'] celery_cache = caches['celery'] -from ..models import FUser, LoginRecord +from ..models import FUser, LoginRecord, Follow from rest_framework_simplejwt.tokens import RefreshToken from ..serializers.user_serializers import UserSerializer, ChangePasswordSerializer, UserUpdateSerializer from ..tasks import send_verification_email_task, send_reset_password_email_task