Spaces:
Build error
license: apache-2.0
title: Assignment
sdk: docker
emoji: π¨
colorFrom: purple
colorTo: indigo
Place Review REST API
A production-ready REST API for a mobile app that allows users to review places (shops, doctors, restaurants, etc.), built with Django and Django REST Framework.
Features
- User Registration: Phone-based user registration (one user per phone number)
- Authentication: Token-based authentication for all endpoints
- Reviews: Users can add reviews with 1-5 ratings for any place
- Smart Search: Search places by name (exact match prioritized) and/or minimum rating
- Place Details: View place information with all reviews, current user's review shown first
- Automatic Place Creation: Places are automatically created when adding a review if they don't exist
Technology Stack
- Framework: Django 5.0 with Django REST Framework
- Database: SQLite (can be easily switched to PostgreSQL or MySQL)
- Authentication: Token-based authentication
- Data Generation: Faker for realistic sample data
Installation
Prerequisites
- Python 3.8 or higher
- pip (Python package manager)
Setup Steps
Clone or extract the project
cd "d:\SDE intern Assignment"Create a virtual environment (recommended)
python -m venv venv # On Windows venv\Scripts\activate # On macOS/Linux source venv/bin/activateInstall dependencies
pip install -r requirements.txtRun database migrations
python manage.py makemigrations python manage.py migratePopulate the database with sample data
python manage.py populate_dataThis will create:
- 50 users with realistic names and phone numbers
- 100 places (restaurants, cafes, shops, doctors, gyms, salons)
- 300+ reviews with varied ratings
Note: The command will display sample user credentials that you can use for testing.
Create a superuser (optional, for admin access)
python manage.py createsuperuserRun the development server
python manage.py runserverThe API will be available at
http://127.0.0.1:8000/
API Endpoints
All endpoints (except registration and login) require authentication via token header:
Authorization: Token YOUR_AUTH_TOKEN
1. User Registration
Endpoint: POST /api/register/
Description: Register a new user with name and phone number.
Request Body:
{
"name": "John Doe",
"phone": "1234567890"
}
Response (201 Created):
{
"user": {
"id": 1,
"name": "John Doe",
"phone": "1234567890"
},
"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
}
Error (400 Bad Request):
{
"phone": ["user with this phone already exists."]
}
2. User Login
Endpoint: POST /api/login/
Description: Login with phone number to receive authentication token.
Request Body:
{
"phone": "1234567890"
}
Response (200 OK):
{
"user": {
"id": 1,
"name": "John Doe",
"phone": "1234567890"
},
"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
}
Error (404 Not Found):
{
"error": "User with this phone number does not exist"
}
3. Add Review
Endpoint: POST /api/reviews/add/
Description: Add a review for a place. If the place doesn't exist, it will be created automatically.
Headers:
Authorization: Token YOUR_TOKEN
Request Body:
{
"place_name": "Joe's Pizza",
"place_address": "123 Main St, New York, NY",
"rating": 5,
"review_text": "Best pizza in town! The crust is perfect."
}
Response (201 Created):
{
"message": "Review added successfully",
"review": {
"id": 1,
"user_name": "John Doe",
"rating": 5,
"text": "Best pizza in town! The crust is perfect.",
"created_at": "2024-01-01T12:00:00Z"
}
}
Notes:
- If a place with the exact name and address exists, the review will be added to it
- If the place doesn't exist, it will be created automatically
- If the user has already reviewed this place, the review will be updated
4. Search Places
Endpoint: GET /api/places/search/
Description: Search for places by name and/or minimum rating.
Headers:
Authorization: Token YOUR_TOKEN
Query Parameters:
name(optional): Search by place name (case-insensitive, exact matches shown first)min_rating(optional): Filter by minimum average rating
Examples:
Search by name only:
GET /api/places/search/?name=pizza
Search by minimum rating only:
GET /api/places/search/?min_rating=4
Search by both:
GET /api/places/search/?name=pizza&min_rating=4
Response (200 OK):
[
{
"id": 1,
"name": "Joe's Pizza",
"address": "123 Main St, New York, NY",
"average_rating": 4.5
},
{
"id": 2,
"name": "Pizza Paradise",
"address": "456 Oak Ave, Brooklyn, NY",
"average_rating": 4.2
}
]
Search Logic:
- Exact matches are shown first, followed by partial matches
- Case-insensitive search
- Results are filtered by minimum rating if specified
5. Place Details
Endpoint: GET /api/places/{place_id}/
Description: Get detailed information about a place, including all reviews. The current user's review appears first, followed by all other reviews sorted by newest first.
Headers:
Authorization: Token YOUR_TOKEN
Example:
GET /api/places/1/
Response (200 OK):
{
"id": 1,
"name": "Joe's Pizza",
"address": "123 Main St, New York, NY",
"average_rating": 4.5,
"reviews": [
{
"id": 5,
"user_name": "John Doe",
"rating": 5,
"text": "Best pizza in town!",
"created_at": "2024-01-01T12:00:00Z"
},
{
"id": 3,
"user_name": "Jane Smith",
"rating": 4,
"text": "Great pizza, slightly pricey",
"created_at": "2024-01-02T14:00:00Z"
},
{
"id": 1,
"user_name": "Bob Johnson",
"rating": 5,
"text": "Amazing crust!",
"created_at": "2023-12-30T10:00:00Z"
}
]
}
Error (404 Not Found):
{
"error": "Place not found"
}
Testing the API
Using curl
- Register a user:
curl -X POST http://127.0.0.1:8000/api/register/ \
-H "Content-Type: application/json" \
-d "{\"name\": \"Test User\", \"phone\": \"9999999999\"}"
- Login (use a phone from the populate_data output):
curl -X POST http://127.0.0.1:8000/api/login/ \
-H "Content-Type: application/json" \
-d "{\"phone\": \"1234567890\"}"
- Add a review (replace YOUR_TOKEN):
curl -X POST http://127.0.0.1:8000/api/reviews/add/ \
-H "Content-Type: application/json" \
-H "Authorization: Token YOUR_TOKEN" \
-d "{\"place_name\": \"New Place\", \"place_address\": \"123 Test St\", \"rating\": 5, \"review_text\": \"Excellent!\"}"
- Search places:
curl -X GET "http://127.0.0.1:8000/api/places/search/?name=pizza&min_rating=4" \
-H "Authorization: Token YOUR_TOKEN"
- Get place details:
curl -X GET http://127.0.0.1:8000/api/places/1/ \
-H "Authorization: Token YOUR_TOKEN"
Using Postman or Similar Tools
- Import the API endpoints
- Set up an environment variable for the auth token
- Test each endpoint according to the examples above
Database Schema
User Model
id: Primary key (auto-generated)phone: Unique phone number (used for authentication)name: User's namedate_joined: Timestamp of registration
Place Model
id: Primary key (auto-generated)name: Place nameaddress: Place addresscreated_at: Timestamp- Unique constraint: (name, address)
Review Model
id: Primary key (auto-generated)user_id: Foreign key to Userplace_id: Foreign key to Placerating: Integer (1-5)text: Review textcreated_at: Timestamp- Unique constraint: (user, place) - one review per user per place
Production Deployment Notes
For production deployment, you should:
- Change the SECRET_KEY in
settings.pyto a secure random value - Set DEBUG = False in
settings.py - Configure ALLOWED_HOSTS with your domain
- Use PostgreSQL or MySQL instead of SQLite:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'your_db_name', 'USER': 'your_db_user', 'PASSWORD': 'your_db_password', 'HOST': 'localhost', 'PORT': '5432', } } - Set up static files serving
- Use a production WSGI server like Gunicorn or uWSGI
- Set up HTTPS with SSL certificates
Project Structure
SDE intern Assignment/
βββ manage.py # Django management script
βββ requirements.txt # Python dependencies
βββ db.sqlite3 # SQLite database (auto-generated)
βββ place_review_api/ # Main project directory
β βββ __init__.py
β βββ settings.py # Django settings
β βββ urls.py # Root URL configuration
β βββ asgi.py # ASGI configuration
β βββ wsgi.py # WSGI configuration
βββ reviews/ # Reviews app
βββ __init__.py
βββ admin.py # Admin interface configuration
βββ apps.py # App configuration
βββ models.py # Database models
βββ serializers.py # DRF serializers
βββ views.py # API views
βββ urls.py # App URL routing
βββ management/ # Management commands
β βββ __init__.py
β βββ commands/
β βββ __init__.py
β βββ populate_data.py # Data population script
βββ migrations/ # Database migrations (auto-generated)
βββ __init__.py
Design Decisions and Assumptions
Phone-based Authentication: Users register and login with phone numbers. No password is required in this basic version, but it can be easily extended.
SQLite Database: Used for portability and ease of submission. The code works with any relational database (PostgreSQL, MySQL, etc.) by simply changing the database configuration.
Atomic Place Creation: When adding a review, if a place with the same name and address doesn't exist, it's created atomically using
get_or_create().Review Updates: If a user reviews the same place twice, their review is updated rather than creating a duplicate.
Search Priority: Exact name matches are shown before partial matches to improve relevance.
Review Sorting: On the place details page, the current user's review always appears first (if they've reviewed it), followed by all other reviews sorted by newest first.
Rating Distribution: The sample data generator creates reviews with ratings skewed toward positive (4-5 stars) to simulate realistic rating distributions.
Token Authentication: Simple and effective for mobile apps. Tokens never expire in this version but can be configured to expire.
Code Quality Highlights
- Type Safety: Proper use of Django's field validators and constraints
- Database Integrity: Unique constraints and foreign key relationships
- Atomic Operations: Uses transactions for data population
- Error Handling: Comprehensive error responses with appropriate HTTP status codes
- Code Documentation: Docstrings for all views and complex methods
- DRY Principle: Reusable serializers and efficient database queries
- Security: Token authentication required for all sensitive endpoints
- Performance: Database indexes on commonly queried fields
License
This project is submitted as part of a technical assessment.