Assignment / README.md
redhairedshanks1's picture
Update README.md
730e337 verified
---
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
1. **Clone or extract the project**
```bash
cd "d:\SDE intern Assignment"
```
2. **Create a virtual environment (recommended)**
```bash
python -m venv venv
# On Windows
venv\Scripts\activate
# On macOS/Linux
source venv/bin/activate
```
3. **Install dependencies**
```bash
pip install -r requirements.txt
```
4. **Run database migrations**
```bash
python manage.py makemigrations
python manage.py migrate
```
5. **Populate the database with sample data**
```bash
python manage.py populate_data
```
This 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.
6. **Create a superuser (optional, for admin access)**
```bash
python manage.py createsuperuser
```
7. **Run the development server**
```bash
python manage.py runserver
```
The 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**:
```json
{
"name": "John Doe",
"phone": "1234567890"
}
```
**Response** (201 Created):
```json
{
"user": {
"id": 1,
"name": "John Doe",
"phone": "1234567890"
},
"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
}
```
**Error** (400 Bad Request):
```json
{
"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**:
```json
{
"phone": "1234567890"
}
```
**Response** (200 OK):
```json
{
"user": {
"id": 1,
"name": "John Doe",
"phone": "1234567890"
},
"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
}
```
**Error** (404 Not Found):
```json
{
"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**:
```json
{
"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):
```json
{
"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):
```json
[
{
"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):
```json
{
"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):
```json
{
"error": "Place not found"
}
```
## Testing the API
### Using curl
1. **Register a user**:
```bash
curl -X POST http://127.0.0.1:8000/api/register/ \
-H "Content-Type: application/json" \
-d "{\"name\": \"Test User\", \"phone\": \"9999999999\"}"
```
2. **Login** (use a phone from the populate_data output):
```bash
curl -X POST http://127.0.0.1:8000/api/login/ \
-H "Content-Type: application/json" \
-d "{\"phone\": \"1234567890\"}"
```
3. **Add a review** (replace YOUR_TOKEN):
```bash
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!\"}"
```
4. **Search places**:
```bash
curl -X GET "http://127.0.0.1:8000/api/places/search/?name=pizza&min_rating=4" \
-H "Authorization: Token YOUR_TOKEN"
```
5. **Get place details**:
```bash
curl -X GET http://127.0.0.1:8000/api/places/1/ \
-H "Authorization: Token YOUR_TOKEN"
```
### Using Postman or Similar Tools
1. Import the API endpoints
2. Set up an environment variable for the auth token
3. 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 name
- `date_joined`: Timestamp of registration
### Place Model
- `id`: Primary key (auto-generated)
- `name`: Place name
- `address`: Place address
- `created_at`: Timestamp
- **Unique constraint**: (name, address)
### Review Model
- `id`: Primary key (auto-generated)
- `user_id`: Foreign key to User
- `place_id`: Foreign key to Place
- `rating`: Integer (1-5)
- `text`: Review text
- `created_at`: Timestamp
- **Unique constraint**: (user, place) - one review per user per place
## Production Deployment Notes
For production deployment, you should:
1. **Change the SECRET_KEY** in `settings.py` to a secure random value
2. **Set DEBUG = False** in `settings.py`
3. **Configure ALLOWED_HOSTS** with your domain
4. **Use PostgreSQL or MySQL** instead of SQLite:
```python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_db_name',
'USER': 'your_db_user',
'PASSWORD': 'your_db_password',
'HOST': 'localhost',
'PORT': '5432',
}
}
```
5. **Set up static files** serving
6. **Use a production WSGI server** like Gunicorn or uWSGI
7. **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
1. **Phone-based Authentication**: Users register and login with phone numbers. No password is required in this basic version, but it can be easily extended.
2. **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.
3. **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()`.
4. **Review Updates**: If a user reviews the same place twice, their review is updated rather than creating a duplicate.
5. **Search Priority**: Exact name matches are shown before partial matches to improve relevance.
6. **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.
7. **Rating Distribution**: The sample data generator creates reviews with ratings skewed toward positive (4-5 stars) to simulate realistic rating distributions.
8. **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.