diff --git a/anfisa_for_friends/anfisa_for_friends/settings.py b/anfisa_for_friends/anfisa_for_friends/settings.py index a8c9efe0..ca1b7d6a 100644 --- a/anfisa_for_friends/anfisa_for_friends/settings.py +++ b/anfisa_for_friends/anfisa_for_friends/settings.py @@ -9,6 +9,8 @@ ALLOWED_HOSTS = [] INSTALLED_APPS = [ + 'users.apps.UsersConfig', + 'statistic.apps.StatisticConfig', 'homepage.apps.HomepageConfig', 'ice_cream.apps.IceCreamConfig', 'about.apps.AboutConfig', @@ -94,3 +96,9 @@ ] DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +AUTH_USER_MODEL = 'users.CustomUser' + +LOGIN_URL = 'users:login' +LOGOUT_URL = 'users:logout' +LOGIN_REDIRECT_URL = 'homepage:index' diff --git a/anfisa_for_friends/anfisa_for_friends/urls.py b/anfisa_for_friends/anfisa_for_friends/urls.py index 08c8ba7e..21867092 100644 --- a/anfisa_for_friends/anfisa_for_friends/urls.py +++ b/anfisa_for_friends/anfisa_for_friends/urls.py @@ -5,5 +5,7 @@ path('', include('homepage.urls', namespace='homepage')), path('about/', include('about.urls', namespace='about')), path('ice_cream/', include('ice_cream.urls', namespace='ice_cream')), + path('statistic/', include('statistic.urls', namespace='statistic')), + path('auth/', include('users.urls', namespace='users')), path('admin/', admin.site.urls), ] diff --git a/anfisa_for_friends/static_dev/img/image-holder.png b/anfisa_for_friends/static_dev/img/image-holder.png new file mode 100644 index 00000000..55e7e4d2 Binary files /dev/null and b/anfisa_for_friends/static_dev/img/image-holder.png differ diff --git a/anfisa_for_friends/statistic/__init__.py b/anfisa_for_friends/statistic/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/anfisa_for_friends/statistic/admin.py b/anfisa_for_friends/statistic/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/anfisa_for_friends/statistic/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/anfisa_for_friends/statistic/apps.py b/anfisa_for_friends/statistic/apps.py new file mode 100644 index 00000000..a38a6cc0 --- /dev/null +++ b/anfisa_for_friends/statistic/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class StatisticConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'statistic' diff --git a/anfisa_for_friends/statistic/migrations/__init__.py b/anfisa_for_friends/statistic/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/anfisa_for_friends/statistic/models.py b/anfisa_for_friends/statistic/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/anfisa_for_friends/statistic/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/anfisa_for_friends/statistic/tests.py b/anfisa_for_friends/statistic/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/anfisa_for_friends/statistic/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/anfisa_for_friends/statistic/urls.py b/anfisa_for_friends/statistic/urls.py new file mode 100644 index 00000000..02f2f6ae --- /dev/null +++ b/anfisa_for_friends/statistic/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +app_name = 'statistic' + +urlpatterns = [ + path('google/', views.google_search, name='google_search'), + path('yandex/', views.yandex_search, name='yandex_search'), +] diff --git a/anfisa_for_friends/statistic/views.py b/anfisa_for_friends/statistic/views.py new file mode 100644 index 00000000..2cb68c6e --- /dev/null +++ b/anfisa_for_friends/statistic/views.py @@ -0,0 +1,9 @@ +from django.http import HttpResponse + + +def google_search(request): + return HttpResponse('Это станица для поисковой системы Google') + + +def yandex_search(request): + return HttpResponse('Это станица для поисковой системы Yandex') diff --git a/anfisa_for_friends/templates/about/description.html b/anfisa_for_friends/templates/about/description.html index 373d14cf..37b2f5ba 100644 --- a/anfisa_for_friends/templates/about/description.html +++ b/anfisa_for_friends/templates/about/description.html @@ -1,7 +1,10 @@ {% extends "base.html" %} {% block title %} - Анфиса для друзей. Описание проекта + Анфиса для друзей. О проекте {% endblock %} {% block content %} -

Описание проекта

+

О проекте

+

+ Каталог экзотических сортов мороженого. +

