Hi everyone.

Yesterday, I managed to fill SQLite database with some dummy data and display it using Jinja2 template tags.

Today, I would like to polish my design a little bit more.

My idea is to use Bootstrap 4 cards design to display ordered list of products.

Why not use table layout you ask?

Well, because Bootstrap 4 tables are great for a comprehensive list of items, where each item is represented by plain text.

Plain text is boring.

I want images, badges and alerts grouped into single cell.

With Bootstrap 4 cards, I can do that with built in grid system using columns and rows.

I will lose responsiveness thought.

Bootstrap 4 cards are not responsive and resizing your screen will break the layout.

My approach is to create a separate mobile web version, that will sit on a subdomain.

Whenever user visits my web from mobile, Cloudflare will redirect him to my mobile version.

It sounds more complicated than just bending my design with CSS media queries.

We will see.

I will make decision when I see significant traffic coming from mobile phones.

Okay.

Back to my design.

Let’s add some html.

Cool.

Each Bootstrap 4 card displays one product and its name.

To add company name to each card, I need to figure out how to do left join in Flask-SQLAlchemy.

I designed my database so company data are stored in a separate Company Table.

If I left join Company table to Products table, I will be able to get dataset I want.

Will this ORM query work?

products = Product.join(Company, Company.id == Product.company_id, isouter=True)

Nope.

Got Internal server error.

Gunicorn logs reveal why.

AttributeError: type object 'Product' has no attribute β€˜join'

Ok, seems I forgot query syntax in query.

products = Product.query.join(Company, Company.id == Product.company_id, isouter=True)

Nice, no error this time. Tables are joined.

ORM query above will translate into plain SQL like this.

SELECT product.id AS product_id, product.name AS product_name, product.company_id AS product_company_id
FROM product LEFT OUTER JOIN company ON company.id = product.company_id

But where is the column from left joined Company table?

I try to print query result set into command line to see whats happening.

for row in products:
    print(row.Product)
    print(row.Company)

Refreshing Flask page ends with an error.

print(row.Product)
AttributeError: 'Product' object has no attribute 'Product'

By looking at SQLAlchemy documentation I overhaul query syntax.

products = db.session.query(Product, Company).join(Company, Company.id == Product.company_id).all()

Query result set above will finally return both tables and their columns.

[(<Product 1>, <Company 1>), (<Product 2>, <Company 2>)]

Now I should be able to access company name column in the template.

Great.

Product title is displayed together with company name, but it is ugly as f.

Let’s polish design a little more with our own CSS styles.

To do that, I have to create a new folder called “static” inside my project folder and create a new CSS file style.css.

Then I need to include style.ccs into header section.

<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles/style.css') }}">

When I try to load css file in my browser, I get not found error.

Instead of dynamic url, I try to add absolute path to my css file.

http://financia.local/static/css/styles.css

No luck.

I try do declare static path in __init__ file like below.

app = Flask(__name__, static_url_path='/static’)

Still not found error.

This is driving me nuts and my time is running out. I will give it a shot next time.

Today, I want to finish my layout with few template tricks.

Like, how to round float numbers with Jinja2 syntax.

product["price"]|round(1)

Or how to convert float number to integer number.

{{product["price"]|round(0)|int}}

And what if I don’t want trailing zeroes behind my float numbers? I will use rstrip.

{{product["float"].rstrip('0').rstrip('.')}}

Ok, time to call it a day.

I didn’t progress much today.

In the next session, I want to focus on solving the puzzle with static files.

Without it, I won’t be able to serve images, javascript codes and css files.

Thanks for reading and see you next time!

Share it!