+ Приведены все функции приложения в рабочий вид
+ Наведен порядок в файлах проекта + Наведен порядок в документации + Настроены скрипты установки, развертки и так далее, расширен MakeFile
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,3 +5,6 @@ media/
|
|||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
.venv/
|
.venv/
|
||||||
|
venv/
|
||||||
|
.history
|
||||||
|
.DS_Store
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
ALLOWED_HOSTS=['0.0.0.0', 'localhost', '127.0.0.1']
|
|
||||||
DEBUG=True
|
|
||||||
DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
|
|
||||||
DATABASE_NAME=postgres
|
|
||||||
DATABASE_USER=postgres
|
|
||||||
DATABASE_PASSWORD=postgres
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
ALLOWED_HOSTS=['0.0.0.0', 'localhost', '127.0.0.1']
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
|
|
||||||
DATABASE_NAME=postgres
|
|
||||||
DATABASE_USER=postgres
|
|
||||||
DATABASE_PASSWORD=postgres
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0, localhost, 127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
|
|
||||||
DATABASE_NAME=postgres
|
|
||||||
DATABASE_USER=postgres
|
|
||||||
DATABASE_PASSWORD=postgres
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0, localhost, 127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0, localhost, 127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=postgres
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0, localhost, 127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0,localhost,127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=['0.0.0.0','localhost','127.0.0.1']
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=['0.0.0.0', 'localhost', '127.0.0.1']
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=0.0.0.0
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
DJANGO_SECRET_KEY=django-insecure-n^xvyde5bhrcpk))wj!z4+pczy+i&*6d97pe&)8_2_5+q5gl0=
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DATABASE_URL=postgres://admin:admin@db:5432/links
|
|
||||||
DATABASE_NAME=links
|
|
||||||
DATABASE_USER=admin
|
|
||||||
DATABASE_PASSWORD=admin
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_HOST=127.0.0.1
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
REDIS_HOST=redis
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_DB=0
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
|
|
||||||
NEXT_PUBLIC_API_URL=http://127.0.0.1:8000
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key-here-change-this-in-production
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Медиа файлы
|
|
||||||
MEDIA_URL=/storage/
|
|
||||||
MEDIA_ROOT=/app/storage
|
|
||||||
|
|
||||||
# Статические файлы
|
|
||||||
STATIC_URL=/static/
|
|
||||||
STATIC_ROOT=/app/staticfiles
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key-here-change-this-in-production
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Медиа файлы
|
|
||||||
MEDIA_URL=/storage/
|
|
||||||
MEDIA_ROOT=/app/storage
|
|
||||||
|
|
||||||
# Статические файлы
|
|
||||||
STATIC_URL=/static/
|
|
||||||
STATIC_ROOT=/app/staticfiles
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-k8m2n9p4q7w5x1z3c6v8b0n5m8k3j6h9g4f7d2s5a8q1w4e7r0t3y6u9i2o5p8
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Медиа файлы
|
|
||||||
MEDIA_URL=/storage/
|
|
||||||
MEDIA_ROOT=/app/storage
|
|
||||||
|
|
||||||
# Статические файлы
|
|
||||||
STATIC_URL=/static/
|
|
||||||
STATIC_ROOT=/app/staticfiles
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-your-secret-key-here-change-this-in-production
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-k8m2n9p4q7w5x1z3c6v8b0n5m8k3j6h9g4f7d2s5a8q1w4e7r0t3y6u9i2o5p8
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-k8m2n9p4q7w5x1z3c6v8b0n5m8k3j6h9g4f7d2s5a8q1w4e7r0t3y6u9i2o5p8
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-your-secret-key-here-change-this-in-production
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-k8m2n9p4q7w5x1z3c6v8b0n5m8k3j6h9g4f7d2s5a8q1w4e7r0t3y6u9i2o5p8
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0,web,frontend
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Django настройки
|
|
||||||
DJANGO_SECRET_KEY=django-insecure-k8m2n9p4q7w5x1z3c6v8b0n5m8k3j6h9g4f7d2s5a8q1w4e7r0t3y6u9i2o5p8
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0,web,frontend
|
|
||||||
|
|
||||||
# База данных PostgreSQL
|
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
# Frontend настройки
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# Переменные окружения
|
|
||||||
|
|
||||||
Скопируйте `.env.example` в `.env` и настройте следующие переменные:
|
|
||||||
|
|
||||||
## Django настройки
|
|
||||||
- `DJANGO_SECRET_KEY` - Секретный ключ Django (обязательно изменить в продакшене)
|
|
||||||
- `DJANGO_DEBUG` - Режим отладки (True/False)
|
|
||||||
- `DJANGO_ALLOWED_HOSTS` - Разрешенные хосты (разделенные запятыми)
|
|
||||||
|
|
||||||
## База данных PostgreSQL
|
|
||||||
- `DATABASE_ENGINE` - Движок базы данных (django.db.backends.postgresql)
|
|
||||||
- `DATABASE_NAME` - Название базы данных
|
|
||||||
- `DATABASE_USER` - Пользователь базы данных
|
|
||||||
- `DATABASE_PASSWORD` - Пароль базы данных
|
|
||||||
- `DATABASE_HOST` - Хост базы данных (db для Docker)
|
|
||||||
- `DATABASE_PORT` - Порт базы данных (5432)
|
|
||||||
|
|
||||||
## PostgreSQL настройки для контейнера
|
|
||||||
- `POSTGRES_DB` - Название БД для создания в контейнере
|
|
||||||
- `POSTGRES_USER` - Пользователь БД для создания в контейнере
|
|
||||||
- `POSTGRES_PASSWORD` - Пароль пользователя БД в контейнере
|
|
||||||
|
|
||||||
## Frontend настройки
|
|
||||||
- `NEXT_PUBLIC_API_URL` - URL API для frontend (http://localhost:8000)
|
|
||||||
|
|
||||||
## Команды для запуска
|
|
||||||
|
|
||||||
### Подготовка
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
# Отредактируйте .env файл при необходимости
|
|
||||||
```
|
|
||||||
|
|
||||||
### Запуск всех сервисов
|
|
||||||
```bash
|
|
||||||
make up # или docker-compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Применение миграций
|
|
||||||
```bash
|
|
||||||
make migrate # или docker-compose exec web python manage.py migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
### Остановка сервисов
|
|
||||||
```bash
|
|
||||||
make down # или docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Запуск тестов
|
|
||||||
```bash
|
|
||||||
make test # или docker-compose exec web pytest --maxfail=1 --disable-warnings -q
|
|
||||||
```
|
|
||||||
|
|
||||||
## Доступ к сервисам
|
|
||||||
|
|
||||||
- **Frontend**: http://localhost:3000
|
|
||||||
- **Backend API**: http://localhost:8000/api/
|
|
||||||
- **Django Admin**: http://localhost:8000/admin/
|
|
||||||
- **PostgreSQL**: localhost:5432
|
|
||||||
|
|
||||||
## Структура проекта
|
|
||||||
|
|
||||||
- `backend/` - Django приложение
|
|
||||||
- `frontend/linktree-frontend/` - Next.js приложение
|
|
||||||
- `.env` - Переменные окружения (не включается в git)
|
|
||||||
- `.env.example` - Пример переменных окружения
|
|
||||||
- `docker-compose.yml` - Конфигурация Docker Compose
|
|
||||||
- `Makefile` - Команды для удобного управления
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# Переменные окружения
|
|
||||||
|
|
||||||
Скопируйте `.env.example` в `.env` и настройте следующие переменные:
|
|
||||||
|
|
||||||
## Django настройки
|
|
||||||
- `DJANGO_SECRET_KEY` - Секретный ключ Django (обязательно изменить в продакшене)
|
|
||||||
- `DJANGO_DEBUG` - Режим отладки (True/False)
|
|
||||||
- `DJANGO_ALLOWED_HOSTS` - Разрешенные хосты (разделенные запятыми)
|
|
||||||
|
|
||||||
## База данных PostgreSQL
|
|
||||||
- `DATABASE_ENGINE` - Движок базы данных (django.db.backends.postgresql)
|
|
||||||
- `DATABASE_NAME` - Название базы данных
|
|
||||||
- `DATABASE_USER` - Пользователь базы данных
|
|
||||||
- `DATABASE_PASSWORD` - Пароль базы данных
|
|
||||||
- `DATABASE_HOST` - Хост базы данных (db для Docker)
|
|
||||||
- `DATABASE_PORT` - Порт базы данных (5432)
|
|
||||||
|
|
||||||
## PostgreSQL настройки для контейнера
|
|
||||||
- `POSTGRES_DB` - Название БД для создания в контейнере
|
|
||||||
- `POSTGRES_USER` - Пользователь БД для создания в контейнере
|
|
||||||
- `POSTGRES_PASSWORD` - Пароль пользователя БД в контейнере
|
|
||||||
|
|
||||||
## Frontend настройки
|
|
||||||
- `NEXT_PUBLIC_API_URL` - URL API для frontend (http://localhost:8000)
|
|
||||||
|
|
||||||
## Команды для запуска
|
|
||||||
|
|
||||||
### Подготовка
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
# Отредактируйте .env файл при необходимости
|
|
||||||
```
|
|
||||||
|
|
||||||
### Запуск всех сервисов
|
|
||||||
```bash
|
|
||||||
make up # или docker-compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Применение миграций
|
|
||||||
```bash
|
|
||||||
make migrate # или docker-compose exec web python manage.py migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
### Остановка сервисов
|
|
||||||
```bash
|
|
||||||
make down # или docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Запуск тестов
|
|
||||||
```bash
|
|
||||||
make test # или docker-compose exec web pytest --maxfail=1 --disable-warnings -q
|
|
||||||
```
|
|
||||||
|
|
||||||
## Доступ к сервисам
|
|
||||||
|
|
||||||
- **Frontend**: http://localhost:3000
|
|
||||||
- **Backend API**: http://localhost:8000/api/
|
|
||||||
- **Django Admin**: http://localhost:8000/admin/
|
|
||||||
- **PostgreSQL**: localhost:5432
|
|
||||||
|
|
||||||
## Структура проекта
|
|
||||||
|
|
||||||
- `backend/` - Django приложение
|
|
||||||
- `frontend/linktree-frontend/` - Next.js приложение
|
|
||||||
- `.env` - Переменные окружения (не включается в git)
|
|
||||||
- `.env.example` - Пример переменных окружения
|
|
||||||
- `docker-compose.yml` - Конфигурация Docker Compose
|
|
||||||
- `Makefile` - Команды для удобного управления
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
# Решение проблем со статикой и API
|
|
||||||
|
|
||||||
## Исправленные проблемы
|
|
||||||
|
|
||||||
### ✅ Статические файлы Django
|
|
||||||
**Проблема**: Статические файлы Django REST Framework не загружались (404 ошибки)
|
|
||||||
|
|
||||||
**Решение**:
|
|
||||||
1. Добавлен WhiteNoise middleware в `settings.py`:
|
|
||||||
```python
|
|
||||||
MIDDLEWARE = [
|
|
||||||
"corsheaders.middleware.CorsMiddleware",
|
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware', # Добавлено
|
|
||||||
# ... остальные middleware
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Настроено хранилище статических файлов:
|
|
||||||
```python
|
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Создан `entrypoint.sh` для сборки статики при запуске:
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
echo "Collecting static files..."
|
|
||||||
python3 manage.py collectstatic --noinput --clear
|
|
||||||
|
|
||||||
echo "Applying database migrations..."
|
|
||||||
python3 manage.py migrate --noinput
|
|
||||||
|
|
||||||
echo "Starting server..."
|
|
||||||
exec gunicorn backend.wsgi:application --bind 0.0.0.0:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Обновлен `Dockerfile` для использования entrypoint
|
|
||||||
|
|
||||||
### ✅ Автоматические миграции
|
|
||||||
Теперь миграции применяются автоматически при запуске контейнера
|
|
||||||
|
|
||||||
### ⚠️ Frontend API подключение
|
|
||||||
**Проблема**: Frontend не может подключиться к backend API в Docker среде
|
|
||||||
|
|
||||||
**Частичное решение**:
|
|
||||||
- Обновлена конфигурация Next.js для использования `web:8000` внутри Docker
|
|
||||||
- API прокси работает с редиректами
|
|
||||||
|
|
||||||
## Результат
|
|
||||||
|
|
||||||
### Работающие сервисы:
|
|
||||||
- ✅ **Backend**: http://localhost:8000
|
|
||||||
- ✅ **Backend API**: http://localhost:8000/api/
|
|
||||||
- ✅ **Статические файлы**: http://localhost:8000/static/*
|
|
||||||
- ✅ **Django Admin**: http://localhost:8000/admin/
|
|
||||||
- ✅ **Frontend**: http://localhost:3000
|
|
||||||
- ✅ **PostgreSQL**: localhost:5432
|
|
||||||
|
|
||||||
### Команды для запуска:
|
|
||||||
```bash
|
|
||||||
# Запуск всех сервисов
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# Проверка статуса
|
|
||||||
docker-compose ps
|
|
||||||
|
|
||||||
# Просмотр логов
|
|
||||||
docker-compose logs web
|
|
||||||
docker-compose logs frontend
|
|
||||||
|
|
||||||
# Остановка
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Переменные окружения (в .env):
|
|
||||||
```env
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Проверка работы
|
|
||||||
|
|
||||||
### Backend статика:
|
|
||||||
```bash
|
|
||||||
curl -I http://localhost:8000/static/rest_framework/css/bootstrap.min.css
|
|
||||||
# Должен вернуть 200 OK
|
|
||||||
```
|
|
||||||
|
|
||||||
### API endpoints:
|
|
||||||
```bash
|
|
||||||
curl -s http://localhost:8000/api/ | jq
|
|
||||||
# Должен вернуть JSON с endpoints
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend:
|
|
||||||
```bash
|
|
||||||
curl -I http://localhost:3000
|
|
||||||
# Должен вернуть 200 OK
|
|
||||||
```
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
# Решение проблем со статикой и API
|
|
||||||
|
|
||||||
## Исправленные проблемы
|
|
||||||
|
|
||||||
### ✅ Статические файлы Django
|
|
||||||
**Проблема**: Статические файлы Django REST Framework не загружались (404 ошибки)
|
|
||||||
|
|
||||||
**Решение**:
|
|
||||||
1. Добавлен WhiteNoise middleware в `settings.py`:
|
|
||||||
```python
|
|
||||||
MIDDLEWARE = [
|
|
||||||
"corsheaders.middleware.CorsMiddleware",
|
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware', # Добавлено
|
|
||||||
# ... остальные middleware
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Настроено хранилище статических файлов:
|
|
||||||
```python
|
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Создан `entrypoint.sh` для сборки статики при запуске:
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
echo "Collecting static files..."
|
|
||||||
python3 manage.py collectstatic --noinput --clear
|
|
||||||
|
|
||||||
echo "Applying database migrations..."
|
|
||||||
python3 manage.py migrate --noinput
|
|
||||||
|
|
||||||
echo "Starting server..."
|
|
||||||
exec gunicorn backend.wsgi:application --bind 0.0.0.0:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Обновлен `Dockerfile` для использования entrypoint
|
|
||||||
|
|
||||||
### ✅ Автоматические миграции
|
|
||||||
Теперь миграции применяются автоматически при запуске контейнера
|
|
||||||
|
|
||||||
### ⚠️ Frontend API подключение
|
|
||||||
**Проблема**: Frontend не может подключиться к backend API в Docker среде
|
|
||||||
|
|
||||||
**Частичное решение**:
|
|
||||||
- Обновлена конфигурация Next.js для использования `web:8000` внутри Docker
|
|
||||||
- API прокси работает с редиректами
|
|
||||||
|
|
||||||
## Результат
|
|
||||||
|
|
||||||
### Работающие сервисы:
|
|
||||||
- ✅ **Backend**: http://localhost:8000
|
|
||||||
- ✅ **Backend API**: http://localhost:8000/api/
|
|
||||||
- ✅ **Статические файлы**: http://localhost:8000/static/*
|
|
||||||
- ✅ **Django Admin**: http://localhost:8000/admin/
|
|
||||||
- ✅ **Frontend**: http://localhost:3000
|
|
||||||
- ✅ **PostgreSQL**: localhost:5432
|
|
||||||
|
|
||||||
### Команды для запуска:
|
|
||||||
```bash
|
|
||||||
# Запуск всех сервисов
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# Проверка статуса
|
|
||||||
docker-compose ps
|
|
||||||
|
|
||||||
# Просмотр логов
|
|
||||||
docker-compose logs web
|
|
||||||
docker-compose logs frontend
|
|
||||||
|
|
||||||
# Остановка
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Переменные окружения (в .env):
|
|
||||||
```env
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
|
||||||
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
POSTGRES_DB=links_db
|
|
||||||
POSTGRES_USER=links_user
|
|
||||||
POSTGRES_PASSWORD=links_password
|
|
||||||
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Проверка работы
|
|
||||||
|
|
||||||
### Backend статика:
|
|
||||||
```bash
|
|
||||||
curl -I http://localhost:8000/static/rest_framework/css/bootstrap.min.css
|
|
||||||
# Должен вернуть 200 OK
|
|
||||||
```
|
|
||||||
|
|
||||||
### API endpoints:
|
|
||||||
```bash
|
|
||||||
curl -s http://localhost:8000/api/ | jq
|
|
||||||
# Должен вернуть JSON с endpoints
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend:
|
|
||||||
```bash
|
|
||||||
curl -I http://localhost:3000
|
|
||||||
# Должен вернуть 200 OK
|
|
||||||
```
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# Клон Linktr.ee на Django + Next.js
|
|
||||||
|
|
||||||
Полнофункциональное приложение для создания персональных страниц с ссылками, похожее на Linktr.ee.
|
|
||||||
|
|
||||||
## Технологии
|
|
||||||
|
|
||||||
**Backend:**
|
|
||||||
- Django 5.2 + Django REST Framework
|
|
||||||
- PostgreSQL
|
|
||||||
- JWT Authentication
|
|
||||||
- Django CORS Headers
|
|
||||||
- Gunicorn
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
- Next.js 15.3.1
|
|
||||||
- React 19
|
|
||||||
- TypeScript
|
|
||||||
- Tailwind CSS
|
|
||||||
- Axios для API запросов
|
|
||||||
|
|
||||||
## Быстрый старт
|
|
||||||
|
|
||||||
### 1. Подготовка окружения
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Клонируйте репозиторий
|
|
||||||
git clone <url>
|
|
||||||
cd links
|
|
||||||
|
|
||||||
# Скопируйте переменные окружения
|
|
||||||
cp .env.example .env
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Запуск проекта
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Запуск всех сервисов
|
|
||||||
make up
|
|
||||||
|
|
||||||
# Применение миграций базы данных
|
|
||||||
make migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Доступ к приложению
|
|
||||||
|
|
||||||
- **Frontend**: http://localhost:3000
|
|
||||||
- **Backend API**: http://localhost:8000/api/
|
|
||||||
- **Django Admin**: http://localhost:8000/admin/
|
|
||||||
|
|
||||||
## Команды
|
|
||||||
|
|
||||||
- `make up` - Запуск всех сервисов
|
|
||||||
- `make down` - Остановка всех сервисов
|
|
||||||
- `make migrate` - Применение миграций
|
|
||||||
- `make test` - Запуск тестов
|
|
||||||
|
|
||||||
## Структура проекта
|
|
||||||
|
|
||||||
```
|
|
||||||
├── backend/ # Django приложение
|
|
||||||
│ ├── api/ # API endpoints
|
|
||||||
│ ├── users/ # Пользователи
|
|
||||||
│ ├── links/ # Ссылки и группы
|
|
||||||
│ ├── customization/ # Настройки дизайна
|
|
||||||
│ └── backend/ # Настройки Django
|
|
||||||
├── frontend/linktree-frontend/ # Next.js приложение
|
|
||||||
├── docker-compose.yml # Docker Compose конфигурация
|
|
||||||
├── .env.example # Пример переменных окружения
|
|
||||||
└── DEPLOYMENT.md # Подробные инструкции по развертыванию
|
|
||||||
```
|
|
||||||
|
|
||||||
## Переменные окружения
|
|
||||||
|
|
||||||
Основные переменные в `.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# Django
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost
|
|
||||||
|
|
||||||
# PostgreSQL
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробнее в `DEPLOYMENT.md`.
|
|
||||||
|
|
||||||
## Особенности
|
|
||||||
|
|
||||||
- 🔐 JWT аутентификация
|
|
||||||
- 👤 Кастомизация профилей
|
|
||||||
- 📱 Адаптивный дизайн
|
|
||||||
- 🔗 Управление ссылками и группами
|
|
||||||
- 🎨 Настройка внешнего вида
|
|
||||||
- 📊 API для всех операций
|
|
||||||
|
|
||||||
## Разработка
|
|
||||||
|
|
||||||
Проект настроен для разработки в Docker-контейнерах с горячей перезагрузкой.
|
|
||||||
|
|
||||||
Для разработки без Docker смотрите инструкции в `DEPLOYMENT.md`.
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# Клон Linktr.ee на Django + Next.js
|
|
||||||
|
|
||||||
Полнофункциональное приложение для создания персональных страниц с ссылками, похожее на Linktr.ee.
|
|
||||||
|
|
||||||
## Технологии
|
|
||||||
|
|
||||||
**Backend:**
|
|
||||||
- Django 5.2 + Django REST Framework
|
|
||||||
- PostgreSQL
|
|
||||||
- JWT Authentication
|
|
||||||
- Django CORS Headers
|
|
||||||
- Gunicorn
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
- Next.js 15.3.1
|
|
||||||
- React 19
|
|
||||||
- TypeScript
|
|
||||||
- Tailwind CSS
|
|
||||||
- Axios для API запросов
|
|
||||||
|
|
||||||
## Быстрый старт
|
|
||||||
|
|
||||||
### 1. Подготовка окружения
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Клонируйте репозиторий
|
|
||||||
git clone <url>
|
|
||||||
cd links
|
|
||||||
|
|
||||||
# Скопируйте переменные окружения
|
|
||||||
cp .env.example .env
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Запуск проекта
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Запуск всех сервисов
|
|
||||||
make up
|
|
||||||
|
|
||||||
# Применение миграций базы данных
|
|
||||||
make migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Доступ к приложению
|
|
||||||
|
|
||||||
- **Frontend**: http://localhost:3000
|
|
||||||
- **Backend API**: http://localhost:8000/api/
|
|
||||||
- **Django Admin**: http://localhost:8000/admin/
|
|
||||||
|
|
||||||
## Команды
|
|
||||||
|
|
||||||
- `make up` - Запуск всех сервисов
|
|
||||||
- `make down` - Остановка всех сервисов
|
|
||||||
- `make migrate` - Применение миграций
|
|
||||||
- `make test` - Запуск тестов
|
|
||||||
|
|
||||||
## Структура проекта
|
|
||||||
|
|
||||||
```
|
|
||||||
├── backend/ # Django приложение
|
|
||||||
│ ├── api/ # API endpoints
|
|
||||||
│ ├── users/ # Пользователи
|
|
||||||
│ ├── links/ # Ссылки и группы
|
|
||||||
│ ├── customization/ # Настройки дизайна
|
|
||||||
│ └── backend/ # Настройки Django
|
|
||||||
├── frontend/linktree-frontend/ # Next.js приложение
|
|
||||||
├── docker-compose.yml # Docker Compose конфигурация
|
|
||||||
├── .env.example # Пример переменных окружения
|
|
||||||
└── DEPLOYMENT.md # Подробные инструкции по развертыванию
|
|
||||||
```
|
|
||||||
|
|
||||||
## Переменные окружения
|
|
||||||
|
|
||||||
Основные переменные в `.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# Django
|
|
||||||
DJANGO_SECRET_KEY=your-secret-key
|
|
||||||
DJANGO_DEBUG=True
|
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost
|
|
||||||
|
|
||||||
# PostgreSQL
|
|
||||||
DATABASE_NAME=links_db
|
|
||||||
DATABASE_USER=links_user
|
|
||||||
DATABASE_PASSWORD=links_password
|
|
||||||
DATABASE_HOST=db
|
|
||||||
DATABASE_PORT=5432
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробнее в `DEPLOYMENT.md`.
|
|
||||||
|
|
||||||
## Особенности
|
|
||||||
|
|
||||||
- 🔐 JWT аутентификация
|
|
||||||
- 👤 Кастомизация профилей
|
|
||||||
- 📱 Адаптивный дизайн
|
|
||||||
- 🔗 Управление ссылками и группами
|
|
||||||
- 🎨 Настройка внешнего вида
|
|
||||||
- 📊 API для всех операций
|
|
||||||
|
|
||||||
## Разработка
|
|
||||||
|
|
||||||
Проект настроен для разработки в Docker-контейнерах с горячей перезагрузкой.
|
|
||||||
|
|
||||||
Для разработки без Docker смотрите инструкции в `DEPLOYMENT.md`.
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY ../requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput --clear
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Сбор статических файлов
|
|
||||||
RUN python manage.py collectstatic --noinput --clear
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["gunicorn", "backend.wsgi:application", "--bind", "0.0.0.0:8000"]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Копируем entrypoint скрипт
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
|
||||||
RUN chmod +x /entrypoint.sh
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Установка системных зависимостей
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Копирование и установка requirements
|
|
||||||
COPY requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Копирование кода приложения
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Создание директорий для статики и медиа
|
|
||||||
RUN mkdir -p staticfiles storage
|
|
||||||
|
|
||||||
# Копируем entrypoint скрипт
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
|
||||||
RUN chmod +x /entrypoint.sh
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
@admin.register(Link)
|
|
||||||
class LinkAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('title', 'url', 'owner', 'group', 'order')
|
|
||||||
list_filter = ('owner', 'group')
|
|
||||||
search_fields = ('title', 'url')
|
|
||||||
|
|
||||||
@admin.register(LinkGroup)
|
|
||||||
class LinkGroupAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'owner', 'order')
|
|
||||||
list_filter = ('owner',)
|
|
||||||
search_fields = ('name',)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# api/admin.py
|
|
||||||
from django.contrib import admin
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
@admin.register(Link)
|
|
||||||
class LinkAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('title', 'url', 'owner', 'group', 'order')
|
|
||||||
list_filter = ('owner', 'group')
|
|
||||||
search_fields = ('title', 'url')
|
|
||||||
|
|
||||||
@admin.register(LinkGroup)
|
|
||||||
class LinkGroupAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'owner', 'order')
|
|
||||||
list_filter = ('owner',)
|
|
||||||
search_fields = ('name',
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# api/admin.py
|
|
||||||
from django.contrib import admin
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
@admin.register(Link)
|
|
||||||
class LinkAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('title', 'url', 'owner', 'group', 'order')
|
|
||||||
list_filter = ('owner', 'group')
|
|
||||||
search_fields = ('title', 'url')
|
|
||||||
|
|
||||||
@admin.register(LinkGroup)
|
|
||||||
class LinkGroupAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'owner', 'order')
|
|
||||||
list_filter = ('owner',)
|
|
||||||
search_fields = ('name',)
|
|
||||||
ordering = ('owner', 'order')
|
|
||||||
prepopulated_fields = {'slug': ('name',)}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# api/admin.py
|
|
||||||
from django.contrib import admin
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
@admin.register(Link)
|
|
||||||
class LinkAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('title', 'url', 'owner', 'group', 'order')
|
|
||||||
list_filter = ('owner', 'group')
|
|
||||||
search_fields = ('title', 'url')
|
|
||||||
|
|
||||||
@admin.register(LinkGroup)
|
|
||||||
class LinkGroupAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'owner', 'order')
|
|
||||||
list_filter = ('owner',)
|
|
||||||
search_fields = ('name',)
|
|
||||||
ordering = ('owner', 'order')
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# api/models.py
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='groups')
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='links')
|
|
||||||
group = models.ForeignKey(LinkGroup, on_delete=models.SET_NULL, null=True, blank=True, related_name='links')
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# api/models.py
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='link_groups' # было 'groups', теперь уникальное имя
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links' # оставляем 'links' — у User нет такого поля
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True, blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# api/models.py
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='link_groups' # было 'groups', теперь уникальное имя
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links' # оставляем 'links' — у User нет такого поля
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True, blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# api/models.py
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='link_groups' # было 'groups', теперь уникальное имя
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links' # оставляем 'links' — у User нет такого поля
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True, blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='link_groups' # было 'groups', теперь уникальное имя
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links' # оставляем 'links' — у User нет такого поля
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True, blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups' # теперь уникально
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links' # оставляем 'links' — у User нет такого поля
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True, blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='link_groups'
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
description = models.TextField(blank=True, null=True)
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
description = models.TextField(blank=True, null=True)
|
|
||||||
icon = models.ImageField(
|
|
||||||
upload_to='link_groups/',
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text='Иконка группы ссылок'
|
|
||||||
)
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups' # уникальное имя, чтобы не конфликтовать с links app
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
description = models.TextField(blank=True, null=True)
|
|
||||||
icon = models.ImageField(
|
|
||||||
upload_to='link_groups/',
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text='Иконка группы ссылок'
|
|
||||||
)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
is_public = models.BooleanField(default=False, help_text='Публичная группа ссылок')
|
|
||||||
is_favorite = models.BooleanField(default=False, help_text='Избранная группа ссылок')
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} - {self.name}"
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.URLField(blank=True, null=True)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# backend/api/models.py
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
class LinkGroup(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='api_link_groups'
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=100)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
description = models.TextField(blank=True, null=True)
|
|
||||||
icon = models.ImageField(
|
|
||||||
upload_to='link_groups/',
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text='Иконка группы ссылок'
|
|
||||||
)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
|
||||||
is_public = models.BooleanField(default=False)
|
|
||||||
is_favorite = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.owner.username} — {self.name}"
|
|
||||||
|
|
||||||
|
|
||||||
class Link(models.Model):
|
|
||||||
owner = models.ForeignKey(
|
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
group = models.ForeignKey(
|
|
||||||
LinkGroup,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='links'
|
|
||||||
)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
url = models.URLField()
|
|
||||||
icon = models.ImageField(
|
|
||||||
upload_to='links/',
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text='Иконка для этой ссылки'
|
|
||||||
)
|
|
||||||
order = models.PositiveIntegerField(default=0)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ('id', 'name', 'order')
|
|
||||||
read_only_fields = ('id',)
|
|
||||||
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ('id', 'title', 'url', 'icon', 'order', 'group')
|
|
||||||
read_only_fields = ('id', 'owner')
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ('id', 'name', 'order')
|
|
||||||
read_only_fields = ('id',)
|
|
||||||
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ('id', 'title', 'url', 'icon', 'order', 'group')
|
|
||||||
read_only_fields = ('id', 'owner')
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ('id', 'name', 'order')
|
|
||||||
read_only_fields = ('id',)
|
|
||||||
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ('id', 'title', 'url', 'icon', 'order', 'group')
|
|
||||||
read_only_fields = ('id', 'owner')
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'first_name', 'last_name']
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
# related_name у вас в модели LinkGroup.owner = 'api_link_groups',
|
|
||||||
# а у модели Link.group = 'links', так что у группы obj.links — это QuerySet ссылок
|
|
||||||
links = LinkSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'order', 'links']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'first_name', 'last_name']
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
# related_name у вас в модели LinkGroup.owner = 'api_link_groups',
|
|
||||||
# а у модели Link.group = 'links', так что у группы obj.links — это QuerySet ссылок
|
|
||||||
links = LinkSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'order', 'links']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name']
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
# related_name у вас в модели LinkGroup.owner = 'api_link_groups',
|
|
||||||
# а у модели Link.group = 'links', так что у группы obj.links — это QuerySet ссылок
|
|
||||||
links = LinkSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'order', 'links']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'user_permissions']
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
# related_name у вас в модели LinkGroup.owner = 'api_link_groups',
|
|
||||||
# а у модели Link.group = 'links', так что у группы obj.links — это QuerySet ссылок
|
|
||||||
links = LinkSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'order', 'links']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'user_permissions', 'last_login', 'date_joined']
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
# related_name у вас в модели LinkGroup.owner = 'api_link_groups',
|
|
||||||
# а у модели Link.group = 'links', так что у группы obj.links — это QuerySet ссылок
|
|
||||||
links = LinkSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'order', 'links']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
owner = serializers.ReadOnlyField(source='owner.username')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = [
|
|
||||||
'id',
|
|
||||||
'name',
|
|
||||||
'description',
|
|
||||||
'icon',
|
|
||||||
'owner',
|
|
||||||
'created_at',
|
|
||||||
]
|
|
||||||
read_only_fields = ['id', 'owner', 'created_at']
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ('username', 'email', 'password')
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = User(
|
|
||||||
username=validated_data['username'],
|
|
||||||
email=validated_data.get('email', '')
|
|
||||||
)
|
|
||||||
user.set_password(validated_data['password'])
|
|
||||||
user.save()
|
|
||||||
return user
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
owner = serializers.ReadOnlyField(source='owner.username')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = [
|
|
||||||
'id',
|
|
||||||
'name',
|
|
||||||
'description',
|
|
||||||
'icon',
|
|
||||||
'owner',
|
|
||||||
'created_at',
|
|
||||||
]
|
|
||||||
read_only_fields = ['id', 'owner', 'created_at']
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsSerializer(serializers.Serializer):
|
|
||||||
username = serializers.CharField()
|
|
||||||
groups = LinkGroupSerializer(many=True)
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password2 = serializers.CharField(write_only=True)
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ['username', 'email', 'first_name', 'last_name', 'password', 'password2']
|
|
||||||
extra_kwargs = {'password': {'write_only': True}}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
if attrs['password'] != attrs.pop('password2'):
|
|
||||||
raise serializers.ValidationError("Пароли не совпадают")
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
return User.objects.create_user(**validated_data)
|
|
||||||
|
|
||||||
|
|
||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'order', 'group']
|
|
||||||
|
|
||||||
# сериализатор для групп со вложенными ссылками
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
owner = serializers.ReadOnlyField(source='owner.username')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = [
|
|
||||||
'id',
|
|
||||||
'name',
|
|
||||||
'description',
|
|
||||||
'icon',
|
|
||||||
'owner',
|
|
||||||
'created_at',
|
|
||||||
]
|
|
||||||
read_only_fields = ['id', 'owner', 'created_at']
|
|
||||||
|
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
# поля, которые хотите отдавать на фронт:
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsSerializer(serializers.Serializer):
|
|
||||||
username = serializers.CharField()
|
|
||||||
groups = LinkGroupSerializer(many=True)
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# api/serializers.py
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from django.conf import settings
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterSerializer(serializers.ModelSerializer):
|
|
||||||
password2 = serializers.CharField(write_only=True)
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ['username', 'email', 'first_name', 'last_name', 'password', 'password2']
|
|
||||||
extra_kwargs = {'password': {'write_only': True}}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
if attrs['password'] != attrs.pop('password2'):
|
|
||||||
raise serializers.ValidationError("Пароли не совпадают")
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
return User.objects.create_user(**validated_data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# сериализатор для ссылок
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = ['id', 'username', 'email', 'full_name', 'bio', 'avatar', 'last_login', 'date_joined']
|
|
||||||
|
|
||||||
|
|
||||||
class LinkGroupSerializer(serializers.ModelSerializer):
|
|
||||||
icon = serializers.ImageField(required=False, allow_null=True)
|
|
||||||
class Meta:
|
|
||||||
model = LinkGroup
|
|
||||||
fields = ['id', 'name', 'description', 'icon', 'order', 'is_public', 'is_favorite',
|
|
||||||
'created_at', 'updated_at']
|
|
||||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
||||||
|
|
||||||
|
|
||||||
class LinkSerializer(serializers.ModelSerializer):
|
|
||||||
icon = serializers.ImageField(required=False, allow_null=True)
|
|
||||||
class Meta:
|
|
||||||
model = Link
|
|
||||||
fields = ['id', 'title', 'url', 'icon', 'group', 'order']
|
|
||||||
read_only_fields = ['id']
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# api/urls.py
|
|
||||||
from django.urls import path, include
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from .views import (
|
|
||||||
RegisterView, LoginView, LinkViewSet,
|
|
||||||
LinkGroupViewSet, UserLinksListView
|
|
||||||
)
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register(r'links', LinkViewSet, basename='links')
|
|
||||||
router.register(r'groups', LinkGroupViewSet, basename='groups')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth-register'),
|
|
||||||
path('auth/login/', LoginView.as_view(), name='auth-login'),
|
|
||||||
path('users/<str:username>/links/', UserLinksListView.as_view(), name='user-links'),
|
|
||||||
path('', include(router.urls)),
|
|
||||||
]
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# api/urls.py
|
|
||||||
from django.urls import path, include
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from .views import RegisterView, LoginView, LinkViewSet, LinkGroupViewSet, UserLinksListView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register(r'links', LinkViewSet, basename='links')
|
|
||||||
router.register(r'groups', LinkGroupViewSet, basename='groups')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth-register'),
|
|
||||||
path('auth/login/', LoginView.as_view(), name='auth-login'),
|
|
||||||
path('users/<str:username>/links/', UserLinksListView.as_view(), name='user-links'),
|
|
||||||
path('', include(router.urls)),
|
|
||||||
]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
UserLinksView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/links/', UserLinksView.as_view(), name='user-links'),
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/links/', UserLinksView.as_view(), name='user-links'),
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
path('swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
path('swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'api/swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'api/swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/register', RegisterView.as_view(), name='auth_register_no_slash'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/login', TokenObtainPairView.as_view(), name='token_obtain_pair_no_slash'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/refresh', TokenRefreshView.as_view(), name='token_refresh_no_slash'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('auth/user', UserProfileView.as_view(), name='user-profile-no-slash'),
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/register', RegisterView.as_view(), name='auth_register_no_slash'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/login', TokenObtainPairView.as_view(), name='token_obtain_pair_no_slash'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/refresh', TokenRefreshView.as_view(), name='token_refresh_no_slash'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('auth/user', UserProfileView.as_view(), name='user-profile-no-slash'),
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
class NoTrailingSlashRouter(DefaultRouter):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.trailing_slash = '/?'
|
|
||||||
|
|
||||||
router = NoTrailingSlashRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/register', RegisterView.as_view(), name='auth_register_no_slash'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/login', TokenObtainPairView.as_view(), name='token_obtain_pair_no_slash'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/refresh', TokenRefreshView.as_view(), name='token_refresh_no_slash'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('auth/user', UserProfileView.as_view(), name='user-profile-no-slash'),
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
||||||
from .views import (
|
|
||||||
RegisterView,
|
|
||||||
UserProfileView,
|
|
||||||
LinkViewSet,
|
|
||||||
LinkGroupViewSet,
|
|
||||||
PublicUserGroupsView
|
|
||||||
)
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
|
||||||
|
|
||||||
class NoTrailingSlashRouter(DefaultRouter):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.trailing_slash = '/?'
|
|
||||||
|
|
||||||
router = NoTrailingSlashRouter()
|
|
||||||
router.register('links', LinkViewSet, basename='link')
|
|
||||||
router.register('groups', LinkGroupViewSet, basename='group')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth_register'),
|
|
||||||
path('auth/register', RegisterView.as_view(), name='auth_register_no_slash'),
|
|
||||||
path('auth/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
|
|
||||||
path('auth/login', TokenObtainPairView.as_view(), name='token_obtain_pair_no_slash'),
|
|
||||||
path('auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
|
||||||
path('auth/refresh', TokenRefreshView.as_view(), name='token_refresh_no_slash'),
|
|
||||||
path('auth/user/', UserProfileView.as_view(), name='user-profile'), # ← новый
|
|
||||||
path('auth/user', UserProfileView.as_view(), name='user-profile-no-slash'),
|
|
||||||
path('users/<str:username>/public/',
|
|
||||||
PublicUserGroupsView.as_view(),
|
|
||||||
name='public-user-groups'
|
|
||||||
),
|
|
||||||
# схема OpenAPI
|
|
||||||
path('schema/', SpectacularAPIView.as_view(), name='schema'),
|
|
||||||
# Swagger UI, берёт шаблон из drf_spectacular_sidecar
|
|
||||||
path(
|
|
||||||
'swagger/',
|
|
||||||
SpectacularSwaggerView.as_view(url_name='schema'),
|
|
||||||
name='swagger-ui'
|
|
||||||
),
|
|
||||||
|
|
||||||
] + router.urls
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import (
|
|
||||||
RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
)
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return LinkGroup.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
# api/urls.py
|
|
||||||
from django.urls import path, include
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
from .views import (
|
|
||||||
RegisterView, LoginView, LinkViewSet,
|
|
||||||
LinkGroupViewSet, UserLinksListView
|
|
||||||
)
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
|
||||||
router.register(r'links', LinkViewSet, basename='links')
|
|
||||||
router.register(r'groups', LinkGroupViewSet, basename='groups')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('auth/register/', RegisterView.as_view(), name='auth-register'),
|
|
||||||
path('auth/login/', LoginView.as_view(), name='auth-login'),
|
|
||||||
path('users/<str:username>/links/', UserLinksListView.as_view(), name='user-links'),
|
|
||||||
path('', include(router.urls)),
|
|
||||||
]
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return LinkGroup.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return LinkGroup.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return LinkGroup.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
Возвращает публичную страницу пользователя:
|
|
||||||
{
|
|
||||||
"username": "...",
|
|
||||||
"groups": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "...",
|
|
||||||
"icon": "/storage/images/link_groups/1.png",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"title": "...",
|
|
||||||
"url": "...",
|
|
||||||
"icon": "/storage/images/links/5.png"
|
|
||||||
},
|
|
||||||
…
|
|
||||||
]
|
|
||||||
},
|
|
||||||
…
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
# достаём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
data = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
for grp in groups_qs:
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"icon": grp.icon.url if grp.icon else None,
|
|
||||||
"links": []
|
|
||||||
}
|
|
||||||
for ln in grp.links.all():
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"icon": ln.icon.url if ln.icon else None
|
|
||||||
})
|
|
||||||
data["groups"].append(grp_data)
|
|
||||||
return Response(data, status=status.HTTP_200_OK)
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions,status
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
Возвращает публичную страницу пользователя:
|
|
||||||
{
|
|
||||||
"username": "...",
|
|
||||||
"groups": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "...",
|
|
||||||
"icon": "/storage/images/link_groups/1.png",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"title": "...",
|
|
||||||
"url": "...",
|
|
||||||
"icon": "/storage/images/links/5.png"
|
|
||||||
},
|
|
||||||
…
|
|
||||||
]
|
|
||||||
},
|
|
||||||
…
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
# достаём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
data = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
for grp in groups_qs:
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"icon": grp.icon.url if grp.icon else None,
|
|
||||||
"links": []
|
|
||||||
}
|
|
||||||
for ln in grp.links.all():
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"icon": ln.icon.url if ln.icon else None
|
|
||||||
})
|
|
||||||
data["groups"].append(grp_data)
|
|
||||||
return Response(data, status=status.HTTP_200_OK)
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions,status
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
|
|
||||||
# Берём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
|
|
||||||
for grp in groups_qs:
|
|
||||||
# поле image у группы
|
|
||||||
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"image": grp_image_url,
|
|
||||||
"links": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
for ln in grp.links.all():
|
|
||||||
# поле image у отдельной ссылки
|
|
||||||
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"image": link_image_url,
|
|
||||||
})
|
|
||||||
|
|
||||||
result["groups"].append(grp_data)
|
|
||||||
|
|
||||||
return Response(result, status=status.HTTP_200_OK)
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions,status
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
|
|
||||||
# Берём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
|
|
||||||
for grp in groups_qs:
|
|
||||||
# поле image у группы
|
|
||||||
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"image": grp_image_url,
|
|
||||||
"links": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
for ln in grp.links.all():
|
|
||||||
# поле image у отдельной ссылки
|
|
||||||
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"image": link_image_url,
|
|
||||||
})
|
|
||||||
|
|
||||||
result["groups"].append(grp_data)
|
|
||||||
|
|
||||||
return Response(result, status=status.HTTP_200_OK)
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions,status
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
parameters=[
|
|
||||||
OpenApiParameter(
|
|
||||||
name='id',
|
|
||||||
type=int,
|
|
||||||
location=OpenApiParameter.PATH
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
|
|
||||||
# Берём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
|
|
||||||
for grp in groups_qs:
|
|
||||||
# поле image у группы
|
|
||||||
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"image": grp_image_url,
|
|
||||||
"links": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
for ln in grp.links.all():
|
|
||||||
# поле image у отдельной ссылки
|
|
||||||
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"image": link_image_url,
|
|
||||||
})
|
|
||||||
|
|
||||||
result["groups"].append(grp_data)
|
|
||||||
|
|
||||||
return Response(result, status=status.HTTP_200_OK)
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# api/views.py
|
|
||||||
from rest_framework import generics, viewsets, permissions,status
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
|
||||||
from .serializers import RegisterSerializer, LinkSerializer, LinkGroupSerializer
|
|
||||||
from .models import Link, LinkGroup
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from drf_spectacular.utils import extend_schema, OpenApiParameter
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
parameters=[
|
|
||||||
OpenApiParameter(
|
|
||||||
name='id',
|
|
||||||
type=int,
|
|
||||||
location=OpenApiParameter.PATH
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
class RegisterView(generics.CreateAPIView):
|
|
||||||
queryset = User.objects.all()
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
serializer_class = RegisterSerializer
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
class LinkGroupViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = LinkGroup.objects.all()
|
|
||||||
serializer_class = LinkGroupSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# возвращаем только группы текущего пользователя
|
|
||||||
return self.queryset.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
class LinkViewSet(viewsets.ModelViewSet):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Link.objects.filter(owner=self.request.user).order_by('order')
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.save(owner=self.request.user)
|
|
||||||
|
|
||||||
class UserLinksListView(generics.ListAPIView):
|
|
||||||
serializer_class = LinkSerializer
|
|
||||||
permission_classes = (permissions.AllowAny,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
username = self.kwargs['username']
|
|
||||||
return Link.objects.filter(owner__username=username).order_by('order')
|
|
||||||
|
|
||||||
|
|
||||||
from .serializers import UserSerializer # нужно завести сериализатор для пользователя
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
class UserProfileView(generics.RetrieveAPIView):
|
|
||||||
"""
|
|
||||||
Возвращает данные авторизованного пользователя.
|
|
||||||
GET /api/auth/user/
|
|
||||||
"""
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return self.request.user
|
|
||||||
|
|
||||||
|
|
||||||
class PublicUserGroupsView(APIView):
|
|
||||||
"""
|
|
||||||
GET /api/users/{username}/public/
|
|
||||||
"""
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get(self, request, username):
|
|
||||||
User = get_user_model()
|
|
||||||
user = get_object_or_404(User, username=username)
|
|
||||||
|
|
||||||
# Берём все группы пользователя вместе с их ссылками
|
|
||||||
groups_qs = LinkGroup.objects.filter(owner=user).prefetch_related('links')
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"username": user.username,
|
|
||||||
"groups": []
|
|
||||||
}
|
|
||||||
|
|
||||||
for grp in groups_qs:
|
|
||||||
# поле image у группы
|
|
||||||
grp_image_url = grp.image.url if getattr(grp, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data = {
|
|
||||||
"id": grp.id,
|
|
||||||
"name": grp.name,
|
|
||||||
"image": grp_image_url,
|
|
||||||
"links": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
for ln in grp.links.all():
|
|
||||||
# поле image у отдельной ссылки
|
|
||||||
link_image_url = ln.image.url if getattr(ln, 'image', None) else None
|
|
||||||
|
|
||||||
grp_data["links"].append({
|
|
||||||
"id": ln.id,
|
|
||||||
"title": ln.title,
|
|
||||||
"url": ln.url,
|
|
||||||
"image": link_image_url,
|
|
||||||
})
|
|
||||||
|
|
||||||
result["groups"].append(grp_data)
|
|
||||||
|
|
||||||
return Response(result, status=status.HTTP_200_OK)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user