mirror of
https://github.com/MarcZierle/photo-log-backend.git
synced 2025-04-04 11:54:38 +00:00
add phototags
This commit is contained in:
parent
e91e83df40
commit
d160bf3e7b
4
.gitignore
vendored
Normal file → Executable file
4
.gitignore
vendored
Normal file → Executable file
@ -1,2 +1,6 @@
|
||||
static/*
|
||||
./*/*pycache*/*
|
||||
**/__pycache__
|
||||
*/migrations/*
|
||||
env/
|
||||
static_bk/
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,38 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2021-10-27 11:22
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
api/photolog_generator.py
Normal file → Executable file
0
api/photolog_generator.py
Normal file → Executable file
0
api/photolog_layout.py
Normal file → Executable file
0
api/photolog_layout.py
Normal file → Executable file
@ -1,5 +1,11 @@
|
||||
from rest_framework import serializers
|
||||
from photo_log.models import PhotoGroup, Photo, PhotoLog
|
||||
from photo_log.models import PhotoGroup, Photo, PhotoLog, PhotoTag
|
||||
|
||||
|
||||
class PhotoTagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = PhotoTag
|
||||
fields = ('id', 'name', 'color')
|
||||
|
||||
|
||||
class PhotoGroupSerializer(serializers.ModelSerializer):
|
||||
@ -15,15 +21,17 @@ class PhotosSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class PhotoSerializer(serializers.ModelSerializer):
|
||||
tag = PhotoTagSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Photo
|
||||
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'intersections', 'original_image', 'cropped_image', 'ocr_text')
|
||||
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'intersections', 'original_image', 'cropped_image', 'ocr_text', 'tag')
|
||||
|
||||
|
||||
class PhotoUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Photo
|
||||
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'ocr_text')
|
||||
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'ocr_text', 'tag')
|
||||
|
||||
|
||||
class PhotoLogSerializer(serializers.ModelSerializer):
|
||||
|
@ -14,6 +14,9 @@ from .views import (
|
||||
UpdatePhotoLogAPIView,
|
||||
UpdatePhotoAPIView,
|
||||
GeneratePhotoLogAPIView,
|
||||
PhotoTagsAPIView,
|
||||
RetrieveUpdateDestroyPhotoTagAPIView,
|
||||
CreatePhotoTagAPIView,
|
||||
)
|
||||
|
||||
|
||||
@ -33,4 +36,7 @@ urlpatterns = [
|
||||
path('updatephotolog/<int:pk>/', UpdatePhotoLogAPIView.as_view()),
|
||||
path('updatephoto/<int:pk>/', UpdatePhotoAPIView.as_view()),
|
||||
path('generatephotolog/<int:pk>/', GeneratePhotoLogAPIView.as_view()),
|
||||
path('phototag/', CreatePhotoTagAPIView.as_view()),
|
||||
path('phototags/', PhotoTagsAPIView.as_view()),
|
||||
path('phototag/<int:pk>/', RetrieveUpdateDestroyPhotoTagAPIView.as_view()),
|
||||
]
|
||||
|
23
api/views.py
23
api/views.py
@ -1,7 +1,7 @@
|
||||
from rest_framework import generics, views, status
|
||||
from rest_framework.response import Response
|
||||
from django.shortcuts import get_list_or_404
|
||||
from photo_log.models import PhotoGroup, Photo, PhotoLog
|
||||
from photo_log.models import PhotoGroup, Photo, PhotoLog, PhotoTag
|
||||
from .serializers import (
|
||||
PhotoGroupSerializer,
|
||||
PhotosSerializer,
|
||||
@ -9,6 +9,7 @@ from .serializers import (
|
||||
PhotoUpdateSerializer,
|
||||
PhotoLogSerializer,
|
||||
PhotoLogsSerializer,
|
||||
PhotoTagSerializer,
|
||||
)
|
||||
|
||||
from .photolog_generator import generate_photolog_from_latex
|
||||
@ -22,6 +23,21 @@ from io import BytesIO
|
||||
from PIL import Image, ExifTags
|
||||
|
||||
|
||||
class PhotoTagsAPIView(generics.ListAPIView):
|
||||
queryset = PhotoTag.objects.all()
|
||||
serializer_class = PhotoTagSerializer
|
||||
|
||||
|
||||
class CreatePhotoTagAPIView(generics.CreateAPIView):
|
||||
queryset = PhotoTag.objects.all()
|
||||
serializer_class = PhotoTagSerializer
|
||||
|
||||
|
||||
class RetrieveUpdateDestroyPhotoTagAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = PhotoTag.objects.all()
|
||||
serializer_class = PhotoTagSerializer
|
||||
|
||||
|
||||
class PhotoGroupAPIView(generics.ListAPIView):
|
||||
queryset = PhotoGroup.objects.all()
|
||||
serializer_class = PhotoGroupSerializer
|
||||
@ -135,7 +151,7 @@ class GeneratePhotoLogAPIView(generics.RetrieveAPIView):
|
||||
|
||||
if log_bytes:
|
||||
photolog.pdf.save('log.pdf', ContentFile(log_bytes))
|
||||
return Response({'pdf': 'https://server.riezel.com%s' % str(photolog.pdf.url)})
|
||||
return Response({'pdf': 'https://zierle-training.riezel.com%s' % str(photolog.pdf.url)})
|
||||
|
||||
return Response({"error": "Not Found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
@ -191,6 +207,9 @@ def rotateByExif(img):
|
||||
|
||||
exif = img._getexif()
|
||||
|
||||
if not exif:
|
||||
return img
|
||||
|
||||
if exif[orientation] == 3:
|
||||
img=img.rotate(180, expand=True)
|
||||
elif exif[orientation] == 6:
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
config/package-lock.json
generated
Normal file → Executable file
0
config/package-lock.json
generated
Normal file → Executable file
@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-z465dl_(vk55hxbm0bj*mp-ok3!*=ssw#!$5s2nrxa!9j+67z+
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['server.riezel.com', 'localhost', '127.0.0.1', '192.168.1.244']
|
||||
ALLOWED_HOSTS = ['zierle-training.riezel.com', 'localhost', '127.0.0.1', '192.168.1.244']
|
||||
|
||||
|
||||
# Application definition
|
||||
@ -45,6 +45,7 @@ INSTALLED_APPS = [
|
||||
'corsheaders',
|
||||
'drf_yasg',
|
||||
'django_tex',
|
||||
'colorfield',
|
||||
|
||||
# local
|
||||
'accounts',
|
||||
@ -110,8 +111,8 @@ ASGI_APPLICATION = 'config.asgi.application'
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'www_db',
|
||||
'USER': 'www_db_user',
|
||||
'NAME': 'zierle_training_db',
|
||||
'USER': 'zierle_training_db_user',
|
||||
'PASSWORD': 'UI&hWG,El7G{A2c0n=qIULv:b',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '5432',
|
||||
@ -157,12 +158,37 @@ USE_TZ = True
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
|
||||
#STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/")]
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
|
||||
|
||||
MINIO = False
|
||||
if MINIO:
|
||||
# MinIO S3 Object-Storage
|
||||
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
|
||||
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
|
||||
|
||||
AWS_ACCESS_KEY_ID = 'zierle-trainig-minio'
|
||||
AWS_SECRET_ACCESS_KEY = 'iGWJt7IFlKzufMtVTnl4W4kGmHz0TTBG'
|
||||
AWS_STORAGE_BUCKET_NAME = 'zierle-training'
|
||||
AWS_S3_ENDPOINT_URL = 'https://minio.riezel.com'
|
||||
AWS_DEFAULT_ACL = 'public'
|
||||
|
||||
MEDIA_URL = 'https://minio.riezel.com/zierle-training/'
|
||||
STATIC_URL = 'https://minio.riezel.com/zierle-training/'
|
||||
|
||||
AWS_S3_OBJECT_PARAMETERS = {
|
||||
'CacheControl': 'public, max-age=86400',
|
||||
}
|
||||
else:
|
||||
#MEDIA_URL = 'media/'
|
||||
#MEDIA_ROOT = BASE_DIR / 'media'
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
|
||||
#STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/")]
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,8 +1,9 @@
|
||||
from django.contrib import admin
|
||||
from .models import PhotoGroup, Photo, PhotoLog
|
||||
from .models import PhotoGroup, Photo, PhotoLog, PhotoTag
|
||||
|
||||
|
||||
admin.site.register(PhotoGroup)
|
||||
admin.site.register(Photo)
|
||||
admin.site.register(PhotoLog)
|
||||
admin.site.register(PhotoTag)
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-05 17:12
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import photo_log.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PhotoGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, unique=True)),
|
||||
('date', models.DateField(null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Photo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('legacy_id', models.IntegerField(blank=True, null=True, unique=True)),
|
||||
('original_image', models.ImageField(upload_to='original_images/')),
|
||||
('cropped_image', models.ImageField(blank=True, null=True, upload_to='cropped_images/')),
|
||||
('ocr_text', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), size=None)),
|
||||
('group', models.ForeignKey(default=photo_log.models.get_default_photogroup, on_delete=django.db.models.deletion.SET_DEFAULT, to='photo_log.photogroup')),
|
||||
],
|
||||
),
|
||||
]
|
@ -1,23 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-05 17:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='cropped_image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to='static/cropped_images/'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='original_image',
|
||||
field=models.ImageField(upload_to='static/original_images/'),
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-06 08:52
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0002_auto_20220105_1757'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='ocr_text',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, null=True, size=None),
|
||||
),
|
||||
]
|
@ -1,20 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-06 12:48
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import photo_log.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0003_alter_photo_ocr_text'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='group',
|
||||
field=models.ForeignKey(blank=True, default=photo_log.models.get_default_photogroup, on_delete=django.db.models.deletion.SET_DEFAULT, to='photo_log.photogroup'),
|
||||
),
|
||||
]
|
@ -1,26 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-13 13:32
|
||||
|
||||
import datetime
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0004_alter_photo_group'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PhotoLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=5000)),
|
||||
('date', models.DateField(default=datetime.date.today)),
|
||||
('render_date', models.BooleanField(blank=True, default=True)),
|
||||
('start_slide_image', models.IntegerField(blank=True, default=3, null=True)),
|
||||
('slides', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), size=None)),
|
||||
],
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-13 15:11
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0005_photolog'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photolog',
|
||||
name='slides',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), blank=True, default=[], size=None),
|
||||
),
|
||||
]
|
@ -1,20 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-13 15:13
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
import photo_log.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0006_alter_photolog_slides'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photolog',
|
||||
name='slides',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), blank=True, default=photo_log.models.get_empty_photolog_default, size=None),
|
||||
),
|
||||
]
|
@ -1,24 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-18 18:47
|
||||
|
||||
from django.db import migrations, models
|
||||
import photo_log.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0007_alter_photolog_slides'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='cropped_image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to=photo_log.models.get_cropped_photo_path),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='original_image',
|
||||
field=models.ImageField(upload_to=photo_log.models.get_original_photo_path),
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-18 19:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import photo_log.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0008_auto_20220118_1847'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='photolog',
|
||||
name='pdf',
|
||||
field=models.FileField(blank=True, null=True, upload_to=photo_log.models.get_photolog_pdf_path),
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-21 11:47
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0009_photolog_pdf'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='bbox_coords',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(default=None, null=True), size=2), blank=True, default=None, null=True, size=4),
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-01-22 11:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0010_photo_bbox_coords'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='ocr_text',
|
||||
field=models.CharField(blank=True, max_length=200, null=True),
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-05-03 14:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0011_alter_photo_ocr_text'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='rotate',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2022-05-04 07:28
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photo_log', '0012_photo_rotate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='intersections',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(default=None, null=True), size=2), blank=True, default=None, null=True, size=None),
|
||||
),
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,12 +2,22 @@ from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.dispatch import receiver
|
||||
|
||||
from colorfield.fields import ColorField
|
||||
|
||||
from datetime import date
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
|
||||
class PhotoTag(models.Model):
|
||||
name = models.CharField(unique=True, null=False, blank=False, max_length=100)
|
||||
color = ColorField(default='#FFE5B4')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class PhotoGroup(models.Model):
|
||||
name = models.CharField(unique=True, null=False, max_length=200)
|
||||
date = models.DateField(null=True)
|
||||
@ -63,6 +73,13 @@ class Photo(models.Model):
|
||||
default=get_default_photogroup
|
||||
)
|
||||
ocr_text = models.CharField(max_length=200, null=True, blank=True)
|
||||
tag = models.ForeignKey(
|
||||
PhotoTag,
|
||||
null=True,
|
||||
blank=False,
|
||||
on_delete=models.SET_NULL,
|
||||
default=None,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Photo #" + str(self.id)
|
||||
|
13
req.txt
13
req.txt
@ -1,13 +0,0 @@
|
||||
imageio==2.13.5
|
||||
imutils==0.5.4
|
||||
networkx==2.6.3
|
||||
numpy==1.22.0
|
||||
opencv-python==4.5.5.62
|
||||
packaging==21.3
|
||||
Pillow==9.0.0
|
||||
pyparsing==3.0.6
|
||||
pytesseract==0.3.8
|
||||
PyWavelets==1.2.0
|
||||
scikit-image==0.19.1
|
||||
scipy==1.7.3
|
||||
tifffile==2021.11.2
|
@ -1,19 +1,64 @@
|
||||
asgiref==3.4.1
|
||||
attrs==21.4.0
|
||||
autobahn==22.4.2
|
||||
Automat==20.2.0
|
||||
beautifulsoup4==4.10.0
|
||||
certifi==2021.10.8
|
||||
cffi==1.15.0
|
||||
channels==3.0.4
|
||||
charset-normalizer==2.0.7
|
||||
constantly==15.1.0
|
||||
coreapi==2.3.3
|
||||
coreschema==0.0.4
|
||||
cryptography==37.0.2
|
||||
daphne==3.0.2
|
||||
Django==3.2.8
|
||||
django-cors-headers==3.12.0
|
||||
django-filter==21.1
|
||||
django-tex==1.1.10
|
||||
djangorestframework==3.13.1
|
||||
drf-yasg==1.20.0
|
||||
gunicorn==20.1.0
|
||||
hyperlink==21.0.0
|
||||
idna==3.3
|
||||
imageio==2.13.5
|
||||
imutils==0.5.4
|
||||
incremental==21.3.0
|
||||
inflection==0.5.1
|
||||
itypes==1.2.0
|
||||
Jinja2==3.1.2
|
||||
lxml==4.6.3
|
||||
Markdown==3.3.7
|
||||
MarkupSafe==2.1.1
|
||||
networkx==2.6.3
|
||||
numpy==1.22.0
|
||||
opencv-python==4.5.5.62
|
||||
packaging==21.3
|
||||
Pillow==9.0.0
|
||||
psycopg2==2.9.1
|
||||
pyasn1==0.4.8
|
||||
pyasn1-modules==0.2.8
|
||||
pycparser==2.21
|
||||
pyOpenSSL==22.0.0
|
||||
pyparsing==3.0.6
|
||||
pytesseract==0.3.8
|
||||
python-dateutil==2.8.2
|
||||
pytz==2021.3
|
||||
PyWavelets==1.2.0
|
||||
requests==2.26.0
|
||||
ruamel.yaml==0.17.21
|
||||
ruamel.yaml.clib==0.2.6
|
||||
scikit-image==0.19.1
|
||||
scipy==1.7.3
|
||||
service-identity==21.1.0
|
||||
six==1.16.0
|
||||
soupsieve==2.2.1
|
||||
sqlparse==0.4.2
|
||||
tifffile==2021.11.2
|
||||
tqdm==4.62.3
|
||||
Twisted==22.4.0
|
||||
txaio==22.2.1
|
||||
typing_extensions==4.2.0
|
||||
uritemplate==4.1.1
|
||||
urllib3==1.26.7
|
||||
zope.interface==5.4.0
|
||||
|
0
templates/photolog.tex
Normal file → Executable file
0
templates/photolog.tex
Normal file → Executable file
Loading…
Reference in New Issue
Block a user