gr421_pomdm 1 rok temu
commit
32ccce413f

+ 0 - 0
__init__.py


BIN
db.sqlite3


+ 0 - 0
exam/__init__.py


+ 16 - 0
exam/asgi.py

@@ -0,0 +1,16 @@
+"""
+ASGI config for exam project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'exam.settings')
+
+application = get_asgi_application()

+ 130 - 0
exam/settings.py

@@ -0,0 +1,130 @@
+"""
+Django settings for exam project.
+
+Generated by 'django-admin startproject' using Django 5.0.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.0/ref/settings/
+"""
+
+from pathlib import Path
+from django.core.management.commands.runserver import Command as runserver
+
+
+# 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/5.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-zwz)m$hzf2=1!*h$=u4xow8$80++qndo4r!+-!s^l4-q^wy6mn'
+
+# 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',
+    'shop.apps.ShopConfig',
+    'bootstrap4',
+]
+
+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 = 'exam.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 = 'exam.wsgi.application'
+
+# Database
+# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': BASE_DIR / 'db.sqlite3',
+    }
+}
+
+# Password validation
+# https://docs.djangoproject.com/en/5.0/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/5.0/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_TZ = True
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.0/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+LOGOUT_REDIRECT_URL='/'
+
+LOGIN_REDIRECT_URL='/'
+
+AUTH_USER_MODEL = 'shop.CastomUser'
+
+MEDIA_URL = 'image/'
+

+ 31 - 0
exam/urls.py

@@ -0,0 +1,31 @@
+"""design URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/3.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.contrib import admin
+from django.urls import path
+from django.urls import include
+from django.views.generic import RedirectView
+from django.conf.urls.static import static
+from django.conf import settings
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+]
+
+urlpatterns += [
+     path('', include('shop.urls')),
+]
+
+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

+ 16 - 0
exam/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for exam project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'exam.settings')
+
+application = get_wsgi_application()

BIN
image/Синий.jpg


BIN
image/зеленый.jpg


+ 22 - 0
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', 'exam.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()

+ 1 - 0
shop/__init__.py

@@ -0,0 +1 @@
+

+ 6 - 0
shop/admin.py

@@ -0,0 +1,6 @@
+from django.contrib import admin
+from .models import *
+
+admin.site.register(CastomUser)
+admin.site.register(Category)
+admin.site.register(Application)

+ 6 - 0
shop/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class ShopConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'shop'

+ 71 - 0
shop/forms.py

@@ -0,0 +1,71 @@
+from .models import CastomUser
+from django.core.exceptions import ValidationError
+from django.core.validators import RegexValidator
+from django import forms
+
+
+from .validators import validate_pasword_len
+
+
+class RegisterUserForm(forms.ModelForm):
+    first_name = forms.CharField(
+        label='Имя',
+        validators=[RegexValidator('^[а-яА-Я- -]+$',
+                                   message="Разрешены только кириллица, дефис и пробелы")],
+        error_messages={'required': 'Обязательное поле', }
+    )
+    last_name = forms.CharField(
+        label='Фамилия',
+        validators=[RegexValidator('^[а-яА-Я- -]+$',
+                                   message="Разрешены только кириллица, дефис и пробелы")],
+        error_messages={'required': 'Обязательное поле', }
+    )
+    username = forms.CharField(label='Логин',
+                                validators=[RegexValidator('^[a-zA-Z0-9-]+$',
+                                                                message = "Разрешены только латиница, цифры или тире")],
+                                error_messages={
+                                        'required': 'Обязательное поле',
+                                        'unique': 'Данный логин занят'
+                                })
+    email = forms.EmailField(label='Anpec злектронной почт',
+                            error_messages={
+                                'invalid': 'Hе правильный формат адреса',
+                                'unique': 'Данный адрес занят'
+                            })
+    password = forms.CharField(label='Пароль',
+                                widget=forms.PasswordInput,
+                                validators=[validate_pasword_len],
+                                error_messages={
+                                    'required': 'Обязательное поле',
+                                })
+    password2 = forms.CharField(label='Пapоль (повторно)',
+                                widget=forms.PasswordInput,
+                                error_messages={
+                                    'required': 'Обязательное поле',
+                                })
+    rules = forms.BooleanField(required=True,
+                                label='Согласие с правилами регистрации',
+                               error_messages={
+                                   'required': 'Обязательное поле',
+                               })
+    def clean(self):
+        super().clean()
+        password = self.cleaned_data.get('password')
+        password2 = self.cleaned_data.get('password2')
+        if password and password2 and password != password2:
+            raise ValidationError({
+                'password2': ValidationError('Введенные пароли не совпадант', соdе='password_mismatch')
+        })
+    def save(self, commit=True):
+        user = super().save(commit=False)
+        user.set_password(self.cleaned_data.get('password'))
+        if commit:
+            user.save()
+        return user
+    class Meta:
+        model = CastomUser
+        fields = ('first_name', 'last_name', 'username', 'email', 'password', 'password2', 'rules')
+
+
+class SearchForm(forms.Form):
+    query = forms.CharField(max_length=255, required=False, label= 'Search')

