Metadata-Version: 2.4
Name: django-rentals
Version: 0.3.1
Summary: A Django Rest API for rental (vehicle/gear) listings, availability, and bookings.
Author-email: Awais Jibran <awaisdar001@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Awais Jibran
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/DestinationPak/django-rentals
Project-URL: Changelog, https://github.com/DestinationPak/django-rentals/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/DestinationPak/django-rentals/issues
Project-URL: Source, https://github.com/DestinationPak/django-rentals
Keywords: django,rentals,rest,api
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: AUTHORS
Requires-Dist: Django<6.0,>=4.2
Requires-Dist: djangorestframework<3.19,>=3.16
Requires-Dist: django-filter<26.2,>=23.2
Requires-Dist: drf-spectacular>=0.28.0
Requires-Dist: swapper>=1.3.0
Provides-Extra: dev
Requires-Dist: factory-boy>=3.3; extra == "dev"
Requires-Dist: Faker; extra == "dev"
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-django>=4.5.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pylint>=2.0; extra == "dev"
Requires-Dist: pylint-django>=2.5.0; extra == "dev"
Requires-Dist: pylint-plugin-utils; extra == "dev"
Requires-Dist: isort; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx>=7.0; extra == "docs"
Requires-Dist: myst-parser>=2.0; extra == "docs"
Requires-Dist: furo; extra == "docs"
Dynamic: license-file

# Django Rentals API

