'BlogPost' object has no attribute 'post_id' + Can't display comments that


I created a BlogPost model(working fine) and then a BlogInfo model that has a foreign key variable to the previous one.

I successfully stored data from the form I created based on my BlogInfo model but can't show them after refreshing the codes. For example, I have a blog that has its blog_validated_id as 46. Then when the users see that blog, they can click a button, comment on a form using my Blog Info model (that form will have a model that stores a column called blog_post_id that will be 46).

Now, after the users commented, I want them to be redirected to that same blog_page, except that there will be all the blog comments that have blog_post_id as 46.

The 2 paragraphs above are the ideal thing I want to achieve. However, I meet 2 problems:

-1st one:

Once I commented and submit the blog info comment form (form2 in the codes below), I get this error: AttributeError: 'BlogPost' object has no attribute 'post_id' My traceback then end at these codes, which is at the end of my BlogPost model(which is shown together with BlogInfo model down below):

def __repr__(self): return f"Post ID: {self.post_id} -- Date:{self.date}---{self.problem_name}"

BlogPost and BlogInfo models:

class BlogPost(db.Model): __tablename__ = 'blog_post' users = db.relationship(User) blog_id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer,db.ForeignKey('users.id'), nullable=False) #users.id is taken from the tablename(users) and id in its table bloginfos2 = db.relationship('BlogInfo', backref="comment2", lazy=True) def __init__(self, user_id): self.user_id = user_id def __repr__(self): return f"Post ID: {self.post_id}" class BlogInfo(db.Model): __tablename__ = 'blog_info' users=db.relationship(User) blog_post=db.relationship(BlogPost) blog_info_id = db.Column(db.Integer, primary_key=True) blog_post_id = db.Column(db.Integer, db.ForeignKey('blog_post.blog_id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) text = db.Column(db.Text, nullable=False) def __init__(self, blog_post_id, user_id, text): self.blog_post_id = blog_post_id self.user_id = user_id self.text = text def __repr__(self): return f"Blog info ID:{self.blog_info_id}--Blog id:{self.blog_post_id} -- Date:{self.date} -- {self.text}"

Blog Info comment form(the one that the users commented):

{% for post2 in comment_blogs.items %}

<small class="">Posted on:{{ post2.date.strftime('%Y-%m-%d') }}</small>

<p class="card-text ml-5">{{ post2.text }}

{% endfor %}

My views.py:

@blog_posts.route('/<int:blog_validated_id>', methods=['GET', 'POST']) def blog_view(blog_validated_id): blog_view = BlogPost.query.get_or_404(blog_validated_id) print(blog_validated_id) form2=BlogInfoForm() if form2.validate_on_submit(): blog_comment_validated = BlogInfo(text=form2.text.data, user_id=current_user.id, blog_post_id=blog_validated_id) db.session.add(blog_comment_validated) db.session.commit() flash("Blog's comment added") page = request.args.get('page', 1, type=int) comment_blogs1 = BlogInfo.query.filter(BlogInfo.blog_post_id.ilike(blog_validated_id)).order_by(BlogInfo.date.desc()) comment_blogs = comment_blogs1.paginate(page=page,per_page=3) return redirect(url_for('blog_posts.blog_view', post=blog_view, form2=form2,comment_blogs=comment_blogs, comment_text=blog_comment_validated.text, blog_validated_id=blog_validated_id)) page = request.args.get('page', 1, type=int) comment_blogs = BlogInfo.query.order_by(BlogInfo.date.desc()).paginate(page=page, per_page=3) return render_template('blog_view.html', post=blog_view, form2=form2, comment_blogs=comment_blogs, blog_validated_id=blog_validated_id)

If you wonder how I got blog_validated_id, please look at my 2st problem (it will be fast and straightaway)

-2st one:

I think that the codes above (which is now referenced below) is not working. After I redirect url_for (blog_posts.blog_view), my html file still show all the blog info comments that has blog_post_id different to blog_validated_id .I think that my python codes is not saving blog_validated_id:

comment_blogs1 = BlogInfo.query.filter(BlogInfo.blog_post_id.ilike(blog_validated_id)).order_by(BlogInfo.date.desc())

Very importantly, blog_validated_id is a variable I passed from a HTML file to the python's blog_posts.blog view codes above.

The HTML file that leads to blog_posts.blog view python codes:

{% for post in many_posts.items%} <a href="{{ url_for('blog_posts.blog_view', blog_validated_id=post.blog_id) }}">Readmore</a> {% endfor %}

The many_posts variable above is all the blogs and blog_validated_id is the id of each individuals blog.

I'm a beginner in coding and I'm struggling with the 2 problems above. I would greatly appreciate it if you could help me.

Thank you.


In the class BlogPost you write in __repr__:

return f"Post ID: {self.post_id} -- Date:{self.date}---{self.problem_name}"

Shouldn't this be either

return f"Post ID: {self.pk} -- Date:{self.date}---{self.problem_name}"


return f"Post ID: {self.blog_id} -- Date:{self.date}---{self.problem_name}"

Other Comments 1:

The way you declare primary keys and foreign keys is a little unusual compared to the way that I'm normally doing it. (It's probably not the cause of your issue, but it makes in my opinion the code more complicated to read for a benefice, that I don't understand.

if you create a model then Django automatically adds a primary key and calls it id. I don't see a reason to change this behavior. People using Django are used to the fact, that Model.id is the primary key. They don't even have to kook at the declaration of your model. If you change its name, people don't understand until they look at your class definition. So I'd suggest to not explicitly declare a primary key. and just remove

blog_id = db.Column(db.Integer, primary_key=True)

from the declaration of BlogPost and

blog_info_id = db.Column(db.Integer, primary_key=True)

from the declaration of BlogInfo

If you do this because you work with a database that pre-dates your Django project, then I understand. Though I in a similar situation declared a model the Django way (and let django also decide the table name) and copied the data from original tables into the new ones. (This doesn't work of course if you want Django and your old software access the same tables)

To make a reference to a models own primary key just write self.pk or (if you don't explicitly declare a primary key self.id) (self.id is supposed to be faster. self.pk is a little cleaner as it works also if a primary key has been declared explicitly. Look at Django queries - id vs pk to form your own opinion)

Other comments 2 If you declare Foreign keys the way it is shown in the tutorials, then you would just write.

from django.db import models class BlogInfo(models.Model): blog_post = models.ForeignKey( 'BlogPost', on_delete=models.CASCADE, # change this to your desired behaviour null=True)

You notice two things It's just called blog_post and not blog_post_id. So in python code if you have a BlogInfo entry (e.g. blog_info = BlogInfo.objects.all()[0])

Then you just write blog_info.blog_post blog_post and you have an instance of type BlogPost If you really want the id, just type blog_info.blog_post.id

It would of course change your queries instead of


you had to write

BlogInfo.objects.get(blog_post_id=47) # double _ between blog_post and id


BlogInfo.objects.get(blog_post_pk=47) # double _ between blog_post and pk