+ 212 - 0
shop/migrations/0001_initial.py

@@ -0,0 +1,212 @@
+# Generated by Django 5.0 on 2023-12-26 02:01
+
+import django.contrib.auth.models
+import django.contrib.auth.validators
+import django.core.validators
+import django.db.models.deletion
+import django.utils.timezone
+import shop.models
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    initial = True
+
+    dependencies = [
+        ("auth", "0012_alter_user_first_name_max_length"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="Category",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "name",
+                    models.CharField(help_text="Введите категории", max_length=100),
+                ),
+            ],
+        ),
+        migrations.CreateModel(
+            name="CastomUser",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "last_login",
+                    models.DateTimeField(
+                        blank=True, null=True, verbose_name="last login"
+                    ),
+                ),
+                (
+                    "is_superuser",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates that this user has all permissions without explicitly assigning them.",
+                        verbose_name="superuser status",
+                    ),
+                ),
+                (
+                    "username",
+                    models.CharField(
+                        error_messages={
+                            "unique": "A user with that username already exists."
+                        },
+                        help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
+                        max_length=150,
+                        unique=True,
+                        validators=[
+                            django.contrib.auth.validators.UnicodeUsernameValidator()
+                        ],
+                        verbose_name="username",
+                    ),
+                ),
+                (
+                    "is_staff",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates whether the user can log into this admin site.",
+                        verbose_name="staff status",
+                    ),
+                ),
+                (
+                    "is_active",
+                    models.BooleanField(
+                        default=True,
+                        help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
+                        verbose_name="active",
+                    ),
+                ),
+                (
+                    "date_joined",
+                    models.DateTimeField(
+                        default=django.utils.timezone.now, verbose_name="date joined"
+                    ),
+                ),
+                ("first_name", models.CharField(max_length=254, verbose_name="Имя")),
+                ("last_name", models.CharField(max_length=254, verbose_name="Фамилия")),
+                ("email", models.CharField(max_length=254, verbose_name="Пoчтa")),
+                ("password", models.CharField(max_length=254, verbose_name="Пapoль")),
+                (
+                    "role",
+                    models.CharField(
+                        choices=[("admin", "Администратор"), ("user", "Пoльзователь")],
+                        default="user",
+                        max_length=254,
+                        verbose_name="Poль",
+                    ),
+                ),
+                (
+                    "groups",
+                    models.ManyToManyField(
+                        blank=True,
+                        help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
+                        related_name="user_set",
+                        related_query_name="user",
+                        to="auth.group",
+                        verbose_name="groups",
+                    ),
+                ),
+                (
+                    "user_permissions",
+                    models.ManyToManyField(
+                        blank=True,
+                        help_text="Specific permissions for this user.",
+                        related_name="user_set",
+                        related_query_name="user",
+                        to="auth.permission",
+                        verbose_name="user permissions",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "user",
+                "verbose_name_plural": "users",
+                "abstract": False,
+            },
+            managers=[
+                ("objects", django.contrib.auth.models.UserManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            name="Application",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("title", models.CharField(max_length=200)),
+                ("summary", models.TextField(help_text="Опишите свою заявку ")),
+                (
+                    "photo_file",
+                    models.ImageField(
+                        max_length=254,
+                        upload_to="image/",
+                        validators=[
+                            shop.models.Application.validate_image,
+                            django.core.validators.FileExtensionValidator(
+                                ["jpg", "jpeg", "png", "bmp"]
+                            ),
+                        ],
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        choices=[
+                            ("N", "Новая"),
+                            ("P", "Принято в работу"),
+                            ("C", "Выполнено"),
+                        ],
+                        default="N",
+                        max_length=254,
+                        verbose_name="Статус",
+                    ),
+                ),
+                (
+                    "date",
+                    models.DateTimeField(
+                        default=django.utils.timezone.now,
+                        verbose_name="Дата добавления",
+                    ),
+                ),
+                (
+                    "user",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to=settings.AUTH_USER_MODEL,
+                        verbose_name="Пользователь",
+                    ),
+                ),
+                (
+                    "category",
+                    models.ForeignKey(
+                        help_text="Выберите категорию",
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="shop.category",
+                    ),
+                ),
+            ],
+        ),
+    ]

