init commit
This commit is contained in:
0
smartsoltech/web/__init__.py
Normal file
0
smartsoltech/web/__init__.py
Normal file
41
smartsoltech/web/admin.py
Normal file
41
smartsoltech/web/admin.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from django.contrib import admin
|
||||
from .models import Service, Project, Client, Order, Review, BlogPost, Category
|
||||
|
||||
@admin.register(Service)
|
||||
class ServiceAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'category', 'price')
|
||||
search_fields = ('name', 'category')
|
||||
|
||||
@admin.register(Project)
|
||||
class ProjectAdmin(admin.ModelAdmin):
|
||||
list_display = ('name','category', 'client')
|
||||
list_filter = ('category',)
|
||||
search_fields = ('name', 'client__first_name', 'client__last_name')
|
||||
|
||||
@admin.register(Client)
|
||||
class ClientAdmin(admin.ModelAdmin):
|
||||
list_display = ('first_name', 'last_name', 'email', 'phone_number')
|
||||
search_fields = ('first_name', 'last_name', 'email')
|
||||
|
||||
@admin.register(Order)
|
||||
class OrderAdmin(admin.ModelAdmin):
|
||||
list_display = ('client', 'order_date', 'client_email', 'client_phone', 'service', 'order_date', 'status')
|
||||
list_filter = ('status','client', 'order_date')
|
||||
search_fields = ('client__first_name', 'service__name','status','client', 'order_date')
|
||||
|
||||
@admin.register(Review)
|
||||
class ReviewAdmin(admin.ModelAdmin):
|
||||
list_display = ('client', 'service', 'rating', 'review_date')
|
||||
list_filter = ('rating',)
|
||||
search_fields = ('client__first_name', 'service__name')
|
||||
|
||||
@admin.register(BlogPost)
|
||||
class BlogPostAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'published_date')
|
||||
search_fields = ('title',)
|
||||
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name','description')
|
||||
search_fields = ('name',)
|
||||
|
||||
6
smartsoltech/web/apps.py
Normal file
6
smartsoltech/web/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WebConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'web'
|
||||
88
smartsoltech/web/migrations/0001_initial.py
Normal file
88
smartsoltech/web/migrations/0001_initial.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-06 07:28
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlogPost',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=200)),
|
||||
('content', models.TextField()),
|
||||
('published_date', models.DateTimeField(auto_now_add=True)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='static/img/blog/')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Category',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Client',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('first_name', models.CharField(max_length=100)),
|
||||
('last_name', models.CharField(max_length=100)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('phone_number', models.CharField(max_length=15)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='static/img/customer/')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Project',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('description', models.TextField()),
|
||||
('completion_date', models.DateField()),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='static/img/project/')),
|
||||
('category', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='web.category')),
|
||||
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='web.client')),
|
||||
],
|
||||
),
|
||||
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)),
|
||||
('description', models.TextField()),
|
||||
('price', models.DecimalField(decimal_places=2, max_digits=10)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='static/img/services/')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='services', to='web.category')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Review',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('rating', models.IntegerField()),
|
||||
('comment', models.TextField()),
|
||||
('review_date', models.DateTimeField(auto_now_add=True)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='static/img/review/')),
|
||||
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='web.client')),
|
||||
('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='web.service')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Order',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('order_date', models.DateTimeField(auto_now_add=True)),
|
||||
('status', models.CharField(choices=[('pending', 'Pending'), ('completed', 'Completed'), ('cancelled', 'Cancelled')], max_length=50)),
|
||||
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='web.client')),
|
||||
('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='web.service')),
|
||||
],
|
||||
),
|
||||
]
|
||||
19
smartsoltech/web/migrations/0002_category_description.py
Normal file
19
smartsoltech/web/migrations/0002_category_description.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-06 07:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('web', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='category',
|
||||
name='description',
|
||||
field=models.TextField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-06 09:01
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('web', '0002_category_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='review',
|
||||
name='project',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='web.project'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='web.category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='review',
|
||||
name='service',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='web.service'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-06 09:08
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('web', '0003_review_project_alter_project_category_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='category',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='web.category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='service',
|
||||
name='category',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='services', to='web.category'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-06 10:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('web', '0004_alter_project_category_alter_service_category'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='client_email',
|
||||
field=models.EmailField(default='notprovided@example.com', max_length=254),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='client_phone',
|
||||
field=models.CharField(default='unknown', max_length=15),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='message',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='order',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('pending', 'Pending'), ('completed', 'Completed'), ('cancelled', 'Cancelled')], default='pending', max_length=50),
|
||||
),
|
||||
]
|
||||
0
smartsoltech/web/migrations/__init__.py
Normal file
0
smartsoltech/web/migrations/__init__.py
Normal file
87
smartsoltech/web/models.py
Normal file
87
smartsoltech/web/models.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# web/models.py
|
||||
from django.db import models
|
||||
|
||||
class Category(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
description = models.TextField()
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Service(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
description = models.TextField()
|
||||
price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='services')
|
||||
image = models.ImageField(upload_to='static/img/services/', blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def average_rating(self):
|
||||
reviews = self.reviews.all()
|
||||
if reviews:
|
||||
return sum(review.rating for review in reviews) / reviews.count()
|
||||
return 0
|
||||
|
||||
def review_count(self):
|
||||
return self.reviews.count()
|
||||
class Project(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
description = models.TextField()
|
||||
completion_date = models.DateField()
|
||||
client = models.ForeignKey('Client', on_delete=models.CASCADE, related_name='projects')
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='projects')
|
||||
image = models.ImageField(upload_to='static/img/project/', blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Review(models.Model):
|
||||
client = models.ForeignKey('Client', on_delete=models.CASCADE, related_name='reviews')
|
||||
service = models.ForeignKey('Service', on_delete=models.CASCADE, related_name='reviews', null=True, blank=True)
|
||||
project = models.ForeignKey('Project', on_delete=models.CASCADE, related_name='reviews', null=True, blank=True)
|
||||
rating = models.IntegerField()
|
||||
comment = models.TextField()
|
||||
review_date = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ImageField(upload_to='static/img/review/', blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.service:
|
||||
return f"Review by {self.client} for service: {self.service}"
|
||||
elif self.project:
|
||||
return f"Review by {self.client} for project: {self.project}"
|
||||
else:
|
||||
return f"Review by {self.client}"
|
||||
|
||||
class Client(models.Model):
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=100)
|
||||
email = models.EmailField()
|
||||
phone_number = models.CharField(max_length=15)
|
||||
image = models.ImageField(upload_to='static/img/customer/', blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
class Order(models.Model):
|
||||
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='orders')
|
||||
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='orders')
|
||||
client_email = models.EmailField(default='notprovided@example.com')
|
||||
client_phone = models.CharField(max_length=15, default='unknown')
|
||||
message = models.TextField(blank=True, null=True)
|
||||
order_date = models.DateTimeField(auto_now_add=True)
|
||||
status = models.CharField(max_length=50, choices=[('pending', 'Pending'), ('completed', 'Completed'), ('cancelled', 'Cancelled')], default='pending')
|
||||
|
||||
def __str__(self):
|
||||
return f"Order #{self.id} by {self.client.first_name} {self.client.last_name}"
|
||||
|
||||
|
||||
|
||||
class BlogPost(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
content = models.TextField()
|
||||
published_date = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ImageField(upload_to='static/img/blog/', blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
0
smartsoltech/web/templates/.gitignore
vendored
Normal file
0
smartsoltech/web/templates/.gitignore
vendored
Normal file
53
smartsoltech/web/templates/web/about.html
Normal file
53
smartsoltech/web/templates/web/about.html
Normal file
@@ -0,0 +1,53 @@
|
||||
{% extends 'web/base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<section class="position-relative py-4 py-xl-5">
|
||||
<div class="container position-relative">
|
||||
<div class="row mb-5">
|
||||
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||
<h2>Contact us</h2>
|
||||
<p class="w-lg-50">Curae hendrerit donec commodo hendrerit egestas tempus, turpis facilisis nostra nunc. Vestibulum dui eget ultrices.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex justify-content-center">
|
||||
<div class="col-md-6 col-lg-4 col-xl-4">
|
||||
<div class="d-flex flex-column justify-content-center align-items-start h-100">
|
||||
<div class="d-flex align-items-center p-3">
|
||||
<div class="bs-icon-md bs-icon-rounded bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon"><svg class="bi bi-telephone" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3.654 1.328a.678.678 0 0 0-1.015-.063L1.605 2.3c-.483.484-.661 1.169-.45 1.77a17.568 17.568 0 0 0 4.168 6.608 17.569 17.569 0 0 0 6.608 4.168c.601.211 1.286.033 1.77-.45l1.034-1.034a.678.678 0 0 0-.063-1.015l-2.307-1.794a.678.678 0 0 0-.58-.122l-2.19.547a1.745 1.745 0 0 1-1.657-.459L5.482 8.062a1.745 1.745 0 0 1-.46-1.657l.548-2.19a.678.678 0 0 0-.122-.58L3.654 1.328zM1.884.511a1.745 1.745 0 0 1 2.612.163L6.29 2.98c.329.423.445.974.315 1.494l-.547 2.19a.678.678 0 0 0 .178.643l2.457 2.457a.678.678 0 0 0 .644.178l2.189-.547a1.745 1.745 0 0 1 1.494.315l2.306 1.794c.829.645.905 1.87.163 2.611l-1.034 1.034c-.74.74-1.846 1.065-2.877.702a18.634 18.634 0 0 1-7.01-4.42 18.634 18.634 0 0 1-4.42-7.009c-.362-1.03-.037-2.137.703-2.877L1.885.511z"></path>
|
||||
</svg></div>
|
||||
<div class="px-2">
|
||||
<h6 class="mb-0">Телефон</h6>
|
||||
<p class="mb-0"><a href ="tel:01056936103">010-5693-6103</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center p-3">
|
||||
<div class="bs-icon-md bs-icon-rounded bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon"><svg class="bi bi-envelope" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"></path>
|
||||
</svg></div>
|
||||
<div class="px-2">
|
||||
<h6 class="mb-0">Email</h6>
|
||||
<p class="mb-0"><a href="mailto:a.choi@smartsoltech.kr">a.choI@smartsoltech.kr</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center p-3">
|
||||
<div class="bs-icon-md bs-icon-rounded bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon"><svg class="bi bi-pin" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M4.146.146A.5.5 0 0 1 4.5 0h7a.5.5 0 0 1 .5.5c0 .68-.342 1.174-.646 1.479-.126.125-.25.224-.354.298v4.431l.078.048c.203.127.476.314.751.555C12.36 7.775 13 8.527 13 9.5a.5.5 0 0 1-.5.5h-4v4.5c0 .276-.224 1.5-.5 1.5s-.5-1.224-.5-1.5V10h-4a.5.5 0 0 1-.5-.5c0-.973.64-1.725 1.17-2.189A5.921 5.921 0 0 1 5 6.708V2.277a2.77 2.77 0 0 1-.354-.298C4.342 1.674 4 1.179 4 .5a.5.5 0 0 1 .146-.354zm1.58 1.408-.002-.001.002.001m-.002-.001.002.001A.5.5 0 0 1 6 2v5a.5.5 0 0 1-.276.447h-.002l-.012.007-.054.03a4.922 4.922 0 0 0-.827.58c-.318.278-.585.596-.725.936h7.792c-.14-.34-.407-.658-.725-.936a4.915 4.915 0 0 0-.881-.61l-.012-.006h-.002A.5.5 0 0 1 10 7V2a.5.5 0 0 1 .295-.458 1.775 1.775 0 0 0 .351-.271c.08-.08.155-.17.214-.271H5.14c.06.1.133.191.214.271a1.78 1.78 0 0 0 .37.282"></path>
|
||||
</svg></div>
|
||||
<div class="px-2">
|
||||
<h6 class="mb-0">Мы находимся:</h6>
|
||||
<p class="mb-0">Чолланамдо, Кванджу</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-5 col-xl-4">
|
||||
<div></div>
|
||||
<h1>О нас</h1>
|
||||
<p>Мы - команда профессионалов в своей отрасли. В нашей команде есть все, программисты, сетевые инженеры, системные администраторы, </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
27
smartsoltech/web/templates/web/base.html
Normal file
27
smartsoltech/web/templates/web/base.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% load static %}
|
||||
<!-- web/templates/web/base.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="manifest" href="/static/manifest.json">
|
||||
<script src="{% static 'assets/js/modal-init.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'assets/css/modal-styles.css' %}">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="{% static 'assets/js/modal-init.js' %}"></script>
|
||||
<title>{% block title %}Smartsoltech{% endblock %}</title>
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'assets/css/styles.min.css' %}">
|
||||
</head>
|
||||
<body>
|
||||
{% include 'web/navbar.html' %}
|
||||
<div class="container mt-4">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% include 'web/footer.html' %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
49
smartsoltech/web/templates/web/footer.html
Normal file
49
smartsoltech/web/templates/web/footer.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!-- web/templates/web/footer.html -->
|
||||
{% load static %}
|
||||
<footer class="text-light bg-dark pt-5 pb-4">
|
||||
<div class="container text-md-left">
|
||||
<div class="row text-md-left">
|
||||
<div class="col-md-3 col-lg-3 col-xl-3 mx-auto mt-3">
|
||||
<h5 class="text-uppercase text-warning mb-4 font-weight-bold">Company Name</h5>
|
||||
<p>Here you can use rows and columns to organize your footer content. Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
|
||||
</div>
|
||||
<div class="col-md-2 col-lg-2 col-xl-2 mx-auto mt-3">
|
||||
<h5 class="text-uppercase text-warning mb-4 font-weight-bold">Products</h5>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Product 1</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Product 2</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Product 3</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Product 4</a></p>
|
||||
</div>
|
||||
<div class="col-md-3 col-lg-2 col-xl-2 mx-auto mt-3">
|
||||
<h5 class="text-uppercase text-warning mb-4 font-weight-bold">Useful Links</h5>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Your Account</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Become an Affiliate</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Shipping Rates</a></p>
|
||||
<p><a class="text-light" href="#" style="text-decoration: none;">Help</a></p>
|
||||
</div>
|
||||
<div class="col-md-4 col-lg-3 col-xl-3 mx-auto mt-3">
|
||||
<h5 class="text-uppercase text-warning mb-4 font-weight-bold">Contact</h5>
|
||||
<p><i class="fas fa-home mr-3"></i> 123 Street, City, State</p>
|
||||
<p><i class="fas fa-envelope mr-3"></i> info@example.com</p>
|
||||
<p><i class="fas fa-phone mr-3"></i> + 01 234 567 88</p>
|
||||
<p><i class="fas fa-print mr-3"></i> + 01 234 567 89</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="mb-4" />
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-7 col-lg-8">
|
||||
<p class="text-md-left">© 2024 Company Name. All rights reserved.</p>
|
||||
</div>
|
||||
<div class="col-md-5 col-lg-4">
|
||||
<div class="text-md-right">
|
||||
<ul class="list-unstyled list-inline">
|
||||
<li class="list-inline-item"><a class="btn-floating btn-sm text-light" href="#" style="font-size: 23px;"><i class="fab fa-facebook"></i></a></li>
|
||||
<li class="list-inline-item"><a class="btn-floating btn-sm text-light" href="#" style="font-size: 23px;"><i class="fab fa-twitter"></i></a></li>
|
||||
<li class="list-inline-item"><a class="btn-floating btn-sm text-light" href="#" style="font-size: 23px;"><i class="fab fa-google-plus"></i></a></li>
|
||||
<li class="list-inline-item"><a class="btn-floating btn-sm text-light" href="#" style="font-size: 23px;"><i class="fab fa-linkedin-in"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
23
smartsoltech/web/templates/web/header.html
Normal file
23
smartsoltech/web/templates/web/header.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- web/templates/web/header.html -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="{% url 'home' %}">Smartsoltech</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'home' %}">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Услуги</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Проекты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Контакты</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
26
smartsoltech/web/templates/web/home.html
Normal file
26
smartsoltech/web/templates/web/home.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!-- web/templates/web/home.html -->
|
||||
{% extends 'web/base.html' %}
|
||||
|
||||
{% block title %}Главная{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Добро пожаловать в Smartsoltech</h1>
|
||||
<p>Предоставляем современные решения для бизнеса, включая разработку ПО, установку видеонаблюдения и многое другое.</p>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h2>Наши Услуги</h2>
|
||||
<p>Посмотрите наши предложения и выберите то, что вам нужно.</p>
|
||||
<a class="btn btn-primary" href="services">Подробнее</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h2>Наши Проекты</h2>
|
||||
<p>Посмотрите на наши успешные проекты.</p>
|
||||
<a class="btn btn-primary" href="#">Подробнее</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h2>Блог</h2>
|
||||
<p>Последние новости и обновления в нашем блоге.</p>
|
||||
<a class="btn btn-primary" href="#">Читать</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
15
smartsoltech/web/templates/web/navbar.html
Normal file
15
smartsoltech/web/templates/web/navbar.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{% load static %}
|
||||
<nav class="navbar navbar-expand-md bg-dark py-3" data-bs-theme="dark">
|
||||
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex justify-content-center align-items-center me-2 bs-icon"><svg class="bi bi-bezier" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M0 10.5A1.5 1.5 0 0 1 1.5 9h1A1.5 1.5 0 0 1 4 10.5v1A1.5 1.5 0 0 1 2.5 13h-1A1.5 1.5 0 0 1 0 11.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm10.5.5A1.5 1.5 0 0 1 13.5 9h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM6 4.5A1.5 1.5 0 0 1 7.5 3h1A1.5 1.5 0 0 1 10 4.5v1A1.5 1.5 0 0 1 8.5 7h-1A1.5 1.5 0 0 1 6 5.5zM7.5 4a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5z"></path>
|
||||
<path d="M6 4.5H1.866a1 1 0 1 0 0 1h2.668A6.517 6.517 0 0 0 1.814 9H2.5c.123 0 .244.015.358.043a5.517 5.517 0 0 1 3.185-3.185A1.503 1.503 0 0 1 6 5.5zm3.957 1.358A1.5 1.5 0 0 0 10 5.5v-1h4.134a1 1 0 1 1 0 1h-2.668a6.517 6.517 0 0 1 2.72 3.5H13.5c-.123 0-.243.015-.358.043a5.517 5.517 0 0 0-3.185-3.185z"></path>
|
||||
</svg></span><span>SmartSolTech</span></a><button class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||
<div id="navcol-5" class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item"><a class="nav-link active" href="/services/">Услуги</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#">Наши проекты</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="about">О нас</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
81
smartsoltech/web/templates/web/order.html
Normal file
81
smartsoltech/web/templates/web/order.html
Normal file
@@ -0,0 +1,81 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4 py-xl-5">
|
||||
<div class="row mb-5">
|
||||
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||
<h2>Отзывы</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-2 row-cols-lg-3">
|
||||
{% for review in reviews %}
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p class="bg-body-tertiary border rounded border-0 p-4">{{ review.comment }}</p>
|
||||
<div class="d-flex">
|
||||
{% if review.client.image %}
|
||||
<img class="rounded-circle flex-shrink-0 me-3 fit-cover" width="50" height="50" src="{{ review.client.image.url }}" />
|
||||
{% else %}
|
||||
<img class="rounded-circle flex-shrink-0 me-3 fit-cover" width="50" height="50" src="https://cdn.bootstrapstudio.io/placeholders/1400x800.png" />
|
||||
{% endif %}
|
||||
<div>
|
||||
<p class="fw-bold text-primary mb-0">{{ review.client.first_name }} {{ review.client.last_name }}</p>
|
||||
<p class="text-muted mb-0">Оценка: {{ review.rating }} из 5</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="orderModal" class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Оформление заявки на услугу</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post">
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Выбор услуги</label>
|
||||
<select id="service" class="form-select" name="service">
|
||||
{% for service in services %}
|
||||
<option value="{{ service.id }}">{{ service.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Имя</label>
|
||||
<input id="name" class="form-control" type="text" name="name" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Телефон</label>
|
||||
<input id="phone" class="form-control" type="tel" name="phone" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Адрес электронной почты</label>
|
||||
<input id="email" class="form-control" type="email" name="email" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Описание услуги</label>
|
||||
<textarea id="description" class="form-control" name="description" rows="4"></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Дата связи</label>
|
||||
<input id="contact_date" class="form-control" type="date" name="contact_date" required />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="submit" class="btn btn-primary">Отправить заявку</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
160
smartsoltech/web/templates/web/service_detail.html
Normal file
160
smartsoltech/web/templates/web/service_detail.html
Normal file
@@ -0,0 +1,160 @@
|
||||
<!-- web/templates/web/service_detail.html -->
|
||||
{% extends 'web/base.html' %}
|
||||
{% load static %}
|
||||
{% block title %}Услуга - {{ service.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="container py-4 py-xl-5">
|
||||
<div class="row gy-4 gy-md-0">
|
||||
<div class="col-md-6">
|
||||
<div class="p-xl-5 m-xl-5"><img class="rounded img-fluid w-100 fit-cover" style="min-height: 300px;" src="{{ service.image.url }}" /></div>
|
||||
</div>
|
||||
<div class="col-md-6 d-md-flex align-items-md-center">
|
||||
<div style="max-width: 350px;">
|
||||
<h2 class="text-uppercase fw-bold">{{ service.name }}<br /></h2>
|
||||
<p class="my-3">{{ service.description }}</p>
|
||||
<a class="btn btn-primary btn-lg me-2" role="button" href="#" data-bs-toggle="modal" data-bs-target="#orderModal">Order Service</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Модальное окно для оформления заявки -->
|
||||
<div id="orderModal" class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Оформление заявки на услугу</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="orderForm" method="post" action="{% url 'create_order' pk=service.pk %}">
|
||||
{% csrf_token %}
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Имя</label>
|
||||
<input id="client_name" class="form-control" type="text" name="client_name" required minlength="2" maxlength="50" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Телефон</label>
|
||||
<input id="client_phone" class="form-control" type="tel" name="client_phone" required pattern="^\+?[0-9\s\-]{7,15}$" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Адрес электронной почты</label>
|
||||
<input id="client_email" class="form-control" type="email" name="client_email" required />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Описание услуги</label>
|
||||
<textarea id="message" class="form-control" name="message" rows="4" required minlength="10" maxlength="1000"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="submit" class="btn btn-primary">Отправить заявку</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container py-4 py-xl-5">
|
||||
<div class="row mb-5">
|
||||
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||
<h2>Отзывы</h2>
|
||||
<p>Пожалуйста, оставьте отзыв, нажав на кнопку ниже. Нам важна ваша обратная связь. Спасибо!</p>
|
||||
<button class="btn btn-primary mb-4" type="button" data-bs-toggle="modal" data-bs-target="#addReview">Добавить отзыв</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="addReview" class="modal fade" role="dialog" tabindex="-1">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Добавить отзыв</h3>
|
||||
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Пожалуйста, заполните форму ниже, чтобы оставить отзыв. Если вы хотите, чтобы ваше имя не отображалось, выберите опцию "Анонимный отзыв". Спасибо!</p>
|
||||
</div>
|
||||
<form>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Имя</label>
|
||||
<input id="firstName" class="form-control" type="text" maxlength="50" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Фамилия</label>
|
||||
<input id="lastName" class="form-control" type="text" maxlength="50" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Адрес электронной почты</label>
|
||||
<input id="email" class="form-control" type="email" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<select id="rating" class="form-select">
|
||||
<option value="0" selected>Пожалуйста, введите свою оценку</option>
|
||||
<option value="1">*</option>
|
||||
<option value="2">**</option>
|
||||
<option value="3">***</option>
|
||||
<option value="4">****</option>
|
||||
<option value="5">*****</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label">Отзыв</label>
|
||||
<textarea id="review" class="form-control" rows="3" maxlength="2000"></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<div class="form-check">
|
||||
<input id="anonDisplay" class="form-check-input" type="checkbox" />
|
||||
<label class="form-check-label" for="anonDisplay">Отображать анонимно</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button id="submitReview" class="btn btn-primary" type="button">Отправить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-1 row-cols-sm-2 row-cols-lg-3">
|
||||
{% for review in reviews %}
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ review.comment }}</p>
|
||||
<div class="d-flex">
|
||||
{% if review.client.image %}
|
||||
<img class="rounded-circle flex-shrink-0 me-3 fit-cover" width="50" height="50" src="{{ review.client.image.url }}" />
|
||||
{% else %}
|
||||
<img class="rounded-circle flex-shrink-0 me-3 fit-cover" width="50" height="50" src="https://cdn.bootstrapstudio.io/placeholders/1400x800.png" />
|
||||
{% endif %}
|
||||
<div>
|
||||
<p class="fw-bold text-primary mb-0">{{ review.client.first_name }} {{ review.client.last_name }}</p>
|
||||
<p class="text-muted mb-0">Оценка: {{ review.rating }} из 5</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
// JavaScript для дополнительной проверки формы
|
||||
document.getElementById('orderForm').addEventListener('submit', function (event) {
|
||||
let phoneInput = document.getElementById('client_phone');
|
||||
let phonePattern = /^\+?[0-9\s\-]{7,15}$/;
|
||||
|
||||
if (!phonePattern.test(phoneInput.value)) {
|
||||
alert('Введите правильный номер телефона.');
|
||||
event.preventDefault(); // Останавливаем отправку формы
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
32
smartsoltech/web/templates/web/services.html
Normal file
32
smartsoltech/web/templates/web/services.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends 'web/base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4 py-xl-5">
|
||||
<div class="row mb-5">
|
||||
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||
<h2>Наши Услуги</h2>
|
||||
<p class="w-lg-50">Предоставляем современные решения для вашего бизнеса. Ознакомьтесь с нашими услугами ниже.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row gy-4 row-cols-1 row-cols-md-2 row-cols-xl-3">
|
||||
{% for service in services %}
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
{% if service.image %}
|
||||
<img class="card-img-top w-100 d-block fit-cover" style="width: 300px; height: 200px; object-fit: cover;" src="{{ service.image.url }}" />
|
||||
{% else %}
|
||||
<img class="card-img-top w-100 d-block fit-cover" style="width: 300px; height: 200px; object-fit: cover;" src="{{ service.image}}" />
|
||||
{% endif %}
|
||||
<div class="card-body p-4">
|
||||
<h4 class="card-title">
|
||||
<a href="{% url 'service_detail' service.pk %}">{{ service.name }}</a>
|
||||
</h4>
|
||||
<p class="card-text">{{ service.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
3
smartsoltech/web/tests.py
Normal file
3
smartsoltech/web/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
18
smartsoltech/web/urls.py
Normal file
18
smartsoltech/web/urls.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# web/urls.py
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.home, name='home'),
|
||||
path('service/<int:pk>/', views.service_detail, name='service_detail'),
|
||||
path('project/<int:pk>/', views.project_detail, name='project_detail'),
|
||||
path('client/<int:pk>/', views.client_detail, name='client_detail'),
|
||||
path('blog/<int:pk>/', views.blog_post_detail, name='blog_post_detail'),
|
||||
path('services/', views.services_view, name='services'),
|
||||
path('create_order/<int:pk>/', views.create_order, name='create_order'),
|
||||
path('about', views.about_view, name="about_view"),
|
||||
]
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
67
smartsoltech/web/views.py
Normal file
67
smartsoltech/web/views.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from .models import Service, Project, Client, BlogPost, Review, Order
|
||||
from django.db.models import Avg
|
||||
|
||||
|
||||
def home(request):
|
||||
return render(request, 'web/home.html')
|
||||
|
||||
def service_detail(request, pk):
|
||||
service = get_object_or_404(Service, pk=pk)
|
||||
projects_in_category = Project.objects.filter(category=service.category)
|
||||
average_rating = service.reviews.aggregate(Avg('rating'))['rating__avg'] or 0
|
||||
total_reviews = service.reviews.count()
|
||||
reviews = service.reviews.all()
|
||||
return render(request, 'web/service_detail.html', {
|
||||
'service': service,
|
||||
'projects_in_category': projects_in_category,
|
||||
'average_rating': average_rating,
|
||||
'total_reviews': total_reviews,
|
||||
'reviews': reviews,
|
||||
})
|
||||
|
||||
def project_detail(request, pk):
|
||||
project = get_object_or_404(Project, pk=pk)
|
||||
return render(request, 'web/project_detail.html', {'project': project})
|
||||
|
||||
def client_detail(request, pk):
|
||||
client = get_object_or_404(Client, pk=pk)
|
||||
return render(request, 'web/client_detail.html', {'client': client})
|
||||
|
||||
def blog_post_detail(request, pk):
|
||||
blog_post = get_object_or_404(BlogPost, pk=pk)
|
||||
return render(request, 'web/blog_post_detail.html', {'blog_post': blog_post})
|
||||
|
||||
def services_view(request):
|
||||
services = Service.objects.all()
|
||||
return render(request, 'web/services.html', {'services': services})
|
||||
|
||||
def create_order(request, pk):
|
||||
if request.method == 'POST':
|
||||
service = get_object_or_404(Service, pk=pk)
|
||||
client_name = request.POST.get('client_name')
|
||||
client_email = request.POST.get('client_email')
|
||||
client_phone = request.POST.get('client_phone')
|
||||
message = request.POST.get('message')
|
||||
|
||||
# Создаем клиента, если он не существует
|
||||
client, created = Client.objects.get_or_create(
|
||||
email=client_email,
|
||||
defaults={'first_name': client_name, 'phone_number': client_phone}
|
||||
)
|
||||
|
||||
# Создаем новый заказ
|
||||
order = Order(
|
||||
service=service,
|
||||
client=client,
|
||||
client_email=client.email,
|
||||
client_phone=client.client_phone,
|
||||
message=message,
|
||||
)
|
||||
order.save()
|
||||
|
||||
# Редирект на страницу подтверждения или обратно к услуге
|
||||
return redirect('service_detail', pk=pk)
|
||||
|
||||
def about_view(request):
|
||||
return render(request, 'web/about.html')
|
||||
Reference in New Issue
Block a user