diff --git a/Practice/Stupina/coolapp/admin.py b/Practice/Stupina/coolapp/admin.py new file mode 100644 index 0000000..4c434ef --- /dev/null +++ b/Practice/Stupina/coolapp/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +# Register your models here. + +from django.contrib import admin +from .models import Film, Comments + +admin.site.register(Film) +admin.site.register(Comments) diff --git a/Practice/Stupina/coolapp/forms.py b/Practice/Stupina/coolapp/forms.py new file mode 100644 index 0000000..04b093c --- /dev/null +++ b/Practice/Stupina/coolapp/forms.py @@ -0,0 +1,15 @@ +from django import forms +from .models import Film, Comments + + +class FilmForm(forms.ModelForm): + class Meta: + model = Film + fields = ('name', 'state', 'date_exist', 'desc', 'rate') +# поля pub_date и id заполняются сами + + +class CommentsForm(forms.ModelForm): + class Meta: + model = Comments + fields = ('comment',) diff --git a/Practice/Stupina/coolapp/models.py b/Practice/Stupina/coolapp/models.py new file mode 100644 index 0000000..800cf9b --- /dev/null +++ b/Practice/Stupina/coolapp/models.py @@ -0,0 +1,24 @@ +from django.db import models +from django.core.validators import MaxValueValidator, MinValueValidator + +# Create your models here. +class Film(models.Model): + #атрибуты name, desc, pub_date, rate - столбцы + name = models.CharField(max_length=200) + # TextField() - тип поля + state = models.TextField(null=True) + date_exist = models.DateField(default='0') + desc = models.TextField() + # 'date published' - как поле будет выглядеть при выводе на экран в терминале + # auto_now_add=True - когда будет добавляться новая запись, + # это поле будет автоматически проставляться, исходя из текущего времени + pub_date = models.DateTimeField('date published', auto_now_add=True) + rate = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)], default=1) + + +class Comments(models.Model): + films_id = models.ForeignKey(Film, on_delete=models.CASCADE, null=True) + comment = models.TextField() + + + diff --git a/Practice/Stupina/coolapp/static/favicon.png b/Practice/Stupina/coolapp/static/favicon.png new file mode 100644 index 0000000..a167f51 Binary files /dev/null and b/Practice/Stupina/coolapp/static/favicon.png differ diff --git a/Practice/Stupina/coolapp/templates/coolapp/base.html b/Practice/Stupina/coolapp/templates/coolapp/base.html new file mode 100644 index 0000000..13d5d8b --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/base.html @@ -0,0 +1,22 @@ + +{% load static %} + + + + + + + + + About films + + + +

Site about films

+

Фильмы

+

Создать новый фильм

+
+ {% block content %} + {% endblock %} + + diff --git a/Practice/Stupina/coolapp/templates/coolapp/film_id.html b/Practice/Stupina/coolapp/templates/coolapp/film_id.html new file mode 100644 index 0000000..ef997d7 --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/film_id.html @@ -0,0 +1,25 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + + +

{{ film.name }}

+

Страна : - {{ film.state }}

+

Описание: {{ film.desc }}

+

Дата создания: {{ film.date_exist }}

+{% if film.pub_date %} +

Дата публикации отзыва: - {{ film.pub_date }}

+{% else %} +

Дата публикации отзыва: - Unknown

+{% endif %} +

Оценка: {{ film.rate }}

+{% for com in comm %} +

Комментарии: {{com.comment }}

+{% endfor %} + +

Оставить комментарий:

+
{% csrf_token %} + {{ com_form.as_p }} + + +
+{% endblock content %} diff --git a/Practice/Stupina/coolapp/templates/coolapp/films.html b/Practice/Stupina/coolapp/templates/coolapp/films.html new file mode 100644 index 0000000..b7a9bd1 --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/films.html @@ -0,0 +1,18 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + + +{% for film in films %} + +

{{ film.name }}

+

Описание: {{ film.desc }}

+{% if film.pub_date %} +

Дата публикации : - {{ film.pub_date }}

