Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
79 changes: 39 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,77 @@
## Summary
## Résumé

Holiday lettings website
Site web d'Orange County Lettings

## Local development
## Développement local

### Prerequisites
### Prérequis

- GitHub account with read access to this repository
- Compte GitHub avec accès en lecture à ce repository
- Git CLI
- SQLite3 CLI
- Python interpreter, version 3.6 or higher.
- Interpréteur Python, version 3.6 ou supérieure

In the rest of the local development documentation, it is assumed the command `python` in
your OS shell runs the above Python interpreter (unless a virtual environment is activated)
Dans le reste de la documentation sur le développement local, il est supposé que la commande `python` de votre OS shell exécute l'interpréteur Python ci-dessus (à moins qu'un environnement virtuel ne soit activé).

### macOS / Linux

#### Clone the repository
#### Cloner le repository

- `cd /path/to/put/project/in`
- `git clone https://github.com/grking8/oc-lettings-site.git`
- `git clone https://github.com/OpenClassrooms-Student-Center/Python-OC-Lettings-FR.git`

#### Create the virtual environment
#### Créer l'environnement virtuel

- `cd /path/to/oc-lettings-site`
- `cd /path/to/Python-OC-Lettings-FR`
- `python -m venv venv`
- `apt-get install python3-venv` (If previous step errors with package not found on Ubuntu)
- Activate the environment `source venv/bin/activate`
- Confirm the command `python` now runs the Python interpreter in the virtual environment,
- `apt-get install python3-venv` (Si l'étape précédente comporte des erreurs avec un paquet non trouvé sur Ubuntu)
- Activer l'environnement `source venv/bin/activate`
- Confirmer que la commande `python` exécute l'interpréteur Python dans l'environnement virtuel
`which python`
- Confirm the version of the Python interpreter is 3.6 or higher `python --version`
- Confirm the command `pip` runs the pip executable in the virtual environment, `which pip`
- To deactivate the environment, `deactivate`
- Confirmer que la version de l'interpréteur Python est la version 3.6 ou supérieure `python --version`
- Confirmer que la commande `pip` exécute l'exécutable pip dans l'environnement virtuel, `which pip`
- Pour désactiver l'environnement, `deactivate`

#### Run the site
#### Exécuter le site

- `cd /path/to/oc-lettings-site`
- `cd /path/to/Python-OC-Lettings-FR`
- `source venv/bin/activate`
- `pip install --requirement requirements.txt`
- `python manage.py runserver`
- Go to `http://localhost:8000` in a browser
- Confirm the site is running and can be navigated (you should see several profiles and lettings)
- Aller sur `http://localhost:8000` dans un navigateur.
- Confirmer que le site fonctionne et qu'il est possible de naviguer (vous devriez voir plusieurs profils et locations).

#### Linting

- `cd /path/to/oc-lettings-site`
- `cd /path/to/Python-OC-Lettings-FR`
- `source venv/bin/activate`
- `flake8`

#### Unit tests
#### Tests unitaires

- `cd /path/to/oc-lettings-site`
- `cd /path/to/Python-OC-Lettings-FR`
- `source venv/bin/activate`
- `pytest`

#### Database
#### Base de données

- `cd /path/to/oc-lettings-site`
- Open a shell session `sqlite3`
- Connect to the database `.open oc-lettings-site.sqlite3`
- Display tables in the database `.tables`
- Display columns in the profiles table, `pragma table_info(oc_lettings_site_profile);`
- Run a query on the profiles table, `select user_id, favorite_city from
oc_lettings_site_profile where favorite_city like 'B%';`
- `.quit` to exit
- `cd /path/to/Python-OC-Lettings-FR`
- Ouvrir une session shell `sqlite3`
- Se connecter à la base de données `.open oc-lettings-site.sqlite3`
- Afficher les tables dans la base de données `.tables`
- Afficher les colonnes dans le tableau des profils, `PRAGMA table_info(oc_lettings_site_profile);`
- Lancer une requête sur la table des profils, `select user_id, favorite_city from
SELECT user_id, favorite_city FROM oc_lettings_site_profile WHERE favorite_city LIKE 'B%';`
- `.quit` pour quitter

#### Admin panel
#### Panel d'administration

- Go to `http://localhost:8000/admin`
- Login with user `admin`, password `Abc1234!`
- Aller sur `http://localhost:8000/admin`
- Connectez-vous avec l'utilisateur `admin`, mot de passe `Abc1234!`

### Windows

Using PowerShell, as above except
Utilisation de PowerShell, comme ci-dessus sauf :

- To activate the virtual environment, `.\venv\Scripts\Activate.ps1`
- Replace `which <my-command>` with `(Get-Command <my-command>).Path`
- Pour activer l'environnement virtuel, `.\venv\Scripts\Activate.ps1`
- Remplacer `which <my-command>` par `(Get-Command <my-command>).Path`
Empty file added lettings/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions lettings/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Admin configuration for the 'lettings' application.

Registers the Letting and Address models for management in the Django Admin interface.
"""
from django.contrib import admin
from .models import Letting, Address

admin.site.register(Letting)
admin.site.register(Address)
5 changes: 5 additions & 0 deletions lettings/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class LettingsConfig(AppConfig):
name = 'lettings'
36 changes: 36 additions & 0 deletions lettings/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 3.0 on 2025-10-27 11:52

import django.core.validators
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Address',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('number', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(9999)])),
('street', models.CharField(max_length=64)),
('city', models.CharField(max_length=64)),
('state', models.CharField(max_length=2, validators=[django.core.validators.MinLengthValidator(2)])),
('zip_code', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(99999)])),
('country_iso_code', models.CharField(max_length=3, validators=[django.core.validators.MinLengthValidator(3)])),
],
),
migrations.CreateModel(
name='Letting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=256)),
('address', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='lettings.Address')),
],
),
]
41 changes: 41 additions & 0 deletions lettings/migrations/0002_data_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from django.db import migrations


def migrate_letting_data(apps, schema_editor):
OldAddress = apps.get_model('oc_lettings_site', 'Address')
OldLetting = apps.get_model('oc_lettings_site', 'Letting')

NewAddress = apps.get_model('lettings', 'Address')
NewLetting = apps.get_model('lettings', 'Letting')

for old_address in OldAddress.objects.all():
NewAddress.objects.create(
number=old_address.number,
street=old_address.street,
city=old_address.city,
state=old_address.state,
zip_code=old_address.zip_code,
country_iso_code=old_address.country_iso_code,
id=old_address.id
)

for old_letting in OldLetting.objects.all():
new_address = NewAddress.objects.get(id=old_letting.address_id)

NewLetting.objects.create(
title=old_letting.title,
address=new_address,
id=old_letting.id
)


class Migration(migrations.Migration):

dependencies = [
('lettings', '0001_initial'),
('oc_lettings_site', '0001_initial'),
]

operations = [
migrations.RunPython(migrate_letting_data, migrations.RunPython.noop),
]
17 changes: 17 additions & 0 deletions lettings/migrations/0003_auto_20251027_1732.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.0 on 2025-10-27 17:32

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('lettings', '0002_data_migration'),
]

operations = [
migrations.AlterModelOptions(
name='address',
options={'verbose_name_plural': 'Addresses'},
),
]
Empty file added lettings/migrations/__init__.py
Empty file.
54 changes: 54 additions & 0 deletions lettings/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Models for the 'lettings' application, defining the structure for addresses and rental properties.
"""
from django.db import models
from django.core.validators import MaxValueValidator, MinLengthValidator


class Address(models.Model):
"""
Represents a physical address for a Letting property.

Fields:
number (PositiveIntegerField): The street number (max 9999).
street (CharField): The street name (max 64 characters).
city (CharField): The city name (max 64 characters).
state (CharField): The two-letter state abbreviation (e.g., 'CA').
zip_code (PositiveIntegerField): The zip code (max 99999).
country_iso_code (CharField): The three-letter ISO country code (e.g., 'USA').
"""
number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)])
street = models.CharField(max_length=64)
city = models.CharField(max_length=64)
state = models.CharField(max_length=2, validators=[MinLengthValidator(2)])
zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)])
country_iso_code = models.CharField(
max_length=3, validators=[MinLengthValidator(3)]
)

