Initial commit
0
account/__init__.py
Normal file
5
account/admin.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from .models import *
|
||||
|
||||
|
||||
admin.site.register(SiteUser)
|
6
account/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccountConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'account'
|
10
account/forms.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from .models import SiteUser
|
||||
|
||||
|
||||
class SiteUserForm(UserCreationForm):
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = SiteUser
|
||||
fields = ('name', 'surname', 'email', 'phone')
|
||||
error_css_class = 'error'
|
33
account/migrations/0001_initial.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.1.1 on 2022-09-11 21:55
|
||||
|
||||
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='SiteUser',
|
||||
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')),
|
||||
('surname', models.CharField(max_length=60)),
|
||||
('name', models.CharField(max_length=60)),
|
||||
('email', models.EmailField(max_length=254, unique=True)),
|
||||
('phone', models.CharField(max_length=16, unique=True)),
|
||||
('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={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
18
account/migrations/0002_siteuser_is_staff.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.1 on 2022-09-11 22:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='siteuser',
|
||||
name='is_staff',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
0
account/migrations/__init__.py
Normal file
57
account/models.py
Normal file
@ -0,0 +1,57 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import PermissionsMixin, AbstractBaseUser, BaseUserManager
|
||||
|
||||
|
||||
class SiteAccountManager(BaseUserManager):
|
||||
def create_user(self, email, name, surname, phone, password):
|
||||
user = self.model(email=email, name=name, surname=surname, phone=phone, password=password)
|
||||
user.set_password(password)
|
||||
user.is_staff = False
|
||||
user.is_superuser = False
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def create_superuser(self, email, name, surname, phone, password):
|
||||
user = self.create_user(email=email, name=name, surname=surname, phone=phone, password=password)
|
||||
user.is_active = True
|
||||
user.is_staff = True
|
||||
user.is_superuser = True
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def get_by_natural_key(self, email_):
|
||||
print(email_)
|
||||
return self.get(email=email_)
|
||||
|
||||
|
||||
class SiteUser(AbstractBaseUser, PermissionsMixin):
|
||||
"""
|
||||
Here we are subclassing the Django AbstractBaseUser, which comes with only
|
||||
3 fields:
|
||||
1 - password
|
||||
2 - last_login
|
||||
3 - is_active
|
||||
Note than all fields would be required unless specified otherwise, with
|
||||
`required=False` in the parentheses.
|
||||
The PermissionsMixin is a model that helps you implement permission settings
|
||||
as-is or modified to your requirements.
|
||||
More info: https://goo.gl/YNL2ax
|
||||
"""
|
||||
surname = models.CharField(max_length=60, verbose_name="Фамилия")
|
||||
name = models.CharField(max_length=60, verbose_name="Имя")
|
||||
email = models.EmailField(unique=True, verbose_name="Email")
|
||||
phone = models.CharField(unique=True, max_length=16, verbose_name="Телефон")
|
||||
is_staff = models.BooleanField(default=False, verbose_name="Разрешение на вход в админку")
|
||||
REQUIRED_FIELDS = ['name', 'surname', 'phone']
|
||||
USERNAME_FIELD = 'email'
|
||||
|
||||
objects = SiteAccountManager()
|
||||
|
||||
def get_short_name(self):
|
||||
return self.email
|
||||
|
||||
def natural_key(self):
|
||||
return self.email
|
||||
|
||||
def __str__(self):
|
||||
return self.email
|
3
account/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
29
account/urls.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""stall 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 . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='account'),
|
||||
# path('account', views.account, name='account'),
|
||||
# path('account_<str:action>', views.account_action, name='account_action'),
|
||||
#
|
||||
# path('catalog/', views.catalog, name='catalog'),
|
||||
# path('catalog/<int:product_id>/', views.product_view, name='product_view'),
|
||||
# path('cart', views.cart, name='cart'),
|
||||
]
|
||||
|
21
account/views.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from .forms import SiteUserForm
|
||||
|
||||
|
||||
def index(request):
|
||||
if request.method == 'POST':
|
||||
form = SiteUserForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return HttpResponse("User was created successfully.")
|
||||
else:
|
||||
return HttpResponse("There was an error.")
|
||||
else:
|
||||
form = SiteUserForm()
|
||||
|
||||
return render(request, 'account.html', {'form': form})
|
||||
|
||||
|
||||
# def index(request):
|
||||
# return render(request, 'account.html')
|
0
api/__init__.py
Normal file
3
api/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
api/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'api'
|
3
api/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
3
api/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
23
api/urls.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""stall 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.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('<method_name>', views.call_method, name='call_method')
|
||||
]
|
||||
|
12
api/views.py
Normal file
@ -0,0 +1,12 @@
|
||||
import json
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
def call_method(request, method_name):
|
||||
tmp = {}
|
||||
for key in request.GET:
|
||||
tmp[key] = request.GET[key]
|
||||
response = HttpResponse(json.dumps({"response": {"method": method_name, "params": tmp}}, ensure_ascii=True))
|
||||
response.headers["Content-type"] = "application/json"
|
||||
return response
|
0
arka/__init__.py
Normal file
16
arka/asgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for arka 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/4.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'arka.settings')
|
||||
|
||||
application = get_asgi_application()
|
144
arka/settings.py
Normal file
@ -0,0 +1,144 @@
|
||||
"""
|
||||
Django settings for stall project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.2.10.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.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
|
||||
PROJECT_ROOT = os.path.dirname(__file__)
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-59tghb+-((1(j5zq5m_=5v4zfna8m&^e6aet5wxrb@ol&n!*41'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["arka.topserv4824.duckdns.org", "192.168.0.160", "localhost"]
|
||||
CSRF_TRUSTED_ORIGINS = ['https://arka.topserv4824.duckdns.org']
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'api.apps.ApiConfig',
|
||||
'dev.apps.DevConfig',
|
||||
'index.apps.IndexConfig',
|
||||
'account.apps.AccountConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_extensions',
|
||||
]
|
||||
|
||||
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 = 'arka.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
||||
'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 = 'arka.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
||||
# }
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'vlad_arkadb',
|
||||
'USER': 'vlad_arka',
|
||||
'PASSWORD': '#e1LjpSY74^2',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_USER_MODEL = 'account.SiteUser'
|
||||
|
||||
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.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'ru-RU'
|
||||
|
||||
TIME_ZONE = 'Europe/Moscow'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
27
arka/urls.py
Normal file
@ -0,0 +1,27 @@
|
||||
"""arka URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.1/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, include
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('account/', include('account.urls')),
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
path('api/', include('api.urls')),
|
||||
path('dev/', include('dev.urls')),
|
||||
path('', include('index.urls')),
|
||||
]
|
16
arka/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for arka 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/4.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'arka.settings')
|
||||
|
||||
application = get_wsgi_application()
|
0
dev/__init__.py
Normal file
5
dev/admin.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from .models import *
|
||||
|
||||
# admin.site.register(DevEventType)
|
||||
admin.site.register(DevEventLog)
|
6
dev/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class DevConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'dev'
|
32
dev/migrations/0001_initial.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Generated by Django 4.1.1 on 2022-09-11 21:55
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DevEventType',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DevEventLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128)),
|
||||
('event_time', models.DateTimeField(auto_now_add=True)),
|
||||
('description', models.TextField()),
|
||||
('event_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dev.deveventtype')),
|
||||
],
|
||||
),
|
||||
]
|
0
dev/migrations/__init__.py
Normal file
18
dev/models.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class DevEventType(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class DevEventLog(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
event_time = models.DateTimeField(auto_now_add=True, blank=True)
|
||||
event_type = models.ForeignKey(DevEventType, on_delete=models.CASCADE)
|
||||
description = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return self.event_type.name + ": " + self.name
|
3
dev/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
23
dev/urls.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""stall 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.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.dev_index, name='dev_index')
|
||||
]
|
||||
|
8
dev/views.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
from .models import *
|
||||
|
||||
|
||||
def dev_index(request):
|
||||
events = DevEventLog.objects.all().order_by('-event_time')
|
||||
return render(request, 'dev.html', {"events": events})
|
0
index/__init__.py
Normal file
3
index/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
index/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IndexConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'index'
|
3
index/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
3
index/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
24
index/urls.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""stall 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.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='index'),
|
||||
path('about', views.about, name='about')
|
||||
]
|
||||
|
9
index/views.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request, 'index.html')
|
||||
|
||||
|
||||
def about(request):
|
||||
return render(request, 'about.html')
|
22
manage.py
Executable file
@ -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', 'arka.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()
|
BIN
static/css/._style.css
Normal file
80
static/css/catalog-style.css
Normal file
@ -0,0 +1,80 @@
|
||||
body {
|
||||
overflow: scroll;
|
||||
}
|
||||
.catalog-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
.catalog-categories {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
border: solid 1px gray;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.catalog-categories a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.catalog-products {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-grow: 1;
|
||||
align-items: stretch;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.product {
|
||||
border: solid 1px gray;
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.product img {
|
||||
border-radius: 5%; /* Радиус скругления */
|
||||
box-shadow: 0 0 0 3px transparent; /* Параметры теней */
|
||||
width: 210px;
|
||||
height: 210px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* для мобилок <= 700px */
|
||||
@media screen and (max-width: 701px) {
|
||||
.catalog-container {
|
||||
display: block;
|
||||
}
|
||||
.catalog-categories {
|
||||
flex: 1;
|
||||
}
|
||||
.catalog-products {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
display: grid;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
.product {
|
||||
display: inline-flex;
|
||||
}
|
||||
.product img {
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
margin-bottom: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* для экранов > 700px */
|
||||
@media screen and (min-width: 700px) {
|
||||
.product {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.catalog-categories {
|
||||
display: block;
|
||||
min-width: 230px;
|
||||
}
|
||||
}
|
46
static/css/product-view-style.css
Normal file
@ -0,0 +1,46 @@
|
||||
.options-list {
|
||||
|
||||
}
|
||||
|
||||
.option-item {
|
||||
margin: 5px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.option-selected {
|
||||
border: solid 2px red;
|
||||
}
|
||||
|
||||
/* для мобилок <= 700px */
|
||||
@media screen and (max-width: 701px) {
|
||||
.product-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#product-photo-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
#product-photo {
|
||||
width: 90%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* для экранов > 700px */
|
||||
@media screen and (min-width: 700px) {
|
||||
.product-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
#product-photo-container {
|
||||
margin-right: 2em;
|
||||
}
|
||||
#product-photo {
|
||||
max-width: 500px;
|
||||
min-width: 50%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
83
static/css/style.css
Normal file
@ -0,0 +1,83 @@
|
||||
/* ========== THEME ========== */
|
||||
body {
|
||||
--text-color: #222;
|
||||
--bkg-color: #fff;
|
||||
--bkg-color2: #bbb;
|
||||
}
|
||||
body.dark-theme {
|
||||
--text-color: #eee;
|
||||
--bkg-color: #121212;
|
||||
--bkg-color2: #303030;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* defaults to dark theme */
|
||||
body {
|
||||
--text-color: #eee;
|
||||
--bkg-color: #121212;
|
||||
--bkg-color2: #303030;
|
||||
}
|
||||
body.light-theme {
|
||||
--text-color: #222;
|
||||
--bkg-color: #fff;
|
||||
--bkg-color2: #bbb;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
background: transparent;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bkg-color);
|
||||
}
|
||||
|
||||
h1, p {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* ========== MAIN STYLES ========== */
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
background: var(--bkg-color2);
|
||||
}
|
||||
|
||||
nav * {
|
||||
margin: 10px;
|
||||
width: 12em;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
font-size: medium;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.header-wrapper img {
|
||||
margin-right: 10px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
|
||||
}
|
||||
|
||||
.header-wrapper div * {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
BIN
static/favicon.webp
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
static/images/no-photo.webp
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/images/products/7up.webp
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
static/images/products/adrenaline-rush.webp
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/images/products/cola-unorig.webp
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
static/images/products/hi-energy.webp
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/images/products/lays-150-crab.webp
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
static/images/products/lays-150-lobster.webp
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
static/images/products/lays-150-smetana-luk.webp
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
static/images/products/lays-150-smetana-zelen.webp
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
static/images/products/lays-150-zel-luk.webp
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
static/images/products/mirinda.webp
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
static/images/products/power-tor-yagoda.webp
Normal file
After Width: | Height: | Size: 9.1 KiB |
12
static/js/main.js
Normal file
@ -0,0 +1,12 @@
|
||||
// скрипт...
|
||||
|
||||
// Listen for a click on the button
|
||||
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
document.getElementById("theme-switcher").addEventListener("click", function () {
|
||||
if (prefersDarkScheme.matches) {
|
||||
document.body.classList.toggle("light-theme");
|
||||
} else {
|
||||
document.body.classList.toggle("dark-theme");
|
||||
}
|
||||
});
|
BIN
static/m.mp3
Normal file
BIN
static/m.ogg
Normal file
BIN
static/m2.mp3
Normal file
17
templates/about.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Арка | О нас {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1> О нас </h1>
|
||||
<p>
|
||||
На этой странице должен быть написан текст об этой компании.
|
||||
</p>
|
||||
|
||||
<h3>Контакты</h3>
|
||||
<ul>
|
||||
<li><a href="https://t.me/Vlad_ost_31">@Vlad_ost_31</a> - Владислав, разработчик сайта.</li>
|
||||
<li><a href="https://t.me/n3luna">@n3luna</a> - Георгий, разработчик мобильного приложения.</li>
|
||||
<li><a href="https://t.me/sergey_investing">@sergey_investing</a> - Сергей, дизайнер, верстальщик.</li>
|
||||
<li><a href="https://t.me/PavelIvanchenko">@PavelIvanchenko</a> - Павел, просто главный.</li>
|
||||
</ul>
|
||||
{% endblock %}
|
15
templates/account.html
Normal file
@ -0,0 +1,15 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Аккаунт | вход {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1> Ваш аккаунт </h1>
|
||||
<h3>Регистрация</h3>
|
||||
<form action="" method="POST">{% csrf_token %}
|
||||
<table>
|
||||
<tbody>
|
||||
{{ form.as_table }}
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit">Регистрация</button>
|
||||
</form>
|
||||
{% endblock %}
|
44
templates/base.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title> {% block title %} Арка {% endblock %} </title>
|
||||
{% load static %}
|
||||
<link rel="icon" type="image/webp" href="{% static 'favicon.webp' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
|
||||
{% block styles %} {% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<div class="header-wrapper">
|
||||
<img alt="logo" src="{% static 'favicon.webp' %}">
|
||||
<div>
|
||||
<h3>Арка</h3>
|
||||
<h6>Сайт для анонимного ремонта</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{% if user %}
|
||||
<h5 style="text-align: right">{{ user.user_name }}</h5>
|
||||
{% else %}
|
||||
<h5>Anonim</h5>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
<nav>
|
||||
<a href="{% url 'index' %}">На главную</a>
|
||||
<a href="{% url 'account' %}">Аккаунт</a>
|
||||
<a href="{% url 'dev_index' %}">Dev</a>
|
||||
<a href="{% url 'about' %}">О нас</a>
|
||||
{# <button id="theme-switcher">Переключить тему</button>#}
|
||||
</nav>
|
||||
<main id="content">
|
||||
{% block content %} тут должен быть контент {% endblock %}
|
||||
</main>
|
||||
|
||||
{# <footer> {% block footer %} {% endblock %} </footer>#}
|
||||
{# <script src="{% static 'js/main.js' %}"></script>#}
|
||||
</body>
|
||||
</html>
|
30
templates/cart.html
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Корзина {% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
{% load static %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/catalog-style.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1> Ваша корзина </h1>
|
||||
{% if user %}
|
||||
{% if cart_objects %}
|
||||
{% for ojb in cart_objects %}
|
||||
{# 'item_count', 'prod', 'prod__prod_name', 'prod__prod_price', 'prod__prod_available', 'prod__prod_photo', 'prod__category__cat_name' #}
|
||||
<a class="product" href="/catalog/{{ obj.1 }}/" style="text-decoration: none">
|
||||
<img src="/static/images/{% if obj.5 %}no-photo.webp{% else %}products/{{ obj.5 }}{% endif %}" alt="photo">
|
||||
<div>
|
||||
<div> {{ ojb.0 }}шт </div>
|
||||
<div><strong> {{ ojb.2 }} </strong>₽</div>
|
||||
<div> {{ ojb.3 }} доступно </div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<h3 style="text-align: center">Корзина пуста!</h3>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
нужно войти...
|
||||
{% endif %}
|
||||
{% endblock %}
|
45
templates/catalog.html
Normal file
@ -0,0 +1,45 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Каталог {% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
{% load static %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/catalog-style.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
Каталог
|
||||
{% if cat_name %}
|
||||
/ {{ cat_name }}
|
||||
{% endif %}
|
||||
</h1>
|
||||
<div class="catalog-container">
|
||||
<div class="catalog-categories">
|
||||
<h4 style="text-align: center">Категории</h4>
|
||||
<ul>
|
||||
<li><a href="{% url 'catalog' %}">Все категории</a></li>
|
||||
{% for c in categories %}
|
||||
<li><a href="{% url 'catalog' %}?cat={{ c.id }}">{{ c.cat_name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% if products %}
|
||||
<div class="catalog-products">
|
||||
{% for p in products %}
|
||||
<a class="product" href="{% url 'product_view' p.id %}" style="text-decoration: none">
|
||||
<img src="{{ p.get_photo_url }}" alt="photo">
|
||||
<div>
|
||||
<div> {{ p.prod_name }} </div>
|
||||
<div><strong> {{ p.prod_price }} </strong>₽</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="display: flex; flex-wrap: wrap; align-content: center; flex-grow: 1;">
|
||||
<h3 style="text-align: center; width: 100%">Упс, тут нет доступных товаров...</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
59
templates/dev.html
Normal file
@ -0,0 +1,59 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Арка | DevLog {% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
<style>
|
||||
.event-type {
|
||||
background: #c447a1;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.event-date {
|
||||
background: var(--bkg-color2);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.event-wrapper {
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
border-bottom: 2px solid var(--text-color);
|
||||
}
|
||||
|
||||
.event-wrapper:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
details div {
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 1px solid var(--text-color);
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1> DevLog </h1>
|
||||
|
||||
{% if events %}
|
||||
{% for e in events %}
|
||||
<div class="event-wrapper">
|
||||
<span class="event-type">{{ e.event_type }}</span>
|
||||
<span class="event-date">{{ e.event_time }}</span>
|
||||
<h2>{{ e.name }}</h2>
|
||||
<details>
|
||||
<summary>Описание</summary>
|
||||
<div>
|
||||
{{ e.description | safe }}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<h2>Не передан объект <i>events</i> в шаблон</h2>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
21
templates/index.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Арка | Главная {% endblock %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<h1> Главная страница </h1>
|
||||
|
||||
Правила<br>
|
||||
|
||||
1) не скамить<br>
|
||||
2) скамим только мы<br>
|
||||
3) {криво,косо,жопо}руких не принимаем<br>
|
||||
|
||||
<div style="margin-top: 50px">
|
||||
<h3>Ну а пока тут нет нужного контента можно послушать музычку</h3>
|
||||
<audio controls preload="none">
|
||||
<source src="{% static 'm.mp3' %}" type="audio/mp3">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
26
templates/product-view.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Каталог {% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
{% load static %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/product-view-style.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1> {{ product.prod_name }} </h1>
|
||||
{% if product %}
|
||||
<div class="product-container">
|
||||
<div id="product-photo-container">
|
||||
<img id="product-photo" src="{{ product.get_photo_url }}" alt="photo">
|
||||
</div>
|
||||
<div>
|
||||
<h3>Цена: <span id="price-banner">{{ product.prod_price }}</span></h3>
|
||||
<p id="product-description">{{ product.prod_description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="display: flex; flex-wrap: wrap; align-content: center; flex-grow: 1;">
|
||||
<h3 style="text-align: center; width: 100%">Упс, товар не найден...</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
16
templates/registration/login.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %} Аккаунт | вход {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1> Ваш аккаунт </h1>
|
||||
<h3>Вход</h3>
|
||||
<form action="{% url 'login' %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
<tbody>
|
||||
{{ form.as_table }}
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit">Войти</button>
|
||||
</form>
|
||||
{% endblock %}
|