+{% else %} +

Дата публикации: - Unknown

+{% endif %} +

Оценка : {{ film.rate }}

+{% endfor %} + + +{% endblock content %} diff --git a/Practice/Stupina/coolapp/templates/coolapp/index.html b/Practice/Stupina/coolapp/templates/coolapp/index.html new file mode 100644 index 0000000..07bb8a8 --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/index.html @@ -0,0 +1,12 @@ + + +{% extends 'coolapp/base.html' %} +{% block content %} +
+

Hello everybody!

+

Вы находитесь на сайте "{{sitename}}".

+

Здесь Вы можете найти информацию о фильмах, их краткое описание и рейтинг

+
+ +{% endblock content %} diff --git a/Practice/Stupina/coolapp/templates/coolapp/new.html b/Practice/Stupina/coolapp/templates/coolapp/new.html new file mode 100644 index 0000000..0dd155a --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/new.html @@ -0,0 +1,16 @@ +{% extends 'coolapp/base.html' %} +{% block content %} + + + +

Добавление нового фильма

+{% if flag %} +
{% csrf_token %} +{{ form.as_p }} + +
+{% else %} +

Ошибка: У Вас нет прав для данной операции!

+{% endif %} + +{% endblock content %} \ No newline at end of file diff --git a/Practice/Stupina/coolapp/templates/coolapp/no_exit.html b/Practice/Stupina/coolapp/templates/coolapp/no_exit.html new file mode 100644 index 0000000..0008d3b --- /dev/null +++ b/Practice/Stupina/coolapp/templates/coolapp/no_exit.html @@ -0,0 +1,7 @@ + +{% extends 'coolapp/base.html' %} +{% block content %} + +

Error: Фильма с таким id на сайте еще нет!