class Meta:
verbose_name_plural = "Addresses"

def __str__(self):
"""
Returns a string representation of the Address, showing number and street.
"""
return f'{self.number} {self.street}'


class Letting(models.Model):
"""
Represents a letting property available for rent.

Fields:
title (CharField): The descriptive title of the letting (max 256 characters).
address (OneToOneField): A one-to-one relationship to the Address model.
"""
title = models.CharField(max_length=256)
address = models.OneToOneField(Address, on_delete=models.CASCADE)

def __str__(self):
"""
Returns the title of the Letting as its string representation.
"""
return self.title
45 changes: 45 additions & 0 deletions lettings/templates/lettings/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block title %}Lettings{% endblock title %}

{% block content %}


<div class="container px-5 py-5 text-center">
<div class="row justify-content-center">
<div class="col-lg-8">
<h1 class="page-header-ui-title mb-3 display-6">Lettings</h1>
</div>
</div>
</div>

<div class="container px-5">
<div class="row gx-5 justify-content-center">
<div class="col-lg-10">
<hr class="mb-0" />
{% if lettings_list %}
<ul class="list-group list-group-flush list-group-careers">
{% for letting in lettings_list %}
<li class="list-group-item">
<a href="{% url 'lettings:letting' letting_id=letting.id %}">{{ letting.title }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No lettings are available.</p>
{% endif %}
</div>
</div>
</div>

<div class="container px-5 py-5 text-center">
<div class="justify-content-center">
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'index' %}">
Home
</a>
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'profiles:index' %}">
Profiles
</a>
</div>
</div>

{% endblock %}
41 changes: 41 additions & 0 deletions lettings/templates/lettings/letting.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends "base.html" %}
{% load static %}
{% block title %}{{ title }}{% endblock title %}

{% block content %}

<div class="container px-5 py-5 text-center">
<div class="row justify-content-center">
<div class="col-lg-8">
<h1 class="page-header-ui-title mb-3 display-6">{{ title }}</h1>
</div>
</div>
</div>

<div class="container px-5 py-5 text-center">
<div class="card">
<div class="card-body">
<div class="icon-stack icon-stack-lg bg-primary text-white mb-3"><i data-feather="home"></i></div>
<p>{{ address.number }} {{ address.street }}</p>
<p>{{ address.city }}, {{ address.state }} {{ address.zip_code }}</p>
<p>{{ address.country_iso_code }}</p>
</div>
</div>
</div>

<div class="container px-5 py-5 text-center">
<div class="justify-content-center">
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'lettings:index' %}">
<i class="ms-2" data-feather="arrow-right"></i>
Back
</a>
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'index' %}">
Home
</a>
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'profiles:index' %}">
Profiles
</a>
</div>
</div>

{% endblock %}
Loading