{% endblock %} diff --git a/anfisa_for_friends/templates/base.html b/anfisa_for_friends/templates/base.html index 6219c7a6..9a61e2d6 100644 --- a/anfisa_for_friends/templates/base.html +++ b/anfisa_for_friends/templates/base.html @@ -10,9 +10,11 @@ {% include "includes/header.html" %} -
+
+
{% block content %} {% endblock %} +
{% include "includes/footer.html" %} diff --git a/anfisa_for_friends/templates/homepage/index.html b/anfisa_for_friends/templates/homepage/index.html index 3d2191c0..059f0f48 100644 --- a/anfisa_for_friends/templates/homepage/index.html +++ b/anfisa_for_friends/templates/homepage/index.html @@ -3,5 +3,5 @@ Анфиса для друзей. Главная {% endblock %} {% block content %} -

Главная страница

+

Главная страница

{% endblock %} diff --git a/anfisa_for_friends/templates/ice_cream/detail.html b/anfisa_for_friends/templates/ice_cream/detail.html index a6af384c..97ce7694 100644 --- a/anfisa_for_friends/templates/ice_cream/detail.html +++ b/anfisa_for_friends/templates/ice_cream/detail.html @@ -1,10 +1,21 @@ {% extends "base.html" %} +{% load static %} {% block title %} - Анфиса для друзей. Подробное описание мороженого + Анфиса для друзей. {{ ice_cream.title }} {% endblock %} {% block content %} -

Подробное описание мороженого

-

{{ ice_cream.title }}

-

{{ ice_cream.description }}

+

{{ ice_cream.title }}

+
+
+

Описание

+

{{ ice_cream.description }}

+
+
+ +
+
{% endblock %} - \ No newline at end of file diff --git a/anfisa_for_friends/templates/ice_cream/list.html b/anfisa_for_friends/templates/ice_cream/list.html index 65f098c2..17701bed 100644 --- a/anfisa_for_friends/templates/ice_cream/list.html +++ b/anfisa_for_friends/templates/ice_cream/list.html @@ -1,19 +1,33 @@ {% extends "base.html" %} +{% load static %} {% block title %} Анфиса для друзей. Каталог мороженого {% endblock %} {% block content %} -

Каталог мороженого

- -{% endblock %} \ No newline at end of file +

Каталог мороженого

+
+ {% for ice_cream in ice_cream_list %} +
+
+ + +
+
{{ ice_cream.title }}
+

+ {{ ice_cream.description|truncatewords:10 }} +

+ + Подробнее --> + +
+
+
+ {% endfor %} +
+{% endblock %} diff --git a/anfisa_for_friends/templates/includes/footer.html b/anfisa_for_friends/templates/includes/footer.html index 2d3af22c..ef9f1777 100644 --- a/anfisa_for_friends/templates/includes/footer.html +++ b/anfisa_for_friends/templates/includes/footer.html @@ -1,3 +1,3 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/anfisa_for_friends/templates/includes/header.html b/anfisa_for_friends/templates/includes/header.html index 66520481..9c3a5a75 100644 --- a/anfisa_for_friends/templates/includes/header.html +++ b/anfisa_for_friends/templates/includes/header.html @@ -1,17 +1,63 @@ {% load static %} +{% with request.resolver_match.view_name as view_name %}
- -
\ No newline at end of file + +{% endwith %} \ No newline at end of file diff --git a/anfisa_for_friends/templates/users/login.html b/anfisa_for_friends/templates/users/login.html new file mode 100644 index 00000000..b72cb73c --- /dev/null +++ b/anfisa_for_friends/templates/users/login.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %} + Login +{% endblock %} + +{% block content %} +

Login

+
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/anfisa_for_friends/templates/users/signup.html b/anfisa_for_friends/templates/users/signup.html new file mode 100644 index 00000000..87cfda74 --- /dev/null +++ b/anfisa_for_friends/templates/users/signup.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %} + Sign Up +{% endblock %} + +{% block content %} +

Sign Up

