10 Commits

8 changed files with 215 additions and 20 deletions

View File

@@ -1,6 +1,6 @@
from django.contrib import admin
from .models import ToDoList
from .models import ToDoList, ToDoItem
class ToDoListAdmin(admin.ModelAdmin):
@@ -9,4 +9,11 @@ class ToDoListAdmin(admin.ModelAdmin):
list_editable = ["title"]
class ToDoItemAdmin(admin.ModelAdmin):
model = ToDoItem
list_display = ["parent", "finished", "text", "created_at"]
list_editable = ["finished", "text"]
admin.site.register(ToDoList, ToDoListAdmin)
admin.site.register(ToDoItem, ToDoItemAdmin)

View File

@@ -1,20 +1,62 @@
from rest_framework import viewsets, serializers, permissions
from rest_framework import routers
from django_filters.rest_framework import DjangoFilterBackend
from .models import ToDoList
from .models import ToDoList, ToDoItem
class ToDoListField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
user = self.context["request"].user
return ToDoList.objects.filter(user=user)
class ToDoItemSerializer(serializers.HyperlinkedModelSerializer):
parent = ToDoListField(many=False, read_only=False, help_text="ID родительского списка")
class Meta:
model = ToDoItem
fields = ["id", "text", "finished", "created_at", "parent"]
class ToDoItemViewSet(viewsets.ModelViewSet):
serializer_class = ToDoItemSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_fields = ["parent", "finished"]
def get_queryset(self):
user = self.request.user
if not user.is_authenticated:
# ветка только для генерации схемы
return ToDoItem.objects.all()
return ToDoItem.objects.filter(parent__user=user)
class ToDoListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ToDoList
fields = ["title", "created_at"]
fields = ["id", "title", "created_at"]
def create(self, validated_data):
todo_list = ToDoList.objects.create(
user=self.context["request"].user, title=validated_data["title"]
)
return todo_list
class ToDoListViewSet(viewsets.ModelViewSet):
queryset = ToDoList.objects.all()
serializer_class = ToDoListSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
if not user.is_authenticated:
# ветка только для генерации схемы
return ToDoList.objects.all()
return ToDoList.objects.filter(user=user)
router = routers.DefaultRouter()
router.register(r"lists", ToDoListViewSet)
router.register(r"lists", ToDoListViewSet, basename="ToDoLists")
router.register(r"todo_items", ToDoItemViewSet, basename="ToDoItems")

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2 on 2021-04-17 11:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("backend", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="todoitem",
name="finished",
field=models.BooleanField(default=False),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 3.2 on 2021-04-17 11:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("backend", "0002_todoitem_finished"),
]
operations = [
migrations.AlterField(
model_name="todoitem",
name="created_at",
field=models.DateTimeField(auto_now_add=True, db_index=True),
),
migrations.AlterField(
model_name="todoitem",
name="finished",
field=models.BooleanField(db_index=True, default=False),
),
migrations.AlterField(
model_name="todolist",
name="created_at",
field=models.DateTimeField(auto_now_add=True, db_index=True),
),
]

View File

@@ -5,10 +5,11 @@ from django.contrib.auth.models import User
class ToDoList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, default=None)
title = models.CharField(max_length=250)
created_at = models.DateTimeField(auto_now_add=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
class ToDoItem(models.Model):
parent = models.ForeignKey(ToDoList, on_delete=models.CASCADE, null=False, default=None)
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
finished = models.BooleanField(default=False, null=False, db_index=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)

View File

@@ -27,8 +27,8 @@ SECRET_KEY = "django-insecure-toz+*lt(ejm!l*)92w2ciqoh^1kz#a(abbpcn54-dbw(nxoy&7
DEBUG = True
ALLOWED_HOSTS = []
if DEBUG:
ALLOWED_HOSTS = ["0.0.0.0"]
if DEBUG:
ALLOWED_HOSTS = ["0.0.0.0", "localhost", "127.0.0.1"]
# Application definition
@@ -45,13 +45,7 @@ INSTALLED_APPS = [
]
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'Bearer': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
}
}
"SECURITY_DEFINITIONS": {"Bearer": {"type": "apiKey", "name": "Authorization", "in": "header"}}
}
MIDDLEWARE = [
@@ -130,7 +124,12 @@ SIMPLE_JWT = {
}
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework_simplejwt.authentication.JWTAuthentication",)
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 100,
}

View File

@@ -1,4 +1,5 @@
djangorestframework==3.12.4
django-filter==2.4.0
markdown==3.3.4
appdirs==1.4.4
asgiref==3.3.4

View File

@@ -1,14 +1,113 @@
#!/usr/bin/env python3
import sys
import tkinter as tk
from tkinter import messagebox as mb
from user import User
if 'win' in sys.platform.lower():
DEFAULT_URL = "http://localhost:8000"
else:
DEFAULT_URL = "http://0.0.0.0:8000"
BASE_W = 580
BASE_H = 400
class Application(tk.Frame):
def __init__(self, master=None):
def __init__(self,
master=None
) -> None:
"""
Функция инициаизации класса
"""
super().__init__(master)
#Иницализируем параметры окна
self.master = master
self.pack(fill=tk.BOTH, expand=1)
self.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
tk.Grid.rowconfigure(master, 0, weight=1)
tk.Grid.columnconfigure(master, 0, weight=1)
# Иницализируем параметры пользователя
self.user = User(url=DEFAULT_URL)
# Настраиваем размеры и включаем иницализацию
self.centerWindow()
self.initAUTH()
def centerWindow(self,
width: str = BASE_W,
heigh: str = BASE_H
) -> None:
"""
Центрирует приложение по центру экрана
:param width: ширина окна
:param heigh: высота окна
"""
sw = self.master.winfo_screenwidth()
sh = self.master.winfo_screenheight()
x = (sw - width) / 2
y = (sh - heigh) / 2
self.master.geometry('%dx%d+%d+%d' % (width, heigh, x, y))
def login_clicked(self) -> None:
"""
Функция авторизации
"""
try:
self.user.auth(self.login.get(), self.password.get())
except Exception as ex:
print(ex)
self.show_info()
def show_info(selfб,
msg: str = None
) -> None:
"""
Показывает передаваемое сообщение в messagebox
:param msg: передаваемое сообщение
"""
if msg is None:
msg = "Неправильный логин или пароль"
mb.showinfo("Информация", msg)
def initAUTH(self) -> None:
"""
Создает окно авторизации программы
"""
#Конфигурируем сетку
for rows in range(25):
tk.Grid.rowconfigure(self, rows, weight=1)
for columns in range(25):
tk.Grid.columnconfigure(self, columns, weight=1)
# Подпись и поле ввода для логина
login_label = tk.Label(self, text="Введите логин")
login_label.grid(row=9, column=12, columnspan=3, rowspan=1, sticky="nsew")
self.login = tk.Entry(self)
self.login.grid(row=10, column=12, columnspan=3, rowspan=1, sticky="nsew")
# Подпись и поле ввода для пароля
password_label = tk.Label(self, text="Введите пароль")
password_label.grid(row=11, column=12, columnspan=3, rowspan=1, sticky="nsew")
self.password = tk.Entry(self, show="*")
self.password.grid(row=12, column=12, columnspan=3, rowspan=1, sticky="nsew")
# Кнопка авториазции
btn = tk.Button(self, text="Войти", command=self.login_clicked)
btn.grid(row=14, column=12, columnspan=3, rowspan=1, sticky="nsew")
if __name__ == "__main__":
app = Application()
master = tk.Tk()
app = Application(master)
app.master.title("ToDo")
app.mainloop()