mirror of
https://github.com/xingsu1021/pthelper.git
synced 2026-06-16 06:57:21 +08:00
新增备份恢复功能,支持sqlite迁移到mysql
This commit is contained in:
11
README.md
11
README.md
@@ -58,7 +58,7 @@ pip install --no-cache-dir -r requirements.txt -i https://pypi.mirrors.ustc.edu.
|
||||
|
||||
```shell
|
||||
1、开放计划任务配置
|
||||
2、支持签到失败重试(忽略cookie失效站点),建议失败重试时间设置5分钟以上
|
||||
2、支持签到失败重试(忽略cookie失效站点),建议失败重试时间设置5分钟以上(由于sqlite单进程模式,因此重试和签到不要放在同一个分钟或小时,建议差距2分钟以上)
|
||||
```
|
||||
|
||||
# v2.0 说明
|
||||
@@ -151,6 +151,15 @@ root 数据库用户名
|
||||
3306 数据库端口
|
||||
pthelper 数据库名称
|
||||
```
|
||||
#sqlite迁移到mysql步骤
|
||||
```shell
|
||||
1、系统管理---》备份恢复,点击备份
|
||||
2、关闭docker
|
||||
3、修改conf下的env.prod,配置你使用的mysql,并创建你配置的数据库
|
||||
4、启动docker
|
||||
5、系统管理---》备份恢复,选择要恢复的文件,然后点击恢复
|
||||
6、刷新页面,重新登录系统
|
||||
```
|
||||
|
||||
## 感谢
|
||||
|
||||
|
||||
@@ -1,74 +1,136 @@
|
||||
|
||||
<!-- 正文开始 -->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<!-- 表单开始 -->
|
||||
<form class="layui-form" id="backuploadForm" lay-filter="backuploadForm" method="POST">{% csrf_token %}
|
||||
<input name="id" type="hidden" value="{{id}}"/>
|
||||
|
||||
<div class="layui-form toolbar">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-filter="backupSubmit" lay-submit> 备份 </button>
|
||||
<button class="layui-btn layui-btn-normal" lay-filter="loadSubmit" lay-submit> 恢复 </button>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button id="exportSubmit" class="layui-btn icon-btn"><i class="layui-icon layui-icon-export"></i>备份数据</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<!-- //表单结束 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="layui-table" id="backuplistTable" lay-filter="backuplistTable"></table>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">说明</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">备份恢复数据
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 表格操作列 -->
|
||||
<script type="text/html" id="backuplistTableBar">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="import">恢复</a>
|
||||
</script>
|
||||
|
||||
<!-- js部分 -->
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'util', 'admin', 'xmSelect', 'formX', 'dropdown'], function () {
|
||||
layui.use(['layer', 'form', 'table', 'tableX', 'util', 'admin', 'xmSelect', 'formX', 'dropdown'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var tableX = layui.tableX;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
var formX = layui.formX;
|
||||
var setter = layui.setter;
|
||||
var xmSelect = layui.xmSelect;
|
||||
|
||||
form.on('submit(backupSubmit)', function (data) {
|
||||
// 渲染表格
|
||||
var insTb = tableX.render({
|
||||
elem: '#backuplistTable',
|
||||
url: setter.base_server + 'common/backup/list',
|
||||
method: 'GET',
|
||||
page: false,
|
||||
cols: [[
|
||||
{field: 'name', title: '文件名称', templet: function (d) {
|
||||
return '<a href="' + d.url + '" class="layui-table-link" lay-event="link" target="_blank">' + d.name + '</a>';
|
||||
}
|
||||
},
|
||||
{align: 'center', toolbar: '#backuplistTableBar', title: '操作', width: 120}
|
||||
]]
|
||||
});
|
||||
|
||||
|
||||
// 工具条点击事件
|
||||
table.on('tool(backuplistTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
var layEvent = obj.event;
|
||||
|
||||
if (layEvent === 'import') {
|
||||
layer.confirm('确定恢复此备份文件 ' + data.name + '?',{icon: 3, title: '提示', shadeClose: true},
|
||||
function (i) {
|
||||
layer.close(i);
|
||||
layer.load(2);
|
||||
$.ajax({
|
||||
url : "common/backup/import",
|
||||
type: 'POST',
|
||||
dataType : "json",
|
||||
data: {'name': data.name, csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
// beforeSend: function(request) {
|
||||
// //django需要csrf验证,Forbidden (CSRF cookie not set.):
|
||||
// request.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
// },
|
||||
success : function(d) {
|
||||
layer.closeAll('loading');
|
||||
if (d.code == 1) {
|
||||
table.reload('backuplistTable', {});
|
||||
layer.msg(d.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(d.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if(layEvent === 'del'){
|
||||
|
||||
//var csrftoken = getCookie('csrftoken');
|
||||
layer.confirm('确定删除此备份文件 ' + data.name + '?',{icon: 3, title: '警告', shadeClose: true},
|
||||
function (i) {
|
||||
layer.close(i);
|
||||
layer.load(2);
|
||||
$.ajax({
|
||||
url : "common/backup/del",
|
||||
type: 'POST',
|
||||
dataType : "json",
|
||||
data: {'name': data.name, csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
// beforeSend: function(request) {
|
||||
// //django需要csrf验证,Forbidden (CSRF cookie not set.):
|
||||
// request.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
// },
|
||||
success : function(d) {
|
||||
layer.closeAll('loading');
|
||||
if (d.code == 1) {
|
||||
table.reload('backuplistTable', {});
|
||||
layer.msg(d.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(d.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 备份按钮点击事件
|
||||
$('#exportSubmit').click(function () {
|
||||
layer.load(2);
|
||||
admin.req('common/backup', {'action':'backup'}, function (data) {
|
||||
admin.req('common/backup/export', function (data) {
|
||||
layer.closeAll('loading');
|
||||
if (data.code == 1) {
|
||||
table.reload('backuplistTable', {});
|
||||
layer.msg(data.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
}
|
||||
}, $('#backuploadForm').attr('method'));
|
||||
}, 'POST');
|
||||
return false;
|
||||
});
|
||||
|
||||
// form.on('submit(backuploadcrtestSubmit)', function (data) {
|
||||
// layer.load(2);
|
||||
// admin.req('common/backuploadcrtest', data.field, function (data) {
|
||||
// layer.closeAll('loading');
|
||||
// if (data.code == 1) {
|
||||
// layer.msg(data.msg, {icon: 1});
|
||||
// } else {
|
||||
// layer.msg(data.msg, {icon: 2});
|
||||
// }
|
||||
// }, $('#backuploadcrForm').attr('method'));
|
||||
// return false;
|
||||
// });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
<style>
|
||||
#baiduocrForm {
|
||||
max-width: 700px;
|
||||
|
||||
}
|
||||
|
||||
#baiduocrForm .layui-form-item {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
#img {
|
||||
width: 25px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
margin-top: 12px;
|
||||
top: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
<!-- 正文开始 -->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<!-- 表单开始 -->
|
||||
<form class="layui-form" id="baiduocrForm" lay-filter="baiduocrForm" method="POST">{% csrf_token %}
|
||||
<input name="id" type="hidden" value="{{id}}"/>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">APP_ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input name="app_id" class="layui-input"
|
||||
lay-verify="required" required value="{{app_id}}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">API_KEY</label>
|
||||
<div class="layui-input-block">
|
||||
<input name="app_key" class="layui-input"
|
||||
lay-verify="required" required value="{{app_key}}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SECRET_KEY</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="secret_key" id="secret_key" class="layui-input" lay-verify="required" required value="{{secret_key}}"/>
|
||||
<!--在输入框后接img标签-->
|
||||
<img id="img" onclick="hideShowPsw()"
|
||||
src="/static/assets/images/icon-visible.png">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-filter="baiduocrSubmit" lay-submit> 提交 </button>
|
||||
<!--
|
||||
<button class="layui-btn layui-btn-normal" lay-filter="baiduocrtestSubmit" lay-submit> 测试 </button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<!-- //表单结束 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">说明</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">申请百度云的免费图片和文字识别,用于验证码识别,天空、皇后必须
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- js部分 -->
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'util', 'admin', 'xmSelect', 'formX', 'dropdown'], function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var util = layui.util;
|
||||
var admin = layui.admin;
|
||||
var formX = layui.formX;
|
||||
var setter = layui.setter;
|
||||
var xmSelect = layui.xmSelect;
|
||||
|
||||
form.on('submit(baiduocrSubmit)', function (data) {
|
||||
layer.load(2);
|
||||
admin.req('common/baiduocr', data.field, function (data) {
|
||||
layer.closeAll('loading');
|
||||
if (data.code == 1) {
|
||||
layer.msg(data.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
}
|
||||
}, $('#baiduocrForm').attr('method'));
|
||||
return false;
|
||||
});
|
||||
|
||||
// form.on('submit(baiduocrtestSubmit)', function (data) {
|
||||
// layer.load(2);
|
||||
// admin.req('common/baiduocrtest', data.field, function (data) {
|
||||
// layer.closeAll('loading');
|
||||
// if (data.code == 1) {
|
||||
// layer.msg(data.msg, {icon: 1});
|
||||
// } else {
|
||||
// layer.msg(data.msg, {icon: 2});
|
||||
// }
|
||||
// }, $('#baiduocrForm').attr('method'));
|
||||
// return false;
|
||||
// });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
var demoImg = document.getElementById("img");
|
||||
var PWD = document.getElementById("secret_key");
|
||||
function hideShowPsw() {
|
||||
if (PWD.type == "password") {
|
||||
PWD.type = "text";
|
||||
demoImg.src = "/static/assets/images/icon-invisible.png"; //图片路径(闭眼图片)
|
||||
} else {
|
||||
PWD.type = "password";
|
||||
demoImg.src = "/static/assets/images/icon-visible.png"; // 图片路径(睁眼图片)
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -13,6 +13,8 @@ urlpatterns = [
|
||||
path('backup', views.BackupView.as_view()),
|
||||
path('backup/export', views_request.backupExport),
|
||||
path('backup/import', views_request.backupImport),
|
||||
path('backup/list', views_request.backupList),
|
||||
path('backup/del', views_request.backupDel),
|
||||
#补签
|
||||
path('signagain', views_request.signAgain),
|
||||
path('signcheck', views_request.signCheck),
|
||||
|
||||
@@ -5,68 +5,6 @@ from django.http import JsonResponse
|
||||
from django.conf import settings
|
||||
from git.repo import Repo
|
||||
|
||||
# Create your views here.
|
||||
#------------------------------
|
||||
#class BaiDuOcrView(LoginRequiredMixin,TemplateView):
|
||||
#"""
|
||||
#百度OCR配置
|
||||
#"""
|
||||
#template_name = 'common/baidu_ocr.html'
|
||||
|
||||
##显示添加模板
|
||||
#def get(self, request, *args, **kwargs):
|
||||
#"""
|
||||
#得到
|
||||
#"""
|
||||
|
||||
#return super(BaiDuOcrView, self).get(request, *args, **kwargs)
|
||||
|
||||
##显示编辑模板
|
||||
#def get_context_data(self, **kwargs):
|
||||
|
||||
##获取记录
|
||||
#orm_count = BaiDuOcr.objects.count()
|
||||
#if orm_count == 0:
|
||||
|
||||
#context = {}
|
||||
#else:
|
||||
##获取一条数据
|
||||
#ormdata = BaiDuOcr.objects.first()
|
||||
#context = {
|
||||
#'id': ormdata.id,
|
||||
#'app_id': ormdata.app_id,
|
||||
#'app_key': ormdata.app_key,
|
||||
#'secret_key': ormdata.secret_key,
|
||||
#}
|
||||
#kwargs.update(context)
|
||||
#return super(BaiDuOcrView, self).get_context_data(**kwargs)
|
||||
|
||||
##数据提交接收方法
|
||||
#def post(self, request, *args, **kwargs):
|
||||
#"""
|
||||
#数据提交
|
||||
#"""
|
||||
#_id = request.POST.get('id','')
|
||||
#app_id = request.POST.get("app_id").strip()
|
||||
#app_key = request.POST.get("app_key").strip()
|
||||
#secret_key = request.POST.get("secret_key").strip()
|
||||
|
||||
#if _id == '':
|
||||
#ormdata = BaiDuOcr.objects.create(app_id=app_id,
|
||||
#app_key=app_key,
|
||||
#secret_key=secret_key,
|
||||
#)
|
||||
#else:
|
||||
#ormdata = BaiDuOcr.objects.get(id=_id)
|
||||
#ormdata.app_id = app_id
|
||||
#ormdata.app_key = app_key
|
||||
#ormdata.secret_key = secret_key
|
||||
|
||||
#ormdata.save()
|
||||
|
||||
#response_data={"code":1,"msg":"添加成功"}
|
||||
|
||||
#return JsonResponse(response_data)
|
||||
|
||||
class BackupView(LoginRequiredMixin,TemplateView):
|
||||
"""
|
||||
|
||||
@@ -7,7 +7,8 @@ from django.core.management import call_command
|
||||
import logging
|
||||
import tempfile
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
import simplejson as json
|
||||
|
||||
from sites.models import SiteInfo,SiteConfig
|
||||
from cron.models import Log
|
||||
@@ -22,23 +23,27 @@ def backupExport(request):
|
||||
logger = logging.getLogger('django')
|
||||
|
||||
if request.method == "POST":
|
||||
action = request.POST.get('action','')
|
||||
|
||||
backup_file = os.path.join(settings.BACKUP_DIR,'pthelper.json')
|
||||
logger.info("Starting backup process.")
|
||||
#backup_file = os.path.join(settings.BACKUP_DIR,'pthelper.json')
|
||||
backup_file = os.path.join(settings.BACKUP_DIR,'export_{}.json'.format(datetime.now().strftime("%Y-%m-%d_%H-%M")))
|
||||
logger.info("开始导出数据.")
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
dump_path = os.path.join(d, 'dump.json')
|
||||
logger.info("Starting data dump...")
|
||||
|
||||
#call_command('dumpdata', '--exclude','cron.Log',natural_foreign=True, output=dump_path)
|
||||
call_command('dumpdata', exclude=['cron.Log'], natural_foreign=True, output=dump_path)
|
||||
#call_command('dumpdata', exclude=['cron.Log'], natural_foreign=True, output=dump_path, format='json', indent=4)
|
||||
call_command('dumpdata', exclude=['authtoken.Token'], natural_foreign=True, natural_primary=True, output=dump_path, format='json', indent=4)
|
||||
|
||||
logger.info("Data dumped.")
|
||||
logger.info("Copying BACKUP_DIR to %s...", backup_file)
|
||||
#shutil.copytree(settings.MEDIA_ROOT, os.path.join(d, 'media'))
|
||||
shutil.copyfile(dump_path, backup_file)
|
||||
|
||||
logger.info('Copy done.')
|
||||
logger.info("备份完成.")
|
||||
logger.info("开始转换备份文件 %s...", backup_file)
|
||||
#将乱码转换成中文
|
||||
with open(dump_path) as f:
|
||||
data = json.load(f)
|
||||
with open(backup_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
logger.info('转换完成.')
|
||||
#backup_path = os.path.join(settings.BACKUP_DIR, datetime.date.today().strftime("%Y-%m-%d.zip"))
|
||||
#with zipfile.ZipFile(backup_path, mode='w') as backup_zip:
|
||||
#for root, dirs, files in os.walk(d):
|
||||
@@ -49,7 +54,7 @@ def backupExport(request):
|
||||
#arcname=os.path.relpath(filepath, d))
|
||||
#logger.info("{} created.".format(backup_path))
|
||||
|
||||
response_data={"code":0,"msg":"ok" }
|
||||
response_data={"code":1,"msg":"备份完成" }
|
||||
|
||||
return JsonResponse(response_data)
|
||||
|
||||
@@ -59,17 +64,57 @@ def backupImport(request):
|
||||
"""
|
||||
数据恢复
|
||||
"""
|
||||
logger = logging.getLogger('django')
|
||||
|
||||
if request.method == "POST":
|
||||
action = request.POST.get('action','')
|
||||
|
||||
backup_file = os.path.join(settings.BACKUP_DIR,'pthelper.json')
|
||||
logger.info("Starting load process.")
|
||||
|
||||
call_command('loaddata', backup_file)
|
||||
name = request.POST.get('name')
|
||||
backup_file = os.path.join(settings.BACKUP_DIR, name)
|
||||
try:
|
||||
|
||||
call_command('loaddata', backup_file)
|
||||
|
||||
response_data={"code":1,"msg":"恢复完成" }
|
||||
except Exception as e:
|
||||
response_data={"code":0,"msg":"恢复失败" + str(e) }
|
||||
|
||||
return JsonResponse(response_data)
|
||||
|
||||
#==================
|
||||
@login_required
|
||||
def backupList(request):
|
||||
"""
|
||||
列出备份数据
|
||||
"""
|
||||
data = {}
|
||||
data['code'] = 0
|
||||
data['msg'] = ""
|
||||
data['data'] = []
|
||||
|
||||
for file_name in os.listdir(settings.BACKUP_DIR):
|
||||
data['data'].append({"name":file_name,
|
||||
"url": "/backups/" + file_name
|
||||
})
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
#==================
|
||||
@login_required
|
||||
def backupDel(request):
|
||||
"""
|
||||
删除备份数据
|
||||
"""
|
||||
name = request.POST.get('name')
|
||||
backup_file = os.path.join(settings.BACKUP_DIR, name)
|
||||
try:
|
||||
|
||||
os.remove(backup_file)
|
||||
|
||||
response_data={"code":1,"msg":"删除成功" }
|
||||
except Exception as e:
|
||||
response_data={"code":0,"msg":"删除失败" + str(e) }
|
||||
|
||||
return JsonResponse(response_data)
|
||||
|
||||
#==================
|
||||
@login_required
|
||||
def signAgain(request):
|
||||
|
||||
23
apps/rss/migrations/0017_config_name_alter_config_url.py
Normal file
23
apps/rss/migrations/0017_config_name_alter_config_url.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.1 on 2022-09-22 15:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rss', '0016_rule_is_paused'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='config',
|
||||
name='name',
|
||||
field=models.CharField(max_length=50, null=True, verbose_name='自定义配置名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='config',
|
||||
name='url',
|
||||
field=models.URLField(blank=True, max_length=350, unique=True, verbose_name='RSS地址'),
|
||||
),
|
||||
]
|
||||
@@ -27,7 +27,8 @@ class FilmType(models.Model):
|
||||
|
||||
class Config(models.Model):
|
||||
"""RSS配置"""
|
||||
url = models.URLField('RSS地址', blank=True, max_length=350)
|
||||
name = models.CharField('自定义配置名称', max_length=50, null=True)
|
||||
url = models.URLField('RSS地址', blank=True, max_length=350, unique=True)
|
||||
#site_name = models.CharField('网站名简称,英文', max_length=50, unique=True)
|
||||
#site_name_cn = models.CharField('网站名简称,中文', max_length=50, unique=True)
|
||||
#on_update 和 on_delete 后面可以跟的词语有四个
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
cols: [[
|
||||
{ type: 'checkbox' },
|
||||
{ field: 'id', title: 'ID', hide: true },
|
||||
{ field: 'name', title: '配置名', width: 200 },
|
||||
{ field: 'site_name', sort: true, title: '站点', width: 180 },
|
||||
{ field: 'url', sort: true, title: 'RSS地址' },
|
||||
{ align: 'center', toolbar: '#rssconfigTableBar', title: '操作', width: 150 }
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<!-- 表单弹窗 -->
|
||||
<form id="rssconfigAddForm" lay-filter="rssconfigAddForm" class="layui-form model-form" method="POST">{% csrf_token %}
|
||||
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">配置名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input name="name" type="text" class="layui-input" lay-verify="required"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点名称</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -54,7 +61,7 @@
|
||||
|
||||
/* 获取所有记录类型 */
|
||||
var loadIndex = layer.load(2);
|
||||
admin.req('sites/siteinfo/select/list', function (res) {
|
||||
admin.req('sites/siteinfo/select/list?flag=1', function (res) {
|
||||
layer.close(loadIndex);
|
||||
if (0 === res.code) {
|
||||
$.each(res.data, function (index, item) {
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
<form id="rssconfigEditForm" lay-filter="rssconfigEditForm" class="layui-form model-form" method="POST">{% csrf_token %}
|
||||
<input name="id" type="hidden" value="{{id}}"/>
|
||||
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">配置名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input name="name" type="text" class="layui-input" lay-verify="required" value="{{name}}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点名称</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
@@ -68,7 +68,8 @@
|
||||
cols: [[
|
||||
{ type: 'checkbox' },
|
||||
{ field: 'id', title: 'ID', hide: true },
|
||||
{ field: 'name', sort: true, title: '名称', width: 120 },
|
||||
{ field: 'name', sort: true, title: '规则名称', width: 120 },
|
||||
{ field: 'config_name', sort: true, title: '配置名称', width: 120 },
|
||||
{ field: 'config_id', sort: true, title: '站点', width: 150 },
|
||||
{ field: 'tools_id', sort: true, title: '下载器', width: 200 },
|
||||
{ field: 'keyword', title: '关键字'},
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">RSS站点</label>
|
||||
<label class="layui-form-label">配置名</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="config_id"></div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">RSS站点</label>
|
||||
<label class="layui-form-label">配置名</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="config_id"></div>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
{ field: 'siteinfo_id', sort: true, title: '站点', width: 150 },
|
||||
{ field: 'seed_details_link', title: '种子介绍页', hide: true },
|
||||
{ field: 'seed_name', title: '名称', templet: function (d) {
|
||||
return '<a href="' + d.seed_details_link +'" target="_blank" id="test'+d.id+'" onmouseover="show('+ d.id +')"; onmouseleave="closeTips();">' + d.seed_name + '</a>';
|
||||
//return '<a href="' + d.seed_details_link +'" target="_blank" id="test'+d.id+'" onmouseover="show('+ d.id +')"; onmouseleave="closeTips();">' + d.seed_name + '</a>';
|
||||
return '<a href="' + d.seed_details_link +'" target="_blank" lay-direction="1" lay-tips="鼠标点击访问种子详情页<br>' + d.seed_name +'">' + d.seed_name + '</a>';
|
||||
}, unresize: true
|
||||
},
|
||||
{ field: 'seed_type', sort: true, title: '类型', width: 150 },
|
||||
|
||||
@@ -62,12 +62,14 @@ class RssConfigAddView(LoginRequiredMixin,TemplateView):
|
||||
"""
|
||||
数据提交
|
||||
"""
|
||||
name = request.POST.get("name","").strip()
|
||||
siteinfo_id = request.POST.get("siteinfo_id").strip()
|
||||
url = request.POST.get("url").strip()
|
||||
|
||||
ormdata_siteinfo = SiteInfo.objects.get(id=int(siteinfo_id))
|
||||
|
||||
ormdata = Config.objects.create(url=url,
|
||||
ormdata = Config.objects.create(name=name,
|
||||
url=url,
|
||||
siteinfo_id=ormdata_siteinfo
|
||||
)
|
||||
|
||||
@@ -101,6 +103,7 @@ class RssConfigEditView(LoginRequiredMixin,TemplateView):
|
||||
|
||||
context = {
|
||||
'id': self._id,
|
||||
'name': self.ormdata.name,
|
||||
'url': self.ormdata.url,
|
||||
'siteinfo_id': self.ormdata.siteinfo_id.id
|
||||
}
|
||||
@@ -112,6 +115,7 @@ class RssConfigEditView(LoginRequiredMixin,TemplateView):
|
||||
"""
|
||||
数据提交
|
||||
"""
|
||||
name = request.POST.get("name","").strip()
|
||||
url = request.POST.get("url").strip()
|
||||
siteinfo_id = request.POST.get("siteinfo_id").strip()
|
||||
|
||||
@@ -122,6 +126,7 @@ class RssConfigEditView(LoginRequiredMixin,TemplateView):
|
||||
ormdata = Config.objects.get(id=_id)
|
||||
|
||||
ormdata.url = url
|
||||
ormdata.name = name
|
||||
ormdata.siteinfo_id=ormdata_siteinfo
|
||||
|
||||
ormdata.save()
|
||||
|
||||
@@ -54,17 +54,18 @@ def config(request):
|
||||
ormdata = Config.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
|
||||
else:
|
||||
|
||||
data['count'] = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).count()
|
||||
data['count'] = Config.objects.filter(Q(name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).count()
|
||||
if pageIndex == 1:
|
||||
ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
|
||||
ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
|
||||
else:
|
||||
ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
|
||||
ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
|
||||
|
||||
for i in ormdata:
|
||||
|
||||
data['data'].append({"id":i.id,
|
||||
"site_name":i.siteinfo_id.siteconfig_name + '(' + i.siteinfo_id.siteconfig_name_cn + ')',
|
||||
"url":i.url,
|
||||
"name":i.name,
|
||||
})
|
||||
#返回json串
|
||||
#return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
|
||||
@@ -121,7 +122,7 @@ def rule(request):
|
||||
for i in ormdata:
|
||||
|
||||
data['data'].append({"id":i.id,
|
||||
#"config_id":i.config_id.siteinfo_id.siteconfig_name_cn,
|
||||
"config_name":i.config_id.name,
|
||||
"config_id":i.config_id.siteinfo_id.siteconfig_name + '(' + i.config_id.siteinfo_id.siteconfig_name_cn + ')',
|
||||
"tools_id":i.tools_id.name,
|
||||
"name":i.name,
|
||||
@@ -263,7 +264,8 @@ def select_rssconfig(request):
|
||||
for i in ormdata:
|
||||
data['data'].append({
|
||||
"id":i.id,
|
||||
"name":i.siteinfo_id.siteconfig_name + "(" + i.siteinfo_id.siteconfig_name_cn + ")"
|
||||
#"name":i.siteinfo_id.siteconfig_name + "(" + i.siteinfo_id.siteconfig_name_cn + ")"
|
||||
"name":i.name + "-----" +i.siteinfo_id.siteconfig_name + "(" + i.siteinfo_id.siteconfig_name_cn + ")"
|
||||
})
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
@@ -19,6 +19,10 @@ import environ
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
|
||||
#在win下解决gbk问题(导出数据)
|
||||
import _locale
|
||||
_locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8'])
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -233,6 +237,7 @@ APSCHEDULER_RUN_NOW_TIMEOUT = 25 # Seconds
|
||||
TMP_LOG_DIR = os.path.join(BASE_DIR, "tmp")
|
||||
if not os.path.exists(TMP_LOG_DIR): os.mkdir(TMP_LOG_DIR)
|
||||
|
||||
BACKUP_URL = "backups/"
|
||||
BACKUP_DIR = os.path.join(BASE_DIR, 'backups')
|
||||
if not os.path.exists(BACKUP_DIR): os.mkdir(BACKUP_DIR)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user