Flask sqlalchemy InterfaceError - python

I'm not sure whats going wrong here...I get this error:
InterfaceError: (InterfaceError) Error binding parameter 0 - probably unsupported type. u'SELECT contact.id AS contact_id, contact.surname AS contact_surname, contact.firstname AS contact_firstname, contact.email AS contact_email, contact.mobile AS contact_mobile, contact.work_location AS contact_work_location \nFROM contact \nWHERE contact.id = ?' ([1],)
My method:
#app.route('/contacts/<int:contact_id>', methods=['GET'])
def contact_detail(contact_id):
if request.method == 'GET':
db.session.query(Contact).filter_by(id=[contact_id]).all()
return render_template('modcontact.html', title = 'Contact Detail')
My models:
class Contact(db.Model):
id = db.Column(db.Integer, primary_key = True)
surname = db.Column(db.String(100))
firstname = db.Column(db.String(100))
email = db.Column(db.String(100))
mobile = db.Column(db.String(20))
work_location = db.Column(db.String(100))
#user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Contact %r>' % (self.surname)
template:
{% extends "base.html" %}
{% block content %}
<h1>List of contacts</h1>
<ul class=contacts>
{% for contacts in contacts %}
<li><h3>
<a href="{{ url_for('contact_detail',contact_id=contacts.id)}}">
{{ contacts.surname }}, {{ contacts.firstname }}
</a>
</h3></li>
{% else %}
<li><em>No contacts available</em></li>
{% endfor %}
</ul>
Add a new contact
{% endblock %}

You pass a list in your query filter. So the parameter in the query is a list therefore the 'Error binding parameter 0'.
Try this instead: db.session.query(Contact).filter_by(id=contact_id).all()

Related

How can I display a nested list of tasks in a Flask application?

I would like to generate output in this format:
<h1>2023-01-16 #task.week_start_date</h1>
<h2>Build a house #task.project.name</h2>
<h3>Buy a a blueprint #task.name</h3>
<h3>Buy some wood #task.name</h3>
<h2>Plan a vacation #task.project.name</h2>
<h3>Ask family where they would like to go #task.name</h3>
<h1>2023-01-23 #task.week_start_date</h1>
<h2>Build a house #task.project.name</h2>
<h3>Build the frame #task.name</h3>
<h2>Plan a vacation #task.project.name</h2>
<h3>Pick a week when all the family can go #task.name</h3>
<h3>Check on plane ticket prices #task.name</h3>
Here is the Flask app:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
db = SQLAlchemy(app)
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
tasks = db.relationship('Task', backref='project', lazy=True)
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
week_start_date = db.Column(db.String)
project_id = db.Column(db.Integer, db.ForeignKey('project.id'), nullable=False)
#app.route('/')
def home():
tasks = Task.query.order_by(Task.week_start_date,Task.project_id).all()
return render_template('home.html', tasks=tasks)
How should I code home() and home.html to achieve the above output?
I tried this in home.html:
{% for task in tasks %}
{% if loop.changed(task.week_start_date) %}
<h1>{{ task.week_start_date }}</h1>
{% endif %}
{% if loop.changed(task.project.id) %}
<h2>{{ task.project.name }}</h2>
{% endif %}
<h3>{{ task.name }}</h3>
{% endfor %}
However, it would create a new H1 for every task, even if the following task had the same start week.

Check if logged in user is the author of a post | Django | If-else doesn't work