+
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/anfisa_for_friends/users/__init__.py b/anfisa_for_friends/users/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/anfisa_for_friends/users/admin.py b/anfisa_for_friends/users/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/anfisa_for_friends/users/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/anfisa_for_friends/users/apps.py b/anfisa_for_friends/users/apps.py new file mode 100644 index 00000000..72b14010 --- /dev/null +++ b/anfisa_for_friends/users/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'users' diff --git a/anfisa_for_friends/users/forms.py b/anfisa_for_friends/users/forms.py new file mode 100644 index 00000000..1497be95 --- /dev/null +++ b/anfisa_for_friends/users/forms.py @@ -0,0 +1,8 @@ +from django.contrib.auth.forms import UserCreationForm +from .models import CustomUser + + +class CustomUserCreationForm(UserCreationForm): + class Meta(UserCreationForm.Meta): + model = CustomUser + fields = ('email',) diff --git a/anfisa_for_friends/users/migrations/0001_initial.py b/anfisa_for_friends/users/migrations/0001_initial.py new file mode 100644 index 00000000..de8b109a --- /dev/null +++ b/anfisa_for_friends/users/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.16 on 2025-09-04 06:17 + +import django.contrib.auth.models +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('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')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('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')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), + ('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()), + ], + ), + ] diff --git a/anfisa_for_friends/users/migrations/0002_alter_customuser_managers.py b/anfisa_for_friends/users/migrations/0002_alter_customuser_managers.py new file mode 100644 index 00000000..d02af45e --- /dev/null +++ b/anfisa_for_friends/users/migrations/0002_alter_customuser_managers.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.16 on 2025-09-04 06:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AlterModelManagers( + name='customuser', + managers=[ + ], + ), + ] diff --git a/anfisa_for_friends/users/migrations/__init__.py b/anfisa_for_friends/users/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/anfisa_for_friends/users/models.py b/anfisa_for_friends/users/models.py new file mode 100644 index 00000000..dd970979 --- /dev/null +++ b/anfisa_for_friends/users/models.py @@ -0,0 +1,48 @@ +from django.contrib.auth.models import AbstractUser, BaseUserManager +from django.db import models +from django.utils.translation import gettext_lazy as _ + + +class CustomUserManager(BaseUserManager): + """ + Custom user model manager where email is the unique identifiers + for authentication instead of usernames. + """ + def create_user(self, email, password, **extra_fields): + """ + Create and save a User with the given email and password. + """ + if not email: + raise ValueError(_('The Email must be set')) + email = self.normalize_email(email) + user = self.model(email=email, **extra_fields) + user.set_password(password) + user.save() + return user + + def create_superuser(self, email, password, **extra_fields): + """ + Create and save a SuperUser with the given email and password. + """ + extra_fields.setdefault('is_staff', True) + extra_fields.setdefault('is_superuser', True) + extra_fields.setdefault('is_active', True) + + if extra_fields.get('is_staff') is not True: + raise ValueError(_('Superuser must have is_staff=True.')) + if extra_fields.get('is_superuser') is not True: + raise ValueError(_('Superuser must have is_superuser=True.')) + return self.create_user(email, password, **extra_fields) + + +class CustomUser(AbstractUser): + username = None + email = models.EmailField(_('email address'), unique=True) + + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = [] + + objects = CustomUserManager() + + def __str__(self): + return self.email diff --git a/anfisa_for_friends/users/tests.py b/anfisa_for_friends/users/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/anfisa_for_friends/users/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/anfisa_for_friends/users/urls.py b/anfisa_for_friends/users/urls.py new file mode 100644 index 00000000..c4242ec9 --- /dev/null +++ b/anfisa_for_friends/users/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views + +app_name = 'users' + +urlpatterns = [ + path('signup/', views.SignUpView.as_view(), name='signup'), + path('login/', views.CustomLoginView.as_view(), name='login'), + path('logout/', views.CustomLogoutView.as_view(), name='logout'), +] diff --git a/anfisa_for_friends/users/views.py b/anfisa_for_friends/users/views.py new file mode 100644 index 00000000..e5e1c64f --- /dev/null +++ b/anfisa_for_friends/users/views.py @@ -0,0 +1,21 @@ +from django.views.generic.edit import CreateView +from django.contrib.auth.views import LoginView, LogoutView +from django.urls import reverse_lazy + +from django.contrib.auth.forms import AuthenticationForm +from .forms import CustomUserCreationForm + + +class SignUpView(CreateView): + form_class = CustomUserCreationForm + success_url = reverse_lazy('homepage:index') + template_name = 'users/signup.html' + + +class CustomLoginView(LoginView): + form_class = AuthenticationForm + template_name = 'users/login.html' + + +class CustomLogoutView(LogoutView): + next_page = reverse_lazy('homepage:index')