Good day. I am learning FastAPI – and doing a very simple CRUD application – using Javascript in front-end and FastAPI as backend. All routes are working using the normal localhost/docs swagger docs. I am using jquery and AJAX in front end.
I have postgresql database connected
So far the POST method is working fine – updates database and display in front-end.
I have created 2 form divs:
1- for create method (POST) – works fine – myForm
2- for update method (PUT) – not working – updateForm(static no toggling etc)
The logic on front end is when I click on edit button (using jquery) I display the data in the updateForm — this part is working. As I am able to console log the data and see everything returned.
However when I want to post(i.e. use PUT) method on the Update Article button (on click) the server sends a reponse 200 ok – but no data is updated in the database.
I would appreciate some assistance – been at this for past two days….
index.html
{% extends 'layout.html' %} {% include 'header.html' %} {% block title %} Home {% endblock %} {% block body %}
<script type="text/javascript">
$(document).ready(function() {
var id;
var title;
var description;
$("#add_button").click(function() {
title = $("#title").val();
description = $("#description").val();
$.ajax({
url: "/notes",
type: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
title: title,
description: description
}),
}).then(setTimeout(location.reload.bind(location), 200));
});
$(".edit_button").click(function(id) {
id = this.id;
$.ajax({
url: "/notes/" + id,
type: "get",
dataType: "json",
contentType: "application/json",
success: function(data) {
$($("#updateForm")[0].update_id).val(data.id);
$($("#updateForm")[0].updatetitle).val(data.title);
$($("#updateForm")[0].updatedescription).val(data.description)
console.log(data)
},
});
});
$(".update_button").click(function(id) {
id = this.id
$.ajax({
url: "/notes/" + id,
type: "patch",
dataType: "json",
contentType: "application/json",
success: function(data) {
console.log("success");
},
});
});
});
</script>
<div class="container">
<div class="row">
<div class="col md-12">
<div class="jumbotron">
<form class="row g-3 mb-5 mt-1" id="myForm">
<div class="col-4">
<label for="title" class="visually-hidden">Article Title</label>
<input name="title" type="" class="form-control" id="title" placeholder="title">
</div>
<div class="col-4">
<label for="description" class="visually-hidden">Article Description</label>
<input name="description" type="" class="form-control" id="description" placeholder="description">
</div>
<div class="col-4 mt-2">
<button id="add_button" type="submit" class="btn btn-primary mt-4">Add Article</button>
</div>
</form>
<form class="row g-3 mb-5 mt-1" id="updateForm">
<div class="col-3">
<label for="updatetitle" class="visually-hidden">ID</label>
<input name="update_id" type="" class="form-control update_id" id="update_id">
</div>
<div class="col-3">
<label for="updatetitle" class="visually-hidden">Title</label>
<input name="updatetitle" type="" class="form-control updatetitle" id="updatetitle">
</div>
<div class="col-3">
<label for="updatedescription" class="visually-hidden">Description</label>
<input name="updatedescription" type="" class="form-control updatedescription" id="updatedescription">
</div>
<div class="col-3 mt-2">
<button id="update_button" type="submit" class="btn btn-primary mt-4" onsubmit="True">Update Article</button>
</div>
</form>
<table class="table" id="data_table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{%for note in notes%}
<tr>
<td>{{note.id}}</td>
<td>{{note.title}}</td>
<td>{{note.description}}</td>
<td>
<a class="btn btn-warning btn-xs edit_button" id="{{note.id}}">Edit</a>
<a class="btn btn-danger btn-xs delete_button" id="{{note.id}}">Delete</a>
</td>
</tr>
{%endfor%}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
main.py
from fastapi import FastAPI
from typing import List, Dict, Any
from fastapi import Depends, FastAPI, HTTPException, Request, Response, Form
from fastapi.encoders import jsonable_encoder
from fastapi.responses import HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from fastapi.templating import Jinja2Templates
from . import crud, models, schemas
from .database import SessionLocal, engine
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
templates = Jinja2Templates(directory="templates")
app.add_middleware(
CORSMiddleware,
allow_credentials = True,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
#original function
# @app.get("/notes", response_model=List[schemas.Note])
# def read_notes(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
# notes = crud.get_notes(db=db, skip=skip, limit=limit)
# return notes
# STEP 1 - HOMEPAGE DISPLAY ALL DATA FUNCTION - WORKING
@app.get("/", response_class=HTMLResponse)
def read_notes(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
notes = crud.get_notes(db=db, skip=skip, limit=limit)
return templates.TemplateResponse("index.html", {
"request": request,
"notes": notes,
})
@app.post("/notes", response_model=schemas.Note, status_code=201)
def create_note(note: schemas.NoteCreate, db: Session = Depends(get_db)):
return crud.create_note(db=db, note=note)
@app.get("/notes/{note_id}", response_model=schemas.Note)
def read_user(note_id: int, db: Session = Depends(get_db)):
db_note = crud.get_note(db=db, note_id=note_id)
if db_note is None:
raise HTTPException(status_code=404, detail="Note not found")
return db_note
@app.put("/notes/{note_id}", response_model=schemas.Note, status_code=200)
async def put_note(note_id: int, note: schemas.NoteCreate, db: Session = Depends(get_db)):
db_note = schemas.Note(id = note_id, title= note.title, description=note.description)
crud.update_note(db=db, note=db_note)
@app.patch("/notes/{note_id}", response_model=schemas.Note, status_code=200)
async def patch_note(note_id: int, note: schemas.NoteCreate, db: Session = Depends(get_db)):
print(note_id)
print(note.title)
print(note.description)
db_note = schemas.Note(id = note_id, title= note.title, description=note.description)
crud.update_note(db=db, note=db_note)
@app.delete("/notes/{note_id}", status_code=204)
async def delete_note(note_id: int, db: Session = Depends(get_db)):
return crud.delete_note(db=db, note_id=note_id)
if __name__ == '__main__':
uvicorn.run("main:app", host="127.0.0.1", port=8000)
schemas.py
from typing import List, Optional
from pydantic import BaseModel
class NoteBase(BaseModel):
title: str
description: str
class NoteCreate(NoteBase):
pass
class Note(NoteBase):
id: int
class Config:
orm_mode = True
models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from .database import Base
class Note(Base):
__tablename__ = "notes"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, nullable=True, default="new")
description = Column(String, nullable=True, default="new")
crud.py
from sqlalchemy.orm import Session
from . import models, schemas
def get_note(db: Session, note_id: int):
return db.query(models.Note).filter(models.Note.id == note_id).first()
def delete_note(db: Session, note_id: int):
db_note = db.query(models.Note).filter(models.Note.id == note_id).first()
db.delete(db_note)
db.commit()
return {}
def get_notes(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Note).offset(skip).limit(limit).all()
def create_note(db: Session, note: schemas.NoteCreate):
db_note = models.Note(title=note.title, description=note.description)
db.add(db_note)
db.commit()
db.refresh(db_note)
return db_note
def update_note(db: Session, note: schemas.Note):
db_note = db.query(models.Note).filter(models.Note.id == note.id).first()
db_note.title = note.title
db_note.description = note.description
db.commit()
db.refresh(db_note)
return db_note
2
Answers
I think there are just two small problems with the code you provided.
First
In index.html you are making a get request when the edit button is clicked. You should be making a
post
orput
instead. You can do this withtype: "post"
or put respectively.index.html
Second
In main.py, both your put_note and patch_note routes are not returning anything. You want to be returning the updated model.
main.py
The issue is with your ajax call.. Modify the update_button click function from
to
and it will work..