Compare commits

..

10 Commits

Author SHA1 Message Date
286f1cb57b add docstrings 2025-09-09 16:32:32 +02:00
aca7042c56 add coverage and bs4 2025-09-09 16:20:39 +02:00
2abad89208 test models, urls, views - 100% 2025-09-09 16:20:15 +02:00
cb3af725b3 avoid testing useless files 2025-09-09 16:19:28 +02:00
dd5bccf708 add doctstings 2025-09-08 11:58:02 +02:00
2fd139de55 handle custom error templates 2025-09-08 09:59:16 +02:00
14fe0ded02 removed unused 2025-09-05 17:23:12 +02:00
c751602eca pep8 2025-09-05 17:11:36 +02:00
f609f2adbf Admin shouldn`t be changed (spec)
This reverts commit b40a7d9030.
2025-09-05 17:07:22 +02:00
b40a7d9030 display more 2025-09-05 16:56:43 +02:00
36 changed files with 556 additions and 290 deletions

6
.coveragerc Normal file
View File

@@ -0,0 +1,6 @@
[run]
source = .
omit = */test*,*000*,*conftest.py,*apps.py,*manage.py,*__init__.py,*asgi*,*wsgi*,*admin.py,*urls.py,*settings.py
[report]
omit = */test*,*000*,*conftest.py,*apps.py,*manage.py,*__init__.py,*asgi*,*wsgi*,*admin.py,*urls.py,*settings.py

View File

@@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@@ -3,6 +3,17 @@ from django.core.validators import MaxValueValidator, MinLengthValidator
class Address(models.Model): class Address(models.Model):
"""
Model of details for a physical location of a property
"""
class Meta:
"""
Fix the plural displayed in admin
"""
verbose_name_plural = "Addresses"
number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)])
street = models.CharField(max_length=64) street = models.CharField(max_length=64)
city = models.CharField(max_length=64) city = models.CharField(max_length=64)
@@ -11,13 +22,18 @@ class Address(models.Model):
country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)])
def __str__(self): def __str__(self):
""" Display object with basic address """
return f'{self.number} {self.street}' return f'{self.number} {self.street}'
class Letting(models.Model): class Letting(models.Model):
"""
Model of an announce for a property to rent
"""
title = models.CharField(max_length=256) title = models.CharField(max_length=256)
address = models.OneToOneField(Address, on_delete=models.CASCADE) address = models.OneToOneField(Address, on_delete=models.CASCADE)
def __str__(self): def __str__(self):
""" display object with title """
return self.title return self.title

View File

@@ -3,14 +3,25 @@ from lettings.models import Letting
def index(request): def index(request):
"""
letting's index page. Retrieve all objects in db then give list to template
:param request; None
:return: render and display template HTML
"""
lettings_list = Letting.objects.all() lettings_list = Letting.objects.all()
context = {'lettings_list': lettings_list} context = {'lettings_list': lettings_list}
return render(request, 'lettings/index.html', context) return render(request, 'lettings/index.html', context)
def letting(request, letting_id): def letting(request, letting_id):
"""
display detail of a particular Letting object
:param request: None
:return: render and display template HTML
"""
letting = Letting.objects.get(id=letting_id) letting = Letting.objects.get(id=letting_id)
context = { context = {
'title': letting.title, 'title': letting.title,
'address': letting.address, 'address': letting.address,
} }
return render(request, 'lettings/letting.html', context) return render(request, 'lettings/letting.html', context)

Binary file not shown.

View File

@@ -2,6 +2,7 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oc_lettings_site.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'oc_lettings_site.settings')
application = get_asgi_application() application = get_asgi_application()

View File

@@ -1 +0,0 @@

View File

@@ -13,9 +13,9 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'fp$9^593hsriajg$_%=5trot9g!1qa@ew(o-1#@=&4%=hp46(s' SECRET_KEY = 'fp$9^593hsriajg$_%=5trot9g!1qa@ew(o-1#@=&4%=hp46(s'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = False
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ["*"]
# Application definition # Application definition
@@ -79,16 +79,20 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 'NAME': 'django.contrib.auth.password_validation.'
'UserAttributeSimilarityValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'NAME': 'django.contrib.auth.password_validation.'
'MinimumLengthValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 'NAME': 'django.contrib.auth.password_validation.'
'CommonPasswordValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 'NAME': 'django.contrib.auth.password_validation.'
'NumericPasswordValidator',
}, },
] ]
@@ -113,4 +117,4 @@ USE_TZ = True
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / "static",] STATICFILES_DIRS = [BASE_DIR / "static"]

View File

@@ -1,46 +1,10 @@
from django.shortcuts import render from django.shortcuts import render
from lettings.models import Letting
from profiles.models import Profile
# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros,
# vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus.
# Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id.
def index(request): def index(request):
"""
Main index of app, home page
:param request: None
:return: render and display homepage
"""
return render(request, 'index.html') return render(request, 'index.html')
# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a
# tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque
def lettings_index(request):
lettings_list = Letting.objects.all()
context = {'lettings_list': lettings_list}
return render(request, 'lettings_index.html', context)
#Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur
# lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet.
# Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet.
def letting(request, letting_id):
letting = Letting.objects.get(id=letting_id)
context = {
'title': letting.title,
'address': letting.address,
}
return render(request, 'letting.html', context)
# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc
# faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d
def profiles_index(request):
profiles_list = Profile.objects.all()
context = {'profiles_list': profiles_list}
return render(request, 'profiles_index.html', context)
# Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac
# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus,
# it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males
def profile(request, username):
profile = Profile.objects.get(user__username=username)
context = {'profile': profile}
return render(request, 'profile.html', context)

268
poetry.lock generated
View File

@@ -12,9 +12,6 @@ files = [
{file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"},
] ]
[package.dependencies]
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
@@ -49,6 +46,44 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
tests = ["attrs[tests-no-zope]", "zope.interface"] tests = ["attrs[tests-no-zope]", "zope.interface"]
tests-no-zope = ["cloudpickle ; platform_python_implementation == \"CPython\"", "cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990) ; platform_python_implementation == \"CPython\"", "mypy (>=0.971,<0.990) ; platform_python_implementation == \"CPython\"", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] tests-no-zope = ["cloudpickle ; platform_python_implementation == \"CPython\"", "cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990) ; platform_python_implementation == \"CPython\"", "mypy (>=0.971,<0.990) ; platform_python_implementation == \"CPython\"", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
[[package]]
name = "beautifulsoup4"
version = "4.13.5"
description = "Screen-scraping library"
optional = false
python-versions = ">=3.7.0"
groups = ["main"]
files = [
{file = "beautifulsoup4-4.13.5-py3-none-any.whl", hash = "sha256:642085eaa22233aceadff9c69651bc51e8bf3f874fb6d7104ece2beb24b47c4a"},
{file = "beautifulsoup4-4.13.5.tar.gz", hash = "sha256:5e70131382930e7c3de33450a2f54a63d5e4b19386eab43a5b34d594268f3695"},
]
[package.dependencies]
soupsieve = ">1.2"
typing-extensions = ">=4.0.0"
[package.extras]
cchardet = ["cchardet"]
chardet = ["chardet"]
charset-normalizer = ["charset-normalizer"]
html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
name = "bs4"
version = "0.0.2"
description = "Dummy package for Beautiful Soup (beautifulsoup4)"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "bs4-0.0.2-py2.py3-none-any.whl", hash = "sha256:abf8742c0805ef7f662dce4b51cca104cffe52b835238afc169142ab9b3fbccc"},
{file = "bs4-0.0.2.tar.gz", hash = "sha256:a48685c58f50fe127722417bae83fe6badf500d54b55f7e39ffe43b798653925"},
]
[package.dependencies]
beautifulsoup4 = "*"
[[package]] [[package]]
name = "colorama" name = "colorama"
version = "0.4.5" version = "0.4.5"
@@ -62,6 +97,110 @@ files = [
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
] ]
[[package]]
name = "coverage"
version = "7.10.6"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "coverage-7.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70e7bfbd57126b5554aa482691145f798d7df77489a177a6bef80de78860a356"},
{file = "coverage-7.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e41be6f0f19da64af13403e52f2dec38bbc2937af54df8ecef10850ff8d35301"},
{file = "coverage-7.10.6-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c61fc91ab80b23f5fddbee342d19662f3d3328173229caded831aa0bd7595460"},
{file = "coverage-7.10.6-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10356fdd33a7cc06e8051413140bbdc6f972137508a3572e3f59f805cd2832fd"},
{file = "coverage-7.10.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80b1695cf7c5ebe7b44bf2521221b9bb8cdf69b1f24231149a7e3eb1ae5fa2fb"},
{file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c33e6378b9d52d3454bd08847a8651f4ed23ddbb4a0520227bd346382bbc6"},
{file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c8a3ec16e34ef980a46f60dc6ad86ec60f763c3f2fa0db6d261e6e754f72e945"},
{file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7d79dabc0a56f5af990cc6da9ad1e40766e82773c075f09cc571e2076fef882e"},
{file = "coverage-7.10.6-cp310-cp310-win32.whl", hash = "sha256:86b9b59f2b16e981906e9d6383eb6446d5b46c278460ae2c36487667717eccf1"},
{file = "coverage-7.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:e132b9152749bd33534e5bd8565c7576f135f157b4029b975e15ee184325f528"},
{file = "coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f"},
{file = "coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc"},
{file = "coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a"},
{file = "coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a"},
{file = "coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62"},
{file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153"},
{file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5"},
{file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619"},
{file = "coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba"},
{file = "coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e"},
{file = "coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c"},
{file = "coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea"},
{file = "coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634"},
{file = "coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6"},
{file = "coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9"},
{file = "coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c"},
{file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a"},
{file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5"},
{file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972"},
{file = "coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d"},
{file = "coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629"},
{file = "coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80"},
{file = "coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6"},
{file = "coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80"},
{file = "coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003"},
{file = "coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27"},
{file = "coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4"},
{file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d"},
{file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc"},
{file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc"},
{file = "coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e"},
{file = "coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32"},
{file = "coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2"},
{file = "coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b"},
{file = "coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393"},
{file = "coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27"},
{file = "coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df"},
{file = "coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb"},
{file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282"},
{file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4"},
{file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21"},
{file = "coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0"},
{file = "coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5"},
{file = "coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b"},
{file = "coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e"},
{file = "coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb"},
{file = "coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034"},
{file = "coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1"},
{file = "coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a"},
{file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb"},
{file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d"},
{file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747"},
{file = "coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5"},
{file = "coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713"},
{file = "coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32"},
{file = "coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65"},
{file = "coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6"},
{file = "coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0"},
{file = "coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e"},
{file = "coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5"},
{file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7"},
{file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5"},
{file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0"},
{file = "coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7"},
{file = "coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930"},
{file = "coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b"},
{file = "coverage-7.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90558c35af64971d65fbd935c32010f9a2f52776103a259f1dee865fe8259352"},
{file = "coverage-7.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8953746d371e5695405806c46d705a3cd170b9cc2b9f93953ad838f6c1e58612"},
{file = "coverage-7.10.6-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c83f6afb480eae0313114297d29d7c295670a41c11b274e6bca0c64540c1ce7b"},
{file = "coverage-7.10.6-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7eb68d356ba0cc158ca535ce1381dbf2037fa8cb5b1ae5ddfc302e7317d04144"},
{file = "coverage-7.10.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b15a87265e96307482746d86995f4bff282f14b027db75469c446da6127433b"},
{file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc53ba868875bfbb66ee447d64d6413c2db91fddcfca57025a0e7ab5b07d5862"},
{file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efeda443000aa23f276f4df973cb82beca682fd800bb119d19e80504ffe53ec2"},
{file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9702b59d582ff1e184945d8b501ffdd08d2cee38d93a2206aa5f1365ce0b8d78"},
{file = "coverage-7.10.6-cp39-cp39-win32.whl", hash = "sha256:2195f8e16ba1a44651ca684db2ea2b2d4b5345da12f07d9c22a395202a05b23c"},
{file = "coverage-7.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:f32ff80e7ef6a5b5b606ea69a36e97b219cd9dc799bcf2963018a4d8f788cfbf"},
{file = "coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3"},
{file = "coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90"},
]
[package.dependencies]
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
[package.extras]
toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
[[package]] [[package]]
name = "django" name = "django"
version = "3.0" version = "3.0"
@@ -83,6 +222,17 @@ sqlparse = ">=0.2.2"
argon2 = ["argon2-cffi (>=16.1.0)"] argon2 = ["argon2-cffi (>=16.1.0)"]
bcrypt = ["bcrypt"] bcrypt = ["bcrypt"]
[[package]]
name = "django-pytest"
version = "0.2.0"
description = "django test runner to use py.test tests"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "django-pytest-0.2.0.tar.gz", hash = "sha256:de21f20f9e7eb941529d75078b18192506a9f6d4ae80f86fbe2f3bcac8e09d71"},
]
[[package]] [[package]]
name = "entrypoints" name = "entrypoints"
version = "0.3" version = "0.3"
@@ -113,28 +263,6 @@ mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.5.0,<2.6.0" pycodestyle = ">=2.5.0,<2.6.0"
pyflakes = ">=2.1.0,<2.2.0" pyflakes = ">=2.1.0,<2.2.0"
[[package]]
name = "importlib-metadata"
version = "4.8.3"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.6"
groups = ["main"]
markers = "python_version < \"3.8\""
files = [
{file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
{file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
]
[package.dependencies]
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
zipp = ">=0.5"
[package.extras]
docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
perf = ["ipython"]
testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "packaging", "pep517", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)"]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "1.1.1" version = "1.1.1"
@@ -176,22 +304,19 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.0.0" version = "1.6.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
] ]
[package.dependencies]
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
dev = ["pre-commit", "tox"] dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"] testing = ["coverage", "pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "py" name = "py"
@@ -260,7 +385,6 @@ files = [
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0" attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""} colorama = {version = "*", markers = "sys_platform == \"win32\""}
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
iniconfig = "*" iniconfig = "*"
packaging = "*" packaging = "*"
pluggy = ">=0.12,<2.0" pluggy = ">=0.12,<2.0"
@@ -270,6 +394,26 @@ tomli = ">=1.0.0"
[package.extras] [package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "pytest-cov"
version = "6.3.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749"},
{file = "pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2"},
]
[package.dependencies]
coverage = {version = ">=7.5", extras = ["toml"]}
pluggy = ">=1.2"
pytest = ">=6.2.5"
[package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
[[package]] [[package]]
name = "pytest-django" name = "pytest-django"
version = "3.9.0" version = "3.9.0"
@@ -301,6 +445,30 @@ files = [
{file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"},
] ]
[[package]]
name = "six"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
]
[[package]]
name = "soupsieve"
version = "2.8"
description = "A modern CSS selector implementation for Beautiful Soup."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c"},
{file = "soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f"},
]
[[package]] [[package]]
name = "sqlparse" name = "sqlparse"
version = "0.4.4" version = "0.4.4"
@@ -332,35 +500,17 @@ files = [
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.1.1" version = "4.15.0"
description = "Backported and Experimental Type Hints for Python 3.6+" description = "Backported and Experimental Type Hints for Python 3.9+"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
markers = "python_version < \"3.8\""
files = [ files = [
{file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"},
{file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
] ]
[[package]]
name = "zipp"
version = "3.6.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.6"
groups = ["main"]
markers = "python_version < \"3.8\""
files = [
{file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
{file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
]
[package.extras]
docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy ; platform_python_implementation != \"PyPy\""]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = ">=3.6" python-versions = ">=3.9"
content-hash = "dc98175b1ff18844811121b4489b45c63c3890bbc11145325f802073521b7b71" content-hash = "e34e8fea6a43e8fe268a2b369103060c957c2e2da85aa8b0887299219efe5735"

View File

@@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@@ -3,9 +3,11 @@ from django.contrib.auth.models import User
class Profile(models.Model): class Profile(models.Model):
"""
Model of a user of the service
"""
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
favorite_city = models.CharField(max_length=64, blank=True) favorite_city = models.CharField(max_length=64, blank=True)
def __str__(self): def __str__(self):
return self.user.username return self.user.username

View File

@@ -3,11 +3,22 @@ from profiles.models import Profile
def index(request): def index(request):
"""
Display the list of all profiles
:param request: None
:return: render and display template as HTML
"""
profiles_list = Profile.objects.all() profiles_list = Profile.objects.all()
context = {'profiles_list': profiles_list} context = {'profiles_list': profiles_list}
return render(request, 'profiles/index.html', context) return render(request, 'profiles/index.html', context)
def profile(request, username): def profile(request, username):
"""
Display the detail of a give profile
:param request: None
:return: render and display template as HTML
"""
profile = Profile.objects.get(user__username=username) profile = Profile.objects.get(user__username=username)
context = {'profile': profile} context = {'profile': profile}
return render(request, 'profiles/profile.html', context) return render(request, 'profiles/profile.html', context)

View File

@@ -6,11 +6,15 @@ authors = [
{name = "Your Name",email = "you@example.com"} {name = "Your Name",email = "you@example.com"}
] ]
readme = "README.md" readme = "README.md"
requires-python = ">=3.6" requires-python = ">=3.9"
dependencies = [ dependencies = [
"django (==3.0)", "django (==3.0)",
"flake8 (==3.7.0)", "flake8 (==3.7.0)",
"pytest-django (==3.9.0)" "pytest-django (==3.9.0)",
"django-pytest (>=0.2.0,<0.3.0)",
"six (>=1.17.0,<2.0.0)",
"pytest-cov (>=6.3.0,<7.0.0)",
"bs4 (>=0.0.2,<0.0.3)",
] ]

2
pytest.ini Normal file
View File

@@ -0,0 +1,2 @@
[pytest]
DJANGO_SETTINGS_MODULE = oc_lettings_site.settings

25
templates/404.html Normal file
View File

@@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block title %}404 Not Found{% 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">Error - 404</h1>
<h2 class="page-header-ui-title mb-3 display-6">Page Not Found</h2>
</div>
</div>
</div>
<div class="container px-5 py-5 text-center">
<div class="justify-content-center">
<p>An error has occurred</p>
<a class="btn fw-500 ms-lg-4 btn-primary px-10" href="{% url 'index' %}">
Back Home
</a>
</div>
</div>
{% endblock %}

24
templates/500.html Normal file
View File

@@ -0,0 +1,24 @@
{% extends "base.html" %}
{% block title %}404 Not Found{% 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">Error - 500</h1>
<h2 class="page-header-ui-title mb-3 display-6">Server Issue</h2>
</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' %}">
Back Home
</a>
</div>
</div>
{% endblock %}

View File

@@ -1,41 +0,0 @@
{% 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 %}

View File

@@ -1,45 +0,0 @@
{% 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 '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 %}

View File

@@ -1,40 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ profile.user.username }}{% 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">{{ profile.user.username }}</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="user"></i></div>
<p><strong>First name :</strong> {{ profile.user.first_name }}</p>
<p><strong>Last name :</strong> {{ profile.user.last_name }}</p>
<p><strong>Email :</strong> {{ profile.user.email }}</p>
<p><strong>Favorite city :</strong> {{ profile.favorite_city }}</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 'profiles_index' %}">
<i class="ms-2" data-feather="arrow-left"></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 'lettings_index' %}">
Lettings
</a>
</div>
</div>
{% endblock %}

View File

@@ -1,43 +0,0 @@
{% extends "base.html" %}
{% block title %}Profiles{% 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">Profiles</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 profiles_list %}
<ul class="list-group list-group-flush list-group-careers">
{% for profile in profiles_list %}
<li class="list-group-item">
<a href="{% url 'profile' username=profile.user.username %}">{{ profile.user.username }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No profiles 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 'lettings_index' %}">
Lettings
</a>
</div>
</div>
{% endblock %}

BIN
tests/.coverage Normal file

Binary file not shown.

0
tests/__init__.py Normal file
View File

83
tests/conftest.py Normal file
View File

@@ -0,0 +1,83 @@
import pytest
from lettings.models import Address, Letting
from profiles.models import Profile
from django.contrib.auth.models import User
@pytest.fixture
@pytest.mark.django_db
def sample_address():
"""
creates temporary Addresses objects in test DB
:return: tuple of Address
"""
address1 = Address.objects.create(
number = 22,
street = "Quality Street",
city = "New-York",
state = "New-York",
zip_code = 10010,
country_iso_code = "US"
)
address2 = Address.objects.create(
number = 18,
street = "Rue Cocotte",
city = "Paris",
state = "Ile-de-France",
zip_code = 75000,
country_iso_code = "FR"
)
return address1, address2
@pytest.fixture
@pytest.mark.django_db
def sample_letting(sample_address):
"""
creates temporary Letting objects in test DB
:return: tuple of Lettings
"""
letting = Letting.objects.create(
title = "Pretty thing",
address = sample_address[0],
)
letting2 = Letting.objects.create(
title = "Ugly thing",
address = sample_address[1],
)
return letting, letting2
@pytest.fixture
@pytest.mark.django_db
def sample_profile():
"""
creates temporary Profile objects in test DB
:return: tuple of Profiles
"""
user = User.objects.create(
username = 'TestUser',
password = 'password',
)
user2 = User.objects.create(
username = 'TestUser2',
password = 'password2',
)
user3 = User.objects.create(
username = 'TestUser3',
password = 'password2',
)
profile = Profile.objects.create(
user=user,
favorite_city="Paris",
)
profile2 = Profile.objects.create(
user=user2,
favorite_city="Marseilles",
)
profile3 = Profile.objects.create(
user=user3,
favorite_city="Rennes",
)
return profile, profile2, profile3

0
tests/unit/__init__.py Normal file
View File

View File

View File

@@ -0,0 +1,15 @@
import pytest
@pytest.mark.django_db
def test_address_str(sample_address):
""" test if Address objects are well created """
assert str(sample_address[0]) == "22 Quality Street"
assert str(sample_address[1]) == "18 Rue Cocotte"
@pytest.mark.django_db
def test_letting_str2(sample_letting):
""" test if Letting objects are well created """
assert str(sample_letting[0]) == "Pretty thing"
assert str(sample_letting[1]) == "Ugly thing"

View File

@@ -0,0 +1,21 @@
import pytest
from django.urls import reverse
from django.test import Client
@pytest.mark.django_db
def test_should_get_200_on_lettings_index():
""" test the server's response """
c = Client()
url = reverse('lettings_index')
response = c.get(url)
assert response.status_code == 200
@pytest.mark.django_db
def test_should_get_200_on_letting_detail(sample_letting):
c = Client()
url = reverse('letting', kwargs={'letting_id':1})
response = c.get(url)
assert response.status_code == 200

View File

@@ -0,0 +1,19 @@
import pytest
from lettings.models import Address, Letting
from django.test import Client
from django.urls import reverse
from bs4 import BeautifulSoup
@pytest.mark.django_db
def test_view_should_display_right_len_list(sample_letting):
"""
test if the list displayed contains the right amount of objects
created in fixture
"""
c = Client()
url = reverse('lettings_index')
response = c.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
li_tags = soup.find_all('li')
assert len(li_tags) == 2

View File

View File

@@ -0,0 +1,18 @@
from django.urls import reverse, resolve
from oc_lettings_site.views import index
from django.test import Client
def test_server_should_answer_200():
""" test the server's response on home """
c = Client()
url = reverse('index')
response = c.get(url)
assert response.status_code == 200
def test_home_url():
""" test the home url """
url = reverse('index')
assert resolve(url).view_name == 'index'
assert resolve(url).func, index()

View File

@@ -0,0 +1,10 @@
from django.test import Client
from django.urls import reverse
def test_view_should_reply_title_on_home():
""" test the content display (title) """
c = Client()
url = reverse('index')
response = c.get(url)
assert "Welcome to Holiday Homes</h1>" in response.content.decode()

View File

View File

@@ -0,0 +1,17 @@
import pytest
from django.contrib.auth.models import User
from profiles.models import Profile
@pytest.mark.django_db
def test_str_profile():
user = User.objects.create(
username = 'TestUser',
password = 'password',
)
profile = Profile.objects.create(
user=user,
favorite_city="Paris",
)
assert str(profile) == "TestUser"

View File

@@ -0,0 +1,21 @@
import pytest
from django.urls import reverse
from django.test import Client
@pytest.mark.django_db
def test_should_get_200_on_profile_index():
""" test the server's response on profile index page """
c = Client()
url = reverse('profiles_index')
response = c.get(url)
assert response.status_code == 200
@pytest.mark.django_db
def test_should_get_200_on_profile_detail(sample_profile):
""" test the server's response on a profile detail page """
c = Client()
url = reverse('profile', kwargs={'username': "TestUser"})
response = c.get(url)
assert response.status_code == 200

View File

@@ -0,0 +1,18 @@
import pytest
from django.test import Client
from django.urls import reverse
from bs4 import BeautifulSoup
@pytest.mark.django_db
def test_view_should_display_right_len_list(sample_profile):
"""
test that html page displays the right amount of objects
created by fixture
"""
c = Client()
url = reverse('profiles_index')
response = c.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
li_tags = soup.find_all('li')
assert len(li_tags) == 3