Skip to content

Feature/add dockerfile #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.
15 changes: 15 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[run]
source =
lettings
profiles
oc_lettings_site

omit =
*/tests/*
*/tests.py
*/migrations/*
*/apps.py
manage.py
oc_lettings_site/wsgi.py
oc_lettings_site/asgi.py
*/__init__.py
44 changes: 44 additions & 0 deletions .github/workflows/django.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Django CI

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.12.3]
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
DJANGO_SETTINGS_MODULE: oc_lettings_site.settings

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Lint with flake8
run: flake8

- name: Run tests
run: pytest

- name: Collect static files
run: python manage.py collectstatic --noinput

- name: Build Docker image
run: docker build -t oc-lettings-site .
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
**/__pycache__
*.pyc
venv
.env
htmlcov
pytest_cache
.coverage
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.12.3-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV DJANGO_SETTINGS_MODULE=oc_lettings_site.settings
ENV PYTHONUNBUFFERED=1

RUN python manage.py collectstatic --noinput

CMD ["gunicorn", "oc_lettings_site.wsgi:application", "--bind", "0.0.0.0:8000"]
Empty file added lettings/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions lettings/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
Admin configuration for lettings app.

This module registers the Letting and Address models with the Django admin interface
to allow management of lettings and addresses through the administration panel.
"""

from django.contrib import admin
from .models import Letting, Address

admin.site.register(Letting)
admin.site.register(Address)
19 changes: 19 additions & 0 deletions lettings/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Module for the lettings application configuration.

This module defines the configuration class for the lettings app.
"""

from django.apps import AppConfig


class LettingsConfig(AppConfig):
"""
Configuration class for the lettings application.
This class is used to set up the application and its settings.
It inherits from Django's AppConfig base class.

:param AppConfig: Django's application configuration base class.
:type AppConfig: django.apps.AppConfig
"""
name = 'lettings'
41 changes: 41 additions & 0 deletions lettings/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 3.0 on 2025-04-14 12:57

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


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.SeparateDatabaseAndState(
state_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')),
],
),
],
database_operations=[],
),
]
Empty file added lettings/migrations/__init__.py
Empty file.
66 changes: 66 additions & 0 deletions lettings/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Module for lettings models.

This module defines the Address and Letting models used to represent lettings data.
"""

from django.db import models
from django.core.validators import MaxValueValidator, MinLengthValidator


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

This model stores address details such as number, street,
city, state, zip code, and country ISO code.

:param models: Django's ORM models module.
:type models: django.db.models
:return: An instance of Address representing a physical address.
:rtype: Address
"""
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)])

def __str__(self):
"""
Return a string representation of the address.

:return: A string combining the number and street.
:rtype: str
"""
return f'{self.number} {self.street}'

class Meta:
"""
This class defines the verbose name and plural form for the Address model.
"""
verbose_name_plural = "Addresses"


class Letting(models.Model):
"""
Represents a letting.

This model stores information about a letting, including its title and the associated address.

:param models: Django's ORM models module.
:type models: django.db.models
:return: An instance of Letting representing a letting record.
:rtype: Letting
"""
title = models.CharField(max_length=256)
address = models.OneToOneField(Address, on_delete=models.CASCADE)

def __str__(self):
"""Return the title of the letting.

:return: The title of the letting.
:rtype: str
"""
return self.title
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h1 class="page-header-ui-title mb-3 display-6">Lettings</h1>
<ul class="list-group list-group-flush list-group-careers">
{% for letting in lettings_list %}
<li class="list-group-item">
<a href="{% url 'letting' letting_id=letting.id %}">{{ letting.title }}</a>
<a href="{% url 'lettings:letting' letting_id=letting.id %}">{{ letting.title }}</a>
</li>
{% endfor %}
</ul>
Expand All @@ -36,7 +36,7 @@ <h1 class="page-header-ui-title mb-3 display-6">Lettings</h1>
<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' %}">
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'profiles:index' %}">
Profiles
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ <h1 class="page-header-ui-title mb-3 display-6">{{ title }}</h1>

<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' %}">
<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' %}">
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'profiles:index' %}">
Profiles
</a>
</div>
Expand Down
59 changes: 59 additions & 0 deletions lettings/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Unit tests for the lettings app.

This module contains test cases for models, views and urls of the lettings application.
"""

from django.test import TestCase
from django.urls import reverse
from .models import Address, Letting


class TestLettings(TestCase):
"""Test class for lettings app."""

def setUp(self):
"""Set up test data."""
self.address = Address.objects.create(
number=123,
street="Test Street",
city="Test City",
state="TS",
zip_code=12345,
country_iso_code="TST"
)
self.letting = Letting.objects.create(
title="Test Letting",
address=self.address
)

def test_address_str_method(self):
"""Test the string representation of Address model."""
assert str(self.address) == "123 Test Street"

def test_letting_str_method(self):
"""Test the string representation of Letting model."""
assert str(self.letting) == "Test Letting"

def test_lettings_index_view(self):
"""Test the index view of lettings app."""
url = reverse('lettings:index')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIn("Lettings", str(response.content))
self.assertEqual(response.templates[0].name, 'lettings/index.html')

def test_letting_detail_view(self):
"""Test the detail view of a letting."""
url = reverse('lettings:letting', kwargs={'letting_id': self.letting.id})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIn(self.letting.title, str(response.content))
self.assertEqual(response.templates[0].name, 'lettings/letting.html')

def test_letting_detail_view_404(self):
"""Test the detail view with invalid letting id."""
url = reverse('lettings:letting', kwargs={'letting_id': 999})
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.assertTemplateNotUsed(response, 'lettings/letting.html')
15 changes: 15 additions & 0 deletions lettings/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Module for the URL configuration of the lettings application.

This module maps URL patterns to their corresponding view functions.
"""

from django.urls import path
from . import views

app_name = 'lettings'

urlpatterns = [
path('', views.index, name='index'),
path('<int:letting_id>/', views.letting, name='letting'),
]
Loading