我有一个文本文件,它是这样的模板:
Question: {QuestionStem}
{answers}
Correct answer: {correctAnswer}
Date: {examDate}
Class: {examClass}
我需要填充它并在考试中的每个问题中保存一份副本。
考试数据来自 T-SQL 查询 (MSSQL),如下所示:
QuestionID QuestionStem QuestionOrder AnswerId AnswerText AnswerOrder isCorrect Class Date
100 What color is the sky? 0 1 Red 0 0 Astronomy 10/1/2024
100 What color is the sky? 0 2 Blue 1 1 Astronomy 10/1/2024
100 What color is the sky? 0 3 Orange 2 0 Astronomy 10/1/2024
100 What color is the sky? 0 4 Green 3 0 Astronomy 10/1/2024
200 The Sun is bright(T/F) 1 11 True 0 1 Astronomy 5/1/2024
200 The Sun is bright(T/F) 1 12 False 1 0 Astronomy 5/1/2024
我需要每次考试的数据来填充模板文件,如下所示:
Question: What color is the sky?
a. Red
b. Blue
c. Orange
d. Green
Correct answer: b
Date: 10/1/2024
Class: Astronomy
Question: The Sun is bright(T/F)
a. True
b. False
Correct answer: a
Date: 5/1/2024
Class: Astronomy
Python 是否有办法获取 SQL 数据,用数据填充模板,然后将其保存为文本文件?
如果您想直接从Python获取T-SQL结果,您可以查看SQLAlchemy,但这取决于您的设置的具体情况,所以我只是假设您可以以某种方式将此查询输出转换为字符串。
你当然可以只使用 fstrings,但是如果这个项目涉及更多一点,或者你希望能够将模板与代码分开,你应该使用 Python 的 Template 类。 一个更复杂、但也更强大的替代方案是成熟的模板引擎,例如 Jinja。
我编写了一些示例代码,它将查询输出作为字符串并将其替换为模板。 这本来可以用更少的参与来完成,但是通过使用数据类,我们可以保持一切都漂亮整洁。
from collections import defaultdict
from dataclasses import dataclass
from operator import attrgetter
from string import Template
# define the template string
# this could come from a file etc.
_TEMPLATE = Template("""
Question: ${question_stem}
${options}
Correct answer: ${correct_answer}
Date: ${exam_date}
Class: ${exam_class}
""")
# define helper classes to do the work
@dataclass
class Answer:
order: str
text: str
correct: bool
def __str__(self):
return self.text
@dataclass
class Question:
order: str
text: str
options: list[Answer]
def __str__(self):
# ensure correct order of options
self.options.sort(key=attrgetter('order'))
# supports multiple correct answers
correct_answer = ", ".join([
str(answer)
for answer
in self.options
if answer.correct
])
# substitute only the known values
return _TEMPLATE.safe_substitute({
'question_stem': self.text,
'options': "\n".join([f'-[ ] {option}' for option in self.options]),
'correct_answer': correct_answer,
})
@dataclass
class Exam:
klass: str
date: str
questions: list[Question]
def __str__(self):
# ensure correct order of options
self.questions.sort(key=attrgetter('order'))
return Template("\n".join([
str(question)
for question
in self.questions
])).substitute({
'exam_class': self.klass,
'exam_date': self.date
}).strip()
@classmethod
def from_data(cls, data: list[list[str]]) -> list['Exam']:
# nested dict with klass -> question -> answer
exams = defaultdict(dict)
# loop over rows
for (question_id, question_stem, question_order,
answer_id, answer_text, answer_order, is_correct,
klass, date) in data:
# one answer per row
answer = Answer(answer_order, answer_text, True if is_correct == "1" else False)
question = exams[(klass, date)].get(question_id)
if question is not None:
question.options.append(answer)
else:
question = Question(question_order, question_stem, [answer])
exams[(klass, date)][question_id] = question
return [cls(klass, date,
[question
for question
in questions.values()])
for (klass, date), questions
in exams.items()]
if __name__ == '__main__':
# your toy data, representing rows from a database query
query_result = """
QuestionID QuestionStem QuestionOrder AnswerId AnswerText AnswerOrder isCorrect Class Date
100 What color is the sky? 0 1 Red 0 0 Astronomy 10/1/2024
100 What color is the sky? 0 2 Blue 1 1 Astronomy 10/1/2024
100 What color is the sky? 0 3 Orange 2 0 Astronomy 10/1/2024
100 What color is the sky? 0 4 Green 3 0 Astronomy 10/1/2024
200 The Sun is bright(T/F) 1 11 True 0 1 Astronomy 5/1/2024
200 The Sun is bright(T/F) 1 12 False 1 0 Astronomy 5/1/2024
"""
# clean this up a bit
rows = [[field.strip() for field in line.split(' ') if field] for line in query_result.splitlines()[2:-1]]
for exam in Exam.from_data(rows):
print(exam)
显然,您必须使用真实数据运行它并调整清理,此外,也许可以使用模板字符串,并将其放入额外的文件中,等等。如果您沿着 SQLAlchemy 的道路走下去,您可能想要挂钩这些类也符合 ORM。