Add initial Django project structure with cleaning app

- Created .gitignore to exclude Python-generated files and virtual environments.
- Added .python-version to specify Python version 3.13.
- Implemented models for Client, Brigade, Service, Order, and CompletedWork.
- Created Django admin configurations for managing models.
- Added management command to seed the database with test data.
- Created initial migrations for the models.
- Developed views and templates for listing and detailing orders, clients, and brigades.
- Set up URL routing for the cleaning app.
- Configured Django settings and WSGI/ASGI entry points.
- Added basic test structure in tests.py.
- Included project metadata in pyproject.toml and uv.lock.
This commit is contained in:
Dmitry
2026-05-16 16:09:37 +03:00
commit 97591a71ea
30 changed files with 867 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
cache/
+1
View File
@@ -0,0 +1 @@
3.13
View File
+36
View File
@@ -0,0 +1,36 @@
from django.contrib import admin
from .models import Client, Brigade, Service, Order, CompletedWork
class CompletedWorkInline(admin.TabularInline):
model = CompletedWork
extra = 1
@admin.register(Client)
class ClientAdmin(admin.ModelAdmin):
list_display = ['full_name', 'phone', 'address', 'preferred_time']
search_fields = ['full_name', 'phone', 'address']
list_filter = ['preferred_time']
@admin.register(Brigade)
class BrigadeAdmin(admin.ModelAdmin):
list_display = ['name', 'supervisor', 'employee_count', 'specialization']
search_fields = ['name', 'supervisor', 'specialization']
@admin.register(Service)
class ServiceAdmin(admin.ModelAdmin):
list_display = ['name', 'price_per_sqm', 'duration_per_sqm']
search_fields = ['name']
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ['id', 'client', 'brigade', 'date', 'start_time', 'end_time']
search_fields = ['client__full_name', 'brigade__name']
list_filter = ['date', 'brigade']
inlines = [CompletedWorkInline]
@admin.register(CompletedWork)
class CompletedWorkAdmin(admin.ModelAdmin):
list_display = ['order', 'service', 'area']
search_fields = ['order__client__full_name', 'service__name']
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class CleaningConfig(AppConfig):
name = 'cleaning'
View File
+95
View File
@@ -0,0 +1,95 @@
import random
from datetime import date, timedelta, time
from django.core.management.base import BaseCommand
from faker import Faker
from cleaning.models import Client, Brigade, Service, Order, CompletedWork
fake = Faker('ru_RU')
class Command(BaseCommand):
help = 'Заполнить базу тестовыми данными'
def handle(self, *args, **options):
CompletedWork.objects.all().delete()
Order.objects.all().delete()
Service.objects.all().delete()
Brigade.objects.all().delete()
Client.objects.all().delete()
time_choices = ['morning', 'day', 'evening', 'any']
clients = []
for _ in range(12):
client = Client.objects.create(
full_name=fake.name(),
address=fake.address().replace('\n', ', '),
phone=fake.phone_number(),
preferred_time=random.choice(time_choices),
)
clients.append(client)
specializations = [
'Генеральная уборка',
'Уборка после ремонта',
'Мытьё окон',
'Химчистка мебели',
'Уборка офисов',
]
brigades = []
for i, spec in enumerate(specializations):
brigade = Brigade.objects.create(
name=f'Бригада «{fake.last_name()}»',
supervisor=fake.name(),
employee_count=random.randint(2, 8),
specialization=spec,
)
brigades.append(brigade)
services_data = [
('Мытьё полов', 25.00, 0.5),
('Мытьё окон', 80.00, 1.2),
('Уборка ванной комнаты', 120.00, 2.0),
('Пылесосинг ковров', 30.00, 0.8),
('Мытьё сантехники', 90.00, 1.5),
('Протирка мебели', 20.00, 0.3),
('Чистка кухонной плиты', 150.00, 3.0),
('Вынос мусора', 10.00, 0.1),
('Мытьё зеркал', 40.00, 0.4),
]
services = []
for name, price, duration in services_data:
service = Service.objects.create(
name=name,
price_per_sqm=price,
duration_per_sqm=duration,
)
services.append(service)
today = date.today()
for i in range(25):
order_date = today + timedelta(days=random.randint(-30, 15))
start_hour = random.randint(8, 16)
duration_hours = random.randint(2, 5)
order = Order.objects.create(
client=random.choice(clients),
brigade=random.choice(brigades),
date=order_date,
start_time=time(start_hour, 0),
end_time=time(start_hour + duration_hours, 0),
)
chosen_services = random.sample(services, k=random.randint(1, 4))
for service in chosen_services:
CompletedWork.objects.create(
order=order,
service=service,
area=round(random.uniform(10, 80), 1),
)
self.stdout.write(self.style.SUCCESS(
f'Готово: {Client.objects.count()} клиентов, '
f'{Brigade.objects.count()} бригад, '
f'{Service.objects.count()} услуг, '
f'{Order.objects.count()} заказов.'
))
@@ -0,0 +1,47 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='Client',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=200, verbose_name='ФИО')),
('address', models.CharField(max_length=300, verbose_name='Адрес')),
('phone', models.CharField(max_length=20, verbose_name='Телефон')),
('preferred_time', models.CharField(
choices=[('morning', 'Утро'), ('day', 'День'), ('evening', 'Вечер'), ('any', 'Не важно')],
default='any',
max_length=10,
verbose_name='Предпочтительное время',
)),
],
options={
'verbose_name': 'Клиент',
'verbose_name_plural': 'Клиенты',
'ordering': ['full_name'],
},
),
migrations.CreateModel(
name='Brigade',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='Название')),
('supervisor', models.CharField(max_length=200, verbose_name='Руководитель')),
('employee_count', models.PositiveIntegerField(verbose_name='Количество сотрудников')),
('specialization', models.CharField(max_length=200, verbose_name='Специализация')),
],
options={
'verbose_name': 'Бригада',
'verbose_name_plural': 'Бригады',
'ordering': ['name'],
},
),
]
+25
View File
@@ -0,0 +1,25 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cleaning', '0001_clients_brigades'),
]
operations = [
migrations.CreateModel(
name='Service',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200, verbose_name='Наименование')),
('price_per_sqm', models.DecimalField(decimal_places=2, max_digits=8, verbose_name='Цена за м2')),
('duration_per_sqm', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='Продолжительность (мин/м2)')),
],
options={
'verbose_name': 'Услуга',
'verbose_name_plural': 'Услуги',
'ordering': ['name'],
},
),
]
+36
View File
@@ -0,0 +1,36 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cleaning', '0002_services'),
]
operations = [
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateField(verbose_name='Дата')),
('start_time', models.TimeField(verbose_name='Время начала')),
('end_time', models.TimeField(verbose_name='Время окончания')),
('client', models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='cleaning.client',
verbose_name='Клиент',
)),
('brigade', models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='cleaning.brigade',
verbose_name='Бригада',
)),
],
options={
'verbose_name': 'Заказ',
'verbose_name_plural': 'Заказы',
'ordering': ['date'],
},
),
]
@@ -0,0 +1,42 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cleaning', '0003_orders'),
]
operations = [
migrations.CreateModel(
name='CompletedWork',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('area', models.DecimalField(decimal_places=2, max_digits=8, verbose_name='Фактическая площадь (м2)')),
('order', models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='cleaning.order',
verbose_name='Заказ',
)),
('service', models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='cleaning.service',
verbose_name='Услуга',
)),
],
options={
'verbose_name': 'Выполненная работа',
'verbose_name_plural': 'Выполненные работы',
},
),
migrations.AddField(
model_name='order',
name='services',
field=models.ManyToManyField(
through='cleaning.CompletedWork',
to='cleaning.service',
verbose_name='Услуги',
),
),
]
View File
+96
View File
@@ -0,0 +1,96 @@
from django.db import models
class Client(models.Model):
TIME_CHOICES = [
('morning', 'Утро'),
('day', 'День'),
('evening', 'Вечер'),
('any', 'Не важно'),
]
full_name = models.CharField('ФИО', max_length=200)
address = models.CharField('Адрес', max_length=300)
phone = models.CharField('Телефон', max_length=20)
preferred_time = models.CharField(
'Предпочтительное время',
max_length=10,
choices=TIME_CHOICES,
default='any',
)
class Meta:
verbose_name = 'Клиент'
verbose_name_plural = 'Клиенты'
ordering = ['full_name']
def __str__(self):
return self.full_name
class Brigade(models.Model):
name = models.CharField('Название', max_length=100)
supervisor = models.CharField('Руководитель', max_length=200)
employee_count = models.PositiveIntegerField('Количество сотрудников')
specialization = models.CharField('Специализация', max_length=200)
class Meta:
verbose_name = 'Бригада'
verbose_name_plural = 'Бригады'
ordering = ['name']
def __str__(self):
return self.name
class Service(models.Model):
name = models.CharField('Наименование', max_length=200)
price_per_sqm = models.DecimalField('Цена за м2', max_digits=8, decimal_places=2)
duration_per_sqm = models.DecimalField('Продолжительность (мин/м2)', max_digits=6, decimal_places=2)
class Meta:
verbose_name = 'Услуга'
verbose_name_plural = 'Услуги'
ordering = ['name']
def __str__(self):
return self.name
class Order(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, verbose_name='Клиент', related_name='orders')
brigade = models.ForeignKey(Brigade, on_delete=models.CASCADE, verbose_name='Бригада', related_name='orders')
date = models.DateField('Дата')
start_time = models.TimeField('Время начала')
end_time = models.TimeField('Время окончания')
services = models.ManyToManyField(Service, through='CompletedWork', verbose_name='Услуги')
class Meta:
verbose_name = 'Заказ'
verbose_name_plural = 'Заказы'
ordering = ['date']
def __str__(self):
return f'Заказ №{self.pk}{self.client} ({self.date})'
def total_cost(self):
total = 0
for work in self.completedwork_set.select_related('service').all(): # type: ignore
total += work.area * work.service.price_per_sqm
return total
class CompletedWork(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, verbose_name='Заказ')
service = models.ForeignKey(Service, on_delete=models.CASCADE, verbose_name='Услуга')
area = models.DecimalField('Фактическая площадь (м2)', max_digits=8, decimal_places=2)
class Meta:
verbose_name = 'Выполненная работа'
verbose_name_plural = 'Выполненные работы'
def __str__(self):
return f'{self.service}{self.area} м2'
def cost(self):
return self.area * self.service.price_per_sqm
+23
View File
@@ -0,0 +1,23 @@
<!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>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'cleaning:index' %}">Клининг</a>
<div>
<a class="nav-link text-white d-inline" href="{% url 'cleaning:order_list' %}">Заказы</a>
</div>
</div>
</nav>
<div class="container mt-4"> {% comment %} mt-4 - mergin-top {% endcomment %}
{% block content %}{% endblock %}
</div>
</body>
</html>
@@ -0,0 +1,43 @@
{% extends 'cleaning/base.html' %}
{% block title %}О бригаде{% endblock %}
{% block content %}
{# mb-4 — отступ снизу, чтобы карточка не прилипала к таблицам #}
<div class="card mb-4">
<div class="card-header"><h4>{{ brigade.name }}</h4></div>
<div class="card-body">
<p><strong>Руководитель:</strong> {{ brigade.supervisor }}</p>
<p><strong>Сотрудников:</strong> {{ brigade.employee_count }}</p>
<p><strong>Специализация:</strong> {{ brigade.specialization }}</p>
</div>
</div>
<h5>Активные заказы</h5>
<table class="table table-hover">
<thead><tr><th>Заказ</th><th>Клиент</th><th>Дата</th></tr></thead>
<tbody>
{% for order in active %}
<tr>
<td><a href="{% url 'cleaning:order_detail' order.pk %}">Заказ №{{ order.pk }}</a></td>
<td>{{ order.client }}</td>
<td>{{ order.date }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h5 class="mt-4">Выполненные заказы</h5>
<table class="table table-hover">
<thead><tr><th>Заказ</th><th>Клиент</th><th>Дата</th></tr></thead>
<tbody>
{% for order in completed %}
<tr>
<td><a href="{% url 'cleaning:order_detail' order.pk %}">Заказ №{{ order.pk }}</a></td>
<td>{{ order.client }}</td>
<td>{{ order.date }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
@@ -0,0 +1,30 @@
{% extends 'cleaning/base.html' %}
{% block title %}О клиенте{% endblock %}
{% block content %}
{# card — карточка с основной информацией о клиенте #}
<div class="card mb-4">
<div class="card-header"><h4>{{ client.full_name }}</h4></div>
<div class="card-body">
<p><strong>Адрес:</strong> {{ client.address }}</p>
<p><strong>Телефон:</strong> {{ client.phone }}</p>
{# get_preferred_time_display — возвращает читаемое значение choices ('morning' → 'Утро') #}
<p><strong>Предпочтительное время:</strong> {{ client.get_preferred_time_display }}</p>
</div>
</div>
<h5>Заказы клиента</h5>
<table class="table table-hover">
<thead><tr><th>Заказ</th><th>Бригада</th><th>Дата</th></tr></thead>
<tbody>
{% for order in client.order_set.all %}
<tr>
<td><a href="{% url 'cleaning:order_detail' order.pk %}">Заказ №{{ order.pk }}</a></td>
<td>{{ order.brigade }}</td>
<td>{{ order.date }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
@@ -0,0 +1,36 @@
{% extends 'cleaning/base.html' %}
{% block title %}Детали заказа{% endblock %}
{% block content %}
{# card — Bootstrap-компонент для группировки информации #}
<div class="card">
<div class="card-header"><h4>Заказ №{{ order.pk }}</h4></div>
<div class="card-body">
<p><strong>Клиент:</strong> <a href="{% url 'cleaning:client_detail' order.client.pk %}">{{ order.client }}</a></p>
<p><strong>Бригада:</strong> <a href="{% url 'cleaning:brigade_detail' order.brigade.pk %}">{{ order.brigade }}</a></p>
<p><strong>Дата:</strong> {{ order.date }}</p>
<p><strong>Время:</strong> {{ order.start_time }} — {{ order.end_time }}</p>
</div>
</div>
<h5 class="mt-4">Выполненные работы</h5> {# mt-4 — отступ сверху #}
<table class="table table-striped">
<thead>
<tr><th>Услуга</th><th>Площадь, м²</th><th>Стоимость, руб.</th></tr>
</thead>
<tbody>
{% for work in order.completedwork_set.all %}
<tr>
<td>{{ work.service.name }}</td>
<td>{{ work.area }}</td>
<td>{{ work.cost }}</td>
</tr>
{% endfor %}
</tbody>
{# tfoot с table-group-divider — отделяет итоговую строку чертой #}
<tfoot class="table-group-divider">
<tr><td colspan="2"><strong>Итого</strong></td><td><strong>{{ order.total_cost }} руб.</strong></td></tr>
</tfoot>
</table>
{% endblock %}
@@ -0,0 +1,31 @@
{% extends 'cleaning/base.html' %}
{% block title %}Заказы{% endblock %}
{% block content %}
<h1>Список заказов</h1>
{# table-striped — чередование цвета строк, table-hover — подсветка при наведении #}
<table class="table table-striped table-hover">
<thead>
<tr>
<th></th>
<th>Клиент</th>
<th>Бригада</th>
<th>Детали</th>
<th>Дата</th>
</tr>
</thead>
<tbody>
{% for order in orders %}
<tr>
<td>{{ forloop.counter }}</td>
{# ссылки ведут на детали клиента, бригады и заказа #}
<td><a href="{% url 'cleaning:client_detail' order.client.pk %}">{{ order.client }}</a></td>
<td><a href="{% url 'cleaning:brigade_detail' order.brigade.pk %}">{{ order.brigade }}</a></td>
<td><a href="{% url 'cleaning:order_detail' order.pk %}">Заказ №{{ order.pk }}</a></td>
<td>{{ order.date }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+13
View File
@@ -0,0 +1,13 @@
from django.urls import path
from . import views
app_name = 'cleaning'
urlpatterns = [
path('', views.index, name='index'),
path('orders/', views.order_list, name='order_list'),
path('order/<int:order_id>/', views.order_detail, name='order_detail'),
path('brigades/<int:pk>/', views.brigade_detail, name='brigade_detail'),
path('clients/<int:pk>/', views.client_detail, name='client_detail'),
]
+34
View File
@@ -0,0 +1,34 @@
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from django.utils import timezone
from .models import Brigade, Order, Client
def index(request):
return redirect('cleaning:order_list')
def order_list(request):
orders = Order.objects.order_by('date')
return render(request, 'cleaning/order_list.html', {'orders': orders})
def order_detail(request, order_id):
order = get_object_or_404(Order.objects.prefetch_related('completedwork_set__service'), pk=order_id)
return render(request, 'cleaning/order_detail.html', {'order': order})
# def brigade_detail(request, pk):
# brigade = get_object_or_404(Brigade, pk=pk)
# return render(request, 'cleaning/brigade_detail.html', {'brigade': brigade})
def brigade_detail(request, pk):
brigade = get_object_or_404(Brigade, pk=pk)
today = timezone.now().date()
active = brigade.orders.filter(date__gte=today).order_by('date') # type: ignore
completed = brigade.orders.filter(date__lt=today).order_by('-date') # type: ignore
return render(request, 'cleaning/brigade_detail.html', {
'brigade': brigade,
'active': active,
'completed': completed,
})
def client_detail(request, pk):
client = get_object_or_404(Client, pk=pk)
orders = client.orders.order_by('date') # type: ignore
return render(request, 'cleaning/client_detail.html', {'client': client})
View File
+16
View File
@@ -0,0 +1,16 @@
"""
ASGI config for config 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/6.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_asgi_application()
+118
View File
@@ -0,0 +1,118 @@
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 6.0.5.
For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""
from pathlib import Path
# 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/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-^*a-kotmr&dhhk))s6vyb2omn24l)llm)e0&0+invb7d@r3b3^'
# 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',
'cleaning',
]
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 = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/6.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/6.0/topics/i18n/
LANGUAGE_CODE = 'ru-ru'
TIME_ZONE = 'Europe/Moscow'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
STATIC_URL = 'static/'
+7
View File
@@ -0,0 +1,7 @@
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('cleaning.urls')),
]
+16
View File
@@ -0,0 +1,16 @@
"""
WSGI config for config 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/6.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_wsgi_application()
Executable
+22
View 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', 'config.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()
+10
View File
@@ -0,0 +1,10 @@
[project]
name = "project-web"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"django>=6.0.5",
"faker>=37.1.0",
]
Generated
+71
View File
@@ -0,0 +1,71 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "asgiref"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" },
]
[[package]]
name = "django"
version = "6.0.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5e/f1/bf85f0d29ef76abf901f193fe8fef4769d3da7794197832bc30151c071d8/django-6.0.5.tar.gz", hash = "sha256:bc6d6872e98a2864c836e42edd644b362db311147dd5aa8d5b82ba7a032f5269", size = 10924131, upload-time = "2026-05-05T13:54:39.329Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/5b/1328f8b84fce040c404f76822bf8c57d254e368e8cbd8bd67ec2b26d75f5/django-6.0.5-py3-none-any.whl", hash = "sha256:9d58a7cb49244e74c8e161d5e403a46d6209f1009ba40f5a66d6aa0d0786a8f0", size = 8368680, upload-time = "2026-05-05T13:54:33.532Z" },
]
[[package]]
name = "faker"
version = "40.15.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7f/13/6741787bd91c4109c7bed047d68273965cd52ce8a5f773c471b949334b6d/faker-40.15.0.tar.gz", hash = "sha256:20f3a6ec8c266b74d4c554e34118b21c3c2056c0b4a519d15c8decb3a4e6e795", size = 1967447, upload-time = "2026-04-17T20:05:27.555Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/a7/a600f8f30d4505e89166de51dd121bd540ab8e560e8cf0901de00a81de8c/faker-40.15.0-py3-none-any.whl", hash = "sha256:71ab3c3370da9d2205ab74ffb0fd51273063ad562b3a3bb69d0026a20923e318", size = 2004447, upload-time = "2026-04-17T20:05:25.437Z" },
]
[[package]]
name = "project-web"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "django" },
{ name = "faker" },
]
[package.metadata]
requires-dist = [
{ name = "django", specifier = ">=6.0.5" },
{ name = "faker", specifier = ">=37.1.0" },
]
[[package]]
name = "sqlparse"
version = "0.5.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" },
]
[[package]]
name = "tzdata"
version = "2026.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" },
]