+ +{% endblock content %} \ No newline at end of file diff --git a/Practice/Stupina/coolapp/urls.py b/Practice/Stupina/coolapp/urls.py new file mode 100644 index 0000000..8fd7d9c --- /dev/null +++ b/Practice/Stupina/coolapp/urls.py @@ -0,0 +1,14 @@ +from django.urls import path +from . import views + +# ---если сюда приходит код какой-то,мы при помощи шаблона urlpatterns перенаправляем этот код в views.index. +# name='index' - это псевдоним для получившегося url, чтоб удобней было обращаться к тому же ресурсу (функции) +# из кода в некоторых случаях. + +urlpatterns = [ + path('', views.index, name='index'), + path('films/', views.films, name='films'), + path('new/', views.new, name='new'), + # если в запросе число: + path('/', views.new, name='new'), +] diff --git a/Practice/Stupina/coolapp/views.py b/Practice/Stupina/coolapp/views.py new file mode 100644 index 0000000..bdceaad --- /dev/null +++ b/Practice/Stupina/coolapp/views.py @@ -0,0 +1,46 @@ +from django.shortcuts import render, redirect +from .models import Film, Comments +from .forms import FilmForm, CommentsForm + + +def index(request): + return render(request, 'coolapp/index.html', {'sitename': 'О фильмах'}) + + +def films(request): + return render(request, 'coolapp/films.html', {'films': Film.objects.all()}) + + +def new(request, film_id=None): + if film_id: + film = Film.objects.get(id=film_id) + if request.method == "POST": + text = request.POST['comment'] + c = Comments(films_id=film, comment=text) + c.save() + return redirect(f'/{film.id}', film=film) + + else: + try: + comments = Comments.objects.filter(films_id=film_id) + return render(request, 'coolapp/film_id.html', + {'film': film, 'comm': comments, 'com_form': CommentsForm(instance=Comments())}) + except Exception: + return render(request, 'coolapp/no_exit.html') + + elif request.method == "POST": + form = FilmForm(request.POST) + print(form.is_valid()) + if form.is_valid(): + film = form.save() + return redirect(f'/{film.id}', film=film) + else: + if request.user.is_superuser: + film = Film() + flag = True + d = {'form': FilmForm(instance=film)} + else: + flag = False + d = {} + d = d | {'flag': flag} + return render(request, 'coolapp/new.html', d) diff --git a/Practice/Stupina/coolsite/settings.py b/Practice/Stupina/coolsite/settings.py new file mode 100644 index 0000000..cacbb2e --- /dev/null +++ b/Practice/Stupina/coolsite/settings.py @@ -0,0 +1,127 @@ +""" +Django settings for coolsite project. + +Generated by 'django-admin startproject' using Django 4.2.4. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path +import os + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-#*q%rz8b35ad*mn4tqj!e%tinjn_sjyxef$fokj#e9b%64+50p' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition +# это приложения, в котором модно использовать шаблоны +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'coolapp' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'coolsite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'coolsite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Europe/Moscow' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') + + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/Practice/Stupina/coolsite/urls.py b/Practice/Stupina/coolsite/urls.py new file mode 100644 index 0000000..c656034 --- /dev/null +++ b/Practice/Stupina/coolsite/urls.py @@ -0,0 +1,35 @@ +""" +URL configuration for coolsite project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.conf.urls import include +from django.urls import path +from django.contrib import admin + +# --прописываем связь с coolapp.urls +# Когда мы обращаемся к серверу (127.0.0.1:8000) приходит запрос, +# сервер начинает анализировать, что дальше идет посде запроса : # к какому ресурсу/файлу/скрипту на сервере идет обращение. +# 127.0.0.1:8000 - пустой запрос +# Если запрос 127.0.0.1:8000/coolapp/ - попадая в главный файл URL, указанная часть URL (coolapp) +# будет сравниваться с каждым шаблоном из списка (coolapp/ - шаблон). Если шаблон совпал, анализируется дальше. +# include('coolapp.urls') - расширяет шаблон: path('coolapp/', views.index, name='index'), +# и вызывается coolapp.views.index--- + + +urlpatterns = [ + path('admin/', admin.site.urls), + path('coolapp/', include('coolapp.urls')), + path('', include('coolapp.urls')), +] diff --git a/Practice/Stupina/db.sqlite3 b/Practice/Stupina/db.sqlite3 new file mode 100644 index 0000000..15d1825 Binary files /dev/null and b/Practice/Stupina/db.sqlite3 differ diff --git a/Practice/Stupina/homework_14/htmlcov/index.html b/Practice/Stupina/homework_14/htmlcov/index.html new file mode 100644 index 0000000..7472c95 --- /dev/null +++ b/Practice/Stupina/homework_14/htmlcov/index.html @@ -0,0 +1,102 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 46% +

+ +
+ +
+

+ coverage.py v7.2.7, + created at 2023-08-14 15:32 +0300 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Modulestatementsmissingexcludedcoverage
task_2.py3921046%
Total3921046%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/Practice/Stupina/homework_14/htmlcov/task_2_py.html b/Practice/Stupina/homework_14/htmlcov/task_2_py.html new file mode 100644 index 0000000..dfa0c55 --- /dev/null +++ b/Practice/Stupina/homework_14/htmlcov/task_2_py.html @@ -0,0 +1,151 @@ + + + + + Coverage for task_2.py: 46% + + + + + +
+ +
+
+

1class IncorrectDataInput(Exception): 

+

2 pass 

+

3 

+

4 

+

5class Money: 

+

6 def __init__(self, x, y): 

+

7 if isinstance(x, int) and isinstance(y, int): 

+

8 if x >= 0 and 0 <= y < 100: 

+

9 self.__x = x 

+

10 self.__y = y 

+

11 self._money = float(f'{self.__x}.{self.__y}') 

+

12 else: 

+

13 raise IncorrectDataInput 

+

14 else: 

+

15 print('Некорректный тип атрибутов') 

+

16 @property 

+

17 def money(self): 

+

18 return self._money 

+

19 

+

20 def __str__(self): 

+

21 return f'{self.__x},{self.__y}' 

+

22 

+

23 def __add__(self, other): 

+

