Yakuzhy Yakuzhy - 2 months ago 15
HTML Question

Creating a blog with Flask

I'm learning flask and I have a little problem.
I made an index template, where are blog post titles.

{% for title in titles %}

<!-- Main Content -->
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-preview">
<a href="{{ url_for('post')}}">
<h2 class="post-title">
{{ title[0] }}
</h2>
</a>

<p class="post-meta">Posted by <a href="#">{{ author }}</a></p>
</div>
</div>
</div>
</div>

{% endfor %}


Here is part of my post.html template.

<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">

<p>{{ post_text1 | safe }}</p>
<hr>
<div class="alert alert-info" role="alert">Posted by
<a href="#" class="alert-link">{{ author }}</a>
</div>
</div>
</div>
</div>


I'm using sqlite3. Currently every title leads to same post.html where is first text from first post.
How to make every title direct to their post text? I mean, if I click on the first title it should bring up post.html and there should be first text. Second title should show second text.
Should I write program, that creates new html for every post or is there any other way?

@app.route('/')
def index():
db = connect_db()
titles = db.execute('select title from entries')
titles = titles.fetchall()
author = db.execute('select author from entries order by id desc')
author = author.fetchone()
return render_template('index.html', titles=titles[:], author=author[0])

@app.route('/post/')
def post():
db = connect_db()
post_text1 = db.execute('select post_text from entries')
post_text1 = post_text1.fetchone()
author = db.execute('select author from entries where id=2')
author = author.fetchone()
return render_template('post.html', post_text1=post_text1[0], author=author[0])

Answer

The problem comes from here <a href="{{ url_for('post')}}">.

What this tells Flask is to make a url for post, which is something you have defined in views as def post(argument) but you are not providing an argument. So if for example you are making you are taking your posts based on id, your view would would ask for /<int:post_id>/ in url and post_id would be passed as an argument based on which you would find the specific post and pass that to the template.

Your url_for should reflect this, you should have {{ url_for('post', post_id=title[1]) }} or wherever you are storing your equivalent of post_id (maybe that's title for you).

Edit:

Baed on your edit, your problem is that you are not telling Flask which post to fetch. You need either ID, or slug, or something that will go in the url and will tell you which post you are looking for. Your function right now is static and is always fetching the first entry in your database. The changes required are:

@app.route('/')
def index():
db = connect_db()
    titles = db.execute('select title, id from entries')
    titles = titles.fetchall()
    author = db.execute('select author from entries order by id desc')
    author = author.fetchone()
return render_template('index.html', titles=titles, author=author[0])

@app.route('/post/<int:post_id>/')
def post(post_id):
    db = connect_db()
    post_text = db.execute('select post_text from entries where id = ?', post_id)
    post_text = post_text1.fetchone()
    author = db.execute('select author from entries where id=2')
    author = author.fetchone()
    return render_template('post.html', post_text1=post_text, author=author)


<a href="{{ url_for('post', post_id=title[1])}}">

Also your author fetching is weird, you should have them stored (at least their ids) next to entries. Then I'd recomend some naming changes etc. It's hard to just answer the question and not write the code for you, as this is a site for answering specific questions, not writing code on demand :) Try to understand what I wrote here, play around with it a bit more etc. to fully undnerstand.

tl;dr: Posts have to get an argument and then fetch a post identified by that argument, the program can't magically tell which post you clicked on.