Feature: Store Locator
Relevant source files
The following files were used as context for generating this wiki page:The Store Locator is a feature within the becathlon application that allows users to find and view details about physical Becathlon store locations. It consists of a searchable list of stores and individual detail pages for each location. The functionality is encapsulated within the apps.stores Django app.
This system provides a bridge between the online e-commerce experience and the physical retail presence of Becathlon. Users can search for stores by name or city and view specific information such as address and opening hours. The feature is composed of a data model to represent stores, views to handle web requests, an API for dynamic searching, and templates for rendering the user interface.
Architecture Overview
The Store Locator feature follows a standard Django Model-View-Template (MVT) architecture. A Store model defines the data structure, Django views handle the business logic for displaying and searching for stores, and HTML templates render the pages. An API endpoint is provided for asynchronous search functionality from the client-side.
Component Diagram
This diagram shows the main components of the stores app and their interactions.
Data Model
The core of the feature is the Store model, which represents a physical store location in the database.
Sources: apps/stores/models.py
Store Model
The Store model contains all the necessary information about a retail location.
# apps/stores/models.py:5-22
class Store(models.Model):
name = models.CharField(max_length=255)
address = models.TextField()
city = models.CharField(max_length=100, blank=True, default='')
country = models.CharField(max_length=100, default='Indonesia')
longitude = models.FloatField()
latitude = models.FloatField()
store_hours = models.TextField(blank=True, null=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name']
def __str__(self):
return f'{self.name} — {self.city}, {self.country}'
Entity Relationship Diagram
The diagram below illustrates the schema for the Store model.
Fields Description
| Field | Type | Description | Constraints / Defaults |
|---|---|---|---|
name | CharField | The name of the store (e.g., "Becathlon Jakarta"). | max_length=255 |
address | TextField | The full street address of the store. | |
city | CharField | The city where the store is located. | max_length=100, blank=True |
country | CharField | The country of the store. | max_length=100, default='Indonesia' |
longitude | FloatField | The geographical longitude for mapping. | |
latitude | FloatField | The geographical latitude for mapping. | |
store_hours | TextField | A text block for store opening hours. | blank=True, null=True |
is_active | BooleanField | A flag to indicate if the store is currently active. | default=True |
created_at | DateTimeField | Timestamp when the store was added. | auto_now_add=True |
updated_at | DateTimeField | Timestamp of the last update. | auto_now=True |
Sources: apps/stores/models.py:6-15, apps/stores/tests.py
Initial Data Fixture
The application uses a JSON fixture to populate the database with an initial set of store locations. This data is loaded into the stores.Store model.
An example record from the fixture:
// apps/stores/fixtures/stores.json:2-13
{
"model": "stores.store",
"pk": 1,
"fields": {
"name": "Decathlon Pondok Indah",
"address": "Jl. Metro Pondok Indah No.1, RT.1/RW.16, Pd. Pinang, Kec. Kby. Lama, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12310",
"city": "Jakarta",
"longitude": 106.7839,
"latitude": -6.2625,
"store_hours": "Monday-Sunday: 10:00 AM - 10:00 PM",
"is_active": true
}
}
Sources: apps/stores/fixtures/stores.json
Backend Views and API
The backend logic is handled by Django views, which render the HTML pages and provide a JSON API for searching.
Sources: apps/stores/views.py
Page Views
locator(request): Renders the main store locator page (locator.html). This is the entry point for the feature.- URL:
/stores/ - Template:
stores/locator.html
- URL:
store_detail(request, store_id): Renders the detail page for a single store, identified by itsstore_id. It fetches theStoreobject and passes it to thestore_detail.htmltemplate.- URL:
/stores/<int:store_id>/ - Template:
stores/store_detail.html
- URL:
Sources: apps/stores/views.py:8-21, apps/stores/templates/stores/locator.html, apps/stores/templates/stores/store_detail.html
Search API (stores_api)
This view provides the search functionality for the store locator. It's an API endpoint that returns a JSON list of stores matching a search query.
- URL:
/stores/api/ - Method:
GET - Response:
JsonResponse
API Request Flow
The diagram below shows the logic flow for a request to the stores_api endpoint.
Search Logic
The API filters Store objects based on the q query parameter. The search is case-insensitive and checks for matches in both the name and city fields of the Store model.
# apps/stores/views.py:40-45
if query:
stores = stores.filter(
Q(name__icontains=query) |
Q(city__icontains=query)
)
If no query is provided, it returns all active stores. The results are always ordered by name.
Sources: apps/stores/views.py:40-45, apps/stores/models.py:18-19
API Response Structure
The API returns a JSON object containing a list of stores. Each store object in the list has the following structure:
{
"id": 1,
"name": "Decathlon Pondok Indah",
"address": "Jl. Metro Pondok Indah No.1...",
"city": "Jakarta",
"country": "Indonesia",
"store_hours": "Monday-Sunday: 10:00 AM - 10:00 PM"
}
Sources: apps/stores/views.py:50-61
Frontend
The user interface for the Store Locator is built with HTML templates and styled with CSS.
Store Locator Page (locator.html)
This is the main search page. It contains a search bar and a container where the search results are dynamically displayed.
- Search Input: An
<input>field withid="storeSearch"allows users to type their search query. - Search Button: A
<button>withid="searchBtn"triggers the search. - Results Container: A
<div>withid="resultsContainer"is used to render the list of stores returned by the API.
<!-- apps/stores/templates/stores/locator.html:7-11 -->
<div class="search-box">
<input type="text" id="storeSearch" placeholder="Search by city or store name..." autocomplete="off">
<button id="searchBtn" class="btn-search">Search</button>
</div>
<div id="resultsContainer" class="results-container">
<p class="no-results">Enter a city or store name to begin your search.</p>
</div>
The page is styled using stores.css, which defines the layout for the search box, results container, and individual store cards.
Sources: apps/stores/templates/stores/locator.html:7-15, apps/stores/static/stores/css/stores.css
Store Detail Page (store_detail.html)
This page displays detailed information for a single store. It receives a store object from the store_detail view and renders its attributes.
- Store Name:
{{ store.name }} - Address:
{{ store.address }}, {{ store.city }}, {{ store.country }} - Store Hours:
{{ store.store_hours }}
A "Back to Stores" link allows users to navigate back to the main locator page.
<!-- apps/stores/templates/stores/store_detail.html:7-17 -->
<h2 style="font-size:2rem; margin-bottom:1rem;">{{ store.name }}</h2>
<p style="color:#ccc;">{{ store.address }}, {{ store.city }}, {{ store.country }}</p>
<div style="margin-top:2rem;">
<h3 style="font-weight:400; margin-bottom:0.5rem;">Store Hours</h3>
{% if store.store_hours %}
<pre style="background:rgba(255,255,255,0.05); padding:1rem; border-radius:4px; white-space:pre-wrap;">{{ store.store_hours }}</pre>
{% else %}
<p style="color:#888;">Store hours not available</p>
{% endif %}
</div>
Sources: apps/stores/templates/stores/store_detail.html:7-17
Summary
The Store Locator feature is a well-defined module within the becathlon project that effectively connects the online platform with its physical stores. It uses a simple data model, a clean set of views, and a dedicated API endpoint to provide a responsive and user-friendly search experience. The use of a data fixture ensures that the application has a set of stores available immediately upon setup.