I want to check if the logged in user is the author of a post in my Forum. I have written some code to figure that out:
<div class="right-section-posts">
user: {{ user }} <!--Output: Admin-->
author: {{ post.author }} <!--Output: Admin-->
{% if user == post.author %}
<form action="DELETE">
{% csrf_token %}
<button type="submit" class="delete-btn" name="post-id" value="{{ post.id }}">Delete</button>
</form>
<button class="edit-btn">Edit</button>
{% endif %}
</div>
They both output the same but the statement returns false! Why?
Models.py
class Post(models.Model):
vote_count = models.IntegerField(default=0)
id = models.BigAutoField(primary_key=True)
created_at = models.DateField(default=date.today)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
tags = models.CharField(max_length=200)
author = models.CharField(max_length=100, default="none")
def __str__(self):
return str(self.id) + ' ' + self.title
I tried different ways to get the Current user and the author. Doesn't work to.
(I think you might say that I should use ForeignKey instead of ´CharField´, when using that I get this Error:
ERROR: Column forum_app_post.author_id does not exist.
LINE 1: ...app_post". "description", "forum_app_post". "tags", "forum_app...
^
HINT: Perhaps the intention was to refer to the "forum_app_post.author" column.
)
The author field cannot be a CharField because it represents the user. You need to set author field as foreignkey.
You need to update your model like this:
from django.contrib.auth.models import User
class Post(models.Model):
vote_count = models.IntegerField(default=0)
id = models.BigAutoField(primary_key=True)
created_at = models.DateField(default=date.today)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
tags = models.CharField(max_length=200)
author = models.ForeignKey(User,on_delete= models.CASCADE, verbose_name='Post Author')
def __str__(self):
return str(self.id) + ' ' + self.title
If you want to check the logged in user from all the registered posts, you should get all the posts first.
def get_all_posts(request):
posts = Post.objects.filter.all()
context = {
"posts" : posts,
}
return render(request,"my_page.html",context)
Then in the html page :
<div class="right-section-posts">
{% if posts %}
{% for post in posts %}
{% if request.user == post.author %}
<!--do what you want here-->
{% else %}
{% endif %}
{% endfor %}
{% else %}
<div class="alert alert-info">You have no registered post yet!</div>
<!-- /.container-fluid -->
</div>
{% endif %}
</div>
I also recommend using django-taggit for tags.

Flask - commit FieldList to database using SQLAlchemy?

I am trying to commit fields generated from a FiedList but getting the error:
AttributeError: 'str' object has no attribute 'data'
What I'm trying to do is add a list of fields to the database which I can then retrieve and display on the page.
#App.py
#app.route('/', methods=['GET', 'POST'])
def index():
form = MainSubscriptionForm()
if form.validate_on_submit():
for x in form.subscription:
sub = Subscription(company=x.company.data, description=x.description.data)
db.session.add(sub)
db.session.commit()
elif request.method == 'GET':
list = Subscription.query.all()
return render_template('index.html', title="Home", form=form, list=list)
#forms.py
class SubscriptionForm(FlaskForm):
company = StringField(('Company'), validators=[DataRequired(), Length(min=0, max=20)])
description = StringField(('Description'), validators=[Length(min=0, max=120)])
save = SubmitField('Save')
class MainSubscriptionForm(FlaskForm):
subscription = FieldList(FormField(SubscriptionForm), min_entries=1)
#models.py
class Subscription(db.Model):
id = db.Column(db.Integer, primary_key=True)
company = db.Column(db.String(20))
description = db.Column(db.String(120))
#index.html
{% extends "base.html" %}
{% from 'bootstrap/form.html' import render_form_row %}
{% block content %}
<form method="post">
{{ form.csrf_token() }}
{% for sub in form.subscription %}
{{ render_form_row(sub) }}
{% endfor %}
</form>
{{ list }}
{% endblock %}
The issue was that a dictionary was being sent and therefore it was crashing on the below line:
sub = Subscription(company=x.company.data, description=x.description.data)
The solution was to get the key value as per below:
sub = Subscription(company=x.data['company'], description=x.data['description'])

If condition doesn't work with object's attribute

