yp_library.jobs 源代码

import os
from datetime import datetime, timedelta
import copy

import pymssql
from django.db.models import Max, Q
from django.db import transaction

from scheduler.periodic import periodical
from yp_library.models import Reader, Book, LendRecord
from yp_library.utils import days_reminder, violate_reminder


[文档] def update_reader(): """ 更新读者信息 """ with pymssql.connect(server=os.environ["LIB_DB_HOST"], user=os.environ["LIB_DB_USER"], password=os.environ["LIB_DB_PASSWORD"], database=os.environ["LIB_DB"], login_timeout=5) as conn: with conn.cursor(as_dict=True) as cursor: cursor.execute('SELECT ID,IDCardNo FROM Readers') # 暂时采用全部遍历的更新方式,因为存在空缺的数据较多,待书房的数据修订完成后, # 可以更改为只考虑新增数据 with transaction.atomic(): for row in cursor: Reader.objects.update_or_create( id=row['ID'], defaults={'student_id': row['IDCardNo']})
[文档] def update_book(): """ 更新书籍信息 """ largest_id = Book.objects.aggregate(Max('id'))['id__max'] if not largest_id: largest_id = 0 with pymssql.connect(server=os.environ["LIB_DB_HOST"], user=os.environ["LIB_DB_USER"], password=os.environ["LIB_DB_PASSWORD"], database=os.environ["LIB_DB"], login_timeout=5) as conn: with conn.cursor(as_dict=True) as cursor: # 筛选新增数据 cursor.execute(f'''SELECT MarcID,Title,Author,Publisher,ReqNo FROM CircMarc WHERE MarcID>{largest_id}''') new_books = [] for row in cursor: new_books.append( Book( id=row['MarcID'], identity_code=row['ReqNo'], title=row['Title'], author=row['Author'], publisher=row['Publisher'], )) with transaction.atomic(): Book.objects.bulk_create(new_books)
[文档] def update_records(): """ 更新借书记录 """ # 本地最新记录的时间 latest_record_time = LendRecord.objects.aggregate( Max('lend_time'))['lend_time__max'] if not latest_record_time: latest_record_time = datetime.now() - timedelta(days=3650) else: latest_record_time += timedelta(seconds=1) with pymssql.connect(server=os.environ["LIB_DB_HOST"], user=os.environ["LIB_DB_USER"], password=os.environ["LIB_DB_PASSWORD"], database=os.environ["LIB_DB"], login_timeout=5) as conn: with conn.cursor(as_dict=True) as cursor: # 新增借书记录 cursor.execute(f'''SELECT ID,ReaderID,BarCode,LendTM,DueTm FROM LendHist WHERE LendTM > convert(datetime, '{latest_record_time.strftime('%Y-%m-%d %H:%M:%S')}')''' ) results = copy.copy(cursor.fetchall()) with transaction.atomic(): for row in results: bar_code = row['BarCode'].strip()[-6:] # 根据BarCode查询书的编号 cursor.execute(f"""SELECT MarcID FROM Items WHERE BarCode LIKE '%{bar_code}%'""") book_id = cursor.fetchone() if not book_id: book_id = None else: book_id = book_id['MarcID'] reader_id = row['ReaderID'] if not Reader.objects.filter(id=reader_id).exists(): continue LendRecord.objects.update_or_create(id=row['ID'], defaults={ 'reader_id_id': reader_id, 'book_id_id': book_id, 'lend_time': row['LendTM'], 'due_time': row['DueTm'], }) # 未归还的借书记录 unreturned_records = LendRecord.objects.filter(returned=False) # 转换为方便sql查询的形式 unreturned_record_id = list( unreturned_records.values_list('id', flat=True)) unreturned_record_id = ', '.join( list(map(str, unreturned_record_id))) # 更新未归还记录 cursor.execute(f'''SELECT ID,IsReturn,ReturnTime FROM LendHist WHERE ID IN ({unreturned_record_id})''') updated_records = [] for row in cursor: record: LendRecord = unreturned_records.get(id=row['ID']) if row['IsReturn'] == 1: record.returned = True record.return_time = row['ReturnTime'] updated_records.append(record) with transaction.atomic(): LendRecord.objects.bulk_update( updated_records, fields=['returned', 'return_time'], )
[文档] def update_book_status(): time_lower_bound = datetime.now() - timedelta(days=1) recent_records = LendRecord.objects.filter( Q(lend_time__gt=time_lower_bound) | Q(return_time__gt=time_lower_bound)).values_list('book_id', flat=True) books = Book.objects.filter(id__in=recent_records) for book in books: book.returned = not book.lendrecord_set.filter(returned=False).exists() with transaction.atomic(): Book.objects.bulk_update(books, fields=['returned'])
[文档] @periodical('cron', minute=50) def update_lib_data(): update_book_status() update_reader() update_book() update_records()
[文档] @periodical('cron', minute=0) def bookreturn_notification(): """ 该函数每小时在外部被调用,对每一条未归还的借阅记录进行检查 在应还书时间前1天、应还书时间、应还书时间逾期5天发送还书提醒,提醒链接到“我的借阅”界面 在应还书时间逾期7天,将借阅信息改为“超时扣分”,扣除1信用分并发送提醒 """ # 调用days_reminder()发送 days_reminder(-1, '您好!您现有未归还的图书,将于一天内借阅到期,请按时归还至元培书房!') days_reminder(0, '您好!您现有未归还的图书,已经借阅到期,请及时归还至元培书房!') days_reminder(5, '您好!您现有未归还的图书,已经借阅到期五天,请尽快归还至元培书房!到期一周未归还将扣除您的信用分1分!') days_reminder(7, '您好!您现有未归还的图书,已经借阅到期一周,请尽快归还至元培书房!') violate_reminder(7, '由于借阅超时一周,您已被扣除信用分1分!')