在 Peewee 中组合可选的已通过查询过滤器

Combining Optional Passed query filters in Peewee

我正在尝试 Link 烧瓶服务器到 Peewee 数据库。我有一个传递

形式数据的 Rest GET 请求

{'a':1,'b':2, 'filter':{'name':'Foo', 'count':3}}

我想编写一个方法,将我的过滤器转换为数据库查询并将其执行到 return 他们的资源:

import datetime
import peewee as pw
import uuid

DATABASE = "Resources.db"

database = pw.SqliteDatabase(DATABASE)


class BaseModel(pw.Model):
    class Meta:
        database = database


class Resource(BaseModel):
    name = pw.CharField(unique=True)
    current_count = pw.IntegerField(default=1)
    total_count = pw.IntegerField(default=1)
    flavor = pw.CharField(default="undefined")
    users = pw.TextField()
    metadata = pw.TextField(default="")
    is_avalible = pw.BooleanField(default=True)
    uuid = pw.UUIDField(primary_key=True, default=uuid.uuid4)
    max_reservation_time = pw.IntegerField(default=10)

    def __str__(self):
        return f"My name is {self.name} {vars(self)}"

这有点像我的资源。这是我正在尝试做的......(不是一个完整的工作示例)

def filter(filters):

    for i,j in filters.items():
        dq = Resource.select().where(getattr(Resource, i) == j)

    for resource in dq:
        print(resource)

if __name__ == "__main__":
    try:
        database.connect()
    except pw.OperationalError:
        print("Open Connection")
    try:
        create_tables()
    except pw.OperationalError:
        print("Resource table already exists!")

    with database.atomic():
        reso = Resource.create(name="Burns", current_count=4, total_count=5, users="Bar", blah=2)

    filter({'name':"Burns","total_count":5})

这里我希望返回:My name is Burns {'__data__': {'uuid': UUID('80808e3a-4b10-47a5-9d4f-ff9ff9ca6f5c'), 'name': 'Burns', 'current_count': 4, 'total_count': 5, 'flavor': 'undefined', 'users': 'Grant', 'metadata': '', 'is_avalible': True, 'max_reservation_time': 10}, '_dirty': set(), '__rel__': {}}我相信我可以创建个人 peewee.expressions 并以某种方式加入他们,我只是不确定如何。

由于 peewee 表达式可以使用内置的 &| 运算符任意组合,我们将使用 reduce() 函数使用给定的操作数组合列表:

def filter(filters):
    expression_list = [getattr(Resource, field) == value
                       for field, value in filters.items()]
    # To combine all expressions with "AND":
    anded_expr = reduce(operator.and_, expression_list)

    # To combine all expressions with "OR":
    ored_expr = reduce(operator.or_, expression_list)

    # Then:
    return Resource.select().where(anded_expr)  # or, ored_expr

感谢@coleifer 的提醒。这是我的解决方案:

OP_MAP = {
    "==": pw.OP.EQ,
    "!=": pw.OP.NE,
    ">": pw.OP.GT,
    "<": pw.OP.LT,
    ">=": pw.OP.GTE,
    "<=": pw.OP.LTE,
}

def _generate_expressions(model, query_filter):
    expressions = []
    for expression in query_filter:
        expressions.append(
            pw.Expression(
                getattr(model, expression["attr"]), OP_MAP[expression["op"]], expression["value"]
            )
        )
    return expressions

def generate_query(model, query_data):
    if query_data.get("filters") is None:
        database_query = model.select()
    else:
        database_query = model.select().where(
            *(_generate_expressions(model, query_data["filters"]))
        )
    return database_query

我传递了对象的类型,我想在过滤器数据中为其创建表达式和运算符。迭代过滤器我可以构建表达式并将它们组合起来。