[![PyPI version](https://img.shields.io/pypi/v/django-rentals.svg)](https://pypi.org/project/django-rentals/)
[![Python versions](https://img.shields.io/pypi/pyversions/django-rentals.svg)](https://pypi.org/project/django-rentals/)
[![License](https://img.shields.io/pypi/l/django-rentals.svg)](https://github.com/DestinationPak/django-rentals/blob/master/LICENSE)
[![Unit Tests](https://github.com/DestinationPak/django-rentals/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/DestinationPak/django-rentals/actions/workflows/unit-tests.yml)

A Django REST API for vehicle/gear rental operators, listings, availability, and bookings —
the sibling package to [django-trips](https://pypi.org/project/django-trips/), part of the
[DestinationPak](https://destinationpak.com) platform.

## Installation

```bash
pip install django-rentals
```

## Usage

Add the app (and `django_filters`, used by the catalog/availability filtering below) to
your installed apps:

```python
INSTALLED_APPS = [
    ...
    'django_filters',
    'django_rentals',
]
```

## Migrate

```bash
python manage.py migrate
```

Mount its urls under a namespace of your choosing:

```python
urlpatterns = [
    ...
    path('rentals/', include('django_rentals.urls')),
]
```

This mounts the whole app under your own chosen prefix (`rentals/` above) with the lib's
own `v1/` version underneath it, e.g. `rentals/v1/listings/`,
`rentals/v1/schema/redoc/`. The app versions itself independently of your project's own
API version.

## Domain model

`RentalOperator` (the tenant/owner entity, mirrors `django_trips.Host`) → `RentalListing`
(one bookable vehicle or gear kit, mirrors `Trip`) → `RentalAvailability` (a bookable date,
mirrors `TripSchedule`) → `RentalBooking` (mirrors `TripBooking`, but books a
`start_date`/`end_date` range rather than a single departure date).

There is deliberately no separate tier/package model the way `django_trips` has
`TripPackage` — a distinct `RentalListing` per vehicle/kit already serves that purpose.

Like `django_trips`, this package is tenancy-oblivious: it has no concept of which user is
allowed to manage a given `RentalOperator`. That authorization layer belongs to whichever
project installs this app (see destipak's `docs/multi-tenancy-design.md` for the pattern
this is meant to plug into).

## Public API

Read-only and unauthenticated (`AllowAny`) unless noted:

- `listings/` - the published catalog. Filterable via query params: `?category=`,
  `?location=<id>`, `?operator=<id>`.
- `listings/<slug>/` - one listing's detail, including its images and availabilities.
- `operators/` - active, verified `RentalOperator`s.
- `availabilities/` - date-range availability search across active listings. Filterable via
  `?listing=<slug>`, `?date_from=`, `?date_to=` (any combination; omitting all three returns
  every upcoming bookable date).
- `bookings/create/` - guest booking (no auth required).
- `bookings/lookup/?number=&email=` - guest "find my booking".
- `bookings/<number>/` - authenticated traveller's own booking (retrieve/update/cancel).
- `schema/`, `schema/swagger-ui/`, `schema/redoc/` - this app's own OpenAPI schema, scoped
  to just these endpoints regardless of what else your project mounts.

## Custom Location model

`django_rentals.Location` (a plain `name`/`slug`/`lat`/`lng` model - no region/parent
hierarchy, unlike `django_trips.Location`) is swappable, the same way Django's own
`AUTH_USER_MODEL` is. `RentalListing.location` is the only location field on `RentalListing`
now - the original free-text `RentalListing.city` field has been dropped. If you're upgrading
from a version that still had it, a prior migration best-effort backfilled `location` from each
existing `city` string before `city` itself was removed.

Two settings, both optional and both defaulting to this package's own bundled model:

- **`DJANGO_RENTALS_LOCATION_MODEL`** - an `"app_label.ModelName"` string naming which model
  actually satisfies the FK, e.g. `DJANGO_RENTALS_LOCATION_MODEL = "myapp.City"`. Your model
  doesn't need to share `Location`'s field names.
- **`DJANGO_RENTALS_LOCATION_ADAPTER`** - a dotted path to a `django_rentals.location_adapter
  .LocationAdapter` subclass telling this app how to read your model's fields as if they were
  `Location`'s (`get_name`, `get_slug`, `get_lat`, `get_lng`). `RentalListingSerializer` exposes
  `location` as a nested object through this adapter, and `?location=<id>` filters on it directly.

Building a brand-new Location model rather than reusing one you already have? Inherit
`django_rentals.models.AbstractLocation` instead of writing an adapter - it's a plain abstract
Django model (the same shape `AbstractUser` is - real fields and concrete methods, not an
interface class) already carrying `name`/`slug`/`lat`/`lng` and their read methods, so you get
a working swap with no `DJANGO_RENTALS_LOCATION_ADAPTER` at all:

```python
# myapp/models.py
from django_rentals.models import AbstractLocation

class MyLocation(AbstractLocation):
    city_code = models.CharField(max_length=10)
```

```python
# settings.py
DJANGO_RENTALS_LOCATION_MODEL = "myapp.MyLocation"
```

Reusing an existing model instead - one you can't restructure, or one shared with other
libraries - stick with the adapter approach above; that's what it's for.

**Set both before your project's first `migrate`.** Like `AUTH_USER_MODEL`, this is a
swappable-model setting - Django resolves it once when the app loads, and a swap made after
`Location`'s own table has already been created (and other tables have already foreign-keyed
into it) doesn't retroactively move that data; it needs a real data migration instead of a
config change.

For a worked example of a real swap: the DestinationPakistan platform (this package's own
primary consumer, a private project) points this setting directly at its own `public.Location`
model, with no adapter override at all - `public.Location` already has `name`/`slug`/`lat`, plus
an `lng` property alias (its own field is `lon`, matching django-trips' naming), so the default
`LocationAdapter` reads it correctly with no subclass. See `docs/location-model-swap-design.md`
in that project for the full writeup.

## Development

All development happens inside Docker (`make dev.up`, `make update_db`, `make test`,
`make random_rentals`) — see the Makefile (`make help` lists every target).

## Documentation

This README is also published as browsable docs (`docs/`, built with Sphinx). Build it
locally with:
```bash
pip install -e ".[docs]"
sphinx-build -b html docs docs/_build
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the development/release workflow, and the
[Code of Conduct](CODE_OF_CONDUCT.md). Found a security issue? See
[SECURITY.md](SECURITY.md) rather than opening a public issue.
