поправил форматирование
This commit is contained in:
parent
84e66e7978
commit
feb1493ecd
2
.flake8
2
.flake8
@ -1,7 +1,7 @@
|
|||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 80
|
max-line-length = 80
|
||||||
import-order-style = google
|
import-order-style = google
|
||||||
application-import-names = timetable, tickets, home, films
|
application-import-names = timetable, tickets, home, films, users
|
||||||
exclude =
|
exclude =
|
||||||
.git,
|
.git,
|
||||||
__pycache__,
|
__pycache__,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@ -83,21 +84,25 @@ DATABASES = {
|
|||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{
|
||||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
'NAME': 'django.contrib.auth.'
|
||||||
|
'password_validation.UserAttributeSimilarityValidator',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
'NAME': 'django.contrib.auth.'
|
||||||
|
'password_validation.MinimumLengthValidator',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
'NAME': 'django.contrib.auth.'
|
||||||
|
'password_validation.CommonPasswordValidator',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
'NAME': 'django.contrib.auth.'
|
||||||
|
'password_validation.NumericPasswordValidator',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -10,15 +10,15 @@ urlpatterns = [
|
|||||||
path('films/', include('films.urls'), name='films'),
|
path('films/', include('films.urls'), name='films'),
|
||||||
path('timetable/', include('timetable.urls'), name='timetable'),
|
path('timetable/', include('timetable.urls'), name='timetable'),
|
||||||
path('tickets/', include('tickets.urls'), name='tickets'),
|
path('tickets/', include('tickets.urls'), name='tickets'),
|
||||||
path("auth/", include("users.urls"), name="auth"),
|
path('auth/', include('users.urls'), name='auth'),
|
||||||
path("auth/", include("django.contrib.auth.urls"), name="auth"),
|
path('auth/', include('django.contrib.auth.urls'), name='auth'),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
urlpatterns += static(
|
urlpatterns += static(
|
||||||
settings.MEDIA_URL,
|
settings.MEDIA_URL,
|
||||||
document_root=settings.MEDIA_ROOT,
|
document_root=settings.MEDIA_ROOT,
|
||||||
)
|
)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from films.models import Film, Genre, Actor, Director, Country
|
from films.models import Actor, Country, Director, Film, Genre
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Film)
|
@admin.register(Film)
|
||||||
@ -13,7 +13,7 @@ class FilmAdmin(admin.ModelAdmin):
|
|||||||
'get_image',
|
'get_image',
|
||||||
]
|
]
|
||||||
|
|
||||||
readonly_fields = ("get_image",)
|
readonly_fields = ('get_image',)
|
||||||
|
|
||||||
filter_horizontal = [
|
filter_horizontal = [
|
||||||
Film.genres.field.name,
|
Film.genres.field.name,
|
||||||
@ -28,7 +28,7 @@ class FilmAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
def get_image(self, obj):
|
def get_image(self, obj):
|
||||||
return mark_safe(
|
return mark_safe(
|
||||||
f"<img src='{obj.image_tmb()}' width='50' height='50'",
|
f'<img src="{obj.image_tmb()}" width="50" height="50"',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -62,14 +62,17 @@ class Migration(migrations.Migration):
|
|||||||
"duration",
|
"duration",
|
||||||
models.IntegerField(
|
models.IntegerField(
|
||||||
help_text="Продолжительность фильма (в минутах)",
|
help_text="Продолжительность фильма (в минутах)",
|
||||||
validators=[django.core.validators.MinValueValidator(0)],
|
validators=[
|
||||||
|
django.core.validators.MinValueValidator(0)
|
||||||
|
],
|
||||||
verbose_name="Продолжительность",
|
verbose_name="Продолжительность",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"release_date",
|
"release_date",
|
||||||
models.DateField(
|
models.DateField(
|
||||||
help_text="Дата выхода фильма", verbose_name="Дата релиза"
|
help_text="Дата выхода фильма",
|
||||||
|
verbose_name="Дата релиза",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|||||||
@ -25,7 +25,9 @@ class Migration(migrations.Migration):
|
|||||||
(
|
(
|
||||||
"first_name",
|
"first_name",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text="Имя актера", max_length=100, verbose_name="Имя"
|
help_text="Имя актера",
|
||||||
|
max_length=100,
|
||||||
|
verbose_name="Имя",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -85,7 +87,9 @@ class Migration(migrations.Migration):
|
|||||||
(
|
(
|
||||||
"first_name",
|
"first_name",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
help_text="Имя режиссера", max_length=100, verbose_name="Имя"
|
help_text="Имя режиссера",
|
||||||
|
max_length=100,
|
||||||
|
verbose_name="Имя",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|||||||
@ -6,7 +6,10 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("films", "0006_actor_country_director_film_actors_film_countries_and_more"),
|
(
|
||||||
|
"films",
|
||||||
|
"0006_actor_country_director_film_actors_film_countries_and_more",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import time
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import time
|
||||||
|
|
||||||
import sorl
|
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
Model,
|
|
||||||
CharField,
|
CharField,
|
||||||
IntegerField,
|
|
||||||
DateField,
|
DateField,
|
||||||
|
ImageField,
|
||||||
|
IntegerField,
|
||||||
|
Manager,
|
||||||
ManyToManyField,
|
ManyToManyField,
|
||||||
Manager, ImageField, Min,
|
Min,
|
||||||
|
Model,
|
||||||
)
|
)
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
@ -18,36 +19,51 @@ from sorl.thumbnail import get_thumbnail
|
|||||||
|
|
||||||
class FilmManager(Manager):
|
class FilmManager(Manager):
|
||||||
def released(self):
|
def released(self):
|
||||||
return super().get_queryset().filter(
|
return (
|
||||||
release_date__lt=timezone.now(),
|
super()
|
||||||
|
.get_queryset()
|
||||||
|
.filter(
|
||||||
|
release_date__lt=timezone.now(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def will_be_shown(self):
|
def will_be_shown(self):
|
||||||
current_datetime = timezone.now()
|
current_datetime = timezone.now()
|
||||||
films_with_sessions = super().get_queryset().filter(
|
return (
|
||||||
sessions__start_datetime__gte=current_datetime,
|
super()
|
||||||
).annotate(
|
.get_queryset()
|
||||||
nearest_session=Min('sessions__start_datetime')
|
.filter(
|
||||||
).order_by('nearest_session')
|
sessions__start_datetime__gte=current_datetime,
|
||||||
|
)
|
||||||
return films_with_sessions
|
.annotate(nearest_session=Min('sessions__start_datetime'))
|
||||||
|
.order_by('nearest_session')
|
||||||
|
)
|
||||||
|
|
||||||
def on_main(self):
|
def on_main(self):
|
||||||
current_datetime = timezone.now()
|
current_datetime = timezone.now()
|
||||||
end_datetime = current_datetime + timedelta(days=5)
|
end_datetime = current_datetime + timedelta(days=5)
|
||||||
films_with_sessions = super().get_queryset().filter(
|
queryset = super().get_queryset()
|
||||||
sessions__start_datetime__gte=current_datetime,
|
films_with_sessions = (
|
||||||
sessions__start_datetime__lte=end_datetime,
|
queryset.filter(
|
||||||
).exclude(image=None).distinct().only(
|
sessions__start_datetime__gte=current_datetime,
|
||||||
Film.name.field.name,
|
sessions__start_datetime__lte=end_datetime,
|
||||||
Film.image.field.name,
|
)
|
||||||
Film.description.field.name,
|
.exclude(image=None)
|
||||||
|
.distinct()
|
||||||
|
.only(
|
||||||
|
Film.name.field.name,
|
||||||
|
Film.image.field.name,
|
||||||
|
Film.description.field.name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if films_with_sessions.count() > 5:
|
if films_with_sessions.count() > 5:
|
||||||
films_with_sessions = films_with_sessions[:5]
|
films_with_sessions = films_with_sessions[:5]
|
||||||
elif films_with_sessions.count() > 0:
|
elif films_with_sessions.count() > 0:
|
||||||
films_with_sessions = films_with_sessions[:films_with_sessions.count()]
|
films_with_sessions = films_with_sessions[
|
||||||
|
: films_with_sessions.count()
|
||||||
|
]
|
||||||
|
|
||||||
return films_with_sessions
|
return films_with_sessions
|
||||||
|
|
||||||
|
|
||||||
@ -209,23 +225,23 @@ class Film(Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_image_300x300(self):
|
def get_image_300x300(self):
|
||||||
return sorl.thumbnail.get_thumbnail(
|
return get_thumbnail(
|
||||||
self.image,
|
self.image,
|
||||||
"300x300",
|
'300x300',
|
||||||
crop="center",
|
crop='center',
|
||||||
quality=51,
|
quality=51,
|
||||||
)
|
)
|
||||||
|
|
||||||
def image_tmb(self):
|
def image_tmb(self):
|
||||||
if self.image:
|
if self.image:
|
||||||
tag = f"{self.get_image_300x300().url}"
|
tag = f'{self.get_image_300x300().url}'
|
||||||
return mark_safe(tag)
|
return mark_safe(tag)
|
||||||
|
|
||||||
return "Нет изорбражения"
|
return 'Нет изорбражения'
|
||||||
|
|
||||||
image_tmb.field_name = "image_tmb"
|
image_tmb.field_name = 'image_tmb'
|
||||||
image_tmb.allow_tags = True
|
image_tmb.allow_tags = True
|
||||||
image_tmb.short_description = "Превью"
|
image_tmb.short_description = 'Превью'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'films_films'
|
db_table = 'films_films'
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,9 +1,9 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from films.views import films_list, film_details
|
from films.views import film_details, films_list
|
||||||
|
|
||||||
app_name = 'films'
|
app_name = 'films'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', films_list, name='main'),
|
path('', films_list, name='main'),
|
||||||
path('<int:film_id>/', film_details, name='film_details')
|
path('<int:film_id>/', film_details, name='film_details'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
|
||||||
from films.models import Film
|
from films.models import Film
|
||||||
from timetable.models import FilmSession
|
from timetable.models import FilmSession
|
||||||
@ -19,16 +19,21 @@ def film_details(request: HttpResponse, film_id: int) -> HttpResponse:
|
|||||||
Film.objects.released(),
|
Film.objects.released(),
|
||||||
id=film_id,
|
id=film_id,
|
||||||
)
|
)
|
||||||
film_sessions = FilmSession.objects.nearest_timetable().filter(film_id=film_id)
|
film_sessions = FilmSession.objects.nearest_timetable().filter(
|
||||||
|
film_id=film_id,
|
||||||
|
)
|
||||||
sessions_by_date_and_film = {}
|
sessions_by_date_and_film = {}
|
||||||
|
|
||||||
for session in film_sessions:
|
for session in film_sessions:
|
||||||
session_date = session.start_datetime.date()
|
session_date = session.start_datetime.date()
|
||||||
if session_date not in sessions_by_date_and_film:
|
if session_date not in sessions_by_date_and_film:
|
||||||
sessions_by_date_and_film[session_date] = {}
|
sessions_by_date_and_film[session_date] = {}
|
||||||
|
|
||||||
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
||||||
|
|
||||||
if session.film not in film_sessions_for_date:
|
if session.film not in film_sessions_for_date:
|
||||||
film_sessions_for_date[session.film] = []
|
film_sessions_for_date[session.film] = []
|
||||||
|
|
||||||
film_sessions_for_date[session.film].append(session)
|
film_sessions_for_date[session.film].append(session)
|
||||||
|
|
||||||
for session_date, session_films in sessions_by_date_and_film.items():
|
for session_date, session_films in sessions_by_date_and_film.items():
|
||||||
@ -36,6 +41,7 @@ def film_details(request: HttpResponse, film_id: int) -> HttpResponse:
|
|||||||
sessions_by_date_and_film[session_date][session_film].sort(
|
sessions_by_date_and_film[session_date][session_film].sort(
|
||||||
key=lambda sorted_session: sorted_session.start_datetime,
|
key=lambda sorted_session: sorted_session.start_datetime,
|
||||||
)
|
)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'film_sessions': sessions_by_date_and_film,
|
'film_sessions': sessions_by_date_and_film,
|
||||||
'item': item,
|
'item': item,
|
||||||
@ -45,4 +51,3 @@ def film_details(request: HttpResponse, film_id: int) -> HttpResponse:
|
|||||||
'films/film_details.html',
|
'films/film_details.html',
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -3,6 +3,7 @@ from datetime import date
|
|||||||
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
from films.models import Film
|
from films.models import Film
|
||||||
from timetable.models import FilmSession
|
from timetable.models import FilmSession
|
||||||
|
|
||||||
@ -16,9 +17,11 @@ def homepage(request):
|
|||||||
session_date = session.start_datetime.date()
|
session_date = session.start_datetime.date()
|
||||||
if session_date not in sessions_by_date_and_film:
|
if session_date not in sessions_by_date_and_film:
|
||||||
sessions_by_date_and_film[session_date] = {}
|
sessions_by_date_and_film[session_date] = {}
|
||||||
|
|
||||||
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
||||||
if session.film not in film_sessions_for_date:
|
if session.film not in film_sessions_for_date:
|
||||||
film_sessions_for_date[session.film] = []
|
film_sessions_for_date[session.film] = []
|
||||||
|
|
||||||
film_sessions_for_date[session.film].append(session)
|
film_sessions_for_date[session.film].append(session)
|
||||||
|
|
||||||
for session_date, session_films in sessions_by_date_and_film.items():
|
for session_date, session_films in sessions_by_date_and_film.items():
|
||||||
@ -35,7 +38,7 @@ def homepage(request):
|
|||||||
'films_sessions': sessions_by_date_and_film,
|
'films_sessions': sessions_by_date_and_film,
|
||||||
'today': date.today(),
|
'today': date.today(),
|
||||||
'tomorrow': date.today() + datetime.timedelta(days=1),
|
'tomorrow': date.today() + datetime.timedelta(days=1),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
template,
|
template,
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""Django's command-line utility for administrative tasks."""
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run administrative tasks."""
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CineSync.settings')
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CineSync.settings')
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Couldn't import Django. Are you sure it's installed and "
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
"available on your PYTHONPATH environment variable? Did you "
|
'available on your PYTHONPATH environment variable? Did you '
|
||||||
"forget to activate a virtual environment?"
|
'forget to activate a virtual environment?',
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
execute_from_command_line(sys.argv)
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from tickets.models import Ticket, Order
|
from tickets.models import Order, Ticket
|
||||||
|
|
||||||
|
|
||||||
class TicketAdminInline(admin.StackedInline):
|
class TicketAdminInline(admin.StackedInline):
|
||||||
|
|||||||
@ -6,7 +6,10 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("tickets", "0006_remove_ticket_profile_remove_ticket_session_and_more"),
|
(
|
||||||
|
"tickets",
|
||||||
|
"0006_remove_ticket_profile_remove_ticket_session_and_more",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
from django.db.models import ForeignKey, CASCADE, Model, IntegerField, DateTimeField, Manager
|
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
|
from django.db.models import (
|
||||||
|
CASCADE,
|
||||||
|
DateTimeField,
|
||||||
|
ForeignKey,
|
||||||
|
IntegerField,
|
||||||
|
Manager,
|
||||||
|
Model,
|
||||||
|
)
|
||||||
|
|
||||||
from timetable.models import FilmSession
|
from timetable.models import FilmSession
|
||||||
from users.models import Profile
|
from users.models import Profile
|
||||||
@ -7,8 +14,7 @@ from users.models import Profile
|
|||||||
|
|
||||||
class TicketManager(Manager):
|
class TicketManager(Manager):
|
||||||
def get_tickets_for_session(self, session_id):
|
def get_tickets_for_session(self, session_id):
|
||||||
tickets = super().get_queryset().filter(order__session_id=session_id)
|
return super().get_queryset().filter(order__session_id=session_id)
|
||||||
return tickets
|
|
||||||
|
|
||||||
|
|
||||||
class Order(Model):
|
class Order(Model):
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from tickets.views import order_success, my_orders
|
from tickets.views import my_orders, order_success
|
||||||
|
|
||||||
app_name = 'tickets'
|
app_name = 'tickets'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('order/success', order_success, name='order_success'),
|
path('order/success', order_success, name='order_success'),
|
||||||
path('my/', my_orders, name='my_orders')
|
path('my/', my_orders, name='my_orders'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import render, get_list_or_404
|
from django.shortcuts import render
|
||||||
|
|
||||||
from tickets.models import Order, Ticket
|
from tickets.models import Order
|
||||||
|
|
||||||
|
|
||||||
def order_success(request):
|
def order_success(request):
|
||||||
@ -11,16 +11,11 @@ def order_success(request):
|
|||||||
@login_required
|
@login_required
|
||||||
def my_orders(request):
|
def my_orders(request):
|
||||||
user = request.user
|
user = request.user
|
||||||
orders = Order.objects.filter(
|
queryset = Order.objects.filter(profile__id=user.profile.id)
|
||||||
profile__id=user.profile.id,
|
queryset = queryset.select_related('session', 'session__film')
|
||||||
).select_related(
|
queryset = queryset.prefetch_related('tickets')
|
||||||
'session',
|
orders = queryset.order_by('-datetime_order')
|
||||||
'session__film',
|
|
||||||
).prefetch_related(
|
|
||||||
'tickets',
|
|
||||||
).order_by(
|
|
||||||
'-datetime_order'
|
|
||||||
)
|
|
||||||
context = {
|
context = {
|
||||||
'my_orders': orders,
|
'my_orders': orders,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from timetable.models import Auditorium, Row, FilmSession
|
from timetable.models import Auditorium, FilmSession, Row
|
||||||
|
|
||||||
|
|
||||||
class RowAdminInline(admin.StackedInline):
|
class RowAdminInline(admin.StackedInline):
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import pprint
|
|
||||||
from json import loads
|
from json import loads
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from timetable.models import Auditorium, Row
|
from timetable.models import Auditorium
|
||||||
|
|
||||||
|
|
||||||
class SeatSelectionForm(forms.Form):
|
class SeatSelectionForm(forms.Form):
|
||||||
@ -17,13 +16,19 @@ class SeatSelectionForm(forms.Form):
|
|||||||
for i, row in enumerate(auditorium.rows.all(), start=1):
|
for i, row in enumerate(auditorium.rows.all(), start=1):
|
||||||
for seat in range(1, row.column_count + 1):
|
for seat in range(1, row.column_count + 1):
|
||||||
choices.append((f'[{seat}, {str(i)}]', f'[{seat}, {str(i)}]'))
|
choices.append((f'[{seat}, {str(i)}]', f'[{seat}, {str(i)}]'))
|
||||||
|
|
||||||
self.fields['selected_seats'].choices = choices
|
self.fields['selected_seats'].choices = choices
|
||||||
|
|
||||||
for field in self.visible_fields():
|
for field in self.visible_fields():
|
||||||
field.field.widget.attrs.update({"class": "seat_checkbox"})
|
field.field.widget.attrs.update({'class': 'seat_checkbox'})
|
||||||
|
|
||||||
def clean_selected_seats(self):
|
def clean_selected_seats(self):
|
||||||
selected_seats = self.cleaned_data['selected_seats']
|
return (
|
||||||
if isinstance(selected_seats, list) and all(isinstance(item, str) for item in selected_seats):
|
[loads(field) for field in self.cleaned_data['selected_seats']]
|
||||||
selected_seats = [loads(field) for field in selected_seats]
|
if isinstance(self.cleaned_data['selected_seats'], list)
|
||||||
return selected_seats
|
and all(
|
||||||
|
isinstance(item, str)
|
||||||
|
for item in self.cleaned_data['selected_seats']
|
||||||
|
)
|
||||||
|
else self.cleaned_data['selected_seats']
|
||||||
|
)
|
||||||
|
|||||||
@ -26,12 +26,16 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
"number",
|
"number",
|
||||||
models.CharField(max_length=20, verbose_name="Номер кинозала"),
|
models.CharField(
|
||||||
|
max_length=20, verbose_name="Номер кинозала"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"row_count",
|
"row_count",
|
||||||
models.IntegerField(
|
models.IntegerField(
|
||||||
validators=[django.core.validators.MinValueValidator(1)],
|
validators=[
|
||||||
|
django.core.validators.MinValueValidator(1)
|
||||||
|
],
|
||||||
verbose_name="Количество рядов кресел в зале",
|
verbose_name="Количество рядов кресел в зале",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -57,14 +61,18 @@ class Migration(migrations.Migration):
|
|||||||
(
|
(
|
||||||
"row_number",
|
"row_number",
|
||||||
models.IntegerField(
|
models.IntegerField(
|
||||||
validators=[django.core.validators.MinValueValidator(1)],
|
validators=[
|
||||||
|
django.core.validators.MinValueValidator(1)
|
||||||
|
],
|
||||||
verbose_name="Номер ряда",
|
verbose_name="Номер ряда",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"column_count",
|
"column_count",
|
||||||
models.IntegerField(
|
models.IntegerField(
|
||||||
validators=[django.core.validators.MinValueValidator(1)],
|
validators=[
|
||||||
|
django.core.validators.MinValueValidator(1)
|
||||||
|
],
|
||||||
verbose_name="Количество кресел в ряду",
|
verbose_name="Количество кресел в ряду",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -31,12 +31,16 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
"start_datetime",
|
"start_datetime",
|
||||||
models.DateTimeField(verbose_name="Дата и время начала сеанса"),
|
models.DateTimeField(
|
||||||
|
verbose_name="Дата и время начала сеанса"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"price",
|
"price",
|
||||||
models.FloatField(
|
models.FloatField(
|
||||||
validators=[django.core.validators.MinValueValidator(1)],
|
validators=[
|
||||||
|
django.core.validators.MinValueValidator(1)
|
||||||
|
],
|
||||||
verbose_name="Цена билета",
|
verbose_name="Цена билета",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -14,7 +14,9 @@ class Migration(migrations.Migration):
|
|||||||
model_name="filmsession",
|
model_name="filmsession",
|
||||||
name="end_datetime",
|
name="end_datetime",
|
||||||
field=models.DateTimeField(
|
field=models.DateTimeField(
|
||||||
blank=True, null=True, verbose_name="Дата и время начала сеанса"
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Дата и время начала сеанса",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,7 +1,16 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.db.models import Model, CharField, IntegerField, CASCADE, DateTimeField, FloatField, ForeignKey, Manager
|
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
|
from django.db.models import (
|
||||||
|
CASCADE,
|
||||||
|
CharField,
|
||||||
|
DateTimeField,
|
||||||
|
FloatField,
|
||||||
|
ForeignKey,
|
||||||
|
IntegerField,
|
||||||
|
Manager,
|
||||||
|
Model,
|
||||||
|
)
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from films.models import Film
|
from films.models import Film
|
||||||
@ -11,34 +20,23 @@ class FilmSessionsManager(Manager):
|
|||||||
def nearest_timetable(self):
|
def nearest_timetable(self):
|
||||||
current_datetime = timezone.now()
|
current_datetime = timezone.now()
|
||||||
end_datetime = current_datetime + timedelta(days=5)
|
end_datetime = current_datetime + timedelta(days=5)
|
||||||
films_sessions = super().get_queryset().select_related(
|
queryset = super().get_queryset()
|
||||||
'film',
|
queryset = queryset.select_related('film')
|
||||||
).prefetch_related(
|
queryset = queryset.prefetch_related('film__genres', 'film__countries')
|
||||||
'film__genres',
|
queryset = queryset.filter(
|
||||||
'film__countries',
|
|
||||||
).filter(
|
|
||||||
start_datetime__gte=current_datetime,
|
start_datetime__gte=current_datetime,
|
||||||
start_datetime__lte=end_datetime,
|
start_datetime__lte=end_datetime,
|
||||||
).order_by(
|
|
||||||
FilmSession.start_datetime.field.name,
|
|
||||||
)
|
)
|
||||||
return films_sessions
|
return queryset.order_by(FilmSession.start_datetime.field.name)
|
||||||
|
|
||||||
def all_timetable(self):
|
def all_timetable(self):
|
||||||
current_datetime = timezone.now()
|
current_datetime = timezone.now()
|
||||||
films_sessions = super().get_queryset().select_related(
|
queryset = super().get_queryset()
|
||||||
'film',
|
queryset = queryset.select_related('film')
|
||||||
).prefetch_related(
|
queryset = queryset.prefetch_related('film__genres', 'film__countries')
|
||||||
'film__genres',
|
queryset = queryset.filter(start_datetime__gte=current_datetime)
|
||||||
'film__countries',
|
queryset = queryset.prefetch_related(FilmSession.film.field.name)
|
||||||
).filter(
|
return queryset.order_by(FilmSession.start_datetime.field.name)
|
||||||
start_datetime__gte=current_datetime,
|
|
||||||
).prefetch_related(
|
|
||||||
FilmSession.film.field.name,
|
|
||||||
).order_by(
|
|
||||||
FilmSession.start_datetime.field.name,
|
|
||||||
)
|
|
||||||
return films_sessions
|
|
||||||
|
|
||||||
|
|
||||||
class Auditorium(Model):
|
class Auditorium(Model):
|
||||||
@ -121,11 +119,17 @@ class FilmSession(Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.film.name} - {str(self.start_datetime)} - {self.auditorium}'
|
return (
|
||||||
|
f'{self.film.name} - {str(self.start_datetime)}'
|
||||||
|
f' - {self.auditorium}'
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.start_datetime and self.film.duration:
|
if self.start_datetime and self.film.duration:
|
||||||
self.end_datetime = self.start_datetime + timedelta(minutes=self.film.duration)
|
self.end_datetime = self.start_datetime + timedelta(
|
||||||
|
minutes=self.film.duration,
|
||||||
|
)
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from timetable.views import timetable_view, session_view
|
from timetable.views import session_view, timetable_view
|
||||||
|
|
||||||
app_name = 'time_table'
|
app_name = 'time_table'
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,13 @@ from datetime import date
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from timetable.models import FilmSession, Row
|
|
||||||
from timetable.forms import SeatSelectionForm
|
|
||||||
from tickets.models import Order, Ticket
|
from tickets.models import Order, Ticket
|
||||||
|
from timetable.forms import SeatSelectionForm
|
||||||
|
from timetable.models import FilmSession
|
||||||
|
|
||||||
|
|
||||||
def timetable_view(request):
|
def timetable_view(request):
|
||||||
@ -21,9 +21,11 @@ def timetable_view(request):
|
|||||||
session_date = session.start_datetime.date()
|
session_date = session.start_datetime.date()
|
||||||
if session_date not in sessions_by_date_and_film:
|
if session_date not in sessions_by_date_and_film:
|
||||||
sessions_by_date_and_film[session_date] = {}
|
sessions_by_date_and_film[session_date] = {}
|
||||||
|
|
||||||
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
film_sessions_for_date = sessions_by_date_and_film[session_date]
|
||||||
if session.film not in film_sessions_for_date:
|
if session.film not in film_sessions_for_date:
|
||||||
film_sessions_for_date[session.film] = []
|
film_sessions_for_date[session.film] = []
|
||||||
|
|
||||||
film_sessions_for_date[session.film].append(session)
|
film_sessions_for_date[session.film].append(session)
|
||||||
|
|
||||||
for session_date, session_films in sessions_by_date_and_film.items():
|
for session_date, session_films in sessions_by_date_and_film.items():
|
||||||
@ -31,6 +33,7 @@ def timetable_view(request):
|
|||||||
sessions_by_date_and_film[session_date][session_film].sort(
|
sessions_by_date_and_film[session_date][session_film].sort(
|
||||||
key=lambda sorted_session: sorted_session.start_datetime,
|
key=lambda sorted_session: sorted_session.start_datetime,
|
||||||
)
|
)
|
||||||
|
|
||||||
template = render(
|
template = render(
|
||||||
request,
|
request,
|
||||||
'timetable/timetable.html',
|
'timetable/timetable.html',
|
||||||
@ -38,7 +41,7 @@ def timetable_view(request):
|
|||||||
'films_sessions': sessions_by_date_and_film,
|
'films_sessions': sessions_by_date_and_film,
|
||||||
'today': date.today(),
|
'today': date.today(),
|
||||||
'tomorrow': date.today() + datetime.timedelta(days=1),
|
'tomorrow': date.today() + datetime.timedelta(days=1),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
template,
|
template,
|
||||||
@ -60,7 +63,10 @@ def session_view(request, sess_id):
|
|||||||
height = round(session.auditorium.rows.count() * 4 + 7)
|
height = round(session.auditorium.rows.count() * 4 + 7)
|
||||||
|
|
||||||
tickets = Ticket.objects.get_tickets_for_session(session.pk)
|
tickets = Ticket.objects.get_tickets_for_session(session.pk)
|
||||||
occupied_seats = [f"{str(ticket.row_number)}-{str(ticket.column_number)}" for ticket in tickets]
|
occupied_seats = [
|
||||||
|
f'{str(ticket.row_number)}-{str(ticket.column_number)}'
|
||||||
|
for ticket in tickets
|
||||||
|
]
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = SeatSelectionForm(request.POST, auditorium=session.auditorium)
|
form = SeatSelectionForm(request.POST, auditorium=session.auditorium)
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.forms import DateInput, ModelForm
|
|
||||||
from django.contrib.auth.forms import (
|
from django.contrib.auth.forms import (
|
||||||
AuthenticationForm,
|
AuthenticationForm,
|
||||||
PasswordChangeForm,
|
PasswordChangeForm,
|
||||||
@ -8,6 +7,7 @@ from django.contrib.auth.forms import (
|
|||||||
UserChangeForm,
|
UserChangeForm,
|
||||||
UserCreationForm,
|
UserCreationForm,
|
||||||
)
|
)
|
||||||
|
from django.forms import DateInput, ModelForm
|
||||||
|
|
||||||
from users.models import Profile
|
from users.models import Profile
|
||||||
|
|
||||||
|
|||||||
@ -30,12 +30,16 @@ class Migration(migrations.Migration):
|
|||||||
(
|
(
|
||||||
"birthday",
|
"birthday",
|
||||||
models.DateField(
|
models.DateField(
|
||||||
blank=True, null=True, verbose_name="Дата рождения пользователя"
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Дата рождения пользователя",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"role",
|
"role",
|
||||||
models.CharField(max_length=20, verbose_name="Роль пользователя"),
|
models.CharField(
|
||||||
|
max_length=20, verbose_name="Роль пользователя"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"image",
|
"image",
|
||||||
|
|||||||
@ -19,7 +19,9 @@ class Migration(migrations.Migration):
|
|||||||
model_name="profile",
|
model_name="profile",
|
||||||
name="genres",
|
name="genres",
|
||||||
field=models.ManyToManyField(
|
field=models.ManyToManyField(
|
||||||
related_name="profiles", related_query_name="profiles", to="films.genre"
|
related_name="profiles",
|
||||||
|
related_query_name="profiles",
|
||||||
|
to="films.genre",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Model, OneToOneField, CASCADE, DateField, CharField, ImageField, ManyToManyField
|
from django.db.models import (
|
||||||
|
CASCADE,
|
||||||
|
CharField,
|
||||||
|
DateField,
|
||||||
|
ImageField,
|
||||||
|
ManyToManyField,
|
||||||
|
Model,
|
||||||
|
OneToOneField,
|
||||||
|
)
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from sorl.thumbnail import get_thumbnail
|
from sorl.thumbnail import get_thumbnail
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@ -6,7 +6,6 @@ from django.urls import reverse_lazy
|
|||||||
from users.forms import (
|
from users.forms import (
|
||||||
CustomAuthenticationForm,
|
CustomAuthenticationForm,
|
||||||
CustomPasswordChangeForm,
|
CustomPasswordChangeForm,
|
||||||
CustomSetPasswordForm,
|
|
||||||
)
|
)
|
||||||
from users.views import profile, signup
|
from users.views import profile, signup
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.generic import View
|
|
||||||
|
|
||||||
from users.forms import SignUpForm, ProfileForm, UserForm
|
from users.forms import ProfileForm, SignUpForm, UserForm
|
||||||
from users.models import Profile
|
from users.models import Profile
|
||||||
|
|
||||||
__all__ = []
|
__all__ = []
|
||||||
@ -59,4 +56,3 @@ def profile(request):
|
|||||||
'user': request.user,
|
'user': request.user,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 79
|
line-length = 79
|
||||||
|
skip-string-normalization = 'true'
|
||||||
exclude = '''
|
exclude = '''
|
||||||
venv/
|
venv/
|
||||||
.git/
|
.git/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user