24 res = round(self._money + other._money, 2) 

+

25 res = str(res).split('.') 

+

26 return Money(int(res[0]), int(res[1])) 

+

27 

+

28 def __sub__(self, other): 

+

29 

+

30 res = round(self._money - other._money, 2) 

+

31 if res < 0: 

+

32 print('Денежная сумма не может быть отрицательной') 

+

33 return None 

+

34 else: 

+

35 res = str(res).split('.') 

+

36 return Money(int(res[0]), int(res[1])) 

+

37 

+

38 def __lt__(self, other): 

+

39 return self._money < other._money 

+

40 

+

41 def __eq__(self, other): 

+

42 return self._money == other._money 

+

43 

+

44 def __le__(self, other): 

+

45 return self._money <= other._money 

+

46 

+

47 

+

48if __name__ == '__main__': 

+

49 ob1 = Money(10, 20) 

+

50 ob2 = Money(10, 4) 

+

51 

+

52 print(ob1, ob2) 

+

53 print(ob1 - ob2) 

+

54 print(ob1 >= ob2) 

+
+ + + diff --git a/Practice/Stupina/homework_14/task_2.py b/Practice/Stupina/homework_14/task_2.py new file mode 100644 index 0000000..e40cda5 --- /dev/null +++ b/Practice/Stupina/homework_14/task_2.py @@ -0,0 +1,54 @@ +class IncorrectDataInput(Exception): + pass + + +class Money: + def __init__(self, x, y): + if isinstance(x, int) and isinstance(y, int): + if x >= 0 and 0 <= y < 100: + self.__x = x + self.__y = y + self._money = float(f'{self.__x}.{self.__y}') + else: + raise IncorrectDataInput + else: + print('Некорректный тип атрибутов') + @property + def money(self): + return self._money + + def __str__(self): + return f'{self.__x},{self.__y}' + + def __add__(self, other): + res = round(self._money + other._money, 2) + res = str(res).split('.') + return Money(int(res[0]), int(res[1])) + + def __sub__(self, other): + + res = round(self._money - other._money, 2) + if res < 0: + print('Денежная сумма не может быть отрицательной') + return None + else: + res = str(res).split('.') + return Money(int(res[0]), int(res[1])) + + def __lt__(self, other): + return self._money < other._money + + def __eq__(self, other): + return self._money == other._money + + def __le__(self, other): + return self._money <= other._money + + +if __name__ == '__main__': + ob1 = Money(10, 20) + ob2 = Money(10, 4) + + print(ob1, ob2) + print(ob1 - ob2) + print(ob1 >= ob2) diff --git a/Practice/Stupina/homework_14/test_task_2.py b/Practice/Stupina/homework_14/test_task_2.py new file mode 100644 index 0000000..998e0a2 --- /dev/null +++ b/Practice/Stupina/homework_14/test_task_2.py @@ -0,0 +1,39 @@ +import unittest +from task_2 import Money, IncorrectDataInput + + +class MyTest(unittest.TestCase): + ob1 = Money(10, 20) + ob2 = Money(10, 0) + ob3 = Money(5, 30) + + def test_money_eq(self): + self.assertEquals(str(self.ob1), '10,20') + + def test_sub(self): + self.assertEquals(str(self.ob1-self.ob2), '0,2') + + def test_add(self): + self.assertEquals(str(self.ob1 + self.ob3), '15,5') + + def test_lt(self): + self.assertTrue(self.ob1 > self.ob3) + + def test_eq(self): + self.assertFalse(self.ob1 == self.ob3) + + def test_le(self): + self.assertTrue(self.ob2 <= self.ob1) + + def test_er(self): + with self.assertRaises(IncorrectDataInput): + Money(-5, 30) + + def test_er1(self): + with self.assertRaises(IncorrectDataInput): + Money(5, 306) + + + + + diff --git a/Practice/Stupina/manage.py b/Practice/Stupina/manage.py new file mode 100644 index 0000000..445748c --- /dev/null +++ b/Practice/Stupina/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coolsite.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()