qrpa 1.1.32__py3-none-any.whl → 1.1.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qrpa might be problematic. Click here for more details.
- qrpa/RateLimitedSender.py +45 -45
- qrpa/__init__.py +31 -31
- qrpa/db_migrator.py +600 -600
- qrpa/feishu_bot_app.py +267 -267
- qrpa/fun_base.py +339 -339
- qrpa/fun_excel.py +3059 -3059
- qrpa/fun_file.py +318 -318
- qrpa/fun_web.py +258 -258
- qrpa/fun_win.py +198 -198
- qrpa/mysql_module/new_product_analysis_model.py +429 -0
- qrpa/mysql_module/shein_ledger_model.py +468 -468
- qrpa/mysql_module/shein_product_model.py +484 -484
- qrpa/mysql_module/shein_return_order_model.py +569 -569
- qrpa/shein_daily_report_model.py +375 -375
- qrpa/shein_excel.py +3125 -3125
- qrpa/shein_lib.py +3932 -3609
- qrpa/shein_mysql.py +22 -0
- qrpa/shein_sqlite.py +153 -153
- qrpa/shein_ziniao.py +529 -529
- qrpa/temu_chrome.py +56 -56
- qrpa/temu_excel.py +139 -139
- qrpa/temu_lib.py +154 -154
- qrpa/time_utils.py +882 -882
- qrpa/time_utils_example.py +243 -243
- qrpa/wxwork.py +318 -318
- {qrpa-1.1.32.dist-info → qrpa-1.1.34.dist-info}/METADATA +1 -1
- qrpa-1.1.34.dist-info/RECORD +32 -0
- qrpa-1.1.32.dist-info/RECORD +0 -31
- {qrpa-1.1.32.dist-info → qrpa-1.1.34.dist-info}/WHEEL +0 -0
- {qrpa-1.1.32.dist-info → qrpa-1.1.34.dist-info}/top_level.txt +0 -0
qrpa/shein_daily_report_model.py
CHANGED
|
@@ -1,375 +1,375 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
店铺销售明细数据模型
|
|
5
|
-
使用SQLAlchemy定义store_sales_detail表结构
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from sqlalchemy import and_
|
|
9
|
-
from sqlalchemy import create_engine, Column, Integer, String, Date, DECIMAL, UniqueConstraint
|
|
10
|
-
# from sqlalchemy.ext.declarative import declarative_base
|
|
11
|
-
from sqlalchemy.orm import declarative_base
|
|
12
|
-
from sqlalchemy.orm import sessionmaker
|
|
13
|
-
|
|
14
|
-
from datetime import datetime, timedelta
|
|
15
|
-
|
|
16
|
-
from sqlalchemy import distinct
|
|
17
|
-
|
|
18
|
-
# 创建基础类
|
|
19
|
-
Base = declarative_base()
|
|
20
|
-
|
|
21
|
-
# 定义模型类
|
|
22
|
-
class SheinStoreSalesDetail(Base):
|
|
23
|
-
__tablename__ = 'store_sales_detail'
|
|
24
|
-
|
|
25
|
-
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
26
|
-
store_username = Column(String(255), nullable=True)
|
|
27
|
-
store_name = Column(String(255), nullable=True)
|
|
28
|
-
day = Column(Date, nullable=True)
|
|
29
|
-
sales_num = Column(Integer, nullable=True)
|
|
30
|
-
sales_num_inc = Column(Integer, nullable=True)
|
|
31
|
-
sales_amount = Column(DECIMAL(10, 2), nullable=True)
|
|
32
|
-
sales_amount_inc = Column(DECIMAL(10, 2), nullable=True)
|
|
33
|
-
visitor_num = Column(Integer, nullable=True)
|
|
34
|
-
visitor_num_inc = Column(Integer, nullable=True)
|
|
35
|
-
bak_A_num = Column(Integer, nullable=True)
|
|
36
|
-
bak_A_num_inc = Column(Integer, nullable=True)
|
|
37
|
-
new_A_num = Column(Integer, nullable=True)
|
|
38
|
-
new_A_num_inc = Column(Integer, nullable=True)
|
|
39
|
-
on_sales_product_num = Column(Integer, nullable=True)
|
|
40
|
-
on_sales_product_num_inc = Column(Integer, nullable=True)
|
|
41
|
-
wait_shelf_product_num = Column(Integer, nullable=True)
|
|
42
|
-
wait_shelf_product_num_inc = Column(Integer, nullable=True)
|
|
43
|
-
upload_product_num = Column(Integer, nullable=True)
|
|
44
|
-
upload_product_num_inc = Column(Integer, nullable=True)
|
|
45
|
-
sold_out_product_num = Column(Integer, nullable=True)
|
|
46
|
-
shelf_off_product_num = Column(Integer, nullable=True)
|
|
47
|
-
remark = Column(String(255), nullable=True)
|
|
48
|
-
|
|
49
|
-
__table_args__ = (
|
|
50
|
-
UniqueConstraint('store_username', 'day', name='uq_store_day'),
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def __repr__(self):
|
|
54
|
-
return f"<SheinStoreSalesDetail(store_username={self.store_username}, store_name={self.store_name}, day={self.day})>"
|
|
55
|
-
|
|
56
|
-
class SheinStoreSalesDetailManager:
|
|
57
|
-
"""
|
|
58
|
-
店铺销售明细数据管理器
|
|
59
|
-
提供数据库操作相关方法
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
# database_url = f"mysql+pymysql://{config.mysql_username}:{config.mysql_password}@{config.mysql_host}:{config.mysql_port}/{config.mysql_database}"
|
|
63
|
-
|
|
64
|
-
def __init__(self, database_url=None):
|
|
65
|
-
"""
|
|
66
|
-
初始化数据库连接
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
database_url (str): 数据库连接URL,例如:
|
|
70
|
-
mysql+pymysql://username:password@localhost:3306/database_name
|
|
71
|
-
"""
|
|
72
|
-
if database_url is None:
|
|
73
|
-
database_url = self.database_url
|
|
74
|
-
|
|
75
|
-
self.engine = create_engine(database_url, echo=False)
|
|
76
|
-
self.Session = sessionmaker(bind=self.engine)
|
|
77
|
-
|
|
78
|
-
def create_tables(self):
|
|
79
|
-
"""
|
|
80
|
-
创建数据表
|
|
81
|
-
"""
|
|
82
|
-
Base.metadata.create_all(self.engine)
|
|
83
|
-
print("✅ 数据表检查并创建完毕(如不存在则自动创建)")
|
|
84
|
-
|
|
85
|
-
def drop_tables(self):
|
|
86
|
-
"""
|
|
87
|
-
删除数据表
|
|
88
|
-
"""
|
|
89
|
-
Base.metadata.drop_all(self.engine)
|
|
90
|
-
print("数据表删除成功!")
|
|
91
|
-
|
|
92
|
-
def get_session(self):
|
|
93
|
-
"""
|
|
94
|
-
创建会话
|
|
95
|
-
|
|
96
|
-
Returns:
|
|
97
|
-
session: SQLAlchemy会话对象
|
|
98
|
-
"""
|
|
99
|
-
return self.Session()
|
|
100
|
-
|
|
101
|
-
def get_all_records(self):
|
|
102
|
-
"""
|
|
103
|
-
查询所有记录
|
|
104
|
-
|
|
105
|
-
Returns:
|
|
106
|
-
list: 所有销售明细记录列表
|
|
107
|
-
"""
|
|
108
|
-
session = self.get_session()
|
|
109
|
-
try:
|
|
110
|
-
records = session.query(SheinStoreSalesDetail).all()
|
|
111
|
-
return records
|
|
112
|
-
finally:
|
|
113
|
-
session.close()
|
|
114
|
-
|
|
115
|
-
def get_records_by_username_and_day(self, username, query_day):
|
|
116
|
-
"""
|
|
117
|
-
查询特定用户名和日期的记录
|
|
118
|
-
|
|
119
|
-
Args:
|
|
120
|
-
username (str): 店铺用户名
|
|
121
|
-
query_day (date): 查询日期
|
|
122
|
-
|
|
123
|
-
Returns:
|
|
124
|
-
list: 符合条件的记录列表
|
|
125
|
-
"""
|
|
126
|
-
session = self.get_session()
|
|
127
|
-
try:
|
|
128
|
-
records = session.query(SheinStoreSalesDetail).filter(
|
|
129
|
-
SheinStoreSalesDetail.store_username == username,
|
|
130
|
-
SheinStoreSalesDetail.day == query_day
|
|
131
|
-
).all()
|
|
132
|
-
return records
|
|
133
|
-
finally:
|
|
134
|
-
session.close()
|
|
135
|
-
|
|
136
|
-
def get_records_sorted_by_sales_amount(self):
|
|
137
|
-
"""
|
|
138
|
-
查询记录并按销售金额排序
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
list: 按销售金额倒序排列的记录列表
|
|
142
|
-
"""
|
|
143
|
-
session = self.get_session()
|
|
144
|
-
try:
|
|
145
|
-
records = session.query(SheinStoreSalesDetail).order_by(SheinStoreSalesDetail.sales_amount.desc()).all()
|
|
146
|
-
return records
|
|
147
|
-
finally:
|
|
148
|
-
session.close()
|
|
149
|
-
|
|
150
|
-
def get_limited_records(self, limit):
|
|
151
|
-
"""
|
|
152
|
-
查询并限制结果数量
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
limit (int): 限制的记录数量
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
list: 限制数量的记录列表
|
|
159
|
-
"""
|
|
160
|
-
session = self.get_session()
|
|
161
|
-
try:
|
|
162
|
-
records = session.query(SheinStoreSalesDetail).limit(limit).all()
|
|
163
|
-
return records
|
|
164
|
-
finally:
|
|
165
|
-
session.close()
|
|
166
|
-
|
|
167
|
-
def get_records_by_usernames(self, usernames):
|
|
168
|
-
"""
|
|
169
|
-
查询多个店铺用户名的记录
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
usernames (list): 店铺用户名列表
|
|
173
|
-
|
|
174
|
-
Returns:
|
|
175
|
-
list: 符合条件的记录列表
|
|
176
|
-
"""
|
|
177
|
-
session = self.get_session()
|
|
178
|
-
try:
|
|
179
|
-
records = session.query(SheinStoreSalesDetail).filter(
|
|
180
|
-
SheinStoreSalesDetail.store_username.in_(usernames)
|
|
181
|
-
).all()
|
|
182
|
-
return records
|
|
183
|
-
finally:
|
|
184
|
-
session.close()
|
|
185
|
-
|
|
186
|
-
def record_to_dict(self, record):
|
|
187
|
-
"""
|
|
188
|
-
将记录转换为字典
|
|
189
|
-
|
|
190
|
-
Args:
|
|
191
|
-
record: SQLAlchemy记录对象
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
dict: 记录字典
|
|
195
|
-
"""
|
|
196
|
-
return {column.name: getattr(record, column.name) for column in record.__table__.columns}
|
|
197
|
-
|
|
198
|
-
def get_records_by_condition(self, filter_condition, order_by=None):
|
|
199
|
-
"""
|
|
200
|
-
公共查询函数(包含排序功能)
|
|
201
|
-
|
|
202
|
-
Args:
|
|
203
|
-
filter_condition: SQLAlchemy过滤条件
|
|
204
|
-
order_by: 排序条件
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
list: 符合条件的记录列表
|
|
208
|
-
"""
|
|
209
|
-
session = self.get_session()
|
|
210
|
-
try:
|
|
211
|
-
# 执行查询,添加排序功能
|
|
212
|
-
query = session.query(SheinStoreSalesDetail).filter(filter_condition)
|
|
213
|
-
|
|
214
|
-
# 如果传入了排序条件,则加入排序
|
|
215
|
-
if order_by is not None:
|
|
216
|
-
query = query.order_by(order_by)
|
|
217
|
-
|
|
218
|
-
# 获取查询结果
|
|
219
|
-
records = query.all()
|
|
220
|
-
return records
|
|
221
|
-
|
|
222
|
-
except Exception as e:
|
|
223
|
-
import traceback
|
|
224
|
-
print("数据库错误:", e)
|
|
225
|
-
traceback.print_exc()
|
|
226
|
-
return []
|
|
227
|
-
|
|
228
|
-
finally:
|
|
229
|
-
# 确保会话关闭
|
|
230
|
-
session.close()
|
|
231
|
-
|
|
232
|
-
def get_distinct_store_sales_list(self):
|
|
233
|
-
"""
|
|
234
|
-
获取 distinct 的 store_username 和 store_name
|
|
235
|
-
|
|
236
|
-
Returns:
|
|
237
|
-
list: 唯一店铺用户名列表
|
|
238
|
-
"""
|
|
239
|
-
session = self.get_session()
|
|
240
|
-
try:
|
|
241
|
-
# 执行 distinct 查询,选择唯一的 store_username 和 store_name
|
|
242
|
-
records = session.query(
|
|
243
|
-
distinct(SheinStoreSalesDetail.store_username)
|
|
244
|
-
).all()
|
|
245
|
-
|
|
246
|
-
# 转换查询结果为二维列表格式
|
|
247
|
-
result = [[record[0], ''] for record in records]
|
|
248
|
-
return result
|
|
249
|
-
|
|
250
|
-
finally:
|
|
251
|
-
# 确保会话关闭
|
|
252
|
-
session.close()
|
|
253
|
-
|
|
254
|
-
def get_one_day_records(self, yesterday, order_by=None):
|
|
255
|
-
"""
|
|
256
|
-
获取单日数据
|
|
257
|
-
|
|
258
|
-
Args:
|
|
259
|
-
yesterday (str): 日期字符串,格式:'YYYY-MM-DD'
|
|
260
|
-
order_by: 排序条件,默认按销售数量倒序
|
|
261
|
-
|
|
262
|
-
Returns:
|
|
263
|
-
list: 指定日期的记录列表
|
|
264
|
-
"""
|
|
265
|
-
if order_by is None:
|
|
266
|
-
order_by = SheinStoreSalesDetail.sales_num.desc()
|
|
267
|
-
|
|
268
|
-
# 将字符串日期转换为 datetime.date 对象
|
|
269
|
-
yesterday_date = datetime.strptime(yesterday, '%Y-%m-%d').date()
|
|
270
|
-
|
|
271
|
-
# 定义查询条件
|
|
272
|
-
filter_condition = SheinStoreSalesDetail.day == yesterday_date
|
|
273
|
-
|
|
274
|
-
# 使用公共查询函数,传入排序条件
|
|
275
|
-
return self.get_records_by_condition(filter_condition, order_by)
|
|
276
|
-
|
|
277
|
-
def get_one_month_records(self, year, month, username, order_by=None):
|
|
278
|
-
"""
|
|
279
|
-
获取某年某月的数据
|
|
280
|
-
|
|
281
|
-
Args:
|
|
282
|
-
year (int): 年份
|
|
283
|
-
month (int): 月份
|
|
284
|
-
username (str): 店铺用户名
|
|
285
|
-
order_by: 排序条件,默认按日期升序
|
|
286
|
-
|
|
287
|
-
Returns:
|
|
288
|
-
list: 指定月份的记录列表
|
|
289
|
-
"""
|
|
290
|
-
if order_by is None:
|
|
291
|
-
order_by = SheinStoreSalesDetail.day.asc()
|
|
292
|
-
|
|
293
|
-
# 将年份和月份格式化为日期(构造该月的第一天)
|
|
294
|
-
first_day_of_month = datetime(year, month, 1).date()
|
|
295
|
-
|
|
296
|
-
# 获取该月的最后一天
|
|
297
|
-
last_day_of_month = (first_day_of_month.replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1)
|
|
298
|
-
|
|
299
|
-
# 定义查询条件:查询指定年份和月份的记录
|
|
300
|
-
filter_condition = and_(
|
|
301
|
-
SheinStoreSalesDetail.day >= first_day_of_month,
|
|
302
|
-
SheinStoreSalesDetail.day <= last_day_of_month,
|
|
303
|
-
SheinStoreSalesDetail.store_username == username,
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
# 使用公共查询函数,传入排序条件
|
|
307
|
-
return self.get_records_by_condition(filter_condition, order_by)
|
|
308
|
-
|
|
309
|
-
def get_records_as_dict(self, username, query_day_str):
|
|
310
|
-
"""
|
|
311
|
-
获取指定用户名和日期的记录并转换为字典
|
|
312
|
-
|
|
313
|
-
Args:
|
|
314
|
-
username (str): 店铺用户名
|
|
315
|
-
query_day_str (str): 查询日期字符串,格式:'YYYY-MM-DD'
|
|
316
|
-
|
|
317
|
-
Returns:
|
|
318
|
-
dict: 记录字典,如果没有记录则返回空字典
|
|
319
|
-
"""
|
|
320
|
-
# 将字符串日期转换为 datetime.date 对象
|
|
321
|
-
query_day = datetime.strptime(query_day_str, '%Y-%m-%d').date()
|
|
322
|
-
# 获取数据库会话
|
|
323
|
-
session = self.get_session()
|
|
324
|
-
try:
|
|
325
|
-
# 查询特定条件的记录
|
|
326
|
-
records = session.query(SheinStoreSalesDetail).filter(
|
|
327
|
-
SheinStoreSalesDetail.store_username == username,
|
|
328
|
-
SheinStoreSalesDetail.day == query_day
|
|
329
|
-
).all()
|
|
330
|
-
# 如果没有记录,返回一个空字典
|
|
331
|
-
if not records:
|
|
332
|
-
return {}
|
|
333
|
-
# 将记录转换为字典
|
|
334
|
-
records_dict = [
|
|
335
|
-
{column.name: getattr(record, column.name) for column in SheinStoreSalesDetail.__table__.columns}
|
|
336
|
-
for record in records
|
|
337
|
-
]
|
|
338
|
-
|
|
339
|
-
return records_dict[0]
|
|
340
|
-
|
|
341
|
-
finally:
|
|
342
|
-
session.close()
|
|
343
|
-
|
|
344
|
-
def insert_data(self, data_list):
|
|
345
|
-
"""
|
|
346
|
-
插入多条数据
|
|
347
|
-
|
|
348
|
-
Args:
|
|
349
|
-
data_list (list): 要插入的数据列表,每个元素为字典格式
|
|
350
|
-
"""
|
|
351
|
-
# 获取会话
|
|
352
|
-
session = self.get_session()
|
|
353
|
-
try:
|
|
354
|
-
# 将字典转换为模型对象并插入
|
|
355
|
-
records = []
|
|
356
|
-
for data in data_list:
|
|
357
|
-
record = SheinStoreSalesDetail(**data) # 将字典解包为关键字参数
|
|
358
|
-
records.append(record)
|
|
359
|
-
# 将所有记录添加到会话
|
|
360
|
-
session.add_all(records)
|
|
361
|
-
# 提交事务
|
|
362
|
-
session.commit()
|
|
363
|
-
print(f"成功插入 {len(records)} 条数据")
|
|
364
|
-
except Exception as e:
|
|
365
|
-
# 如果发生错误,回滚事务
|
|
366
|
-
session.rollback()
|
|
367
|
-
print(f"插入数据时发生错误: {e}")
|
|
368
|
-
#raise
|
|
369
|
-
finally:
|
|
370
|
-
# 关闭会话
|
|
371
|
-
session.close()
|
|
372
|
-
|
|
373
|
-
if __name__ == '__main__':
|
|
374
|
-
# 新的管理器方式示例(取消注释以运行测试)
|
|
375
|
-
pass
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
店铺销售明细数据模型
|
|
5
|
+
使用SQLAlchemy定义store_sales_detail表结构
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from sqlalchemy import and_
|
|
9
|
+
from sqlalchemy import create_engine, Column, Integer, String, Date, DECIMAL, UniqueConstraint
|
|
10
|
+
# from sqlalchemy.ext.declarative import declarative_base
|
|
11
|
+
from sqlalchemy.orm import declarative_base
|
|
12
|
+
from sqlalchemy.orm import sessionmaker
|
|
13
|
+
|
|
14
|
+
from datetime import datetime, timedelta
|
|
15
|
+
|
|
16
|
+
from sqlalchemy import distinct
|
|
17
|
+
|
|
18
|
+
# 创建基础类
|
|
19
|
+
Base = declarative_base()
|
|
20
|
+
|
|
21
|
+
# 定义模型类
|
|
22
|
+
class SheinStoreSalesDetail(Base):
|
|
23
|
+
__tablename__ = 'store_sales_detail'
|
|
24
|
+
|
|
25
|
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
26
|
+
store_username = Column(String(255), nullable=True)
|
|
27
|
+
store_name = Column(String(255), nullable=True)
|
|
28
|
+
day = Column(Date, nullable=True)
|
|
29
|
+
sales_num = Column(Integer, nullable=True)
|
|
30
|
+
sales_num_inc = Column(Integer, nullable=True)
|
|
31
|
+
sales_amount = Column(DECIMAL(10, 2), nullable=True)
|
|
32
|
+
sales_amount_inc = Column(DECIMAL(10, 2), nullable=True)
|
|
33
|
+
visitor_num = Column(Integer, nullable=True)
|
|
34
|
+
visitor_num_inc = Column(Integer, nullable=True)
|
|
35
|
+
bak_A_num = Column(Integer, nullable=True)
|
|
36
|
+
bak_A_num_inc = Column(Integer, nullable=True)
|
|
37
|
+
new_A_num = Column(Integer, nullable=True)
|
|
38
|
+
new_A_num_inc = Column(Integer, nullable=True)
|
|
39
|
+
on_sales_product_num = Column(Integer, nullable=True)
|
|
40
|
+
on_sales_product_num_inc = Column(Integer, nullable=True)
|
|
41
|
+
wait_shelf_product_num = Column(Integer, nullable=True)
|
|
42
|
+
wait_shelf_product_num_inc = Column(Integer, nullable=True)
|
|
43
|
+
upload_product_num = Column(Integer, nullable=True)
|
|
44
|
+
upload_product_num_inc = Column(Integer, nullable=True)
|
|
45
|
+
sold_out_product_num = Column(Integer, nullable=True)
|
|
46
|
+
shelf_off_product_num = Column(Integer, nullable=True)
|
|
47
|
+
remark = Column(String(255), nullable=True)
|
|
48
|
+
|
|
49
|
+
__table_args__ = (
|
|
50
|
+
UniqueConstraint('store_username', 'day', name='uq_store_day'),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def __repr__(self):
|
|
54
|
+
return f"<SheinStoreSalesDetail(store_username={self.store_username}, store_name={self.store_name}, day={self.day})>"
|
|
55
|
+
|
|
56
|
+
class SheinStoreSalesDetailManager:
|
|
57
|
+
"""
|
|
58
|
+
店铺销售明细数据管理器
|
|
59
|
+
提供数据库操作相关方法
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
# database_url = f"mysql+pymysql://{config.mysql_username}:{config.mysql_password}@{config.mysql_host}:{config.mysql_port}/{config.mysql_database}"
|
|
63
|
+
|
|
64
|
+
def __init__(self, database_url=None):
|
|
65
|
+
"""
|
|
66
|
+
初始化数据库连接
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
database_url (str): 数据库连接URL,例如:
|
|
70
|
+
mysql+pymysql://username:password@localhost:3306/database_name
|
|
71
|
+
"""
|
|
72
|
+
if database_url is None:
|
|
73
|
+
database_url = self.database_url
|
|
74
|
+
|
|
75
|
+
self.engine = create_engine(database_url, echo=False)
|
|
76
|
+
self.Session = sessionmaker(bind=self.engine)
|
|
77
|
+
|
|
78
|
+
def create_tables(self):
|
|
79
|
+
"""
|
|
80
|
+
创建数据表
|
|
81
|
+
"""
|
|
82
|
+
Base.metadata.create_all(self.engine)
|
|
83
|
+
print("✅ 数据表检查并创建完毕(如不存在则自动创建)")
|
|
84
|
+
|
|
85
|
+
def drop_tables(self):
|
|
86
|
+
"""
|
|
87
|
+
删除数据表
|
|
88
|
+
"""
|
|
89
|
+
Base.metadata.drop_all(self.engine)
|
|
90
|
+
print("数据表删除成功!")
|
|
91
|
+
|
|
92
|
+
def get_session(self):
|
|
93
|
+
"""
|
|
94
|
+
创建会话
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
session: SQLAlchemy会话对象
|
|
98
|
+
"""
|
|
99
|
+
return self.Session()
|
|
100
|
+
|
|
101
|
+
def get_all_records(self):
|
|
102
|
+
"""
|
|
103
|
+
查询所有记录
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
list: 所有销售明细记录列表
|
|
107
|
+
"""
|
|
108
|
+
session = self.get_session()
|
|
109
|
+
try:
|
|
110
|
+
records = session.query(SheinStoreSalesDetail).all()
|
|
111
|
+
return records
|
|
112
|
+
finally:
|
|
113
|
+
session.close()
|
|
114
|
+
|
|
115
|
+
def get_records_by_username_and_day(self, username, query_day):
|
|
116
|
+
"""
|
|
117
|
+
查询特定用户名和日期的记录
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
username (str): 店铺用户名
|
|
121
|
+
query_day (date): 查询日期
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
list: 符合条件的记录列表
|
|
125
|
+
"""
|
|
126
|
+
session = self.get_session()
|
|
127
|
+
try:
|
|
128
|
+
records = session.query(SheinStoreSalesDetail).filter(
|
|
129
|
+
SheinStoreSalesDetail.store_username == username,
|
|
130
|
+
SheinStoreSalesDetail.day == query_day
|
|
131
|
+
).all()
|
|
132
|
+
return records
|
|
133
|
+
finally:
|
|
134
|
+
session.close()
|
|
135
|
+
|
|
136
|
+
def get_records_sorted_by_sales_amount(self):
|
|
137
|
+
"""
|
|
138
|
+
查询记录并按销售金额排序
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
list: 按销售金额倒序排列的记录列表
|
|
142
|
+
"""
|
|
143
|
+
session = self.get_session()
|
|
144
|
+
try:
|
|
145
|
+
records = session.query(SheinStoreSalesDetail).order_by(SheinStoreSalesDetail.sales_amount.desc()).all()
|
|
146
|
+
return records
|
|
147
|
+
finally:
|
|
148
|
+
session.close()
|
|
149
|
+
|
|
150
|
+
def get_limited_records(self, limit):
|
|
151
|
+
"""
|
|
152
|
+
查询并限制结果数量
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
limit (int): 限制的记录数量
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
list: 限制数量的记录列表
|
|
159
|
+
"""
|
|
160
|
+
session = self.get_session()
|
|
161
|
+
try:
|
|
162
|
+
records = session.query(SheinStoreSalesDetail).limit(limit).all()
|
|
163
|
+
return records
|
|
164
|
+
finally:
|
|
165
|
+
session.close()
|
|
166
|
+
|
|
167
|
+
def get_records_by_usernames(self, usernames):
|
|
168
|
+
"""
|
|
169
|
+
查询多个店铺用户名的记录
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
usernames (list): 店铺用户名列表
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
list: 符合条件的记录列表
|
|
176
|
+
"""
|
|
177
|
+
session = self.get_session()
|
|
178
|
+
try:
|
|
179
|
+
records = session.query(SheinStoreSalesDetail).filter(
|
|
180
|
+
SheinStoreSalesDetail.store_username.in_(usernames)
|
|
181
|
+
).all()
|
|
182
|
+
return records
|
|
183
|
+
finally:
|
|
184
|
+
session.close()
|
|
185
|
+
|
|
186
|
+
def record_to_dict(self, record):
|
|
187
|
+
"""
|
|
188
|
+
将记录转换为字典
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
record: SQLAlchemy记录对象
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
dict: 记录字典
|
|
195
|
+
"""
|
|
196
|
+
return {column.name: getattr(record, column.name) for column in record.__table__.columns}
|
|
197
|
+
|
|
198
|
+
def get_records_by_condition(self, filter_condition, order_by=None):
|
|
199
|
+
"""
|
|
200
|
+
公共查询函数(包含排序功能)
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
filter_condition: SQLAlchemy过滤条件
|
|
204
|
+
order_by: 排序条件
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
list: 符合条件的记录列表
|
|
208
|
+
"""
|
|
209
|
+
session = self.get_session()
|
|
210
|
+
try:
|
|
211
|
+
# 执行查询,添加排序功能
|
|
212
|
+
query = session.query(SheinStoreSalesDetail).filter(filter_condition)
|
|
213
|
+
|
|
214
|
+
# 如果传入了排序条件,则加入排序
|
|
215
|
+
if order_by is not None:
|
|
216
|
+
query = query.order_by(order_by)
|
|
217
|
+
|
|
218
|
+
# 获取查询结果
|
|
219
|
+
records = query.all()
|
|
220
|
+
return records
|
|
221
|
+
|
|
222
|
+
except Exception as e:
|
|
223
|
+
import traceback
|
|
224
|
+
print("数据库错误:", e)
|
|
225
|
+
traceback.print_exc()
|
|
226
|
+
return []
|
|
227
|
+
|
|
228
|
+
finally:
|
|
229
|
+
# 确保会话关闭
|
|
230
|
+
session.close()
|
|
231
|
+
|
|
232
|
+
def get_distinct_store_sales_list(self):
|
|
233
|
+
"""
|
|
234
|
+
获取 distinct 的 store_username 和 store_name
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
list: 唯一店铺用户名列表
|
|
238
|
+
"""
|
|
239
|
+
session = self.get_session()
|
|
240
|
+
try:
|
|
241
|
+
# 执行 distinct 查询,选择唯一的 store_username 和 store_name
|
|
242
|
+
records = session.query(
|
|
243
|
+
distinct(SheinStoreSalesDetail.store_username)
|
|
244
|
+
).all()
|
|
245
|
+
|
|
246
|
+
# 转换查询结果为二维列表格式
|
|
247
|
+
result = [[record[0], ''] for record in records]
|
|
248
|
+
return result
|
|
249
|
+
|
|
250
|
+
finally:
|
|
251
|
+
# 确保会话关闭
|
|
252
|
+
session.close()
|
|
253
|
+
|
|
254
|
+
def get_one_day_records(self, yesterday, order_by=None):
|
|
255
|
+
"""
|
|
256
|
+
获取单日数据
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
yesterday (str): 日期字符串,格式:'YYYY-MM-DD'
|
|
260
|
+
order_by: 排序条件,默认按销售数量倒序
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
list: 指定日期的记录列表
|
|
264
|
+
"""
|
|
265
|
+
if order_by is None:
|
|
266
|
+
order_by = SheinStoreSalesDetail.sales_num.desc()
|
|
267
|
+
|
|
268
|
+
# 将字符串日期转换为 datetime.date 对象
|
|
269
|
+
yesterday_date = datetime.strptime(yesterday, '%Y-%m-%d').date()
|
|
270
|
+
|
|
271
|
+
# 定义查询条件
|
|
272
|
+
filter_condition = SheinStoreSalesDetail.day == yesterday_date
|
|
273
|
+
|
|
274
|
+
# 使用公共查询函数,传入排序条件
|
|
275
|
+
return self.get_records_by_condition(filter_condition, order_by)
|
|
276
|
+
|
|
277
|
+
def get_one_month_records(self, year, month, username, order_by=None):
|
|
278
|
+
"""
|
|
279
|
+
获取某年某月的数据
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
year (int): 年份
|
|
283
|
+
month (int): 月份
|
|
284
|
+
username (str): 店铺用户名
|
|
285
|
+
order_by: 排序条件,默认按日期升序
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
list: 指定月份的记录列表
|
|
289
|
+
"""
|
|
290
|
+
if order_by is None:
|
|
291
|
+
order_by = SheinStoreSalesDetail.day.asc()
|
|
292
|
+
|
|
293
|
+
# 将年份和月份格式化为日期(构造该月的第一天)
|
|
294
|
+
first_day_of_month = datetime(year, month, 1).date()
|
|
295
|
+
|
|
296
|
+
# 获取该月的最后一天
|
|
297
|
+
last_day_of_month = (first_day_of_month.replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1)
|
|
298
|
+
|
|
299
|
+
# 定义查询条件:查询指定年份和月份的记录
|
|
300
|
+
filter_condition = and_(
|
|
301
|
+
SheinStoreSalesDetail.day >= first_day_of_month,
|
|
302
|
+
SheinStoreSalesDetail.day <= last_day_of_month,
|
|
303
|
+
SheinStoreSalesDetail.store_username == username,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# 使用公共查询函数,传入排序条件
|
|
307
|
+
return self.get_records_by_condition(filter_condition, order_by)
|
|
308
|
+
|
|
309
|
+
def get_records_as_dict(self, username, query_day_str):
|
|
310
|
+
"""
|
|
311
|
+
获取指定用户名和日期的记录并转换为字典
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
username (str): 店铺用户名
|
|
315
|
+
query_day_str (str): 查询日期字符串,格式:'YYYY-MM-DD'
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
dict: 记录字典,如果没有记录则返回空字典
|
|
319
|
+
"""
|
|
320
|
+
# 将字符串日期转换为 datetime.date 对象
|
|
321
|
+
query_day = datetime.strptime(query_day_str, '%Y-%m-%d').date()
|
|
322
|
+
# 获取数据库会话
|
|
323
|
+
session = self.get_session()
|
|
324
|
+
try:
|
|
325
|
+
# 查询特定条件的记录
|
|
326
|
+
records = session.query(SheinStoreSalesDetail).filter(
|
|
327
|
+
SheinStoreSalesDetail.store_username == username,
|
|
328
|
+
SheinStoreSalesDetail.day == query_day
|
|
329
|
+
).all()
|
|
330
|
+
# 如果没有记录,返回一个空字典
|
|
331
|
+
if not records:
|
|
332
|
+
return {}
|
|
333
|
+
# 将记录转换为字典
|
|
334
|
+
records_dict = [
|
|
335
|
+
{column.name: getattr(record, column.name) for column in SheinStoreSalesDetail.__table__.columns}
|
|
336
|
+
for record in records
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
return records_dict[0]
|
|
340
|
+
|
|
341
|
+
finally:
|
|
342
|
+
session.close()
|
|
343
|
+
|
|
344
|
+
def insert_data(self, data_list):
|
|
345
|
+
"""
|
|
346
|
+
插入多条数据
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
data_list (list): 要插入的数据列表,每个元素为字典格式
|
|
350
|
+
"""
|
|
351
|
+
# 获取会话
|
|
352
|
+
session = self.get_session()
|
|
353
|
+
try:
|
|
354
|
+
# 将字典转换为模型对象并插入
|
|
355
|
+
records = []
|
|
356
|
+
for data in data_list:
|
|
357
|
+
record = SheinStoreSalesDetail(**data) # 将字典解包为关键字参数
|
|
358
|
+
records.append(record)
|
|
359
|
+
# 将所有记录添加到会话
|
|
360
|
+
session.add_all(records)
|
|
361
|
+
# 提交事务
|
|
362
|
+
session.commit()
|
|
363
|
+
print(f"成功插入 {len(records)} 条数据")
|
|
364
|
+
except Exception as e:
|
|
365
|
+
# 如果发生错误,回滚事务
|
|
366
|
+
session.rollback()
|
|
367
|
+
print(f"插入数据时发生错误: {e}")
|
|
368
|
+
#raise
|
|
369
|
+
finally:
|
|
370
|
+
# 关闭会话
|
|
371
|
+
session.close()
|
|
372
|
+
|
|
373
|
+
if __name__ == '__main__':
|
|
374
|
+
# 新的管理器方式示例(取消注释以运行测试)
|
|
375
|
+
pass
|