Deletes deal with removing existing objects in our database.
SQL 语句
DELETE FROM table_name
WHERE condition;
SQLAlchemy 语句
todo = Todo.query.get(todo_id)
db.session.delete(todo)
# or
Todo.query.filter_by(id=todo_id).delete()
db.session.commit()
实现Delete步骤:
- Loop through every items and show a delete button
- Pressing the delete button sends a request that includes which item to delete
- The controller takes the user input, and notifies the models to delete the item object ID
- On successful deletion by the models, the controller should notify the view to refresh the page and redirect to our homepage, showing a fresh of all items to now exclude the removed item.
Using the DELETE method
Requests that delete objects should use the method DELETE, as opposed to POST, GET, etc. when sending requests to the server.
<!DOCTYPE html>
<html>
<head>
<title>Todo app</title>
<style>
.hidden {
display:none;
}
ul {
list-style: none;
padding: 0;
margin: 0;
width: 200px;
}
li {
/* clear: both; */
padding-top: 10px;
}
li button {
-webkit-appearance: none;
border: none;
outline: none;
color: red;
float: right;
cursor: pointer;
font-size: 20px;
}
</style>
</head>
<body>
<form id="form">
<input type="text" id="description" name="description" />
<input type="submit" value="Create" />
</form>
<div id="error" class="hidden">Something went wrong!</div>
<ul id="todos">
{% for d in data %}
<li>
<input class="check-completed" data-id="{
{ d.id }}" type="checkbox" {% if d.completed %} checked {% endif %} />
{
{ d.description }}
<button class="delete-button" data-id="{
{ d.id }}"> X </button>
</li>
{% endfor %}
</ul>
<script>
// Loop over all of the button
const deleteBtns = document.querySelectorAll('.delete-button');
for (let i = 0; i < deleteBtns.length; i++) {
const btn = deleteBtns[i];
btn.onclick = function(e) {
console.log(e);
const todoId = e.target.dataset['id'];
fetch('/todos/' + todoId, {
method: 'DELETE'
});
}
}
// Loop over all of these checkbox elements and listen to the change event with a on change function.
const checkboxes = document.querySelectorAll('.check-completed');
for (let i = 0; i < checkboxes.length; i++) {
const checkbox = checkboxes[i];
checkbox.onchange = function(e) {
console.log('event', e);
const newCompleted = e.target.checked;
const todoId = e.target.dataset['id'];
fetch('/todos/' + todoId + '/set-completed', {
method: 'POST',
body: JSON.stringify({
'completed': newCompleted
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function() {
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
}
// Select on the form
// onsubmit handler to default wound up sending information to the server
// Using the event object, e
document.getElementById('form').onsubmit = function(e) {
// The default behaviro would have done that full page refresh and
// submitted it using the method and action attributes up
e.preventDefault();
// Send the post requests asynchronously using fetch
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
// The value of whatever the user has typed into the description field.
'description': document.getElementById('description').value
}),
headers: {
'Content-Type': 'application/json'
}
})
// give back a promise by which we can then use the
// then method
// callback should give us back a response
.then(function(response) {
// parse out the response which will initially be a string as a JSON response
return response.json();
})
// manipulate the JSON response
.then(function(jsonResponse) {
console.log(jsonResponse);
// Append a child Li element here
const liItem = document.createElement('LI');
liItem.innerHTML = jsonResponse['description'];
document.getElementById('todos').appendChild(liItem);
// it did succeed
document.getElementById("error").className = 'hidden';
})
// catch handler
.catch(function() {
// Remove the class name
document.getElementById("error").className = '';
})
}
</script>
</body>
</html>
from flask import Flask, render_template, request, redirect, url_for, jsonify
from flask_sqlalchemy import SQLAlchemy
import sys
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username@localhost:5432/todoapp'
db = SQLAlchemy(app)
# Link to Flask app as well as the SQLAlchemy database
# migrate will do is start it up so that we can start using the Flask databae migrate commands to began initializing migrations
# and upgrading and downgrading and generating migrations as well.
migrate = Migrate(app, db)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
completed = db.Column(db.Boolean, nullable=False, default=False)
def __repr__(self):
return f'<Todo {
self.id} {
self.description}>'
# Ensure the tables are created for all the models that we've created and they haven't been created.
# db.create_all()
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {
}
try:
# get_json is that it fetches the JSON body that was sent to an object key description.
description = request.get_json()['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
error = True
db.session.rollback()
# debugging sentence
print(sys.exc_info())
finally:
db.session.close()
if not error:
# return a useful JSON object that includes that description.
# jsonify will return JSON data to the client for us.
# whatever we pass in as our JSON object.
return jsonify(body)
@app.route('/todos/<todo_id>/set-completed', methods=['POST'])
def set_completed_todo(todo_id):
try:
completed = request.get_json()['completed']
print('completed', completed)
todo = Todo.query.get(todo_id)
todo.completed = completed
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
return redirect(url_for('index'))
@app.route('/todos/<todo_id>', methods=['DELETE'])
def delete_todo(todo_id):
try:
Todo.query.filter_by(id=todo_id).delete()
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
return jsonify({
'success': True })
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.order_by('id').all())