+ 28 - 0
shop/migrations/0002_product.py

@@ -0,0 +1,28 @@
+# Generated by Django 5.0 on 2023-12-26 03:16
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shop", "0001_initial"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="Product",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=255)),
+                ("description", models.TextField()),
+            ],
+        ),
+    ]

+ 0 - 0
shop/migrations/__init__.py


+ 56 - 0
shop/models.py

@@ -0,0 +1,56 @@
+import django
+from django.contrib.auth.models import AbstractUser
+from django.core.exceptions import ValidationError
+from django.db import models
+from django.core.validators import FileExtensionValidator
+from django.urls import reverse
+from django.utils import timezone
+
+
+class Category (models.Model):
+    name = models.CharField(max_length=100, help_text="Введите категории")
+    def __str__(self):
+        return self.name
+
+class CastomUser(AbstractUser):
+    first_name = models.CharField(max_length=254, verbose_name='Имя', blank=False)
+    last_name = models.CharField(max_length=254, verbose_name='Фамилия', blank=False)
+    email = models.CharField(max_length=254, verbose_name='Пoчтa', blank=False)
+    password = models.CharField(max_length=254, verbose_name='Пapoль', blank=False)
+    role = models.CharField(max_length=254, verbose_name='Poль',
+                            choices=(('admin', 'Администратор'), ('user', 'Пoльзователь')), default='user')
+
+class Application(models.Model):
+    title = models.CharField(max_length=200)
+    summary = models.TextField(help_text="Опишите свою заявку ")
+    STATUS_CHOICES = [
+        ('N', 'Новая'),
+        ('P', 'Принято в работу'),
+        ('C', 'Выполнено')
+    ]
+
+    def validate_image(fieldfile_obj):
+        filesize = fieldfile_obj.file.size
+        megabyte_limit = 2.0
+        if filesize > megabyte_limit * 1024 * 1024:
+            raise ValidationError("Max file size is %sMB" % str(megabyte_limit))
+
+    category = models.ForeignKey(Category, help_text='Выберите категорию', on_delete=models.CASCADE)
+    photo_file = models.ImageField(max_length=254, upload_to='image/', validators=[validate_image, FileExtensionValidator(['jpg', 'jpeg', 'png', 'bmp'])])
+    status = models.CharField(max_length=254, verbose_name='Статус', choices=STATUS_CHOICES, default='N')
+    date = models.DateTimeField(verbose_name='Дата добавления', default=django.utils.timezone.now)
+    user = models.ForeignKey(CastomUser, verbose_name='Пользователь', on_delete=models.CASCADE)
+
+    def get_absolute_url(self):
+        return reverse('application_leist', args=[str(self.id)])
+
+    def __str__(self):
+        return self.title
+
+class Product(models.Model):
+    name = models.CharField(max_length=255)
+    description = models.TextField()
+
+
+def __str__(self):
+    return self.name

+ 5 - 0
shop/static/style.css

@@ -0,0 +1,5 @@
+.sidebar-nav {
+    margin-top: 50px;
+    padding: 0;
+    list-style: none;
+}

+ 0 - 0
shop/templates/application.html


+ 35 - 0
shop/templates/base.html

@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <link
+      rel="stylesheet"
+      href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+    {% load static %}
+    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
+</head>
+<body>
+<div style="display: flex">
+    <div class="sidebar-nav" style="margin: 20px 0 0 20px">
+        <nav>
+            <p><a href="{% url 'index' %}">Главная</a></p>
+            <p><a href="{% url 'search' %}">Поиск</a></p>
+            {% if user.is_authenticated %}
+            <p><a href="{% url 'profil' %}">Профиль</a></p>
+                <a href="{% url 'logout'%}">Выход</a><br>
+            {% else %}
+                <p><a href="{% url 'login' %}">Вход</a></p>
+                <p><a href="{% url 'registration'%}">Регистрация</a></p>
+            {% endif %}
+       </nav>
+    </div>
+    <div style="margin-left: 50px">{% block content %}{% endblock %}</div>
+</div>
+</body>
+</html>
+
+

