Spaces:
Runtime error
Runtime error
Commit
·
cb7f5fc
1
Parent(s):
749e816
added project files and dockerfile
Browse files- Dockerfile +10 -0
- __pycache__/__init__.cpython-39.pyc +0 -0
- __pycache__/app.cpython-39.pyc +0 -0
- __pycache__/database.cpython-39.pyc +0 -0
- app.py +10 -0
- database.py +66 -0
- models/__pycache__/schema.cpython-39.pyc +0 -0
- models/schema.py +98 -0
- requirements.txt +5 -0
- routes/__pycache__/__init__.cpython-39.pyc +0 -0
- routes/__pycache__/student_routes.cpython-39.pyc +0 -0
- routes/student_routes.py +59 -0
Dockerfile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
WORKDIR /app
|
| 3 |
+
COPY requirements.txt ./requirements.txt
|
| 4 |
+
# Install uvicorn
|
| 5 |
+
RUN pip install uvicorn
|
| 6 |
+
# Install dependencies
|
| 7 |
+
RUN pip install -r requirements.txt
|
| 8 |
+
COPY . /app
|
| 9 |
+
ENTRYPOINT ["uvicorn", "app:app"]
|
| 10 |
+
CMD ["--host", "0.0.0.0", "--port", "7860"]
|
__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (162 Bytes). View file
|
|
|
__pycache__/app.cpython-39.pyc
ADDED
|
Binary file (539 Bytes). View file
|
|
|
__pycache__/database.cpython-39.pyc
ADDED
|
Binary file (1.92 kB). View file
|
|
|
app.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from routes.student_routes import router as StudentRouter
|
| 3 |
+
|
| 4 |
+
app = FastAPI(title="FastAPI and MongoDB")
|
| 5 |
+
app.include_router(StudentRouter, tags=["Student"], prefix="/student")
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@app.get("/", tags=["Root"])
|
| 9 |
+
async def root():
|
| 10 |
+
return {"message": "FastAPI and MongoDB"}
|
database.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import motor.motor_asyncio
|
| 2 |
+
import os
|
| 3 |
+
from bson.objectid import ObjectId
|
| 4 |
+
|
| 5 |
+
MONGO_DETAILS = os.getenv("MONGO_DETAILS")
|
| 6 |
+
|
| 7 |
+
client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)
|
| 8 |
+
|
| 9 |
+
database = client.fastapi_students
|
| 10 |
+
|
| 11 |
+
students_collection = database.get_collection("students")
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
# helpers
|
| 15 |
+
def student_helper(student) -> dict:
|
| 16 |
+
return {
|
| 17 |
+
"id": str(student["_id"]),
|
| 18 |
+
"name": student["name"],
|
| 19 |
+
"email": student["email"],
|
| 20 |
+
"password": student["password"],
|
| 21 |
+
"year": student["year"],
|
| 22 |
+
"branch": student["branch"],
|
| 23 |
+
"division": student["division"],
|
| 24 |
+
"pin": student["pin"],
|
| 25 |
+
"gpa": student["gpa"],
|
| 26 |
+
"phone": student["phone"],
|
| 27 |
+
"address": student["address"],
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Retrieve all students present in the database
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
async def get_all():
|
| 34 |
+
students = []
|
| 35 |
+
async for student in students_collection.find():
|
| 36 |
+
students.append(student_helper(student))
|
| 37 |
+
return students
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
async def add(student_data: dict) -> dict:
|
| 41 |
+
student = await students_collection.insert_one(student_data)
|
| 42 |
+
new_student = await students_collection.find_one({"_id": student.inserted_id})
|
| 43 |
+
return student_helper(new_student)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
async def get(PIN: str) -> dict:
|
| 47 |
+
student = await students_collection.find_one({"pin": PIN})
|
| 48 |
+
if student:
|
| 49 |
+
return student_helper(student)
|
| 50 |
+
|
| 51 |
+
async def update(PIN: str, updated_data: dict) -> dict:
|
| 52 |
+
if not updated_data:
|
| 53 |
+
return False
|
| 54 |
+
student = await students_collection.find_one({"pin": PIN})
|
| 55 |
+
if student:
|
| 56 |
+
students_collection.update_one({"pin": PIN}, {"$set": updated_data})
|
| 57 |
+
return True
|
| 58 |
+
return False
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
async def delete(PIN: str):
|
| 62 |
+
student = await students_collection.find_one({"pin": PIN})
|
| 63 |
+
if student:
|
| 64 |
+
await students_collection.delete_one({"pin": PIN})
|
| 65 |
+
return True
|
| 66 |
+
return False
|
models/__pycache__/schema.cpython-39.pyc
ADDED
|
Binary file (3.25 kB). View file
|
|
|
models/schema.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional
|
| 2 |
+
from pydantic import BaseModel, Field, EmailStr
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class StudentSchema(BaseModel):
|
| 6 |
+
name: str = Field(..., example="John Doe",
|
| 7 |
+
description="Name of the student")
|
| 8 |
+
email: EmailStr = Field(..., example="johndoe@gmail.com",
|
| 9 |
+
description="Email of the student")
|
| 10 |
+
password: str = Field(..., example="JohnDoe123",
|
| 11 |
+
description="Password of the student")
|
| 12 |
+
year: int = Field(..., gt=0, lt=5, example=1, description="Year of study")
|
| 13 |
+
branch: str = Field(..., min_length=3,
|
| 14 |
+
example="CSE or Computer Science and Engineering", description="Branch of study")
|
| 15 |
+
division: str = Field(..., min_length=1, max_length=1,
|
| 16 |
+
example="A", description="Division of study")
|
| 17 |
+
pin: str = Field(..., min_length=10, max_length=10,
|
| 18 |
+
example="20KJ1A0501", description="PIN of the student")
|
| 19 |
+
gpa: Optional[float] = Field(
|
| 20 |
+
None, gt=0, lt=10, example=9.0, description="GPA of the student")
|
| 21 |
+
phone: int = Field(..., gt=1000000000, lt=9999999999,
|
| 22 |
+
example=1234567890, description="Phone number of the student")
|
| 23 |
+
address: str = Field(..., min_length=3, max_length=100,
|
| 24 |
+
example="123, 1st cross, 1st main, City, State, Country - 123456", description="Address of the student")
|
| 25 |
+
|
| 26 |
+
class Config:
|
| 27 |
+
schema_extra = {
|
| 28 |
+
"Example": {
|
| 29 |
+
"name": "John Doe",
|
| 30 |
+
"email": "Johndoe@example.com",
|
| 31 |
+
"password": "JohnDoe123",
|
| 32 |
+
"year": 1,
|
| 33 |
+
"branch": "CSE",
|
| 34 |
+
"division": "A",
|
| 35 |
+
"pin": "20KJ1A0501",
|
| 36 |
+
"gpa": 9.0,
|
| 37 |
+
"phone": 1234567890,
|
| 38 |
+
"address": """
|
| 39 |
+
123, 1st cross, 1st main,
|
| 40 |
+
City, State, Country - 123456""",
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class StudentUpdateSchema(BaseModel):
|
| 46 |
+
name: Optional[str] = Field(
|
| 47 |
+
None, example="John Doe", description="Name of the student")
|
| 48 |
+
email: Optional[EmailStr] = Field(
|
| 49 |
+
None, example="johndoe@example.com", description="Email")
|
| 50 |
+
password: Optional[str] = Field(
|
| 51 |
+
None, example="JohnDoe123", description="Password")
|
| 52 |
+
year: Optional[int] = Field(
|
| 53 |
+
None, gt=0, lt=5, example=1, description="Year of study")
|
| 54 |
+
branch: Optional[str] = Field(
|
| 55 |
+
None, min_length=3, example="CSE or Computer Science and Engineering", description="Branch of study")
|
| 56 |
+
division: Optional[str] = Field(
|
| 57 |
+
None, min_length=1, max_length=1, example="A", description="Division of study")
|
| 58 |
+
pin: Optional[str] = Field(None, min_length=10, max_length=10,
|
| 59 |
+
example="20KJ1A0501", description="PIN of the student")
|
| 60 |
+
gpa: Optional[float] = Field(
|
| 61 |
+
None, gt=0, lt=10, example=9.0, description="GPA of the student")
|
| 62 |
+
|
| 63 |
+
phone: Optional[int] = Field(None, gt=1000000000, lt=9999999999,
|
| 64 |
+
example=1234567890, description="Phone number of the student")
|
| 65 |
+
|
| 66 |
+
address: Optional[str] = Field(None, min_length=3, max_length=100,
|
| 67 |
+
example="123, 1st cross, 1st main, City, State, Country - 123456",
|
| 68 |
+
description="Address of the student")
|
| 69 |
+
|
| 70 |
+
class Config:
|
| 71 |
+
schema_extra = {
|
| 72 |
+
"Example": {
|
| 73 |
+
"name": "John Doe",
|
| 74 |
+
"email": "Johndoe@example.com",
|
| 75 |
+
"password": "JohnDoe123",
|
| 76 |
+
"year": 1,
|
| 77 |
+
"branch": "CSE",
|
| 78 |
+
"division": "A",
|
| 79 |
+
"pin": "20KJ1A0501",
|
| 80 |
+
"gpa": 9.0,
|
| 81 |
+
"phone": 1234567890,
|
| 82 |
+
"address": """
|
| 83 |
+
123, 1st cross, 1st main,
|
| 84 |
+
City, State, Country - 123456""",
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def ResponseModel(data, message):
|
| 90 |
+
return {
|
| 91 |
+
"data": [data],
|
| 92 |
+
"code": 200,
|
| 93 |
+
"message": message,
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def ErrorResponseModel(error, code, message):
|
| 98 |
+
return {"error": error, "code": code, "message": message}
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.96.0
|
| 2 |
+
motor==2.5.1
|
| 3 |
+
pydantic==1.10.2
|
| 4 |
+
pydantic[email]
|
| 5 |
+
pymongo==3.13.0
|
routes/__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (171 Bytes). View file
|
|
|
routes/__pycache__/student_routes.cpython-39.pyc
ADDED
|
Binary file (2.51 kB). View file
|
|
|
routes/student_routes.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Body, status
|
| 2 |
+
from fastapi.encoders import jsonable_encoder
|
| 3 |
+
from models.schema import (
|
| 4 |
+
StudentSchema,
|
| 5 |
+
StudentUpdateSchema,
|
| 6 |
+
ResponseModel,
|
| 7 |
+
ErrorResponseModel,
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
from database import *
|
| 11 |
+
|
| 12 |
+
router = APIRouter()
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
@router.post("/", response_description="Student data added into the database")
|
| 16 |
+
async def add_student_data(student: StudentSchema = Body(...)):
|
| 17 |
+
student = jsonable_encoder(student)
|
| 18 |
+
|
| 19 |
+
if get_student_data(student["pin"]):
|
| 20 |
+
return ErrorResponseModel("Student Exist", 404, f"Student with PIN: {student['pin']} already exists.")
|
| 21 |
+
|
| 22 |
+
new_student = await add(student)
|
| 23 |
+
return ResponseModel(new_student, "Student added successfully.")
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@router.get("/all", response_description="Students Data Retrieved")
|
| 27 |
+
async def get_all_students():
|
| 28 |
+
students = await get_all()
|
| 29 |
+
if len(students) < 1:
|
| 30 |
+
return ErrorResponseModel("Empty Database", 404, "No Students data found")
|
| 31 |
+
|
| 32 |
+
if students:
|
| 33 |
+
return ResponseModel(students, "Retrieved all students data")
|
| 34 |
+
ErrorResponseModel("An Error Occurred", 404, "No Students database found")
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@router.get("/{pin}", response_description="Student data retrieved")
|
| 38 |
+
async def get_student_data(pin):
|
| 39 |
+
student = await get(pin)
|
| 40 |
+
if student:
|
| 41 |
+
return ResponseModel(student, "Student data retrieved successfully")
|
| 42 |
+
return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@router.put("/{pin}")
|
| 46 |
+
async def update_student_data(pin: str, data: StudentUpdateSchema = Body(...)):
|
| 47 |
+
data = {k: v for k, v in data.dict().items() if v is not None}
|
| 48 |
+
updated_student = await update(pin, data)
|
| 49 |
+
if updated_student:
|
| 50 |
+
return ResponseModel(updated_student, f"{pin} data updated")
|
| 51 |
+
return ErrorResponseModel("An Error occurred", 404, "Cannot update the data. Maybe pin doesn't exist")
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@router.delete("/delete/{pin}", response_description="Delete student from database")
|
| 55 |
+
async def delete_student(pin: str):
|
| 56 |
+
student = await delete(pin)
|
| 57 |
+
if student:
|
| 58 |
+
return ResponseModel(f"Student with {pin} removed from the database", "Operation Success")
|
| 59 |
+
return ErrorResponseModel("An Error occurred", 404, f"student with PIN {pin} does not exist")
|