im trying to write app similiar to Tinder.
I created models:
class User(db.Model, UserMixin):
id = db.Column('id', db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True, nullable=False)
name = db.Column(db.String(20), nullable=False)
age = db.Column(db.Integer, nullable=False)
description = db.Column(db.String(200), default='')
gender = db.Column(db.String(6), nullable=False)
image = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
likes = db.relationship('Like', backref='liked_by', lazy=True)
def __repr__(self):
return f'User({self.name}, {self.gender}, {self.age}, {self.image})'
class Like(db.Model):
id = db.Column('id', db.Integer, primary_key=True)
like_to = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
I want to current_user wont be able to see user on the home page if he already liked him. And here is my problem to create appropriate if condition. Now it looks like this and doesn't work:
{% block content %}
{% for user in users %}
{% if current_user.gender != user.gender %}
{% **if user.id not in current_user.likes** %}
<form action="{{ url_for('like_profile', user_id=user.id) }}" method="POST">
{{ form.hidden_tag() }}
<p>{{ user.name }}</p>
<p>{{ user.gender }}</p>
<p>{{ user.age }}</p>
<p>User id: {{ user.id }}</p>
<p>User likes: {{ user.likes }}</p>
<p>{{ form.submit }}</p>
</form>
{% endif %}
{% endif %}
{% endfor %}
{% endblock %}
This line: if user.id not in current_user.likes - how should i do this?
The function which creates like:
#app.route('/profile/<int:user_id>', methods=['POST'])
def like_profile(user_id):
user = User.query.get_or_404(user_id)
like = Like(like_to=user.id, liked_by=current_user)
db.session.add(like)
db.session.commit()
flash(f'Like has been given to {user} from {current_user}. {type(current_user.likes)}')
return redirect(url_for('home'))
Ok guys, maybe someone will be interested. I found some resolution.
First:
current_user.likes was giving Like objects like Ilja said.
I changed from lazy=True to lazy='dynamic' in relationship, now it looks like this:
class User(db.Model, UserMixin):
id = db.Column('id', db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True, nullable=False)
name = db.Column(db.String(20), nullable=False)
age = db.Column(db.Integer, nullable=False)
description = db.Column(db.String(200), default='')
gender = db.Column(db.String(6), nullable=False)
image = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
likes = db.relationship('Like', backref='liked_by', lazy='dynamic')
def __repr__(self):
return f'User({self.name}, {self.gender}, {self.age}, {self.image})'
class Like(db.Model):
id = db.Column('id', db.Integer, primary_key=True)
like_to = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Like id: {self.id}, user id: {self.user_id}, like to: {self.like_to}, like from: {self.liked_by}"
And it gave me new functionality, i can: current_user.likes.filter_by(like_to=user.id).first().like_to
what finnaly returns liked user's ID.
And my home template now looks like this:
{% block content %}
{% for user in users %}
{% if current_user.gender != user.gender %}
{% if user.id != current_user.likes.filter_by(like_to=user.id).first().like_to %}
<form action="{{ url_for('like_profile', user_id=user.id) }}" method="POST">
{{ form.hidden_tag() }}
<p>{{ user.name }}</p>
<p>{{ user.gender }}</p>
<p>{{ user.age }}</p>
<p>User id: {{ user.id }}</p>
<p>User likes: {{ user.likes }}</p>
<p>{{ form.submit }}</p>
</form>
{% endif %}
{% endif %}
{% endfor %}
{% endblock %}
Thanks for trying to help me.

Rendering ndb model property in <select> drop down using WTForms

When I render the form the entire ndb model (PartModel is coming through. I'd like to have it render only the part_number property, but actual store the PartModel. I've dug through the WTForms documentation and I'm having a tough time figuring out the right way to do this.
Any thoughts? Relevant files are shown below.
new_dimension.html
<div class="control-group">
<div class="control-label">{{ form.dimension_part.label }}</div>
<div class="controls">
{{ form.dimension_part|safe }}
{% if form.dimension_part.errors %}
<ul class="errors">
{% for error in form.dimension_part.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
views.py
def list_dimensions(part_id=None):
"""List dimensions"""
if part_id is not None:
print "************Part ID is",part_id
Part = PartModel.get_by_id(part_id)
dimensions = DimensionModel.query(DimensionModel.dimension_part==Part.key).fetch()
title = "Dimensions for {}".format(Part.part_name)
else:
dimensions = DimensionModel.query() #creates Query object
title = "All Dimensions"
form = DimensionForm() #pulls in DimensionForm
if form.validate_on_submit():
dimension = DimensionModel(
dimension_part=form.dimension_part.data.key,
dimension_name=form.dimension_name.data,
dimension_value=form.dimension_value.data,
dimension_usl = form.dimension_usl.data,
dimension_lsl = form.dimension_lsl.data,
added_by=users.get_current_user()
)
try:
dimension.put()
dimension_id = dimension.key.id()
flash(u'Dimension %s successfully saved.' % dimension_id, 'success')
return redirect(url_for('list_dimensions'))
except CapabilityDisabledError:
flash(u'App Engine Datastore is currently in read-only mode.', 'info')
return redirect(url_for('list_dimensions'))
return render_template('list_dimensions.html', dimensions=dimensions, form=form,title=title) #pushes query object into template
forms.py
PartForm = model_form(PartModel, wtf.Form, field_args={
'part_name': dict(validators=[validators.Required()]),
'part_number': dict(validators=[validators.Required()])
})
models.py
class PartModel(ndb.Model):
"""Part"""
part_name = ndb.StringProperty(required=True)
part_number = ndb.FloatProperty(required=True)
added_by = ndb.UserProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
class DimensionModel(ndb.Model):
"""Dimension"""
dimension_part = ndb.KeyProperty(required=True,kind=PartModel)
dimension_name = ndb.StringProperty(required=True)
dimension_value = ndb.FloatProperty(required=True)
dimension_usl = ndb.FloatProperty(required=True)
dimension_lsl = ndb.FloatProperty(required=True)
added_by = ndb.UserProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)

Categories