Объединение необязательных пропущенных фильтров запросов в Peewee - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь связать флеш-сервер с базой данных Peewee .У меня есть запрос Rest GET, который передает данные в форме

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

Я хочу написать метод, который преобразует мои фильтры в запрос к базе данных и выполняет его для возврата их ресурса:

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и присоединиться к ним как-то, я просто не знаю, как.

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Спасибо @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

Я передаю тип объекта, для которого я хочу создать выражение и оператор в данных фильтра.Перебирая фильтры, я могу создавать выражения и комбинировать их.

0 голосов
/ 19 декабря 2018

Поскольку выражения 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
...