Spaces:
Build error
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 | |
| 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. |