I am currently working on my cs50 final project. I used the shows search function from week 9 source code as a reference to create my own search function. The search function is called using a form in the navigation bar in layout.html. The search function is not giving any error message in the terminal rather, it is showing the error page on the web application, everything seems fine on the terminal. The search function is similar to the index function and the index function works. I checked the sql query and it gives the appropriate results. Can someone identify the error in the code?
Reference:
https://cdn.cs50.net/2020/fall/lectures/9/src9.pdf- shows0/application.py
application.py
app = Flask(__name__)
#app.errorhandler(Exception)
def handle_exc(e):
if not isinstance(e, HTTPException):
e = InternalServerError()
return render_template("error.html", message=e.name, code=e.code)
db = SQL("sqlite:///ideahub.db")
#app.route("/")
def index():
ideas = db.execute("SELECT ideas.id AS id, username, user_id, idea_name, idea_body, post_date FROM ideas INNER JOIN users ON users.id = ideas.user_id WHERE posted = 1 ORDER BY post_date DESC")
for idea in ideas:
if idea["id"] in [row["idea_id"] for row in db.execute("SELECT idea_id FROM likes WHERE user_id = ?", session.get("user_id", 0))]:
idea["liked"] = True
return render_template("index.html", ideas=ideas)
#app.route("/search")
def search():
query = request.args.get("q")
ideas = db.execute("SELECT ideas.id AS id, username, user_id, idea_name, idea_body, post_date FROM ideas INNER JOIN users ON users.id = ideas.user_id WHERE posted = 1 AND idea_name LIKE '%?%' ORDER BY post_date DESC", query)
for idea in ideas:
if idea["id"] in [row["idea_id"] for row in db.execute("SELECT idea_id FROM likes WHERE user_id = ?", session.get("user_id", 0))]:
idea["liked"] = True
return render_template("search.html", ideas=ideas)
search.html
{% extends "layout.html" %}
{% block title %}
Search Results
{% endblock %}
{% block main %}
{% for i in range(ideas|length) %}
<div class="card bg-white col-10 mx-auto mb-2">
<div class="card-body">
<h5 class="card-title font-weight-bold" role="button" data-toggle="collapse" data-target="#idea-content-{{ i }}" aria-expanded="false">
{{ ideas[i].idea_name }} <i class="fas fa-angle-down fa-lg float-right"></i>
</h5>
<div class="collapse" id="idea-content-{{ i }}">
<p class="fw-600 card-text mb-2">Posted:- {{ ideas[i].post_date|date_format }}</p>
<p class="fw-600 card-text mb-2">Created By:- <a class="text-dark hover-link" href="/profile/{{ ideas[i].user_id }}">{{ ideas[i].username }}</a></p>
<p class="card-text">{{ ideas[i].idea_body }}</p>
{% if session.user_id != ideas[i].user_id %}
<form action="/like">
{% if ideas[i].liked %}
<button class="btn btn-primary mr-2" disabled>Liked!</button>
{% else %}
<button type="submit" class="btn btn-primary mr-2" name="id" value="{{ ideas[i].id }}">Like 💛</button>
{% endif %}
</form>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endblock %}
layout.html
<ul class="navbar-nav ml-auto mt-2">
<li class="nav-item">
<form class="search-bar bg-dark p-2 mr-2 d-flex justify-content-center align-items-center" action="/search">
<input class="search-input text-white border-0 bg-transparent" autocomplete="off" type="search" name="q" placeholder="Search...">
<button class="text-white deco-none float-right border-0 bg-transparent" type="submit"><i class="fas fa-search"></i></button>
</form>
</li>
</ul>
index.html
{% extends "layout.html" %}
{% block title %}
Homepage
{% endblock %}
{% block main %}
<h3 class="text-white offset-1 mb-3">Homepage</h3>
{% for i in range(ideas|length) %}
<div class="card bg-white col-10 mx-auto mb-2">
<div class="card-body">
<h5 class="card-title font-weight-bold" role="button" data-toggle="collapse" data-target="#idea-content-{{ i }}" aria-expanded="false">
{{ ideas[i].idea_name }} <i class="fas fa-angle-down fa-lg float-right"></i>
</h5>
<div class="collapse" id="idea-content-{{ i }}">
<p class="fw-600 card-text mb-2">Posted:- {{ ideas[i].post_date|date_format }}</p>
<p class="fw-600 card-text mb-2">Created By:- <a class="text-dark hover-link" href="/profile/{{ ideas[i].user_id }}">{{ ideas[i].username }}</a></p>
<p class="card-text">{{ ideas[i].idea_body }}</p>
{% if session.user_id != ideas[i].user_id %}
<form action="/like">
{% if ideas[i].liked %}
<button class="btn btn-primary mr-2" disabled>Liked!</button>
{% else %}
<button type="submit" class="btn btn-primary mr-2" name="id" value="{{ ideas[i].id }}">Like 💛</button>
{% endif %}
</form>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endblock %}
This sql gives an error to the effect that there are more parameters than placeholders:
SELECT ideas.id AS id, username, user_id, idea_name, idea_body, post_date
FROM ideas
INNER JOIN users ON users.id = ideas.user_id
WHERE posted = 1 AND idea_name LIKE '%?%'
ORDER BY post_date DESC
This %?% is a string literal. Either break the ? out from quotes or use named parameter (which would also not be in quotes). I don't know why you don't see this error in the flask log. That's ostensibly how I found it on repro.
Related
I'm making a basic chat app with flask.
I have this page and this piece of code
#app.route('/', methods = ['GET', 'POST'])
def chat():
if request.method == 'POST':
message_content = request.form['content']
message_author = request.form['name']
if message_content:
new_message = Message(content = message_content, author = message_author)
db.session.add(new_message)
db.session.commit()
return redirect('/')
else:
all_messages = Message.query.order_by(Message.date.desc()).all()
return render_template('chat.html', posts=all_messages)
and I would like to every time I hit the "Send" button it takes the information of the input in the header and the info of the message. So, my question is, can I take the informations of two different forms with only one button ?
Html code (with a bit of jinja 2):
{% block body %}
<!-- Navbar -->
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Chat</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
</ul>
<form action="/" class="d-flex" method="POST">
FORM THAT CONTAINS THE NAME -- > <input class="form-control me-2" type="search" id="name" placeholder="Name" value="{% if message_author %}{{ message_author }}{% else %}Unknown{% endif %}" aria-label="Search">
<!-- <button class="btn btn-outline-success" type="submit">Save</button> -->
</form>
</div>
</div>
</nav>
<!-- New message form -->
<br>
<div class="bg-light p-5 rounded">
<h2 class="createPost">New message </h2>
<form action="/" method="POST">
<input type="text" name="content" id="content" class="createPost">
<br>
<input type="submit" value="Send" class="btn btn-outline-dark" id="submit">
</form>
</div>
<hr>
<!-- Display messages -->
{% for post in posts %}
<div class="">
{% if post.author %}
{% if post.date %}
<small class="">{{ post.date.replace(microsecond=0) }} - {{ post.author }} : </small>
{% else %}
<small class="">{{ post.author }}</small>
{% endif %}
{% else %}
{% if post.date %}
<small class="">{{ post.date }} - Unkown : </small>
{% else %}
<small class="">N/A - Unkown</small>
{% endif %}
{% endif %}
<p class="">{{ post.content }}</p>
Delete
<!-- Edit -->
<hr>
</div>
{% endfor %}
{% endblock %}
You could create a hidden input inside your send form and on submit copy the value (with javascript) of the input from the other form.
<input id="name" type="text" value="" name="name" class="btn btn-outline-dark" id="submit">
<form>
<input id="hiddenName" type="hidden" value="" name="name" class="btn btn-outline-dark" >
<input onclick="document.getElementById('hiddenName').value = document.getElementById('name').value" type="button" value="Send" class="btn btn-outline-dark" id="submit">
</form>
I know this is my first question and I wouldn't be like writing it here, but I have a problem which I couldn't handle for 2 days now.
I am writing an app in Django, and my goal is to handle requests from google books API and display books in the template which I did.
I wrote a function like this
services.py
from googleapiclient.discovery import build
import json
def get_books_data(query):
"""Retriving data from google books API"""
service = build('books',
'v1',
developerKey=API_KEY
)
request = service.volumes().list(q=query)
response = request.execute()
book_list = [response['items'][item]['volumeInfo']
for item in range(len(response['items']))]
return book_list
I get a list of key: value pairs representing ten books from API.
I passed them into a template like this
views.py
def search(request):
query = request.GET.get('q')
books = get_books_data(query)
context = {
'books': books
}
return render(request, 'books_list.html', context)
This is how book_list.html looks like.
list_book.html
{% extends 'base.html' %}
{% load static %}
{% block content%}
{% for book in books %}
<div class="row">
<div class="col-lg-8 mx-auto">
<ul class="list-group shadow">
<li class="list-group-item">
<div class="media align-items-lg-center flex-column flex-lg-row p-3">
<div class="media-body order-2 order-lg-1">
<h5 class="mt-0 font-weight-bold mb-2">{{ book.title }}</h5>
<p class="font-italic text-muted mb-0 small">{{ book.subtitle }}</p>
{% for identifier in book.industryIdentifiers %}
<p class="font-italic text-muted mb-0 small">{{ identifier.type }} : {{ identifier.identifier }}</p>
{% endfor %}
<p class="font-italic text-muted mb-0 small">Language: {{ book.language }}</p>
<p class="font-italic text-muted mb-0 small">Published date: {{ book.publishedDate }}</p>
<div class="media-body order-2 order-lg-1">
{% if book.authors %}
<h6 class="font-weight-bold my-2">Authors:</h6>
{% for author in book.authors %}
<p class="font-italic text-muted mb-0 small">{{ author }}</p>
{% endfor %}
{% endif %}
</div>
{% if book.pageCount %}
<div class="d-flex align-items-center justify-content-between mt-1">
<h6 class="font-weight-bold my-2">Number of pages: {{book.pageCount}}</h6>
</div>
{% endif %}
</div>
{% if book.imageLinks %}
<img class="thumbnail" src="{{book.imageLinks.thumbnail}}" alt="">
{% else %}
<img class="thumbnail2" src="{% static 'images/placeholder4.png'%}" alt="">
{% endif %}
</div>
<form action="." method="post">
{% csrf_token %}
<button type="submit" class="btn btn-primary">ADD THIS BOOK TO YOUR BOOKSHELF</button>
</form>
</li>
</ul>
</div>
</div>
{% endfor %}
{% endblock content %}
And last part of my task is to have a button in each card with a book, I can use to save a particular book from API to the database.
I am a beginner in Django, and I've tried to use forms, I've read, I could use Django Rest Framework somehow but really, I don't have an idea, how I could approach this problem.
Please, Can you help me?
Than you in advance.
The voting proceess is working fine with this code. The problem is only when redirecting after voting the options.
Exception Type:DoesNotExist
Exception Value:
Category matching query does not exist.
category = Category.objects.get(slug=slug)
urls.py
path('<slug>/',views.options,name='options'),
path('<slug>/vote/', views.vote, name='vote'),
views.py
def home(request):
categories = Category.objects.filter(active=True)
return render(request,'rank/base.html',{'categories': categories,'title':'TheRanker'})
def options(request,slug):
category = Category.objects.get(slug=slug)
options = Option.objects.filter(category=category)
return render(request,'rank/options.html',{'options':options,'title':'options'})
def vote(request,slug):
option = Option.objects.get(slug=slug)
if Vote.objects.filter(slug=slug,voter_id=request.user.id).exists():
messages.error(request,'You Already Voted!')
return redirect('rank:options',slug)
else:
option.votes += 1
option.save()
voter = Vote(voter=request.user,option=option)
voter.save()
messages.success(request,'Voted!')
return redirect('rank:options',slug)
options.html
{% extends "rank/base.html" %}
<title>{% block title %}{{title}}{% endblock title%}</title>
{% load bootstrap4 %}
{% block content %}
<center><br>
<center>{% bootstrap_messages %}</center>
<ol type="1">
{% for option in options %}
<div class="col-lg-6 col-md-6 mb-6">
<div class="card h-100">
<div class="card-body">
<b><li>
<img src="/media/{{option.image}}" width="200" height="100">
<h4>{{option.name}}
</h4>
<h5 class="card-text">{{ option.details}}</h5>
<h5>{{ option.votes }} votes</h5>
<form action="{% url 'rank:vote' option.slug %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-success" value="Vote" >
</form>
</li></b>
</div>
<div class="card-footer">
<small class="text-muted"></small>
</div>
</div>
</div>
{% endfor %}
</ol>
</center>
{% endblock content%}
You're confusing categories and options. The form sends the slug of the option, but then you redirect to the categories view using the same slug. But those are two different models.
I am building a e-commerce flask site and i am stuck on adding to cart secquence.
I have tryed to use a POST request to store it in a db then display it in a /cart view. Any help would be great thanks so much. Heres what i got so far.
models.py
class ATC(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80))
description = db.Column(db.Text)
price = db.Column(db.String(80))
views.py
def shop():
products = Product.query.all()
return render_template('product/index.html', prod=products)
#app.route('/addcart', methods=('GET', 'POST'))
def addcart():
title = request.form['{{ product.title }}']
description = request.form['{{ product.description|safe }}']
price = request.form['{{ product.price }}']
add = ATC(title=title, description=description, price=price)
db.session.add(add)
db.session.commit()
return redirect(url_for('cart'))
index.html (for the shop)
{% if current_user.has_role('admin') %}
<i class="fa fa-plus"> New Product</i>
{% endif %}
<div class="row text-center">
{% for product in prod %}
<div class="col-lg-3 col-md-6 mb-4">
<form name="addForm" id="addForm" method="POST" action="{{ url_for('addcart') }}" novalidate>
<div class="card">
<div class="card-body">
<li class="header"><img src="{{ product.images }}" width="180" height="175"></li>
<p class="card-text1">--------------------------------------</p>
<h4 class="card-title" name="{{ product.title }}">{{ product.title }}</h4>
<p class="card-text" name="{{ product.description|safe }}">{{ product.description|safe }}</p>
</div>
<h4 class="card-title" name="{ product.price }}">${{ product.price }}</h4>
<div class="card-footer">
<button type="submit" class="btn btn-primary" id="sendMessageButton">ATC</button>
{% if current_user.has_role('admin') %}
<div class="row justify-content-center" style="margin-top:5px;">
Delete!
Edit!
</div>
{% endif %}
</div>
</div>
</form>
</div>
{% endfor %}
I want be able to store this info into a db and the display it the the /cart view.
Thanks so much!
In my base template I have this search bar. When I search for something it doesn't actually return anything. I'm not sure if the url is correct because I want it to work on every page.
In the base navbar this is the code:
<form class="navbar-form navbar-left" target="_self">
<div class="form-group">
<label class="control-label" for="search-field">
<i class="glyphicon glyphicon-search"></i></label>
<input type="text/submit" value="{{request.GET.q}}" name="q"
class="form-control search-field"
action={% url 'search_posts' %}
placeholder="Search Airline or Aircraft" id="search-field" />
</div>
</form>
Urls.py
url(r'^$', search_posts, name='search_posts'),
Views.py
def search_posts(request):
aircraft = Aircraft.objects.all()
airline = Airline.objects.all()
query = request.GET.get("q")
if query:
aircraft = aircraft.filter(
Q(name__icontains=query) |
Q(description__icontains=query)
).distinct()
return render(request, 'search_post.html', {'aircraft': aircraft})
Is it possible to combine two models into a variable? I have Aircraft and Airline. Will this work?
queryset_list = Aircraft.objects.all() + Airline.objects.all()
Views.py Updated
def search_posts(request):
aircraft = Aircraft.objects.all()
airline = Airline.objects.all()
query = request.GET.get("q")
aircraft = aircraft.filter(
Q(name__icontains=query) |
Q(description__icontains=query)).distinct()
airline = airline.filter(
Q(name__icontains=query) |
Q(description__icontains=query)).distinct()
return render(request, 'search_post.html', {'aircraft': aircraft,'airline': airline })
search_post.html
<div class="team-boxed">
<div class="container">
<div class="row aircraft">
{% for aircraft in aircraft %}
<div class="col-lg-offset-0 col-md-4 col-sm-3 item">
<div class="box"><img src="{{ aircraft.image.url }}" />
<h3 class="name">{{ aircraft.name }}</h3>
<h4><em>Range: {{ aircraft.maximum_range }} NM</em></h4>
<h4><em> Passengers: {{ aircraft.passengers }}</em></h4>
<h4><em> Speed: {{ aircraft.cruising_speed }} Kt</em></h4>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
Since HTML input elements do not have an action attribute, remove action={% url 'search_posts' %} from <input> and place it inside the <form> like this:
<form action={% url 'search_posts' %} method="GET" ...>
Also remove the type="text/submit" from the input and replace it with just text (in order to present the user a text input box to write the query - thanks Alasdair for that - haven't seen that), like this:
<input type="text" ...>
so, the form should look like this:
<form method="GET" action={% url 'search_posts' %} class="navbar-form navbar-left">
<div class="form-group">
<label class="control-label" for="search-field">
<i class="glyphicon glyphicon-search"></i></label>
<input type="text" value="{{request.GET.q}}" name="q" class="form-control search-field" placeholder="Search Airline or Aircraft" id="search-field" />
</div>
</form>
Concerning the other part of your question, in order to combine two (or more) QuerySets (I can't imagine why you would want to do that), here it is:
qs = list(Aircraft.objects.all()) + list(Airline.objects.all())
Finally in your search_post.html do this:
{% if aircraft.exists %}
<div class="team-boxed">
<div class="container">
<div class="row aircraft">
{% for aircraft in aircraft %}
<div class="col-lg-offset-0 col-md-4 col-sm-3 item">
<div class="box"><img src="{{ aircraft.image.url }}"></div>
<h3 class="name">{{ aircraft.name }}</h3>
<h4><em>Range: {{ aircraft.maximum_range }} NM</em></h4>
<h4><em> Passengers: {{ aircraft.passengers }}</em></h4>
<h4><em> Speed: {{ aircraft.cruising_speed }} Kt</em></h4>
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% if airline.exists %}
<div class="team-boxed">
<div class="container">
<div class="row airline">
{% for airline in airline %}
<div class="col-lg-offset-0 col-md-4 col-sm-3 item">
<div class="box"><img src="{{ airline.image.url }}"></div>
<h3 class="name">{{ airline.name }}</h3>
<h4><em>Range: {{ airline.maximum_range }} NM</em></h4>
<h4><em> Passengers: {{ airline.passengers }}</em></h4>
<h4><em> Speed: {{ airline.cruising_speed }} Kt</em></h4>
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}