question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Preserve model structure when get dicts from SelectQuery

See original GitHub issue

I have three models:

class User(Base):
    name = CharField(null=False)
    photo = BlobField()
    email = CharField(unique=True, null=False)
    password = CharField(null=False)
    website = CharField(unique=True, null=False)
    role = CharField(null=False, default="user")
    reason = TextField(null=True)
    state = CharField(null=False, default="waiting")
    created_at = DateTimeField(null=False, default=datetime.now())

class Channel(Base):
    name = CharField(unique=True, null=False)
    cost = DoubleField(null=False)
    passback = CharField(null=False)

class Campaign(Base):
    name = CharField(null=False)
    user = ForeignKeyField(User, null=False)
    channel = ForeignKeyField(Channel, null=False)
    target = CharField(null=False)
    reason = TextField(null=True)
    description = TextField(null=True)
    state = CharField(null=False, default="waiting")
    created_at = DateTimeField(null=False, default=datetime.now())

If a made a simple query I get the campaigns that I want, joining User and Channel models:

qs = Box(request.args, default_box=True)
page = int(qs.page[0])
state = qs.state[0]
query = (Campaign
               .select(Campaign, User, Channel)
               .join(User, on=(Campaign.user == User.id))
               .join(Channel, on=(Campaign.channel == Channel.id))
               .where(Campaign.state == state)
               .order_by(Campaign.name)
               .paginate(page, 10))

At this point I can simple iterate the query and get the data of joined models:

for cursor in query:
    print(cursor.user.website)  # http://johndoe.com

However, I need to return the query results in JSON, so, I did this (if I try to return the raw SelectQuery I get an “maximum recursion level reached” from ujson):

return json(query.dicts())

And the result is this:

[
  {
    "id": 5,
    "name": "Computers and technology",
    "user": 3,
    "channel": 5,
    "target": "http://janedoe.com",
    "reason": null,
    "description": "This is a campaign for my homepage",
    "state": "active",
    "created_at": 1494099722,
    "photo": "/avatars/jane-doe.jpg",
    "email": "jane.doe.68@mailna.in",
    "password": "$2y$10$p/BuVFoKi9F9SVOc2yJzA.CM6n88xHhMBipNShp4skv9.WBbYxgQ2",
    "website": "http://janedoe.com",
    "role": "USER",
    "cost": 0.04,
    "passback": "https://pcmag.com"
  }
]

All fields are mixed and, obviously, duplicated keys (name property of User and Channel are removed). This is not the expected result. Obviously, I can make a for loop to create a dict for each result and for model properties use model_to_dict:

# convert a select query to a dicts array
    campaigns = []
    for row in query:
        campaign = {}
        campaign["name"] = row.name
        campaign["target"] = row.target
        campaign["user"] = model_to_dict(row.user)
        campaign["channel"] = model_to_dict(row.channel)
        campaign["description"] = row.description
        campaign["reason"] = row.reason
        campaign["state"] = row.state
        campaign["created_at"] = row.created_at
        campaigns.append(campaign)

But this means extra code and I like to keep things simple. So, the question is: exists some way to preserve the model structure when I convert the SelectQuery to dicts?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
coleifercommented, May 14, 2017

Just one hint: you need to call switch() here:

query = (Campaign
               .select(Campaign, User, Channel)
               .join(User, on=(Campaign.user == User.id))
              .switch(Campaign)  # ADD THIS.
               .join(Channel, on=(Campaign.channel == Channel.id))
               .where(Campaign.state == state)
               .order_by(Campaign.name)
               .paginate(page, 10))

Secondly, why not try using the model_to_dict helper? I don’t see why it would be more code or why you’d need to explicitly create the dictionary:

campaigns = [model_to_dict(campaign, recurse=True) for campaign in query]
0reactions
coleifercommented, May 16, 2017

This is all very clearly documented, in my opinion: http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#model_to_dict

Please let me know if you found the docs confusing.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Python: Convert SELECT query list to dict - sql - Stack Overflow
Use GROUP_CONCAT in the query to get all the codes for a city together as a comma-delimited string, then split it up in...
Read more >
Querying — peewee 3.15.4 documentation
We can use Model.select() to retrieve rows from the table. When you construct a SELECT query, the database will return any rows that...
Read more >
Queries as Python Code with SQLAlchemy's Expression ...
Work with your app's data entirely in Python by defining data models and using the session object from SQLAlchemy's ORM.
Read more >
Python MySQL Select From Table [Complete Guide] - PYnative
1. Refer to Python MySQL database connection to connect to MySQL database from Python using MySQL Connector module 2. Next, prepare a SQL...
Read more >
Using dictionaries to store data as key-value pairs
However, for the most part, we'll find ourselves using strings as keys when manually creating dictionary objects and converting real-world data into ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found