G
G
Gennady S2020-08-20 22:56:54
Python
Gennady S, 2020-08-20 22:56:54

What is the correct way to query/restrict multiple relationships in Peewee?

Let's say we have the following simple data structure:

Company(BaseModel):
    id = AutoField()
    # ...

User(BaseModel):
    id = AutoField()
    # ...

Delivery(BaseModel):
    id = AutoField()
     # peewee игнорирует lazy_load=True ?
    manager = ForeignKeyField(User, backref='deliveries', lazy_load=True)
    sender = ForeignKeyField(Company, backref='sender_deliveries')
    receiver = ForeignKeyField(Company, backref='receiver_deliveries')


When it is necessary to request orders with managers, recipients and senders, the following code is assumed: - Peewee will in any case request all external communications, moreover, economical requests by identifiers. But let's say we only want to select senders.
select = Delivery.select().limit(3)

select = Delivery.select(Delivery.id, ..., Delivery.sender).limit(3)

- you have to limit the Delivery fields. This method is warmer, but at the same time, all Company links will be loaded, including, for example, the user-author of the entry with his password.

A more restrictive constraint can't be done (or I haven't found a way) unless we manually constrain the fields and do a JOIN:
Sender = Company.alias()
Receiver = Company.alias()
select = Delivery.select(Delivery.id, Sender, Receiver, ...).limit(3)
select = select.join(Sender, JOIN.LEFT_OUTER, on=(Sender.id == Delivery.sender))
select = select.join(Receiver, JOIN.LEFT_OUTER, on=(Receiver.id == Delivery.receiver))

- firstly, JOIN in many cases has more costs, and secondly, in a sense, the purity of the code breaks down, you will have to pay a lot of attention to the management of the selection of fields and links.

The documentation does a good job of exactly JOIN in the relationship section, but what about the "automatic" selection by ForeignKeyField ? I would like to detect the usual with('sender'), but it didn't work out.

Is there a way to change the selection without select(Model), join(Model)?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
G
Gennady S, 2020-08-30
@gscraft

Actually, there are no other options, there is only one more or less effective way to limit the selection, so as not to sacrifice the selection id INand not pile up columns, implement a method to get columns, for example:

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

    @classmethod
    def fields(cls):
        fields = list()
        for field in cls._meta.sorted_fields:
            if not isinstance(field, ForeignKeyField):
                fields.append(field)
        return fields

And then choose like this (from the example above):
select = Delivery.select(Delivery.sender, *Delivery.fields()).limit(3)

However, this will not cancel the dive, if sender has multiple dependencies, they will all be requested. Plus, if the request implies a condition on the associated model, you will have to do a JOIN and Delivery.senderit will be "duplicated" and other minor inconveniences.
It's a pity, Peewee is one of the most elegant libraries of its kind and allows you to prototype an application very quickly. But the developers' decisions on loading links are strange and it's surprising that lazy_load does not work (and in the opposite case, how to select records with immersion and without JOIN?).

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question