+ 16 - 0
shop/templates/index.html

@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block content %}
+
+<h1>Личный кабинет</h1>
+{% if user.is_authenticated %}
+    <h1>Список заявок</h1>
+{% for application in applications %}
+<p>Временная метка:{{ application.date }}</p>
+<p>Название: {{ application.title }}</p>
+<p>Категория: {{ application.category }}</p>
+<p>Фотография: <img src="{{ application.photo_file.url }}"></p>
+
+
+{% endfor %}
+{% endif %}
+{% endblock %}

+ 7 - 0
shop/templates/logout.html

@@ -0,0 +1,7 @@
+{% extends "base_generic.html" %}
+
+{% block content %}
+  <p>Logged out!</p>
+
+  <a href="{% url 'login'%}">Click here to login again.</a>
+{% endblock %}

+ 13 - 0
shop/templates/profil.html

@@ -0,0 +1,13 @@
+    {% extends "base.html" %}
+
+    {% block content %}
+    <h1>Личный кабинет {{ user }}</h1>
+    {% for application in applications %}
+    <p>Временная метка:{{ application.date }}</p>
+    <p>Название: {{ application.title }}</p>
+    <p>Описание: {{ application.summary }}</p>
+    <p>Категория: {{ application.category }}</p>
+    <p>Статус: {{ application.get_status_display }}</p>
+<a href ="{% url 'deleting' %}">Удалить</a><br>
+    {% endfor %}
+    {% endblock %}

+ 34 - 0
shop/templates/registration.html

