/health/
/error_code_map/ /ec_user/* /diagnose/* /admin/*
This commit is contained in:
commit
f56b66d8f1
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
/upload_file
|
||||
/generate_paper
|
||||
*.pyc
|
||||
0
authentication/__init__.py
Normal file
0
authentication/__init__.py
Normal file
8
authentication/admin.py
Normal file
8
authentication/admin.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
|
||||
from django.contrib import admin
|
||||
from .models import CustomToken
|
||||
|
||||
admin.site.register(CustomToken)
|
||||
6
authentication/apps.py
Normal file
6
authentication/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthenticationConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'authentication'
|
||||
31
authentication/authentication.py
Normal file
31
authentication/authentication.py
Normal file
@ -0,0 +1,31 @@
|
||||
from rest_framework.authentication import TokenAuthentication
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
from .models import CustomToken
|
||||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
from functools import wraps
|
||||
|
||||
class CustomTokenAuthentication(TokenAuthentication):
|
||||
def authenticate(self, request):
|
||||
# 获取请求中的 token
|
||||
token_key = request.headers.get('token')
|
||||
if token_key:
|
||||
# 移除前缀 (如果有 "Token " 前缀的话)
|
||||
if token_key.startswith('Token '):
|
||||
token_key = token_key[6:]
|
||||
# print(token_key)
|
||||
try:
|
||||
# 获取自定义的 Token 对象
|
||||
token = CustomToken.objects.get(key=token_key)
|
||||
|
||||
# 检查 token 是否过期
|
||||
if token.expiration_date < timezone.now():
|
||||
raise AuthenticationFailed('Token has expired.')
|
||||
|
||||
return (token.user, token) # 返回用户和 token
|
||||
|
||||
except CustomToken.DoesNotExist:
|
||||
raise AuthenticationFailed('Invalid token.')
|
||||
|
||||
raise AuthenticationFailed('Authorization header missing or invalid.')
|
||||
|
||||
32
authentication/migrations/0001_initial.py
Normal file
32
authentication/migrations/0001_initial.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-26 08:21
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomToken',
|
||||
fields=[
|
||||
('key', models.CharField(max_length=40, primary_key=True, serialize=False, verbose_name='Key')),
|
||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
||||
('extra_info', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('last_used', models.DateTimeField(auto_now=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Token',
|
||||
'verbose_name_plural': 'Tokens',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-26 08:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='customtoken',
|
||||
name='expiration_date',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
0
authentication/migrations/__init__.py
Normal file
0
authentication/migrations/__init__.py
Normal file
24
authentication/models.py
Normal file
24
authentication/models.py
Normal file
@ -0,0 +1,24 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
class CustomToken(Token):
|
||||
# 在 Token 上添加更多字段(可以根据需求自定义)
|
||||
extra_info = models.CharField(max_length=255, null=True, blank=True) # 示例附加信息字段
|
||||
last_used = models.DateTimeField(auto_now=True) # 记录最后一次使用的时间
|
||||
expiration_date = models.DateTimeField(null=True, blank=True) # 记录 Token 的过期时间
|
||||
|
||||
def __str__(self):
|
||||
# 返回 Token 的字符串表示,包括用户名和 key
|
||||
return f"Token for {self.user.username} - {self.key}"
|
||||
|
||||
def get_user_info(self):
|
||||
# 可以提供一个方法来获取与 Token 关联的用户的更多信息
|
||||
return {
|
||||
"username": self.user.username,
|
||||
"email": self.user.email,
|
||||
"role": self.user.groups.first().name if self.user.groups.exists() else "No role"
|
||||
}
|
||||
|
||||
3
authentication/tests.py
Normal file
3
authentication/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
6
authentication/urls.py
Normal file
6
authentication/urls.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.urls import path
|
||||
from .views import MyProtectedView
|
||||
|
||||
urlpatterns = [
|
||||
path('', MyProtectedView.as_view(), name='protected-view'),
|
||||
]
|
||||
19
authentication/views.py
Normal file
19
authentication/views.py
Normal file
@ -0,0 +1,19 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from authentication.authentication import CustomTokenAuthentication
|
||||
|
||||
class MyProtectedView(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
# 只有认证通过的用户可以访问这个视图
|
||||
|
||||
print(request.user.id) # 访问当前用户
|
||||
return Response({"message": "This is a protected view!"})
|
||||
|
||||
4
celerybeat-schedule.bak
Normal file
4
celerybeat-schedule.bak
Normal file
@ -0,0 +1,4 @@
|
||||
'entries', (0, 6)
|
||||
'__version__', (512, 15)
|
||||
'tz', (1024, 23)
|
||||
'utc_enabled', (1536, 4)
|
||||
BIN
celerybeat-schedule.dat
Normal file
BIN
celerybeat-schedule.dat
Normal file
Binary file not shown.
4
celerybeat-schedule.dir
Normal file
4
celerybeat-schedule.dir
Normal file
@ -0,0 +1,4 @@
|
||||
'entries', (0, 6)
|
||||
'__version__', (512, 15)
|
||||
'tz', (1024, 23)
|
||||
'utc_enabled', (1536, 4)
|
||||
0
diagnose/__init__.py
Normal file
0
diagnose/__init__.py
Normal file
9
diagnose/admin.py
Normal file
9
diagnose/admin.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from . models import Papers
|
||||
|
||||
@admin.register(Papers)
|
||||
|
||||
class PaperAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'uuid', 'status', 'created_at', 'updated_at')
|
||||
6
diagnose/apps.py
Normal file
6
diagnose/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class DiagnoseConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'diagnose'
|
||||
BIN
diagnose/ch.jpg
Normal file
BIN
diagnose/ch.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 928 KiB |
253
diagnose/dp_views.py
Normal file
253
diagnose/dp_views.py
Normal file
@ -0,0 +1,253 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from openai import OpenAI
|
||||
import markdown2
|
||||
import pdfkit
|
||||
from django.conf import settings
|
||||
from django.http import JsonResponse, FileResponse
|
||||
from celery import shared_task
|
||||
import uuid
|
||||
from django.utils import timezone
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from authentication.authentication import CustomTokenAuthentication
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from .models import Papers
|
||||
from ec_user.models import SchoolInfo
|
||||
import json
|
||||
# ============== PYdoc ===================
|
||||
# from docx import Document
|
||||
# import pypandoc
|
||||
# pypandoc.download_pandoc()
|
||||
|
||||
# ================ weasyprint ===========
|
||||
# 库用不了
|
||||
# from weasyprint import HTML
|
||||
# HTML(string=html).write_pdf("output.pdf")
|
||||
|
||||
class DpArguments():
|
||||
subject = "数学"
|
||||
textbook_version = "人教版"
|
||||
|
||||
start_grade = 8
|
||||
start_semester = 1
|
||||
start_chapter = 1
|
||||
|
||||
end_grade = 9
|
||||
end_semester = 1
|
||||
end_chapter = 1
|
||||
|
||||
student = {
|
||||
"grade": 8,
|
||||
"age": 10,
|
||||
"school": "民族小学"
|
||||
}
|
||||
|
||||
def __getstate__(self):
|
||||
# 返回一个字典,包含所有需要序列化的属性
|
||||
state = self.__dict__.copy()
|
||||
# 如果你不想序列化某个属性,可以从字典中删除
|
||||
# 例如: del state['student']
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
# 用字典中的数据恢复对象状态
|
||||
self.__dict__.update(state)
|
||||
|
||||
|
||||
|
||||
def generate_html_paper(md_result, file_path_name):
|
||||
# 写到md中
|
||||
md_file = open(f'{file_path_name}.md', 'w', encoding='utf-8')
|
||||
md_file.write(md_result)
|
||||
md_file.close()
|
||||
|
||||
# 从md中读出来再写到html中
|
||||
md_read_file = open(f'{file_path_name}.md', 'r', encoding='utf-8')
|
||||
md_text = md_read_file.read()
|
||||
md_read_file.close()
|
||||
html = markdown2.markdown(md_text)
|
||||
html_write_file = open(f'{file_path_name}.html', 'w', encoding='utf-8')
|
||||
html_write_file.write(
|
||||
"""<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" async
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML">
|
||||
</script>
|
||||
</head>"""+html)
|
||||
html_write_file.close()
|
||||
|
||||
def convert_to_pdf(file_path_name):
|
||||
# =============== pdfkit ================
|
||||
# 从html中读出来再写到pdf中
|
||||
f = open(f'{file_path_name}.html', 'r', encoding='utf-8')
|
||||
content = f.read()
|
||||
f.close()
|
||||
config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)
|
||||
pdfkit.from_string(content, f'{file_path_name}.pdf', configuration=config)
|
||||
|
||||
@shared_task
|
||||
def async_wraper(file_path_name, uuid_str, subject, textbook_version, start_grade, \
|
||||
start_semester, start_chapter, end_grade, end_semester, end_chapter, student):
|
||||
|
||||
# client = OpenAI(
|
||||
# api_key = settings.OPAI_API_KEY,
|
||||
# base_url = settings.OPAI_BASE_URL,
|
||||
# )
|
||||
# completion = client.chat.completions.create(
|
||||
# model = "deepseek-r1-250120", # your model endpoint ID
|
||||
# messages = [
|
||||
# {"role": "system", "content": "你是教学助手"},
|
||||
# # {"role": "user",
|
||||
# # "content": f"请根据以下信息生成一份检测卷:学科为{subject},教材版本是{textbook_version},\
|
||||
# # 检测范围从{start_grade}年级{start_semester}学期{start_chapter}章\
|
||||
# # 到{end_grade}年级{end_semester}学期{end_chapter}章,学生年级为{student.get('grade')},\
|
||||
# # 年龄为{student.get('age')},所在学校是{student.get('school')}。\
|
||||
# # 根据答题所需时间一个半小时设置题量。题目有梯度。\
|
||||
# # 试卷题目为{subject}{textbook_version}检测卷。只生成题目,不输出答案及说明等其他内容。"
|
||||
# # },
|
||||
# {"role": "user", "content": f"""请严格按照以下要求生成一份{subject}检测卷:
|
||||
# 【试卷信息】
|
||||
# 1. 标题:**{subject}{textbook_version}综合检测卷**
|
||||
# 2. 检测范围:{start_grade}年级{start_semester}学期第{start_chapter}章 至
|
||||
# {end_grade}年级{end_semester}学期第{end_chapter}章
|
||||
# 3. 适用对象:{student.get('school')} {student.get('grade')}年级学生(年龄{student.get('age')})
|
||||
# 【命题要求】
|
||||
# 1. 题型结构:
|
||||
# - 按难度梯度分为基础题(60%)、中档题(30%)、提高题(10%)
|
||||
# - 根据学科特点设计合理的题型(如数学可设置选择题/填空题/计算题/应用题,语文可设置阅读理解/文言文/写作等)
|
||||
# - 同一知识点不重复考查
|
||||
# 2. 题量控制:
|
||||
# - 总题数控制在18-22题(以优秀学生完成时间约75分钟为标准)
|
||||
# - 选择题不超过5题,填空题不超过6题
|
||||
# - 需包含至少1道综合应用题(理科)或材料分析题(文科)
|
||||
# 3. 内容要求:
|
||||
# - 严格按照指定章节范围命题
|
||||
# - 题目表述清晰无歧义,数字单位标注完整
|
||||
# - 禁止出现需图片辅助的题目
|
||||
# - 数学类题目需给出必要公式位置(如"(提示:可用公式____)")
|
||||
# 【输出格式】
|
||||
# 仅输出以下内容:
|
||||
# 1. 试卷标题(加粗居中)
|
||||
# 2. 考试说明(含总分值100分、考试时长、姓名班级填写处)
|
||||
# 3. 分模块的题目内容(标注题型、分值和题号)
|
||||
# 4. "——以下为题目区域——" 分隔线
|
||||
# 禁止包含:
|
||||
# - 答案及解析
|
||||
# - 评分标准
|
||||
# - 额外说明文字
|
||||
# - markdown格式及特殊符号"""}
|
||||
# ],
|
||||
# )
|
||||
# generate_html_paper(completion.choices[0].message.content, file_path_name)
|
||||
import time
|
||||
time.sleep(30)
|
||||
generate_html_paper(""" # Test md""", file_path_name)
|
||||
try:
|
||||
obj = Papers.objects.get(uuid=uuid_str) # 只获取一个对象
|
||||
obj.status = 'D'
|
||||
obj.updated_at = timezone.now()
|
||||
obj.save()
|
||||
except ObjectDoesNotExist:
|
||||
print("warning: record not found")
|
||||
|
||||
class MyProtectedGeneratePaper(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
uuid_str = str(uuid.uuid4())
|
||||
radom_path = user.username +'_'+ uuid_str
|
||||
file_path_name = os.path.join(settings.BASE_DIR, 'generate_paper', radom_path)
|
||||
|
||||
# 处理 POST 请求,更新用户的联系信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
subject = data.get("subject")
|
||||
textbook_version = data.get("textbook_version")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# auth_subjects = user.subjects.all()
|
||||
if not user.subjects.filter(name=subject).exists():
|
||||
print("subject", subject)
|
||||
return JsonResponse({"error_code": "2001"}, status=403)
|
||||
|
||||
if user.subject_usage_count <= 0:
|
||||
return JsonResponse({"error_code": "2002"}, status=403)
|
||||
|
||||
dp_args = DpArguments()
|
||||
dp_args.subject = subject
|
||||
dp_args.textbook_version = textbook_version
|
||||
|
||||
school_obj = SchoolInfo.objects.filter(user=user).first()
|
||||
if school_obj is None:
|
||||
return JsonResponse({"error_code": "2003"}, status=403)
|
||||
|
||||
dp_args.student['age'] = user.age
|
||||
dp_args.student['school'] = school_obj.school_name
|
||||
dp_args.student['grade'] = school_obj.grade
|
||||
|
||||
print(dp_args.student, dp_args.subject, dp_args.textbook_version, dp_args.start_grade, dp_args.start_semester,\
|
||||
dp_args.start_chapter, dp_args.end_grade, dp_args.end_semester, dp_args.end_chapter)
|
||||
# 调用异步任务
|
||||
obj = Papers.objects.create(uuid=uuid_str, user=user, status='P')
|
||||
obj.save()
|
||||
user.subject_usage_count = user.subject_usage_count - 1
|
||||
user.save()
|
||||
async_wraper.delay(file_path_name, uuid_str, \
|
||||
dp_args.subject, dp_args.textbook_version, dp_args.start_grade, dp_args.start_semester, dp_args.start_chapter, \
|
||||
dp_args.end_grade, dp_args.end_semester, dp_args.end_chapter, dp_args.student)
|
||||
return JsonResponse({"status": "success", "uuid": uuid_str})
|
||||
|
||||
class MyProtectedGenerateCheck(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新用户的联系信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
uuid_str = data.get("uuid")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
try:
|
||||
# print(uuid_str)
|
||||
obj = Papers.objects.get(uuid=uuid_str, user=user) # 只获取一个对象
|
||||
if obj.status == 'D':
|
||||
return JsonResponse({"status": "done", "download_url": f'/diagnose/download/?uuid_str={uuid_str}'})
|
||||
else:
|
||||
return JsonResponse({"status": "processing", "download_url": None})
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error_code": "2004"}, status=404)
|
||||
|
||||
class MyProtectedDownloadPaper(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
uuid_str = request.query_params.get('uuid_str', None)
|
||||
if not uuid_str:
|
||||
return JsonResponse({"error": "Missing uuid_str in query parameters"}, status=400)
|
||||
|
||||
user = request.user
|
||||
username = user.username
|
||||
file_path_name = os.path.join(settings.BASE_DIR, 'generate_paper', f'{username}_{uuid_str}')
|
||||
|
||||
# 检查文件是否存在
|
||||
print(file_path_name)
|
||||
if not os.path.exists(file_path_name + ".html"):
|
||||
return JsonResponse({"error_code": "2005"}, status=403)
|
||||
|
||||
convert_to_pdf(file_path_name)
|
||||
|
||||
try:
|
||||
# 直接将文件路径传递给 FileResponse
|
||||
response = FileResponse(open(file_path_name+".pdf", 'rb'), as_attachment=True)
|
||||
response['Content-Disposition'] = f'attachment; filename="{username}_{uuid_str}.pdf"'
|
||||
return response
|
||||
except Exception as e:
|
||||
return JsonResponse({"error": f"Failed to open file: {str(e)}"}, status=500)
|
||||
26
diagnose/migrations/0001_initial.py
Normal file
26
diagnose/migrations/0001_initial.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-27 06:23
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Papers',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uuid', models.CharField(max_length=100)),
|
||||
('status', models.CharField(choices=[('C', '任务创建'), ('P', '生成中'), ('D', '已完成')], default='C', max_length=1)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-27 06:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('diagnose', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='papers',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='papers',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, null=True),
|
||||
),
|
||||
]
|
||||
0
diagnose/migrations/__init__.py
Normal file
0
diagnose/migrations/__init__.py
Normal file
19
diagnose/models.py
Normal file
19
diagnose/models.py
Normal file
@ -0,0 +1,19 @@
|
||||
from django.db import models
|
||||
from ec_user.models import EcUser
|
||||
# Create your models here.
|
||||
|
||||
class Papers(models.Model):
|
||||
STATUS_CHOICES = (
|
||||
('C', '任务创建'),
|
||||
('P', '生成中'),
|
||||
('D', '已完成')
|
||||
)
|
||||
uuid = models.CharField(max_length=100) # 试卷的唯一标识符
|
||||
# 定义一个与EcUser一对多关联的外键
|
||||
user = models.ForeignKey(EcUser, on_delete=models.CASCADE) # 当EcUser被删除时,关联的Papers也会被删除
|
||||
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='C') # 默认值设置为'C'
|
||||
created_at = models.DateTimeField(auto_now_add=True,null=True, blank=True) # 创建时间
|
||||
updated_at = models.DateTimeField(auto_now=True,null=True, blank=True) # 更新时间
|
||||
|
||||
def __str__(self):
|
||||
return self.user.username + '的试卷'
|
||||
43
diagnose/openaitest.py
Normal file
43
diagnose/openaitest.py
Normal file
@ -0,0 +1,43 @@
|
||||
import os
|
||||
from openai import OpenAI
|
||||
import base64
|
||||
|
||||
client = OpenAI(
|
||||
api_key = 'd04d386a-7c67-4927-8251-171a236583a6',
|
||||
base_url = "https://ark.cn-beijing.volces.com/api/v3",
|
||||
)
|
||||
def encode_image(image_path):
|
||||
with open(image_path, "rb") as image_file:
|
||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||
# 将图片转为Base64编码
|
||||
|
||||
# 需要传给大模型的图片
|
||||
image_path = "ch.jpg"
|
||||
base64_image = encode_image(image_path)
|
||||
# Image input:
|
||||
response = client.chat.completions.create(
|
||||
model="doubao-1-5-vision-pro-32k-250115",
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "图中是几个语文题目,帮我分析一下,我是否做对了",
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
# 需要注意:传入Base64编码前需要增加前缀 data:image/{图片格式};base64,{Base64编码}:
|
||||
# PNG图片:"url": f"data:image/png;base64,{base64_image}"
|
||||
# JEPG图片:"url": f"data:image/jpeg;base64,{base64_image}"
|
||||
# WEBP图片:"url": f"data:image/webp;base64,{base64_image}"
|
||||
"url": f"data:image/jpg;base64,{base64_image}"
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
138
diagnose/te.py
Normal file
138
diagnose/te.py
Normal file
@ -0,0 +1,138 @@
|
||||
import _thread as thread
|
||||
import base64
|
||||
import datetime
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
from urllib.parse import urlparse
|
||||
import ssl
|
||||
from datetime import datetime
|
||||
from time import mktime
|
||||
from urllib.parse import urlencode
|
||||
from wsgiref.handlers import format_date_time
|
||||
# websocket-client
|
||||
import websocket
|
||||
|
||||
class Ws_Param(object):
|
||||
# 初始化
|
||||
def __init__(self, APPID, APIKey, APISecret, gpt_url):
|
||||
self.APPID = APPID
|
||||
self.APIKey = APIKey
|
||||
self.APISecret = APISecret
|
||||
self.host = urlparse(gpt_url).netloc
|
||||
self.path = urlparse(gpt_url).path
|
||||
self.gpt_url = gpt_url
|
||||
|
||||
# 生成url
|
||||
def create_url(self):
|
||||
# 生成RFC1123格式的时间戳
|
||||
now = datetime.now()
|
||||
date = format_date_time(mktime(now.timetuple()))
|
||||
|
||||
# 拼接字符串
|
||||
signature_origin = "host: " + self.host + "\n"
|
||||
signature_origin += "date: " + date + "\n"
|
||||
signature_origin += "GET " + self.path + " HTTP/1.1"
|
||||
|
||||
# 进行hmac-sha256进行加密
|
||||
signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'),
|
||||
digestmod=hashlib.sha256).digest()
|
||||
|
||||
signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
|
||||
|
||||
authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
|
||||
|
||||
authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
|
||||
|
||||
# 将请求的鉴权参数组合为字典
|
||||
v = {
|
||||
"authorization": authorization,
|
||||
"date": date,
|
||||
"host": self.host
|
||||
}
|
||||
# 拼接鉴权参数,生成url
|
||||
url = self.gpt_url + '?' + urlencode(v)
|
||||
# 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致
|
||||
return url
|
||||
|
||||
# 收到websocket错误的处理
|
||||
def on_error(ws, error):
|
||||
print("### error:", error)
|
||||
|
||||
# 收到websocket关闭的处理
|
||||
def on_close(ws, status_code, reason):
|
||||
print("")
|
||||
|
||||
# 收到websocket连接建立的处理
|
||||
def on_open(ws):
|
||||
thread.start_new_thread(run, (ws,))
|
||||
|
||||
def run(ws, *args):
|
||||
data = json.dumps(gen_params(appid=ws.appid, question=ws.question))
|
||||
ws.send(data)
|
||||
|
||||
# 收到websocket消息的处理
|
||||
def on_message(ws, message):
|
||||
# print(message)
|
||||
data = json.loads(message)
|
||||
code = data['header']['code']
|
||||
if code != 0:
|
||||
print(f'请求错误: {code}, {data}')
|
||||
ws.close()
|
||||
else:
|
||||
choices = data["payload"]["choices"]
|
||||
status = choices["status"]
|
||||
content = choices["text"][0]["content"]
|
||||
print(content, end='')
|
||||
if status == 2:
|
||||
ws.close()
|
||||
|
||||
def gen_params(appid, question):
|
||||
"""
|
||||
通过appid和用户的提问来生成请参数
|
||||
"""
|
||||
data = {
|
||||
"header": {
|
||||
"app_id": appid,
|
||||
"uid": "1234"
|
||||
},
|
||||
"parameter": {
|
||||
"chat": {
|
||||
"domain": "general",
|
||||
"random_threshold": 0.5,
|
||||
"max_tokens": 4096,
|
||||
"auditing": "default"
|
||||
}
|
||||
},
|
||||
"payload": {
|
||||
"message": {
|
||||
"text": [
|
||||
{"role": "user", "content": question}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
|
||||
def main(appid, api_key, api_secret, gpt_url, question):
|
||||
wsParam = Ws_Param(appid, api_key, api_secret, gpt_url)
|
||||
websocket.enableTrace(False)
|
||||
wsUrl = wsParam.create_url()
|
||||
|
||||
ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open)
|
||||
ws.appid = appid
|
||||
ws.question = question
|
||||
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
|
||||
|
||||
print("end")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试时候在此处正确填写相关信息即可运行
|
||||
main(appid = "0c0a6c2f",
|
||||
api_secret = "Y2UwZjhiYTRhNDM1NjkwNzg3NmEzMTA3",
|
||||
api_key = "42e836c7c40e1ff9dacac9de6b689bb1",
|
||||
gpt_url = "ws://spark-api.xf-yun.com/v3.5/chat",
|
||||
question = '帮我生成一份高三年级英语期中考试试卷,要求包括选择题、填空题、完形填空题、阅读理解题和写作题,每道题都有答案和解析。请直接输出试卷内容,不要输出其他信息。'
|
||||
)
|
||||
36
diagnose/upload_views.py
Normal file
36
diagnose/upload_views.py
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from authentication.authentication import CustomTokenAuthentication
|
||||
import uuid
|
||||
import os
|
||||
from django.conf import settings
|
||||
from django.http import JsonResponse
|
||||
from rest_framework import status
|
||||
|
||||
class MyProtectedUploadfile(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
uuid_str = str(uuid.uuid4())
|
||||
save_file_path = os.path.join(settings.BASE_DIR, 'upload_file', user.username, uuid_str)
|
||||
|
||||
os.makedirs(os.path.dirname(save_file_path), exist_ok=True)
|
||||
|
||||
# 获取上传的文件
|
||||
uploaded_file = request.FILES.get('file')
|
||||
if not uploaded_file:
|
||||
return JsonResponse({"error": "No file uploaded."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 保存文件
|
||||
try:
|
||||
with open(save_file_path, 'wb+') as destination:
|
||||
for chunk in uploaded_file.chunks():
|
||||
destination.write(chunk)
|
||||
except:
|
||||
return JsonResponse({"error": "Error saving file."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
return JsonResponse({"message": "File uploaded successfully."}, status=status.HTTP_200_OK)
|
||||
11
diagnose/urls.py
Normal file
11
diagnose/urls.py
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
from django.urls import path
|
||||
from .dp_views import MyProtectedGeneratePaper, MyProtectedGenerateCheck, MyProtectedDownloadPaper
|
||||
from .upload_views import MyProtectedUploadfile
|
||||
urlpatterns = [
|
||||
path('', MyProtectedGeneratePaper.as_view(), name='api_generate_paper'),
|
||||
path('check/', MyProtectedGenerateCheck.as_view(), name='api_generate_check'),
|
||||
path('download/', MyProtectedDownloadPaper.as_view(), name='api_download_paper'),
|
||||
|
||||
path('upload/', MyProtectedUploadfile.as_view(), name='api_upload_file')
|
||||
]
|
||||
0
ec_user/__init__.py
Normal file
0
ec_user/__init__.py
Normal file
66
ec_user/admin.py
Normal file
66
ec_user/admin.py
Normal file
@ -0,0 +1,66 @@
|
||||
from django.contrib import admin
|
||||
|
||||
|
||||
"""
|
||||
设置后台管理的全局参数
|
||||
"""
|
||||
|
||||
admin.site.site_header = '诊断应用后台'
|
||||
admin.site.site_title = '诊断服务端'
|
||||
admin.site.index_title = '诊断服务端'
|
||||
|
||||
"""
|
||||
设置后台管理的全局参数
|
||||
结束
|
||||
"""
|
||||
from django.urls import reverse
|
||||
from django.utils.html import format_html
|
||||
|
||||
# Register your models here.
|
||||
from . models import EcUser, Subject, SchoolInfo
|
||||
from django import forms
|
||||
|
||||
class UcUserInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = EcUser
|
||||
fields = '__all__'
|
||||
widgets = {
|
||||
'subjects': forms.CheckboxSelectMultiple, # 使用复选框小部件
|
||||
}
|
||||
|
||||
@admin.register(EcUser)
|
||||
class UcUserInfo(admin.ModelAdmin):
|
||||
# 在列表视图中显示哪些字段
|
||||
list_display = ('username','id', 'gender', 'dob', 'political_status', 'custom_link')
|
||||
|
||||
# 通过 fieldsets 分组字段并定义显示顺序
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('username', 'password') # 先显示用户名和密码
|
||||
}),
|
||||
('Personal Information', {
|
||||
'fields': ('name', 'gender', 'age', 'ethnicity', 'dob', 'id_card_number', 'political_status', 'subjects', 'subject_usage_count')
|
||||
}),
|
||||
)
|
||||
|
||||
# 还可以通过 'search_fields' 添加搜索功能
|
||||
search_fields = ('name', 'id_card_number')
|
||||
|
||||
# 可以设置过滤选项,方便后台管理
|
||||
list_filter = ('gender', 'political_status')
|
||||
|
||||
# 可选:设置只读字段
|
||||
# readonly_fields = ('id_card_number',) # 设置身份证号为只读字段
|
||||
form = UcUserInfoForm # 设置使用自定义表单
|
||||
|
||||
def custom_link(self, obj):
|
||||
# 为每个用户添加自定义链接
|
||||
url = reverse('all_info_form', args=[obj.pk]) # 生成链接
|
||||
return format_html('<a href="{}">查看</a>', url) # 创建 HTML 链接
|
||||
|
||||
custom_link.short_description = '详细信息' # 设置列标题
|
||||
|
||||
|
||||
|
||||
admin.site.register(Subject)
|
||||
admin.site.register(SchoolInfo)
|
||||
6
ec_user/apps.py
Normal file
6
ec_user/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class EcUserConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'ec_user'
|
||||
88
ec_user/forms.py
Normal file
88
ec_user/forms.py
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
from django import forms
|
||||
from .models import EcUser, ContactInfo, SchoolInfo, AcademicInfo, HealthInfo, SelfEvaluation
|
||||
from .models import HobbiesInterests, SocialPractice, FamilyInfo, AwardsPunishments
|
||||
|
||||
class BaiscInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = EcUser
|
||||
fields = ['name', 'gender', 'age', 'ethnicity', 'dob', 'id_card_number', 'political_status']
|
||||
|
||||
class ContactInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ContactInfo
|
||||
fields = ['home_address', 'parent_contact', 'student_contact', 'email']
|
||||
|
||||
# SchoolInfo 表单
|
||||
class SchoolInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SchoolInfo
|
||||
fields = ['school_name', 'grade', 'class_name', 'admission_date', 'expected_graduation_date']
|
||||
|
||||
# AcademicInfo 表单
|
||||
class AcademicInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = AcademicInfo
|
||||
fields = ['last_semester_score', 'this_semester_score', 'class_ranking', 'strong_subject', 'weak_subject']
|
||||
|
||||
# HealthInfo 表单
|
||||
class HealthInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = HealthInfo
|
||||
fields = ['height', 'weight', 'blood_type', 'medical_history', 'disability_status', 'disability_category', 'disability_grade']
|
||||
|
||||
# SelfEvaluation 表单
|
||||
class SelfEvaluationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SelfEvaluation
|
||||
fields = ['strengths', 'weaknesses', 'study_attitude', 'future_plans']
|
||||
|
||||
# HobbiesInterests 表单
|
||||
class HobbiesInterestsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = HobbiesInterests
|
||||
fields = ['interests', 'extracurricular_activities']
|
||||
|
||||
# SocialPractice 表单
|
||||
class SocialPracticeForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SocialPractice
|
||||
fields = ['activity_name', 'activity_date', 'activity_location', 'activity_description', 'activity_outcome']
|
||||
|
||||
# FamilyInfo 表单
|
||||
class FamilyInfoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = FamilyInfo
|
||||
fields = ['family_member', 'economic_status']
|
||||
|
||||
# AwardsPunishments 表单
|
||||
class AwardsPunishmentsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = AwardsPunishments
|
||||
fields = ['award_name', 'award_date', 'award_organization', 'discipline_date', 'discipline_issue', 'discipline_outcome']
|
||||
|
||||
|
||||
# 获取或创建各个信息模型实例
|
||||
g_models = {
|
||||
'contact_info': ContactInfo,
|
||||
'school_info': SchoolInfo,
|
||||
'academic_info': AcademicInfo,
|
||||
'health_info': HealthInfo,
|
||||
'self_evaluation': SelfEvaluation,
|
||||
'hobbies_interests': HobbiesInterests,
|
||||
'social_practice': SocialPractice,
|
||||
'family_info': FamilyInfo,
|
||||
'awards_punishments': AwardsPunishments
|
||||
}
|
||||
|
||||
g_form_classes = {
|
||||
'contact_info_form': ContactInfoForm,
|
||||
'school_info_form': SchoolInfoForm,
|
||||
'academic_info_form': AcademicInfoForm,
|
||||
'health_info_form': HealthInfoForm,
|
||||
'self_evaluation_form': SelfEvaluationForm,
|
||||
'hobbies_interests_form': HobbiesInterestsForm,
|
||||
'social_practice_form': SocialPracticeForm,
|
||||
'family_info_form': FamilyInfoForm,
|
||||
'awards_punishments_form': AwardsPunishmentsForm
|
||||
}
|
||||
155
ec_user/migrations/0001_initial.py
Normal file
155
ec_user/migrations/0001_initial.py
Normal file
@ -0,0 +1,155 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 02:55
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EcUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female'), ('O', 'Other')], default='M', max_length=1)),
|
||||
('ethnicity', models.CharField(default='Unknown', max_length=50)),
|
||||
('dob', models.DateField(blank=True, null=True)),
|
||||
('id_card_number', models.CharField(max_length=18, unique=True)),
|
||||
('political_status', models.CharField(default='Unknown', max_length=50)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SocialPractice',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('activity_name', models.CharField(max_length=100)),
|
||||
('activity_date', models.DateField()),
|
||||
('activity_location', models.CharField(max_length=255)),
|
||||
('activity_description', models.TextField()),
|
||||
('activity_outcome', models.TextField()),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SelfEvaluation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('strengths', models.TextField()),
|
||||
('weaknesses', models.TextField()),
|
||||
('study_attitude', models.TextField()),
|
||||
('future_plans', models.TextField()),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SchoolInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('school_name', models.CharField(max_length=255)),
|
||||
('grade', models.CharField(max_length=50)),
|
||||
('class_name', models.CharField(max_length=50)),
|
||||
('admission_date', models.DateField()),
|
||||
('expected_graduation_date', models.DateField()),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HobbiesInterests',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('interests', models.TextField()),
|
||||
('extracurricular_activities', models.TextField()),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HealthInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('height', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('weight', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('blood_type', models.CharField(max_length=3)),
|
||||
('medical_history', models.TextField(blank=True, null=True)),
|
||||
('disability_status', models.BooleanField()),
|
||||
('disability_category', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('disability_grade', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FamilyInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('family_member', models.JSONField()),
|
||||
('economic_status', models.CharField(max_length=50)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ContactInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('home_address', models.CharField(max_length=255)),
|
||||
('parent_contact', models.CharField(max_length=15)),
|
||||
('student_contact', models.CharField(max_length=15)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AwardsPunishments',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('award_name', models.CharField(max_length=100)),
|
||||
('award_date', models.DateField()),
|
||||
('award_organization', models.CharField(max_length=100)),
|
||||
('discipline_date', models.DateField(blank=True, null=True)),
|
||||
('discipline_issue', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('discipline_outcome', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AcademicInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('last_semester_score', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('this_semester_score', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('class_ranking', models.IntegerField()),
|
||||
('strong_subject', models.CharField(max_length=50)),
|
||||
('weak_subject', models.CharField(max_length=50)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
20
ec_user/migrations/0002_alter_socialpractice_user.py
Normal file
20
ec_user/migrations/0002_alter_socialpractice_user.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 03:28
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='socialpractice',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,40 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 04:22
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0002_alter_socialpractice_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='awardspunishments',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='familyinfo',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='hobbiesinterests',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schoolinfo',
|
||||
name='admission_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schoolinfo',
|
||||
name='expected_graduation_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 04:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0003_alter_awardspunishments_user_alter_familyinfo_user_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='academicinfo',
|
||||
name='last_semester_score',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='academicinfo',
|
||||
name='this_semester_score',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True),
|
||||
),
|
||||
]
|
||||
18
ec_user/migrations/0005_alter_academicinfo_class_ranking.py
Normal file
18
ec_user/migrations/0005_alter_academicinfo_class_ranking.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 04:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0004_alter_academicinfo_last_semester_score_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='academicinfo',
|
||||
name='class_ranking',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 04:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0005_alter_academicinfo_class_ranking'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='healthinfo',
|
||||
name='height',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='healthinfo',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 04:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0006_alter_healthinfo_height_alter_healthinfo_weight'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='healthinfo',
|
||||
name='disability_status',
|
||||
field=models.BooleanField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
18
ec_user/migrations/0008_alter_familyinfo_family_member.py
Normal file
18
ec_user/migrations/0008_alter_familyinfo_family_member.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 05:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0007_alter_healthinfo_disability_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='familyinfo',
|
||||
name='family_member',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-25 14:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0008_alter_familyinfo_family_member'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='academicinfo',
|
||||
name='last_semester_score',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='academicinfo',
|
||||
name='this_semester_score',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
25
ec_user/migrations/0010_subject_ecuser_subjects.py
Normal file
25
ec_user/migrations/0010_subject_ecuser_subjects.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-26 03:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0009_alter_academicinfo_last_semester_score_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Subject',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ecuser',
|
||||
name='subjects',
|
||||
field=models.ManyToManyField(blank=True, related_name='users', to='ec_user.subject'),
|
||||
),
|
||||
]
|
||||
18
ec_user/migrations/0011_ecuser_subject_usage_count.py
Normal file
18
ec_user/migrations/0011_ecuser_subject_usage_count.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-26 04:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0010_subject_ecuser_subjects'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ecuser',
|
||||
name='subject_usage_count',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
]
|
||||
18
ec_user/migrations/0012_ecuser_age.py
Normal file
18
ec_user/migrations/0012_ecuser_age.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.19 on 2025-02-27 11:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ec_user', '0011_ecuser_subject_usage_count'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ecuser',
|
||||
name='age',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
0
ec_user/migrations/__init__.py
Normal file
0
ec_user/migrations/__init__.py
Normal file
244
ec_user/models.py
Normal file
244
ec_user/models.py
Normal file
@ -0,0 +1,244 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
|
||||
"""
|
||||
1. UserProfile(用户扩展信息表)继承AbstractUser
|
||||
name: 姓名
|
||||
gender: 性别
|
||||
ethnicity: 民族
|
||||
dob: 出生日期
|
||||
id_card_number: 身份证号码
|
||||
political_status: 政治面貌
|
||||
|
||||
2. ContactInfo(联系方式表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
home_address: 家庭住址
|
||||
parent_contact: 家长联系电话
|
||||
student_contact: 本人联系电话
|
||||
email: 电子邮箱
|
||||
|
||||
3. SchoolInfo(就读信息表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
school_name: 学校名称
|
||||
grade: 年级
|
||||
class: 班级
|
||||
admission_date: 入学时间
|
||||
expected_graduation_date: 预计毕业时间
|
||||
|
||||
4. AcademicInfo(学习情况表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
last_semester_score: 上学期期末成绩
|
||||
this_semester_score: 本学期期中成绩
|
||||
class_ranking: 班级排名
|
||||
strong_subject: 特长学科
|
||||
weak_subject: 薄弱学科
|
||||
|
||||
5. FamilyInfo(家庭情况表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
family_member: 家庭成员信息(可以是多个外键或 JSON 字段来存储)
|
||||
economic_status: 家庭经济状况(是否低保、是否建档立卡等)
|
||||
|
||||
6. AwardsPunishments(奖惩情况表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
award_name: 奖项名称
|
||||
award_date: 奖项颁发时间
|
||||
award_organization: 奖项颁发单位
|
||||
discipline_date: 违纪时间
|
||||
discipline_issue: 违纪事由
|
||||
discipline_outcome: 处理结果
|
||||
|
||||
7. HealthInfo(健康状况表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
height: 身高
|
||||
weight: 体重
|
||||
blood_type: 血型
|
||||
medical_history: 既往病史(重大疾病、过敏史等)
|
||||
disability_status: 是否残疾
|
||||
disability_category: 残疾类别
|
||||
disability_grade: 残疾等级
|
||||
|
||||
8. HobbiesInterests(兴趣爱好表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
interests: 兴趣爱好(如阅读、绘画等)
|
||||
extracurricular_activities: 参加的社团或课外兴趣班
|
||||
|
||||
9. SocialPractice(社会实践表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
activity_name: 活动名称
|
||||
activity_date: 活动时间
|
||||
activity_location: 活动地点
|
||||
activity_description: 活动内容
|
||||
activity_outcome: 活动收获
|
||||
|
||||
10. SelfEvaluation(自我评价表)
|
||||
user: 外键关联到 UserProfile 表。
|
||||
strengths: 优点
|
||||
weaknesses: 不足
|
||||
study_attitude: 学习态度
|
||||
future_plans: 未来规划
|
||||
"""
|
||||
|
||||
|
||||
class Subject(models.Model):
|
||||
name = models.CharField(max_length=100) # 科目名称
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
# EcUser(用户表)
|
||||
class EcUser(AbstractUser):
|
||||
GENDER_CHOICES = [
|
||||
('M', 'Male'),
|
||||
('F', 'Female'),
|
||||
('O', 'Other'),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=100)
|
||||
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='M') # 默认值设置为'M'
|
||||
age = models.IntegerField(null=True, blank=True) # 允许为空,可以为null
|
||||
ethnicity = models.CharField(max_length=50, default='Unknown') # 默认值设置为'Unknown'
|
||||
dob = models.DateField(null=True, blank=True) # 允许为空,可以为null
|
||||
id_card_number = models.CharField(max_length=18, unique=True)
|
||||
political_status = models.CharField(max_length=50, default='Unknown') # 默认值设置为'Unknown'
|
||||
|
||||
# 多选字段:开放权限的科目
|
||||
subjects = models.ManyToManyField(Subject, related_name='users', blank=True) # 允许为空,表示可以选择多个科目
|
||||
# 使用次数限制
|
||||
subject_usage_count = models.IntegerField(default=0)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
# ContactInfo(联系方式表)
|
||||
class ContactInfo(models.Model):
|
||||
user = models.OneToOneField(EcUser, on_delete=models.CASCADE)
|
||||
home_address = models.CharField(max_length=255)
|
||||
parent_contact = models.CharField(max_length=15)
|
||||
student_contact = models.CharField(max_length=15)
|
||||
email = models.EmailField()
|
||||
|
||||
def __str__(self):
|
||||
return f"Contact Info of {self.user.name}"
|
||||
|
||||
# SchoolInfo(就读信息表)
|
||||
class SchoolInfo(models.Model):
|
||||
user = models.OneToOneField(EcUser, on_delete=models.CASCADE)
|
||||
school_name = models.CharField(max_length=255)
|
||||
grade = models.CharField(max_length=50)
|
||||
class_name = models.CharField(max_length=50) # Changed 'class' to 'class_name' to avoid conflict
|
||||
admission_date = models.DateField(null=True, blank=True)
|
||||
expected_graduation_date = models.DateField(null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"School Info of {self.user.name}"
|
||||
|
||||
# AcademicInfo(学习情况表)
|
||||
class AcademicInfo(models.Model):
|
||||
user = models.OneToOneField(EcUser, on_delete=models.CASCADE)
|
||||
# last_semester_score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
|
||||
# this_semester_score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
|
||||
last_semester_score = models.JSONField(null=True, blank=True)
|
||||
this_semester_score = models.JSONField(null=True, blank=True)
|
||||
|
||||
class_ranking = models.IntegerField(null=True, blank=True)
|
||||
strong_subject = models.CharField(max_length=50)
|
||||
weak_subject = models.CharField(max_length=50)
|
||||
|
||||
def __str__(self):
|
||||
return f"Academic Info of {self.user.name}"
|
||||
|
||||
# HealthInfo(健康状况表)
|
||||
class HealthInfo(models.Model):
|
||||
user = models.OneToOneField(EcUser, on_delete=models.CASCADE)
|
||||
height = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
|
||||
weight = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
|
||||
blood_type = models.CharField(max_length=3)
|
||||
medical_history = models.TextField(null=True, blank=True)
|
||||
disability_status = models.BooleanField(null=True, blank=True)
|
||||
disability_category = models.CharField(max_length=50, null=True, blank=True)
|
||||
disability_grade = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"Health Info of {self.user.name}"
|
||||
|
||||
# SelfEvaluation(自我评价表)
|
||||
class SelfEvaluation(models.Model):
|
||||
user = models.OneToOneField(EcUser, on_delete=models.CASCADE)
|
||||
strengths = models.TextField()
|
||||
weaknesses = models.TextField()
|
||||
study_attitude = models.TextField()
|
||||
future_plans = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return f"Self Evaluation of {self.user.name}"
|
||||
|
||||
|
||||
|
||||
# HobbiesInterests(兴趣爱好表)
|
||||
class HobbiesInterests(models.Model):
|
||||
# 定义一个与EcUser一对多关联的外键
|
||||
user = models.ForeignKey(EcUser, on_delete=models.CASCADE)
|
||||
# 定义一个文本字段,用于存储用户的兴趣爱好
|
||||
interests = models.TextField()
|
||||
# 定义一个文本字段,用于存储用户的课外活动
|
||||
extracurricular_activities = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
# 返回用户的名字和兴趣爱好
|
||||
return f"Hobbies and Interests of {self.user.name}"
|
||||
|
||||
# SocialPractice(社会实践表)
|
||||
class SocialPractice(models.Model):
|
||||
# 定义一个与EcUser一对多关联的外键
|
||||
user = models.ForeignKey(EcUser, on_delete=models.CASCADE)
|
||||
# 定义一个活动名称的字符型字段,最大长度为100
|
||||
activity_name = models.CharField(max_length=100)
|
||||
# 定义一个活动日期的日期型字段
|
||||
activity_date = models.DateField()
|
||||
# 定义一个活动地点的字符型字段,最大长度为255
|
||||
activity_location = models.CharField(max_length=255)
|
||||
# 定义一个活动描述的文本型字段
|
||||
activity_description = models.TextField()
|
||||
# 定义一个活动结果的文本型字段
|
||||
activity_outcome = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
# 返回一个字符串,表示该社交实践的用户名称
|
||||
return f"Social Practice of {self.user.name}"
|
||||
|
||||
# FamilyInfo(家庭情况表)
|
||||
class FamilyInfo(models.Model):
|
||||
# 定义一个与EcUser一对多关联的外键
|
||||
user = models.ForeignKey(EcUser, on_delete=models.CASCADE)
|
||||
family_member = models.JSONField(null=True, blank=True) # Store family member info as JSON or use a related model for complex relationships
|
||||
economic_status = models.CharField(max_length=50)
|
||||
|
||||
def __str__(self):
|
||||
x = {
|
||||
"members": [
|
||||
{"relationship": "Father", "name": "John", "age": 45, "occupation": "Engineer"},
|
||||
{"relationship": "Mother", "name": "Jane", "age": 43, "occupation": "Doctor"},
|
||||
{"relationship": "Brother", "name": "Mike", "age": 20, "occupation": "Student"}
|
||||
]
|
||||
}
|
||||
return f"Family Info of {self.user.name}"
|
||||
|
||||
# AwardsPunishments(奖惩情况表)
|
||||
class AwardsPunishments(models.Model):
|
||||
# 定义一个与EcUser一对多关联的外键
|
||||
user = models.ForeignKey(EcUser, on_delete=models.CASCADE)
|
||||
award_name = models.CharField(max_length=100)
|
||||
award_date = models.DateField()
|
||||
award_organization = models.CharField(max_length=100)
|
||||
discipline_date = models.DateField(null=True, blank=True)
|
||||
discipline_issue = models.CharField(max_length=255, null=True, blank=True)
|
||||
discipline_outcome = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"Awards and Punishments of {self.user.name}"
|
||||
296
ec_user/templates/all_info_form.html
Normal file
296
ec_user/templates/all_info_form.html
Normal file
@ -0,0 +1,296 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>All Information Form</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0-alpha1/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f4f4f9;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.container {
|
||||
max-width: 900px;
|
||||
}
|
||||
.form-section {
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-section h4 {
|
||||
font-size: 1.25rem;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-section .border {
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.form-section .mb-3 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.form-section .form-control {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.btn-submit {
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 30px;
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
.btn-submit:hover {
|
||||
background-color: #0056b3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.empty-message {
|
||||
color: #888;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.alert {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* 优化 textarea 的样式 */
|
||||
textarea {
|
||||
height: 150px; /* 设置合适的高度 */
|
||||
resize: vertical; /* 只允许垂直调整大小 */
|
||||
padding: 10px; /* 设置内边距,增加可读性 */
|
||||
}
|
||||
|
||||
/* 如果 textarea 太长,可以设置最大高度 */
|
||||
textarea {
|
||||
width: 100%; /* 设置最大高度,避免过高 */
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% extends 'admin/base_site.html' %}
|
||||
<!-- {% block title %}
|
||||
{{ admin_site.site_title }} - {{ user.username }}'s Profile
|
||||
{% endblock %} -->
|
||||
|
||||
{% block branding %}
|
||||
<h1 id="site-name"><a href="{% url 'admin:index' %}">诊断应用后台</a></h1>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="container mt-5">
|
||||
<h2 class="text-center mb-4">填写信息 - {{ user.name }}</h2>
|
||||
|
||||
<form method="POST">
|
||||
<!-- 联系方式 -->
|
||||
<div class="form-section">
|
||||
<h4>联系方式</h4>
|
||||
{{ contact_info_form.as_p }}
|
||||
</div>
|
||||
|
||||
<!-- 就读信息 -->
|
||||
<div class="form-section">
|
||||
<h4>就读信息</h4>
|
||||
{{ school_info_form.as_p }}
|
||||
</div>
|
||||
|
||||
<!-- 学习情况 -->
|
||||
<div class="form-section">
|
||||
<h4>学习情况</h4>
|
||||
<div id="gradeForm" style="border: 1px solid #ccc; padding: 10px;">
|
||||
<div class="form-group">
|
||||
<label for="subject1">语文</label>
|
||||
<input type="text" id="subject1" name="subject1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject2">数学</label>
|
||||
<input type="text" id="subject2" name="subject2">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject3">英语</label>
|
||||
<input type="text" id="subject3" name="subject3">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject4">物理</label>
|
||||
<input type="text" id="subject4" name="subject4">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject5">化学</label>
|
||||
<input type="text" id="subject5" name="subject5">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject6">生物</label>
|
||||
<input type="text" id="subject6" name="subject6">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject7">历史</label>
|
||||
<input type="text" id="subject7" name="subject7">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject8">地理</label>
|
||||
<input type="text" id="subject8" name="subject8">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject9">政治</label>
|
||||
<input type="text" id="subject9" name="subject9">
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px;">
|
||||
<div id="grades_parse_result">生成json字符串:{}</div>
|
||||
<button type="button" id="parseGrades" class="btn btn-primary">解析成绩</button>
|
||||
|
||||
<div>
|
||||
<label for="json_encoded_grades">输入json字符串</label>
|
||||
<input type="text" id="json_encoded_grades" name="json_encoded_grades">
|
||||
</div>
|
||||
<button type="button" id="showGrades" class="btn btn-primary">展示成绩</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('parseGrades').addEventListener('click', function(event) {
|
||||
// 获取所有科目的成绩输入框
|
||||
const subjects = ['subject1', 'subject2', 'subject3', 'subject4', 'subject5', 'subject6', 'subject7', 'subject8', 'subject9']
|
||||
let grades = {}
|
||||
let atLeastOneFilled = false
|
||||
// 获取每个科目的成绩,检查是否有至少一项成绩填写
|
||||
subjects.forEach(subject => {
|
||||
const grade = document.getElementById(subject).value.trim()
|
||||
if (grade) {
|
||||
grades[subject] = grade
|
||||
atLeastOneFilled = true
|
||||
}
|
||||
});
|
||||
// 检查是否至少填写了一项成绩
|
||||
if (!atLeastOneFilled) {
|
||||
alert("至少填写一门成绩!")
|
||||
return
|
||||
}
|
||||
// 将成绩数据转换为 JSON 格式
|
||||
const jsonGrades = JSON.stringify(grades)
|
||||
// 发送数据到后台(你可以修改为你自己的后台 API)
|
||||
console.log("成绩数据:", jsonGrades)
|
||||
document.getElementById('grades_parse_result').innerHTML = `生成json字符串:${jsonGrades}`
|
||||
navigator.clipboard.writeText(jsonGrades).then(function() {
|
||||
alert("文本已复制到剪贴板!");
|
||||
}).catch(function(err) {
|
||||
alert("复制失败: " + err);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('showGrades').addEventListener('click', function(event) {
|
||||
// 获取 JSON 格式的成绩数据
|
||||
const jsonGrades = document.getElementById('json_encoded_grades').value.trim()
|
||||
if (!jsonGrades) {
|
||||
alert("请输入 JSON 格式的成绩数据!")
|
||||
return
|
||||
}
|
||||
// 解析 JSON 数据
|
||||
const grades = JSON.parse(jsonGrades)
|
||||
const subjects = ['subject1', 'subject2', 'subject3', 'subject4', 'subject5', 'subject6', 'subject7', 'subject8', 'subject9']
|
||||
// 遍历每个科目,填充相应的成绩
|
||||
subjects.forEach(subject => {
|
||||
if (grades[subject]) {
|
||||
document.getElementById(subject).value = grades[subject] // 填充成绩数据
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
{{ academic_info_form.as_p }}
|
||||
</div>
|
||||
|
||||
<!-- 健康状况 -->
|
||||
<div class="form-section">
|
||||
<h4>健康状况</h4>
|
||||
{{ health_info_form.as_p }}
|
||||
</div>
|
||||
|
||||
<!-- 自我评价 -->
|
||||
<div class="form-section">
|
||||
<h4>自我评价</h4>
|
||||
{{ self_evaluation_form.as_p }}
|
||||
</div>
|
||||
<button type="submit" class="btn-submit">提交</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="/ec_user/all_info_edit/{{ user.id }}/hobbies_interests/">
|
||||
<!-- 兴趣爱好 -->
|
||||
<div class="form-section">
|
||||
<h4>兴趣爱好</h4>
|
||||
{{ hobbies_interests_form.management_form }} <!-- 管理表单 -->
|
||||
{% for form in hobbies_interests_form %}
|
||||
<div class="border p-3 mb-3">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="empty-message">没有兴趣爱好信息。</p>
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="/ec_user/all_info_edit/{{ user.id }}/social_practice/">
|
||||
<!-- 社会实践 -->
|
||||
<div class="form-section">
|
||||
<h4>社会实践</h4>
|
||||
{{ social_practice_form.management_form }}
|
||||
{% for form in social_practice_form %}
|
||||
<div class="border p-3 mb-3">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="empty-message">没有社会实践记录。</p>
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="/ec_user/all_info_edit/{{ user.id }}/family_info/">
|
||||
<!-- 家庭情况 -->
|
||||
<div class="form-section">
|
||||
<h4>家庭情况</h4>
|
||||
{{ family_info_form.management_form }}
|
||||
{% for form in family_info_form %}
|
||||
<div class="border p-3 mb-3">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="empty-message">没有家庭情况记录。</p>
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="/ec_user/all_info_edit/{{ user.id }}/awards_punishments/" >
|
||||
<!-- 奖惩情况 -->
|
||||
<div class="form-section">
|
||||
<h4>奖惩情况</h4>
|
||||
{{ awards_punishments_form.management_form }}
|
||||
{% for form in awards_punishments_form %}
|
||||
<div class="border p-3 mb-3">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="empty-message">没有奖惩情况记录。</p>
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0-alpha1/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
9
ec_user/templates/all_info_result.html
Normal file
9
ec_user/templates/all_info_result.html
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
<p>
|
||||
注意管理员实际不应直接修改用户数据
|
||||
</p>
|
||||
<p>
|
||||
对id为 {{ user.id }} 的用户进行了修改。
|
||||
{{ formset.errors }}
|
||||
修改了 {{ model_name }} 的信息。
|
||||
</p>
|
||||
129
ec_user/templates/api_academic_info_test.html
Normal file
129
ec_user/templates/api_academic_info_test.html
Normal file
@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Academic Info API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Academic Info API</h2>
|
||||
|
||||
<h3>Get Academic Info</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getAcademicInfo()">Get Academic Info</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Academic Info</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="last_semester_score">Last Semester Score:</label>
|
||||
<input type="number" id="last_semester_score" placeholder="Enter last semester score" step="0.01">
|
||||
<br><br>
|
||||
<label for="this_semester_score">This Semester Score:</label>
|
||||
<input type="number" id="this_semester_score" placeholder="Enter this semester score" step="0.01">
|
||||
<br><br>
|
||||
<label for="class_ranking">Class Ranking:</label>
|
||||
<input type="number" id="class_ranking" placeholder="Enter class ranking">
|
||||
<br><br>
|
||||
<label for="strong_subject">Strong Subject:</label>
|
||||
<input type="text" id="strong_subject" placeholder="Enter strong subject">
|
||||
<br><br>
|
||||
<label for="weak_subject">Weak Subject:</label>
|
||||
<input type="text" id="weak_subject" placeholder="Enter weak subject">
|
||||
<br><br>
|
||||
<button onclick="updateAcademicInfo()">Update Academic Info</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get academic info via GET request
|
||||
function getAcademicInfo() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/academic_info/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `Last Semester Score: ${data.last_semester_score}, This Semester Score: ${data.this_semester_score}, Class Ranking: ${data.class_ranking}, Strong Subject: ${data.strong_subject}, Weak Subject: ${data.weak_subject}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update academic info via POST request
|
||||
function updateAcademicInfo() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const lastSemesterScore = document.getElementById('last_semester_score').value;
|
||||
const thisSemesterScore = document.getElementById('this_semester_score').value;
|
||||
const classRanking = document.getElementById('class_ranking').value;
|
||||
const strongSubject = document.getElementById('strong_subject').value;
|
||||
const weakSubject = document.getElementById('weak_subject').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !lastSemesterScore || !thisSemesterScore || !classRanking || !strongSubject || !weakSubject) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
last_semester_score: lastSemesterScore,
|
||||
this_semester_score: thisSemesterScore,
|
||||
class_ranking: classRanking,
|
||||
strong_subject: strongSubject,
|
||||
weak_subject: weakSubject
|
||||
};
|
||||
|
||||
fetch(`/ec_user/academic_info/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
134
ec_user/templates/api_awards_punishments_test.html
Normal file
134
ec_user/templates/api_awards_punishments_test.html
Normal file
@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Awards and Punishments API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Awards and Punishments API</h2>
|
||||
|
||||
<h3>Get Awards and Punishments</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getAwardsPunishments()">Get Awards and Punishments</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Awards and Punishments</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="award_name">Award Name:</label>
|
||||
<input type="text" id="award_name" placeholder="Enter award name">
|
||||
<br><br>
|
||||
<label for="award_date">Award Date:</label>
|
||||
<input type="date" id="award_date">
|
||||
<br><br>
|
||||
<label for="award_organization">Award Organization:</label>
|
||||
<input type="text" id="award_organization" placeholder="Enter award organization">
|
||||
<br><br>
|
||||
<label for="discipline_date">Discipline Date (optional):</label>
|
||||
<input type="date" id="discipline_date">
|
||||
<br><br>
|
||||
<label for="discipline_issue">Discipline Issue (optional):</label>
|
||||
<input type="text" id="discipline_issue" placeholder="Enter discipline issue">
|
||||
<br><br>
|
||||
<label for="discipline_outcome">Discipline Outcome (optional):</label>
|
||||
<input type="text" id="discipline_outcome" placeholder="Enter discipline outcome">
|
||||
<br><br>
|
||||
<button onclick="updateAwardsPunishments()">Update Awards and Punishments</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get awards and punishments via GET request
|
||||
function getAwardsPunishments() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/awards_punishments/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = JSON.stringify(data, null, 2);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update awards and punishments via POST request
|
||||
function updateAwardsPunishments() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const awardName = document.getElementById('award_name').value;
|
||||
const awardDate = document.getElementById('award_date').value;
|
||||
const awardOrganization = document.getElementById('award_organization').value;
|
||||
const disciplineDate = document.getElementById('discipline_date').value;
|
||||
const disciplineIssue = document.getElementById('discipline_issue').value;
|
||||
const disciplineOutcome = document.getElementById('discipline_outcome').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !awardName || !awardDate || !awardOrganization) {
|
||||
resultDiv.textContent = "Please fill out all required fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
award_name: awardName,
|
||||
award_date: awardDate,
|
||||
award_organization: awardOrganization,
|
||||
discipline_date: disciplineDate || null,
|
||||
discipline_issue: disciplineIssue || null,
|
||||
discipline_outcome: disciplineOutcome || null
|
||||
};
|
||||
|
||||
fetch(`/ec_user/awards_punishments/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
124
ec_user/templates/api_contact_info_test.html
Normal file
124
ec_user/templates/api_contact_info_test.html
Normal file
@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Contact Info API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Contact Info API</h2>
|
||||
|
||||
<h3>Get Contact Info</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getContactInfo()">Get Contact Info</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Contact Info</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="home_address">Home Address:</label>
|
||||
<input type="text" id="home_address" placeholder="Enter home address">
|
||||
<br><br>
|
||||
<label for="parent_contact">Parent Contact:</label>
|
||||
<input type="text" id="parent_contact" placeholder="Enter parent contact">
|
||||
<br><br>
|
||||
<label for="student_contact">Student Contact:</label>
|
||||
<input type="text" id="student_contact" placeholder="Enter student contact">
|
||||
<br><br>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" placeholder="Enter email">
|
||||
<br><br>
|
||||
<button onclick="updateContactInfo()">Update Contact Info</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get contact info via GET request
|
||||
function getContactInfo() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/contact_info/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `Home Address: ${data.home_address}, Parent Contact: ${data.parent_contact}, Student Contact: ${data.student_contact}, Email: ${data.email}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update contact info via POST request
|
||||
function updateContactInfo() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const homeAddress = document.getElementById('home_address').value;
|
||||
const parentContact = document.getElementById('parent_contact').value;
|
||||
const studentContact = document.getElementById('student_contact').value;
|
||||
const email = document.getElementById('email').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !homeAddress || !parentContact || !studentContact || !email) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
home_address: homeAddress,
|
||||
parent_contact: parentContact,
|
||||
student_contact: studentContact,
|
||||
email: email
|
||||
};
|
||||
|
||||
fetch(`/ec_user/contact_info/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
121
ec_user/templates/api_family_info_test.html
Normal file
121
ec_user/templates/api_family_info_test.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Family Info API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Family Info API</h2>
|
||||
|
||||
<h3>Get Family Info</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getFamilyInfo()">Get Family Info</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Family Info</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="family_member">Family Members (JSON format):</label>
|
||||
<textarea id="family_member" placeholder='Enter family member info as JSON (e.g., [{"name": "John", "relationship": "Father"}])'></textarea>
|
||||
<br><br>
|
||||
<label for="economic_status">Economic Status:</label>
|
||||
<input type="text" id="economic_status" placeholder="Enter economic status">
|
||||
<br><br>
|
||||
<button onclick="updateFamilyInfo()">Update Family Info</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get family info via GET request
|
||||
function getFamilyInfo() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/family_info/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `Family Members: ${JSON.stringify(data.family_member)}, Economic Status: ${data.economic_status}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update family info via POST request
|
||||
function updateFamilyInfo() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const familyMember = document.getElementById('family_member').value;
|
||||
const economicStatus = document.getElementById('economic_status').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !familyMember || !economicStatus) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Convert the family_member field to JSON
|
||||
const familyMemberJSON = JSON.parse(familyMember);
|
||||
|
||||
const postData = {
|
||||
family_member: familyMemberJSON,
|
||||
economic_status: economicStatus
|
||||
};
|
||||
|
||||
fetch(`/ec_user/family_info/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
} catch (error) {
|
||||
resultDiv.textContent = "Invalid JSON format for family members.";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
139
ec_user/templates/api_health_info_test.html
Normal file
139
ec_user/templates/api_health_info_test.html
Normal file
@ -0,0 +1,139 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Health Info API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Health Info API</h2>
|
||||
|
||||
<h3>Get Health Info</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getHealthInfo()">Get Health Info</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Health Info</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="height">Height:</label>
|
||||
<input type="number" id="height" placeholder="Enter height" step="0.01">
|
||||
<br><br>
|
||||
<label for="weight">Weight:</label>
|
||||
<input type="number" id="weight" placeholder="Enter weight" step="0.01">
|
||||
<br><br>
|
||||
<label for="blood_type">Blood Type:</label>
|
||||
<input type="text" id="blood_type" placeholder="Enter blood type">
|
||||
<br><br>
|
||||
<label for="medical_history">Medical History:</label>
|
||||
<textarea id="medical_history" placeholder="Enter medical history"></textarea>
|
||||
<br><br>
|
||||
<label for="disability_status">Disability Status:</label>
|
||||
<input type="checkbox" id="disability_status">
|
||||
<br><br>
|
||||
<label for="disability_category">Disability Category:</label>
|
||||
<input type="text" id="disability_category" placeholder="Enter disability category">
|
||||
<br><br>
|
||||
<label for="disability_grade">Disability Grade:</label>
|
||||
<input type="text" id="disability_grade" placeholder="Enter disability grade">
|
||||
<br><br>
|
||||
<button onclick="updateHealthInfo()">Update Health Info</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get health info via GET request
|
||||
function getHealthInfo() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/health_info/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `Height: ${data.height}, Weight: ${data.weight}, Blood Type: ${data.blood_type}, Medical History: ${data.medical_history}, Disability Status: ${data.disability_status}, Disability Category: ${data.disability_category}, Disability Grade: ${data.disability_grade}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update health info via POST request
|
||||
function updateHealthInfo() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const height = document.getElementById('height').value;
|
||||
const weight = document.getElementById('weight').value;
|
||||
const bloodType = document.getElementById('blood_type').value;
|
||||
const medicalHistory = document.getElementById('medical_history').value;
|
||||
const disabilityStatus = document.getElementById('disability_status').checked;
|
||||
const disabilityCategory = document.getElementById('disability_category').value;
|
||||
const disabilityGrade = document.getElementById('disability_grade').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !height || !weight || !bloodType) {
|
||||
resultDiv.textContent = "Please fill out all required fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
height: height,
|
||||
weight: weight,
|
||||
blood_type: bloodType,
|
||||
medical_history: medicalHistory,
|
||||
disability_status: disabilityStatus,
|
||||
disability_category: disabilityCategory,
|
||||
disability_grade: disabilityGrade
|
||||
};
|
||||
|
||||
fetch(`/ec_user/health_info/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
118
ec_user/templates/api_hobbies_interests_test.html
Normal file
118
ec_user/templates/api_hobbies_interests_test.html
Normal file
@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Hobbies and Interests API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Hobbies and Interests API</h2>
|
||||
|
||||
<h3>Get Hobbies and Interests</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getHobbiesInterests()">Get Hobbies and Interests</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Add Hobbies and Interests</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="interests">Interests:</label>
|
||||
<textarea id="interests" placeholder="Enter interests"></textarea>
|
||||
<br><br>
|
||||
<label for="extracurricular_activities">Extracurricular Activities:</label>
|
||||
<textarea id="extracurricular_activities" placeholder="Enter extracurricular activities"></textarea>
|
||||
<br><br>
|
||||
<button onclick="addHobbiesInterests()">Add Hobbies and Interests</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get hobbies and interests via GET request
|
||||
function getHobbiesInterests() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/hobbies_interests/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
let resultText = '';
|
||||
data.forEach(entry => {
|
||||
resultText += `Interests: ${entry.interests}, Extracurricular Activities: ${entry.extracurricular_activities}<br>`;
|
||||
});
|
||||
resultDiv.innerHTML = resultText;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to add hobbies and interests via POST request
|
||||
function addHobbiesInterests() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const interests = document.getElementById('interests').value;
|
||||
const extracurricularActivities = document.getElementById('extracurricular_activities').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !interests || !extracurricularActivities) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
interests: interests,
|
||||
extracurricular_activities: extracurricularActivities
|
||||
};
|
||||
|
||||
fetch(`/ec_user/hobbies_interests/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
129
ec_user/templates/api_school_info_test.html
Normal file
129
ec_user/templates/api_school_info_test.html
Normal file
@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test School Info API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test School Info API</h2>
|
||||
|
||||
<h3>Get School Info</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getSchoolInfo()">Get School Info</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update School Info</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="school_name">School Name:</label>
|
||||
<input type="text" id="school_name" placeholder="Enter school name">
|
||||
<br><br>
|
||||
<label for="grade">Grade:</label>
|
||||
<input type="text" id="grade" placeholder="Enter grade">
|
||||
<br><br>
|
||||
<label for="class_name">Class Name:</label>
|
||||
<input type="text" id="class_name" placeholder="Enter class name">
|
||||
<br><br>
|
||||
<label for="admission_date">Admission Date:</label>
|
||||
<input type="date" id="admission_date">
|
||||
<br><br>
|
||||
<label for="expected_graduation_date">Expected Graduation Date:</label>
|
||||
<input type="date" id="expected_graduation_date">
|
||||
<br><br>
|
||||
<button onclick="updateSchoolInfo()">Update School Info</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get school info via GET request
|
||||
function getSchoolInfo() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/school_info/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `School Name: ${data.school_name}, Grade: ${data.grade}, Class Name: ${data.class_name}, Admission Date: ${data.admission_date}, Expected Graduation Date: ${data.expected_graduation_date}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update school info via POST request
|
||||
function updateSchoolInfo() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const schoolName = document.getElementById('school_name').value;
|
||||
const grade = document.getElementById('grade').value;
|
||||
const className = document.getElementById('class_name').value;
|
||||
const admissionDate = document.getElementById('admission_date').value;
|
||||
const expectedGraduationDate = document.getElementById('expected_graduation_date').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !schoolName || !grade || !className || !admissionDate || !expectedGraduationDate) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
school_name: schoolName,
|
||||
grade: grade,
|
||||
class_name: className,
|
||||
admission_date: admissionDate,
|
||||
expected_graduation_date: expectedGraduationDate
|
||||
};
|
||||
|
||||
fetch(`/ec_user/school_info/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
124
ec_user/templates/api_self_evaluation_test.html
Normal file
124
ec_user/templates/api_self_evaluation_test.html
Normal file
@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Self Evaluation API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Self Evaluation API</h2>
|
||||
|
||||
<h3>Get Self Evaluation</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getSelfEvaluation()">Get Self Evaluation</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Update Self Evaluation</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="strengths">Strengths:</label>
|
||||
<textarea id="strengths" placeholder="Enter your strengths"></textarea>
|
||||
<br><br>
|
||||
<label for="weaknesses">Weaknesses:</label>
|
||||
<textarea id="weaknesses" placeholder="Enter your weaknesses"></textarea>
|
||||
<br><br>
|
||||
<label for="study_attitude">Study Attitude:</label>
|
||||
<textarea id="study_attitude" placeholder="Enter your study attitude"></textarea>
|
||||
<br><br>
|
||||
<label for="future_plans">Future Plans:</label>
|
||||
<textarea id="future_plans" placeholder="Enter your future plans"></textarea>
|
||||
<br><br>
|
||||
<button onclick="updateSelfEvaluation()">Update Self Evaluation</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get self evaluation via GET request
|
||||
function getSelfEvaluation() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/self_evaluation/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = `Strengths: ${data.strengths}, Weaknesses: ${data.weaknesses}, Study Attitude: ${data.study_attitude}, Future Plans: ${data.future_plans}`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update self evaluation via POST request
|
||||
function updateSelfEvaluation() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const strengths = document.getElementById('strengths').value;
|
||||
const weaknesses = document.getElementById('weaknesses').value;
|
||||
const studyAttitude = document.getElementById('study_attitude').value;
|
||||
const futurePlans = document.getElementById('future_plans').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !strengths || !weaknesses || !studyAttitude || !futurePlans) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
strengths: strengths,
|
||||
weaknesses: weaknesses,
|
||||
study_attitude: studyAttitude,
|
||||
future_plans: futurePlans
|
||||
};
|
||||
|
||||
fetch(`/ec_user/self_evaluation/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
133
ec_user/templates/api_social_practice_test.html
Normal file
133
ec_user/templates/api_social_practice_test.html
Normal file
@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Test Social Practice API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Test Social Practice API</h2>
|
||||
|
||||
<h3>Get Social Practice Records</h3>
|
||||
<label for="user_id_get">User ID:</label>
|
||||
<input type="number" id="user_id_get" min="1" placeholder="Enter user ID">
|
||||
<button onclick="getSocialPractice()">Get Social Practice Records</button>
|
||||
|
||||
<div id="get-result" class="message"></div>
|
||||
|
||||
<h3>Add Social Practice Record</h3>
|
||||
<label for="user_id_post">User ID:</label>
|
||||
<input type="number" id="user_id_post" min="1" placeholder="Enter user ID">
|
||||
<br><br>
|
||||
<label for="activity_name">Activity Name:</label>
|
||||
<input type="text" id="activity_name" placeholder="Enter activity name">
|
||||
<br><br>
|
||||
<label for="activity_date">Activity Date:</label>
|
||||
<input type="date" id="activity_date">
|
||||
<br><br>
|
||||
<label for="activity_location">Activity Location:</label>
|
||||
<input type="text" id="activity_location" placeholder="Enter activity location">
|
||||
<br><br>
|
||||
<label for="activity_description">Activity Description:</label>
|
||||
<textarea id="activity_description" placeholder="Enter activity description"></textarea>
|
||||
<br><br>
|
||||
<label for="activity_outcome">Activity Outcome:</label>
|
||||
<textarea id="activity_outcome" placeholder="Enter activity outcome"></textarea>
|
||||
<br><br>
|
||||
<button onclick="addSocialPractice()">Add Social Practice Record</button>
|
||||
|
||||
<div id="post-result" class="message"></div>
|
||||
|
||||
<script>
|
||||
// Function to get social practice records via GET request
|
||||
function getSocialPractice() {
|
||||
const userId = document.getElementById('user_id_get').value;
|
||||
const resultDiv = document.getElementById('get-result');
|
||||
|
||||
if (!userId) {
|
||||
resultDiv.textContent = "Please enter a valid user ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/ec_user/social_practice/api/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
let resultText = '';
|
||||
data.forEach(entry => {
|
||||
resultText += `Activity Name: ${entry.activity_name}, Activity Date: ${entry.activity_date}, Location: ${entry.activity_location}, Description: ${entry.activity_description}, Outcome: ${entry.activity_outcome}<br><br>`;
|
||||
});
|
||||
resultDiv.innerHTML = resultText;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to add a social practice record via POST request
|
||||
function addSocialPractice() {
|
||||
const userId = document.getElementById('user_id_post').value;
|
||||
const activityName = document.getElementById('activity_name').value;
|
||||
const activityDate = document.getElementById('activity_date').value;
|
||||
const activityLocation = document.getElementById('activity_location').value;
|
||||
const activityDescription = document.getElementById('activity_description').value;
|
||||
const activityOutcome = document.getElementById('activity_outcome').value;
|
||||
const resultDiv = document.getElementById('post-result');
|
||||
|
||||
if (!userId || !activityName || !activityDate || !activityLocation || !activityDescription || !activityOutcome) {
|
||||
resultDiv.textContent = "Please fill out all fields.";
|
||||
return;
|
||||
}
|
||||
|
||||
const postData = {
|
||||
activity_name: activityName,
|
||||
activity_date: activityDate,
|
||||
activity_location: activityLocation,
|
||||
activity_description: activityDescription,
|
||||
activity_outcome: activityOutcome
|
||||
};
|
||||
|
||||
fetch(`/ec_user/social_practice/api/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'token': '486ef8198bb10ba6878eba95771c064ff64db81a'
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
resultDiv.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
resultDiv.textContent = data.message;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
resultDiv.textContent = `Error: ${error.message}`;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
12
ec_user/templates/index.html
Normal file
12
ec_user/templates/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
<a href="/ec_user/api_contact_info_test/"> 联系方式</a>
|
||||
<a href="/ec_user/api_school_info_test/"> 就读信息</a>
|
||||
<a href="/ec_user/api_academic_info_test/"> 学习情况</a>
|
||||
<a href="/ec_user/api_health_info_test/"> 健康状况</a>
|
||||
<a href="/ec_user/api_self_evaluation_test/"> 自我评价</a>
|
||||
<a href="/ec_user/api_hobbies_interests_test/"> 兴趣爱好</a>
|
||||
<a href="/ec_user/api_social_practice_test/"> 社会实践</a>
|
||||
<a href="/ec_user/api_family_info_test/"> 家庭状况</a>
|
||||
<a href="/ec_user/api_awards_punishments_test/"> 奖惩情况</a>
|
||||
<a href="/ec_user/all_info_form/1/"> 信息总览</a>
|
||||
56
ec_user/templates/testlogin.html
Normal file
56
ec_user/templates/testlogin.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login Test</title>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
<script>
|
||||
function hashPassword(password) {
|
||||
return CryptoJS.SHA256(password).toString();
|
||||
}
|
||||
function loginUser() {
|
||||
const username = document.getElementById('username').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
const data = {
|
||||
username: username,
|
||||
password: password
|
||||
};
|
||||
|
||||
fetch('/ec_user/login/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert('Error: ' + data.error);
|
||||
} else {
|
||||
alert('Success: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Login</h2>
|
||||
<form onsubmit="event.preventDefault(); loginUser();">
|
||||
<label for="username">Username:</label><br>
|
||||
<input type="text" id="username" name="username" required><br>
|
||||
<label for="password">Password:</label><br>
|
||||
<input type="password" id="password" name="password" required><br><br>
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
3
ec_user/tests.py
Normal file
3
ec_user/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
58
ec_user/urls.py
Normal file
58
ec_user/urls.py
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
|
||||
from django.urls import path
|
||||
from . views import ec_login, MyProtectedUserLogout, index_test
|
||||
|
||||
from . views import MyProtectedApiContactInfo, api_contact_info_test, MyProtectedApiSchoolInfo, api_school_info_test
|
||||
from . views import MyProtectedApiAcademicInfo, api_academic_info_test, MyProtectedApiHealthInfo, api_health_info_test
|
||||
from . views import MyProtectedApiSelfEvaluationInfo, api_self_evaluation_test, MyProtectedFamilyInfo, api_family_info_test
|
||||
from . views import MyProtectedApiHobbiesInterests, api_hobbies_interests_test, MyProtectedSocialPractice, api_social_practice_test
|
||||
from . views import MyProtectedAwardsPunishments, api_awards_punishments_test , MyProtectedBasicUserInfo
|
||||
|
||||
from . views import all_info_form, all_info_edit
|
||||
|
||||
from . views import MyProtectedUserInfo
|
||||
|
||||
urlpatterns = [
|
||||
path('', index_test, name='index_test'),
|
||||
|
||||
path('login/', ec_login, name='login'),
|
||||
path('logout/', MyProtectedUserLogout.as_view(), name='logout'),
|
||||
|
||||
|
||||
path('contact_info/api/', MyProtectedApiContactInfo.as_view(), name='api_contact_info'),
|
||||
path('api_contact_info_test/', api_contact_info_test, name='api_contact_info_test'),
|
||||
|
||||
path('school_info/api/', MyProtectedApiSchoolInfo.as_view(), name='api_school_info'),
|
||||
path('api_school_info_test/', api_school_info_test, name='api_school_info_test'),
|
||||
|
||||
path('academic_info/api/', MyProtectedApiAcademicInfo.as_view(), name='api_academic_info'),
|
||||
path('api_academic_info_test/', api_academic_info_test, name='api_academic_info_test'),
|
||||
|
||||
path('health_info/api/', MyProtectedApiHealthInfo.as_view(), name='api_health_info'),
|
||||
path('api_health_info_test/', api_health_info_test, name='api_health_info_test'),
|
||||
|
||||
path('self_evaluation/api/', MyProtectedApiSelfEvaluationInfo.as_view(), name='api_self_evaluation'),
|
||||
path('api_self_evaluation_test/', api_self_evaluation_test, name='api_self_evaluation_test'),
|
||||
|
||||
|
||||
path('hobbies_interests/api/', MyProtectedApiHobbiesInterests.as_view(), name='api_hobbies_interests'),
|
||||
path('api_hobbies_interests_test/', api_hobbies_interests_test, name='api_hobbies_interests_test'),
|
||||
|
||||
path('social_practice/api/', MyProtectedSocialPractice.as_view(), name='api_social_practice'),
|
||||
path('api_social_practice_test/', api_social_practice_test, name='api_social_practice_test'),
|
||||
|
||||
path('family_info/api/', MyProtectedFamilyInfo.as_view(), name='api_family_info'),
|
||||
path('api_family_info_test/', api_family_info_test, name='api_family_info_test'),
|
||||
|
||||
path('awards_punishments/api/', MyProtectedAwardsPunishments.as_view(), name='api_awards_punishments'),
|
||||
path('api_awards_punishments_test/', api_awards_punishments_test, name='api_awards_punishments_test'),
|
||||
|
||||
|
||||
path('all_info_form/<int:user_id>/', all_info_form, name='all_info_form'),
|
||||
path('all_info_edit/<int:user_id>/<str:model_name>/', all_info_edit, name='all_info_edit'),
|
||||
|
||||
path('api_user_info/', MyProtectedUserInfo.as_view(), name='api_user_info'),
|
||||
path('basic_user_info/api/', MyProtectedBasicUserInfo.as_view(), name='api_basic_user_info'),
|
||||
|
||||
]
|
||||
659
ec_user/views.py
Normal file
659
ec_user/views.py
Normal file
@ -0,0 +1,659 @@
|
||||
from django.http import JsonResponse, HttpResponse
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.shortcuts import render, redirect
|
||||
from django.forms import modelformset_factory
|
||||
from rest_framework.authtoken.models import Token # 导入 Token 模型
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
from authentication.models import CustomToken
|
||||
from django.contrib.auth.hashers import check_password, make_password # 导入密码哈希比较方法
|
||||
|
||||
|
||||
from .models import EcUser, ContactInfo, SchoolInfo, AcademicInfo, HealthInfo, SelfEvaluation
|
||||
from .models import HobbiesInterests, SocialPractice, FamilyInfo, AwardsPunishments
|
||||
|
||||
from .forms import g_models, g_form_classes
|
||||
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from authentication.authentication import CustomTokenAuthentication
|
||||
|
||||
|
||||
|
||||
def index_test(request):
|
||||
return render(request, 'index.html')
|
||||
|
||||
|
||||
def ec_login(request):
|
||||
if request.method != 'POST':
|
||||
return render(request, 'testlogin.html')
|
||||
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
username = data.get('username')
|
||||
password = data.get('password')
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({'error': 'Invalid JSON'}, status=400)
|
||||
|
||||
if not username or not password:
|
||||
return JsonResponse({'error': 'Missing username or password'}, status=400)
|
||||
|
||||
user = authenticate(username=username, password=password)
|
||||
if user is not None:
|
||||
login(request, user)
|
||||
|
||||
# 生成 Token(你可以选择使用自定义的 CustomToken)
|
||||
# token, created = Token.objects.get_or_create(user=user) # 使用 DRF 提供的 Token 模型
|
||||
# 如果你使用的是自定义的 CustomToken
|
||||
token, created = CustomToken.objects.get_or_create(user=user, defaults={'extra_info': 'your_value', 'expiration_date': timezone.now() + timedelta(days=7)})
|
||||
if not created:
|
||||
token.expiration_date = timezone.now() + timedelta(days=7)
|
||||
token.save()
|
||||
|
||||
return JsonResponse({'message': 'Login Success!', 'token': token.key}) # 返回 token
|
||||
|
||||
else:
|
||||
return JsonResponse({'error': 'Login Failed!'}, status=401)
|
||||
|
||||
class MyProtectedUserLogout(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
if user.is_authenticated:
|
||||
# 删除与当前用户相关的 Token
|
||||
CustomToken.objects.filter(user=user).delete()
|
||||
|
||||
# 进行登出操作
|
||||
logout(request)
|
||||
|
||||
return JsonResponse({'message': 'Logout Successful'}, status=200)
|
||||
else:
|
||||
return JsonResponse({'error': 'User not authenticated'}, status=400)
|
||||
|
||||
|
||||
|
||||
def all_info_form(request, user_id):
|
||||
try:
|
||||
user = EcUser.objects.get(id=user_id)
|
||||
except EcUser.DoesNotExist:
|
||||
return render(request, 'error.html', {"message": "User not found"})
|
||||
|
||||
instances = {}
|
||||
for key, model in g_models.items():
|
||||
if key in ['hobbies_interests', 'social_practice', 'family_info', 'awards_punishments']:
|
||||
instances[key] = model.objects.filter(user=user) # 处理一对多关系
|
||||
else:
|
||||
instance, _ = model.objects.get_or_create(user=user)
|
||||
instances[key] = instance
|
||||
|
||||
if request.method == 'GET':
|
||||
# 初始化所有表单
|
||||
forms = {}
|
||||
for form_key, form_class in g_form_classes.items():
|
||||
if form_key in ['hobbies_interests_form', 'social_practice_form', 'family_info_form', 'awards_punishments_form']:
|
||||
queryset = instances[form_key[:-5]] # 获取对应模型的查询集
|
||||
|
||||
# 如果查询集为空,设置 extra=1 来允许添加空表单
|
||||
if queryset.exists():
|
||||
formset_class = modelformset_factory(queryset.model, form=form_class, extra=0)
|
||||
else:
|
||||
formset_class = modelformset_factory(queryset.model, form=form_class, extra=1)
|
||||
|
||||
# 使用 formset 渲染表单
|
||||
forms[form_key] = formset_class(queryset=queryset)
|
||||
else:
|
||||
forms[form_key] = form_class(instance=instances[form_key[:-5]])
|
||||
|
||||
return render(request, 'all_info_form.html', {'user': user, **forms})
|
||||
|
||||
else:
|
||||
return HttpResponse("Not implemented")
|
||||
|
||||
|
||||
def all_info_edit(request, user_id, model_name):
|
||||
|
||||
try:
|
||||
user = EcUser.objects.get(id=user_id)
|
||||
except EcUser.DoesNotExist:
|
||||
return render(request, 'error.html', {"message": "User not found"})
|
||||
|
||||
instances = g_models[model_name].objects.filter(user=user) # 处理一对多关系
|
||||
print(instances)
|
||||
formset_class = modelformset_factory(model=g_models[model_name], form=g_form_classes[model_name + '_form'], extra=0)
|
||||
formset = formset_class(request.POST, queryset=instances)
|
||||
print(instances)
|
||||
if formset.is_valid():
|
||||
instances = formset.save(commit=False)
|
||||
instances[0].user = user
|
||||
formset.save()
|
||||
else:
|
||||
return render(request, 'all_info_result.html', {'user': user, "model_name": model_name, "formset": formset})
|
||||
|
||||
return render(request, 'all_info_result.html', {'user': user, "model_name": model_name, "formset": None})
|
||||
|
||||
|
||||
# ================= API 接口 =================
|
||||
# +++++++++++++++++++++++++++++++++++++++++++=
|
||||
|
||||
|
||||
class MyProtectedUserInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
# 返回用户的 ID、用户名、剩余次数和主题列表
|
||||
return JsonResponse({"user_id": request.user.id,
|
||||
"name": request.user.name,
|
||||
"username": request.user.username,
|
||||
"remain_count": request.user.subject_usage_count,
|
||||
"subject": list(request.user.subjects.values_list('name', flat=True)),
|
||||
"fill_status":
|
||||
{
|
||||
"contact_info": ContactInfo.objects.filter(user=request.user).exists(),
|
||||
"scholar_info": SchoolInfo.objects.filter(user=request.user).exists(),
|
||||
"academic_info": AcademicInfo.objects.filter(user=request.user).exists(),
|
||||
"health_info": HealthInfo.objects.filter(user=request.user).exists(),
|
||||
"self_evaluation": SelfEvaluation.objects.filter(user=request.user).exists(),
|
||||
"family_info": FamilyInfo.objects.filter(user=request.user).exists(),
|
||||
"hobbies_interests": HobbiesInterests.objects.filter(user=request.user).exists(),
|
||||
"social_practice": SocialPractice.objects.filter(user=request.user).exists(),
|
||||
"awards_punishments": AwardsPunishments.objects.filter(user=request.user).exists(),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
class MyProtectedBasicUserInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
# 获取用户信息并返回 JSON 格式
|
||||
user_info = EcUser.objects.filter(id=user.id).first()
|
||||
if user_info:
|
||||
response_data = {
|
||||
"name": user_info.name,
|
||||
"gender": user_info.get_gender_display(),
|
||||
"age": user_info.age,
|
||||
"ethnicity": user_info.ethnicity,
|
||||
"dob": user_info.dob,
|
||||
"id_card_number": user_info.id_card_number,
|
||||
"political_status": user_info.political_status
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No user info found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新用户信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
name = data.get("name")
|
||||
gender = data.get("gender")
|
||||
age = data.get("age")
|
||||
ethnicity = data.get("ethnicity")
|
||||
dob = data.get("dob")
|
||||
id_card_number = data.get("id_card_number")
|
||||
political_status = data.get("political_status")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 EcUser
|
||||
try:
|
||||
user_info = EcUser.objects.get(id=user.id)
|
||||
except EcUser.DoesNotExist:
|
||||
return JsonResponse({"error": "User not found"}, status=404)
|
||||
|
||||
# 更新用户信息
|
||||
user_info.name = name
|
||||
user_info.gender = gender
|
||||
user_info.age = age
|
||||
user_info.ethnicity = ethnicity
|
||||
user_info.dob = dob
|
||||
user_info.id_card_number = id_card_number
|
||||
user_info.political_status = political_status
|
||||
user_info.save()
|
||||
|
||||
return JsonResponse({"message": "User info updated successfully"})
|
||||
|
||||
|
||||
def api_contact_info_test(req):
|
||||
return render(req, 'api_contact_info_test.html')
|
||||
|
||||
class MyProtectedApiContactInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
# 获取联系信息并返回 JSON 格式
|
||||
contact_info = ContactInfo.objects.filter(user=user).first()
|
||||
if contact_info:
|
||||
response_data = {
|
||||
"home_address": contact_info.home_address,
|
||||
"parent_contact": contact_info.parent_contact,
|
||||
"student_contact": contact_info.student_contact,
|
||||
"email": contact_info.email
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No contact info found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新用户的联系信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
home_address = data.get("home_address")
|
||||
parent_contact = data.get("parent_contact")
|
||||
student_contact = data.get("student_contact")
|
||||
email = data.get("email")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 ContactInfo
|
||||
contact_info, created = ContactInfo.objects.get_or_create(user=user)
|
||||
contact_info.home_address = home_address
|
||||
contact_info.parent_contact = parent_contact
|
||||
contact_info.student_contact = student_contact
|
||||
contact_info.email = email
|
||||
contact_info.save()
|
||||
|
||||
return JsonResponse({"message": "Contact info updated successfully"})
|
||||
|
||||
def api_school_info_test(req):
|
||||
return render(req, 'api_school_info_test.html')
|
||||
|
||||
class MyProtectedApiSchoolInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
# 获取学校信息并返回 JSON 格式
|
||||
school_info = SchoolInfo.objects.filter(user=user).first()
|
||||
if school_info:
|
||||
response_data = {
|
||||
"school_name": school_info.school_name,
|
||||
"grade": school_info.grade,
|
||||
"class_name": school_info.class_name,
|
||||
"admission_date": school_info.admission_date,
|
||||
"expected_graduation_date": school_info.expected_graduation_date
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No school info found"}, status=404)
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新学校信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
school_name = data.get("school_name")
|
||||
grade = data.get("grade")
|
||||
class_name = data.get("class_name")
|
||||
admission_date = data.get("admission_date")
|
||||
expected_graduation_date = data.get("expected_graduation_date")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 SchoolInfo
|
||||
school_info, created = SchoolInfo.objects.get_or_create(user=user)
|
||||
school_info.school_name = school_name
|
||||
school_info.grade = grade
|
||||
school_info.class_name = class_name
|
||||
school_info.admission_date = admission_date
|
||||
school_info.expected_graduation_date = expected_graduation_date
|
||||
school_info.save()
|
||||
|
||||
return JsonResponse({"message": "School info updated successfully"})
|
||||
|
||||
|
||||
|
||||
def api_academic_info_test(req):
|
||||
return render(req, 'api_academic_info_test.html')
|
||||
|
||||
|
||||
class MyProtectedApiAcademicInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取学习情况信息并返回 JSON 格式
|
||||
academic_info = AcademicInfo.objects.filter(user=user).first()
|
||||
if academic_info:
|
||||
response_data = {
|
||||
"last_semester_score": str(academic_info.last_semester_score),
|
||||
"this_semester_score": str(academic_info.this_semester_score),
|
||||
"class_ranking": academic_info.class_ranking,
|
||||
"strong_subject": academic_info.strong_subject,
|
||||
"weak_subject": academic_info.weak_subject
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No academic info found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新用户的学习情况信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
last_semester_score = data.get("last_semester_score")
|
||||
this_semester_score = data.get("this_semester_score")
|
||||
class_ranking = data.get("class_ranking")
|
||||
strong_subject = data.get("strong_subject")
|
||||
weak_subject = data.get("weak_subject")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 AcademicInfo
|
||||
academic_info, created = AcademicInfo.objects.get_or_create(user=user)
|
||||
academic_info.last_semester_score = last_semester_score
|
||||
academic_info.this_semester_score = this_semester_score
|
||||
academic_info.class_ranking = class_ranking
|
||||
academic_info.strong_subject = strong_subject
|
||||
academic_info.weak_subject = weak_subject
|
||||
academic_info.save()
|
||||
|
||||
return JsonResponse({"message": "Academic info updated successfully"})
|
||||
|
||||
|
||||
|
||||
def api_health_info_test(req):
|
||||
return render(req, 'api_health_info_test.html')
|
||||
|
||||
|
||||
class MyProtectedApiHealthInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取健康信息并返回 JSON 格式
|
||||
health_info = HealthInfo.objects.filter(user=user).first()
|
||||
if health_info:
|
||||
response_data = {
|
||||
"height": str(health_info.height),
|
||||
"weight": str(health_info.weight),
|
||||
"blood_type": health_info.blood_type,
|
||||
"medical_history": health_info.medical_history,
|
||||
"disability_status": health_info.disability_status,
|
||||
"disability_category": health_info.disability_category,
|
||||
"disability_grade": health_info.disability_grade
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No health info found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
|
||||
user = request.user
|
||||
# 处理 POST 请求,更新用户的健康信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
height = data.get("height")
|
||||
weight = data.get("weight")
|
||||
blood_type = data.get("blood_type")
|
||||
medical_history = data.get("medical_history")
|
||||
disability_status = data.get("disability_status")
|
||||
disability_category = data.get("disability_category")
|
||||
disability_grade = data.get("disability_grade")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 HealthInfo
|
||||
health_info, created = HealthInfo.objects.get_or_create(user=user)
|
||||
health_info.height = height
|
||||
health_info.weight = weight
|
||||
health_info.blood_type = blood_type
|
||||
health_info.medical_history = medical_history
|
||||
health_info.disability_status = disability_status
|
||||
health_info.disability_category = disability_category
|
||||
health_info.disability_grade = disability_grade
|
||||
health_info.save()
|
||||
|
||||
return JsonResponse({"message": "Health info updated successfully"})
|
||||
|
||||
|
||||
def api_self_evaluation_test(req):
|
||||
return render(req, 'api_self_evaluation_test.html')
|
||||
|
||||
class MyProtectedApiSelfEvaluationInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取自我评价信息并返回 JSON 格式
|
||||
self_evaluation = SelfEvaluation.objects.filter(user=user).first()
|
||||
if self_evaluation:
|
||||
response_data = {
|
||||
"strengths": self_evaluation.strengths,
|
||||
"weaknesses": self_evaluation.weaknesses,
|
||||
"study_attitude": self_evaluation.study_attitude,
|
||||
"future_plans": self_evaluation.future_plans
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No self evaluation found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
|
||||
# 处理 POST 请求,更新用户的自我评价信息
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
strengths = data.get("strengths")
|
||||
weaknesses = data.get("weaknesses")
|
||||
study_attitude = data.get("study_attitude")
|
||||
future_plans = data.get("future_plans")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 查找或创建 SelfEvaluation
|
||||
self_evaluation, created = SelfEvaluation.objects.get_or_create(user=user)
|
||||
self_evaluation.strengths = strengths
|
||||
self_evaluation.weaknesses = weaknesses
|
||||
self_evaluation.study_attitude = study_attitude
|
||||
self_evaluation.future_plans = future_plans
|
||||
self_evaluation.save()
|
||||
|
||||
return JsonResponse({"message": "Self evaluation updated successfully"})
|
||||
|
||||
|
||||
# =================== 以下字段是 一对多 ===================
|
||||
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
def api_hobbies_interests_test(req):
|
||||
return render(req, 'api_hobbies_interests_test.html')
|
||||
|
||||
class MyProtectedApiHobbiesInterests(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取该用户的所有兴趣爱好信息
|
||||
hobbies_interests = HobbiesInterests.objects.filter(user=user)
|
||||
if hobbies_interests.exists():
|
||||
response_data = []
|
||||
for entry in hobbies_interests:
|
||||
response_data.append({
|
||||
"interests": entry.interests,
|
||||
"extracurricular_activities": entry.extracurricular_activities
|
||||
})
|
||||
return JsonResponse(response_data, safe=False)
|
||||
else:
|
||||
return JsonResponse({"error": "No hobbies and interests found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,创建新的兴趣爱好记录
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
interests = data.get("interests")
|
||||
extracurricular_activities = data.get("extracurricular_activities")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 创建新的 HobbiesInterests 记录
|
||||
new_entry = HobbiesInterests.objects.create(
|
||||
user=user,
|
||||
interests=interests,
|
||||
extracurricular_activities=extracurricular_activities
|
||||
)
|
||||
return JsonResponse({"message": "Hobbies and interests added successfully"})
|
||||
|
||||
|
||||
def api_social_practice_test(req):
|
||||
return render(req, 'api_social_practice_test.html')
|
||||
|
||||
class MyProtectedSocialPractice(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取该用户的所有社会实践记录
|
||||
social_practices = SocialPractice.objects.filter(user=user)
|
||||
if social_practices.exists():
|
||||
response_data = []
|
||||
for entry in social_practices:
|
||||
response_data.append({
|
||||
"activity_name": entry.activity_name,
|
||||
"activity_date": entry.activity_date,
|
||||
"activity_location": entry.activity_location,
|
||||
"activity_description": entry.activity_description,
|
||||
"activity_outcome": entry.activity_outcome
|
||||
})
|
||||
return JsonResponse(response_data, safe=False)
|
||||
else:
|
||||
return JsonResponse({"error": "No social practice records found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,创建新的社会实践记录
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
activity_name = data.get("activity_name")
|
||||
activity_date = data.get("activity_date")
|
||||
activity_location = data.get("activity_location")
|
||||
activity_description = data.get("activity_description")
|
||||
activity_outcome = data.get("activity_outcome")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 创建新的 SocialPractice 记录
|
||||
new_entry = SocialPractice.objects.create(
|
||||
user=user,
|
||||
activity_name=activity_name,
|
||||
activity_date=activity_date,
|
||||
activity_location=activity_location,
|
||||
activity_description=activity_description,
|
||||
activity_outcome=activity_outcome
|
||||
)
|
||||
return JsonResponse({"message": "Social practice record added successfully"})
|
||||
|
||||
|
||||
def api_family_info_test(req):
|
||||
return render(req, 'api_family_info_test.html')
|
||||
|
||||
class MyProtectedFamilyInfo(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取该用户的家庭情况记录
|
||||
family_info = FamilyInfo.objects.filter(user=user).first()
|
||||
if family_info:
|
||||
response_data = {
|
||||
"family_member": family_info.family_member,
|
||||
"economic_status": family_info.economic_status
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
else:
|
||||
return JsonResponse({"error": "No family info found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,创建或更新家庭情况记录
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
family_member = data.get("family_member")
|
||||
economic_status = data.get("economic_status")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 创建或更新 FamilyInfo 记录
|
||||
family_info, created = FamilyInfo.objects.get_or_create(user=user)
|
||||
family_info.family_member = family_member
|
||||
family_info.economic_status = economic_status
|
||||
family_info.save()
|
||||
|
||||
return JsonResponse({"message": "Family info updated successfully"})
|
||||
|
||||
|
||||
def api_awards_punishments_test(req):
|
||||
return render(req, 'api_awards_punishments_test.html')
|
||||
|
||||
class MyProtectedAwardsPunishments(APIView):
|
||||
authentication_classes = [CustomTokenAuthentication] # 使用自定义的 Token 认证
|
||||
permission_classes = [IsAuthenticated] # 需要用户认证才能访问
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
|
||||
# 获取该用户的奖惩情况记录
|
||||
awards_punishments = AwardsPunishments.objects.filter(user=user)
|
||||
if awards_punishments.exists():
|
||||
response_data = [
|
||||
{
|
||||
"award_name": ap.award_name,
|
||||
"award_date": ap.award_date,
|
||||
"award_organization": ap.award_organization,
|
||||
"discipline_date": ap.discipline_date,
|
||||
"discipline_issue": ap.discipline_issue,
|
||||
"discipline_outcome": ap.discipline_outcome
|
||||
} for ap in awards_punishments
|
||||
]
|
||||
return JsonResponse(response_data, safe=False)
|
||||
else:
|
||||
return JsonResponse({"error": "No awards or punishments found"}, status=404)
|
||||
|
||||
def post(self, request):
|
||||
user = request.user
|
||||
# 处理 POST 请求,创建或更新奖惩情况记录
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
award_name = data.get("award_name")
|
||||
award_date = data.get("award_date")
|
||||
award_organization = data.get("award_organization")
|
||||
discipline_date = data.get("discipline_date")
|
||||
discipline_issue = data.get("discipline_issue")
|
||||
discipline_outcome = data.get("discipline_outcome")
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({"error": "Invalid JSON format"}, status=400)
|
||||
|
||||
# 创建或更新 AwardsPunishments 记录
|
||||
awards_punishment = AwardsPunishments.objects.create(
|
||||
user=user,
|
||||
award_name=award_name,
|
||||
award_date=award_date,
|
||||
award_organization=award_organization,
|
||||
discipline_date=discipline_date,
|
||||
discipline_issue=discipline_issue,
|
||||
discipline_outcome=discipline_outcome
|
||||
)
|
||||
|
||||
return JsonResponse({"message": "Awards and punishments info updated successfully"})
|
||||
8
educheck/__init__.py
Normal file
8
educheck/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
# 在 Django 启动时加载 Celery
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
16
educheck/asgi.py
Normal file
16
educheck/asgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for educheck 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', 'educheck.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
19
educheck/celery.py
Normal file
19
educheck/celery.py
Normal file
@ -0,0 +1,19 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
from celery import Celery
|
||||
|
||||
# 设置 Django 的 settings 模块
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'educheck.settings')
|
||||
|
||||
# 创建 Celery 应用
|
||||
app = Celery('educheck')
|
||||
|
||||
# 使用 Django 配置中的 Celery 配置
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
|
||||
# celery.py
|
||||
app.conf.broker_connection_retry_on_startup = True
|
||||
|
||||
|
||||
# 自动发现所有的 tasks.py 文件
|
||||
app.autodiscover_tasks()
|
||||
184
educheck/settings.py
Normal file
184
educheck/settings.py
Normal file
@ -0,0 +1,184 @@
|
||||
"""
|
||||
Django settings for educheck project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.2.19.
|
||||
|
||||
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/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# __init__.py
|
||||
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-x!)cojyro)mcft%4r^8&wsn9f8o!5px1=@6mx4eu73ydczx&)j'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*', 'a.debin.cc']
|
||||
|
||||
# Application definition
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'ec_user',
|
||||
'authentication',
|
||||
'diagnose'
|
||||
]
|
||||
|
||||
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 = 'educheck.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'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',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'educheck.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
||||
# }
|
||||
# }
|
||||
|
||||
# settings.py
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL 数据库
|
||||
'NAME': 'educheck', # 数据库名称
|
||||
'USER': 'root', # 数据库用户名
|
||||
'PASSWORD': 'pacpac123.', # 数据库密码
|
||||
'HOST': '127.0.0.1', # 数据库主机(如果数据库在本地就用 localhost)
|
||||
'PORT': '3306', # MySQL 默认端口是 3306
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
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',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'zh-hans'
|
||||
|
||||
TIME_ZONE = 'Asia/Shanghai'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
|
||||
AUTH_USER_MODEL = 'ec_user.EcUser'
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer', # 只返回 JSON 格式的响应
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'authentication.authentication.CustomTokenAuthentication',
|
||||
],
|
||||
}
|
||||
|
||||
ERROR_CODE_MAP = {
|
||||
# 1000 - 用户相关错误
|
||||
|
||||
# 2000 - 生成试卷相关错误
|
||||
'2001': 'user not authorized to generate paper for this subject',
|
||||
'2002': 'user has no remaining usage count for this subject',
|
||||
'2003': 'user has no school info',
|
||||
# 试卷查看
|
||||
'2004': 'record file not found',
|
||||
# 试卷下载
|
||||
'2005': 'requested file not found'
|
||||
}
|
||||
|
||||
|
||||
OPAI_API_KEY = 'e119bd6c-a22a-404e-a002-6d72a2cea65d'
|
||||
OPAI_BASE_URL = 'https://ark.cn-beijing.volces.com/api/v3'
|
||||
|
||||
WKHTMLTOPDF_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
|
||||
|
||||
# settings.py
|
||||
# celery -A educheck worker -l info -P eventlet
|
||||
# celery -A educheck beat -l info
|
||||
|
||||
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0' # 使用 Redis 作为消息中间件
|
||||
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0' # Redis 存储任务结果
|
||||
CELERY_ACCEPT_CONTENT = ['json']
|
||||
CELERY_TASK_SERIALIZER = 'json'
|
||||
34
educheck/urls.py
Normal file
34
educheck/urls.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""
|
||||
URL configuration for educheck 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
|
||||
from django.urls import include
|
||||
from .views import user_profile
|
||||
from .views import health_check
|
||||
from .views import error_code_map
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('ec_user/', include('ec_user.urls')),
|
||||
path('diagnose/', include('diagnose.urls')),
|
||||
|
||||
path('health/', health_check, name='health_check'),
|
||||
path('error_code_map/', error_code_map, name='error_code_map'),
|
||||
|
||||
path('user_profile/<int:user_id>/', user_profile, name='user_profile'),
|
||||
path('auth/', include('authentication.urls')),
|
||||
]
|
||||
15
educheck/views.py
Normal file
15
educheck/views.py
Normal file
@ -0,0 +1,15 @@
|
||||
# views.py
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from ec_user.models import EcUser
|
||||
from django.http import JsonResponse
|
||||
from django.conf import settings
|
||||
|
||||
def health_check(request):
|
||||
return JsonResponse({"status": "ok", "version": "0.0.1"})
|
||||
|
||||
def error_code_map(request):
|
||||
return JsonResponse(settings.ERROR_CODE_MAP)
|
||||
|
||||
def user_profile(request, user_id):
|
||||
user = get_object_or_404(EcUser, id=user_id)
|
||||
return render(request, 'user_profile.html', {'user': user})
|
||||
16
educheck/wsgi.py
Normal file
16
educheck/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for educheck 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', 'educheck.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
28
manage.py
Normal file
28
manage.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'educheck.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
# from django.contrib.auth.hashers import make_password
|
||||
|
||||
# celery -A educheck worker -l info -P eventlet
|
||||
# celery -A educheck beat -l info
|
||||
18
test_api.py
Normal file
18
test_api.py
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
import requests
|
||||
|
||||
# 设置请求头
|
||||
headers = {
|
||||
'token': 'Token 486ef8198bb10ba6878eba95771c064ff64db81a' # 替换 your_token_here 为实际的 token
|
||||
}
|
||||
|
||||
# 发送 GET 请求
|
||||
url = 'http://a.debin.cc:55800/auth/' # 目标 URL
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
# 输出响应
|
||||
if response.status_code == 200:
|
||||
print("Response JSON:", response.json()) # 输出响应的 JSON 数据
|
||||
else:
|
||||
print(f"Request failed with status code {response.status_code}")
|
||||
Loading…
Reference in New Issue
Block a user