@@ -0,0 +1,34 @@
+{% extends "base.html" %}
+
+{% block content %}
+    <h1>Регистрация</h1>
+    <form method="post">
+      {{ form.as_p}}
+      {% csrf_token %}
+      <button
+          type="submit"
+          class="btn btn-primary">
+          Регистрация
+      </button>
+    </form>
+{% endblock %}
+<script>
+    document.querySelector('#id_username').addEventListener('blur', async (event) => {
+        const res = await fetch('/validate_username?username=${event.target.value}).then(res => res.json());
+
+        event.target.parentNode.querySelector('.errorList')?.remove();
+        const errors = document.createElement('ul');
+        errors.classList.add('errorList');
+        if (res.is_taken) {
+            errors.innerHTML += '<li>Логин занят</li>';
+        }
+        if (event.target.value.length == 0) {
+            errors.innerHTML += '<li>Лoгин не может быть пустым</li>';
+        }
+        const re= new RegExp("^[a-zA-Z0-9-]+$");
+        if (!re.test(event.target.value)) {
+            errors.innerHTML += '<li>Разрешены только латиница, цифры или тире</li>';
+        }
+        event.target.parentNode.prepend(errors);
+        })
+</script>

+ 38 - 0
shop/templates/registration/login.html

@@ -0,0 +1,38 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+{% if form.errors %}
+<p>Ваше имя пользователя и пароль не совпадают. Пожалуйста, попробуйте еще раз.</p>
+{% endif %}
+
+{% if next %}
+    {% if user.is_authenticated %}
+    <p>У вашей учетной записи нет доступа к этой странице. Чтобы продолжить,
+    пожалуйста, войдите под учетной записью, у которой есть необходимые права.</p>
+    {% else %}
+    <p>Пожалуйста, войдите, чтобы увидеть эту страницу.</p>
+    {% endif %}
+{% endif %}
+
+<form method="post" action="{% url 'login' %}">
+{% csrf_token %}
+<table>
+<tr>
+    <td>{{ form.username.label_tag }}</td>
+    <td>{{ form.username }}</td>
+</tr>
+<tr>
+    <td>{{ form.password.label_tag }}</td>
+    <td>{{ form.password }}</td>
+</tr>
+</table>
+
+<input type="submit" value="login">
+<input type="hidden" name="next" value="{{ next }}">
+</form>
+
+
+<p><a href="">Lost password?</a></p>
+
+{% endblock %}

+ 0 - 0
shop/templates/registration/register.html


+ 30 - 0
shop/templates/search.html

@@ -0,0 +1,30 @@
+{% extends "base.html" %}
+{% block content %}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Результаты поиска</title>
+</head>
+<body>
+    <h1>Результаты поиска</h1>
+
+    <form method="get" action="{% url 'search' %}">
+        {{ form.as_p }}
+        <button type="submit">Поиск</button>
+    </form>
+
+    {% if results %}
+        <ul>
+            {% for product in results %}
+                <li>{{ product.name }}</li>
+            {% endfor %}
+        </ul>
+    {% else %}
+        <p>Нет такого результата поиска.</p>
+    {% endif %}
+</body>
+</html>
+{% endblock %}

+ 3 - 0
shop/templates/style/style.css

@@ -0,0 +1,3 @@
+h1{
+    color: red;
+}

+ 3 - 0
shop/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 24 - 0
shop/urls.py

@@ -0,0 +1,24 @@
+from django.conf import settings
+from django.conf.urls.static import static
+from django.urls import path
+from . import views
+from .views import validate_username
+from django.contrib.auth.views import LoginView
+from django.contrib.auth.views import LogoutView
+from django.urls import re_path as url
+from .views import *
+
+urlpatterns = [
+    path('', ApplicationListView.as_view(), name='index'),
+    path('login/', LoginView.as_view(), name='login'),
+    path('registration/', views.registration, name='registration'),
+    path('register', views.RegisterView.as_view(), name='register'),
+    path('validate_username', validate_username, name='validate_username'),
+    path('logout/', BBLogoutView.as_view(), name='logout'),
+    path('profil/', ApplicationsByUserListView.as_view(), name='profil'),
+    path('search_result/', search_view, name='search'),
+    path('deleting/', views.ApplicationDelete.as_view(), name='deleting'),
+] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+
+
+

+ 6 - 0
shop/validators.py

@@ -0,0 +1,6 @@
+from django.core.exceptions import ValidationError
+
+
+def validate_pasword_len(password):
+    if len(password) < 6:
+        raise ValidationError('Длина пароля не может быть меньше 6 символов')

+ 85 - 0
shop/views.py

@@ -0,0 +1,85 @@
+from django.contrib.auth import logout
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.contrib.auth.models import User
+from django.contrib.auth.views import LogoutView
+from django.http import JsonResponse
+from django.shortcuts import render, redirect
+from django.urls import reverse_lazy
+from django.views import generic
+from django.views.generic import CreateView
+from .forms import RegisterUserForm, SearchForm
+from .models import Application
+from .models import Product
+from .models import*
+# Create your views here.
+def index(request):
+    return render(request, 'index.html')
+def profil(request):
+    return render(request, 'profil.html')
+
+def login(request):
+    return render(request, 'registration/login.html')
+
+def registration(request):
+    return render(request, 'registration.html')
+
+# def logout(request):
+#     return render(request, 'logout.html')
+
+class RegisterView(CreateView):
+    template_name = 'registration.html'
+    form_class = RegisterUserForm
+    success_url = reverse_lazy('login')
+def validate_username(request):
+    username = request.GET.get('username', None)
+    response = {
+        'is_taken': User.objects.filter(username__iexact=username).exists()
+    }
+    return JsonResponse(response)
+class BBLogoutView(LogoutView):
+    # template_name = 'logout.html'
+    success_url = reverse_lazy('index')
+
+class ApplicationListView(generic.ListView):
+    model = Application
+    template_name = 'index.html'
+    context_object_name = 'applications'
+
+class ApplicationsByUserListView(LoginRequiredMixin, generic.ListView):
+    model = Application
+    template_name = 'profil.html'
+    context_object_name = 'applications'
+
+    def get_queryset(self):
+        return Application.objects.filter(user=self.request.user)
+
+
+
+
+def search_view(request):
+    query = request.GET.get('query', '')
+    results = Product.objects.filter(name__icontains=query)
+    form = SearchForm({'query': query})
+
+    context = {'results': results, 'form': form}
+    return render(request, 'search.html', context)
+
+
+class ApplicationDelete(ApplicationListView):
+    model = Application
+    context_object_name = 'application'
+    template_name = 'deleting.html'
+    success_url = reverse_lazy('request')
+
+    def delete_application(self, pk):
+        application = Application.objects.filter(user=self.request.user, pk=pk)
+
+        if application:
+            application.delete()
+        return redirect('request')
+
+
+
+    def logout_view(request):
+        logout(request)
+        return redirect('base.html')