Add history, community, modify login

This commit is contained in:
Piotr Szkudlarek 2023-12-13 02:11:29 +01:00
parent a4118e2357
commit e146f16f56
45 changed files with 659 additions and 71 deletions

View File

View File

@ -0,0 +1,6 @@
from django.contrib import admin
from . import models
# Register your models here.
admin.site.register(models.Comment)
admin.site.register(models.Post)

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class CommunityConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "Community"

View File

@ -0,0 +1,67 @@
# Generated by Django 4.2.7 on 2023-12-11 15:42
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Post",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=500)),
("content", models.TextField()),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.CreateModel(
name="Comment",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", models.TextField()),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
(
"post",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="Community.post"
),
),
],
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2.7 on 2023-12-11 16:58
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("Community", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="post",
name="date_pub",
field=models.DateField(
auto_now_add=True, default=django.utils.timezone.now
),
preserve_default=False,
),
]

View File

@ -0,0 +1,17 @@
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=500)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
date_pub = models.DateField(auto_now_add=True)
class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,9 @@
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
urlpatterns = [
path("posts/", views.ListPosts.as_view(), name="posts"),
path("posts/<int:pk>", views.PostDetails.as_view(), name="post-details"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -0,0 +1,14 @@
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Post, Comment
# Create your views here.
class ListPosts(ListView):
model = Post
template_name = "list_posts.html"
class PostDetails(DetailView):
model = Post

View File

@ -1,3 +1,5 @@
from django.contrib import admin
from . import models
# Register your models here.
admin.site.register(models.UploadImage)

View File

@ -1,9 +1,11 @@
from django import forms
from .models import DetectImage
from .models import UploadImage
class DetectForm(forms.ModelForm):
class Meta:
model = DetectImage
fields = "__all__"
labels={"image":""}
model = UploadImage
fields = [
"image",
]
labels = {"image": ""}

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2.7 on 2023-12-12 16:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("DetectionApp", "0002_alter_detectimage_image"),
]
operations = [
migrations.AddField(
model_name="detectimage",
name="owner",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
preserve_default=False,
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.7 on 2023-12-12 21:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("DetectionApp", "0003_detectimage_owner"),
]
operations = [
migrations.AddField(
model_name="detectimage",
name="predicted_image_url",
field=models.CharField(default="url", max_length=500),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2.7 on 2023-12-12 21:21
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("DetectionApp", "0004_detectimage_predicted_image_url"),
]
operations = [
migrations.AddField(
model_name="detectimage",
name="date_predicted",
field=models.DateTimeField(
auto_now_add=True, default=django.utils.timezone.now
),
preserve_default=False,
),
]

View File

@ -0,0 +1,37 @@
# Generated by Django 4.2.7 on 2023-12-12 22:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("DetectionApp", "0005_detectimage_date_predicted"),
]
operations = [
migrations.CreateModel(
name="PredictedImage",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("image", models.ImageField(upload_to="plankton/%Y/%m/%d/None")),
("confidence", models.FloatField()),
("class_name", models.CharField(max_length=100)),
(
"original_image",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to="DetectionApp.detectimage",
),
),
],
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2.7 on 2023-12-13 00:25
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("DetectionApp", "0006_predictedimage"),
]
operations = [
migrations.RemoveField(
model_name="detectimage",
name="date_predicted",
),
migrations.AddField(
model_name="predictedimage",
name="date_predicted",
field=models.DateTimeField(
auto_now_add=True, default=django.utils.timezone.now
),
preserve_default=False,
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2.7 on 2023-12-13 00:29
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("DetectionApp", "0007_remove_detectimage_date_predicted_and_more"),
]
operations = [
migrations.AddField(
model_name="predictedimage",
name="owner",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
preserve_default=False,
),
]

View File

@ -0,0 +1,16 @@
# Generated by Django 4.2.7 on 2023-12-13 00:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("DetectionApp", "0008_predictedimage_owner"),
]
operations = [
migrations.RemoveField(
model_name="predictedimage",
name="owner",
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.7 on 2023-12-13 01:08
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("DetectionApp", "0009_remove_predictedimage_owner"),
]
operations = [
migrations.RenameModel(
old_name="DetectImage",
new_name="UploadImage",
),
]

View File

@ -1,11 +1,30 @@
from django.db import models
from django.core.validators import FileExtensionValidator
from django.contrib.auth.models import User
# Create your models here.
class DetectImage(models.Model):
class UploadImage(models.Model):
image = models.ImageField(
upload_to="plankton/%Y/%m/%d/",
validators=[FileExtensionValidator(allowed_extensions=["jpg", "png"])],
)
predicted_image_url = models.CharField(max_length=500)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class PredictedImage(models.Model):
original_image = models.OneToOneField(UploadImage, on_delete=models.CASCADE)
image = models.ImageField(upload_to=f"plankton/%Y/%m/%d/{original_image.name}")
confidence = models.FloatField()
class_name = models.CharField(max_length=100)
date_predicted = models.DateTimeField(auto_now_add=True)
@property
def get_owner(self):
return self.original_image.owner
@property
def get_original_image(self):
return self.original_image.image

View File

@ -6,7 +6,8 @@ from django.contrib.auth import urls
urlpatterns = [
path("detect/", views.DetectView.as_view(), name="detect"),
path("login/", views.LoginView.as_view(), name="login"),
path("logout/", views.logout_view, name="logout"),
path("register/", views.SignupView.as_view(), name="signup"),
path("history/", views.ListHistory.as_view(), name="history"),
path(
"detection/<int:pk>", views.DetectionDetails.as_view(), name="detection-details"
),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -0,0 +1,20 @@
import json
from django.core.files import File
from PIL import Image
from io import BytesIO
from django.conf import settings
from ultralytics import YOLO
MODEL = YOLO("best.pt")
def predict_image(image):
results = MODEL.predict(
image.image.path,
save=True,
project=settings.MEDIA_ROOT,
name=f"{image.image.name}_predicted",
imgsz=[640, 640],
)
x = json.loads(results[0].tojson())
return x

View File

@ -1,13 +1,14 @@
from typing import Any
from django.db.models.query import QuerySet
from django.shortcuts import render, redirect
from django.views import View
from .forms import DetectForm
from django.conf import settings
from ultralytics import YOLO
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth import authenticate, login, logout
# Create your views here.
MODEL = YOLO("best.pt")
from django.views.generic import ListView, DetailView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from .models import UploadImage, PredictedImage
from .utils import predict_image
from django.contrib.auth.mixins import LoginRequiredMixin
class DetectView(View):
@ -18,68 +19,49 @@ class DetectView(View):
form = self.form_class()
return render(request, "upload.html", {"form": form})
@method_decorator(login_required)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
image = form.save()
MODEL.predict(
image.image.path,
save=True,
project=settings.MEDIA_ROOT,
name=f"{image.image.name}_predicted",
imgsz=[640, 640],
image = form.save(commit=False)
image.owner = request.user
image.save()
prediciton_results = predict_image(image)
image.predicted_image_url = (
f"{image.image.name}_predicted/{image.image.name.split('/')[-1]}"
)
image.save()
PredictedImage.objects.create(
original_image=image,
image=image.predicted_image_url,
confidence=prediciton_results[0]["confidence"],
class_name=prediciton_results[0]["name"],
)
saved = form.is_valid()
return render(
request,
"upload.html",
{
"img_saved": saved,
"img_path": f"{image.image.name}_predicted/{image.image.name.split('/')[-1]}",
"img_saved": True,
"img_url": image.predicted_image_url,
},
)
else:
return render(request, "upload.html", {"form": form})
class LoginView(View):
form_class = AuthenticationForm
template_name = "login_signup.html"
class ListHistory(LoginRequiredMixin, ListView):
model = PredictedImage
queryset = PredictedImage.objects.all()
template_name = "history.html"
paginate_by = 4
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {"form": form})
def post(self, request, *args, **kwargs):
form = self.form_class(data=request.POST)
if form.is_valid():
user = authenticate(
username=form.cleaned_data["username"],
password=form.cleaned_data["password"],
)
if user is not None:
login(request, user)
return redirect("detect")
return render(request, self.template_name, {"form": form})
def get_queryset(self) -> QuerySet[Any]:
queryset = PredictedImage.objects.filter(
original_image__owner=self.request.user
).order_by("-date_predicted")
return queryset
class SignupView(View):
form_class = UserCreationForm
template_name = "login_signup.html"
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {"form": form, "signup": True})
def post(self, request, *args, **kwargs):
form = self.form_class(data=request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect("detect")
return render(request, self.template_name, {"form": form, "signup": True})
def logout_view(request):
logout(request)
return redirect("detect")
class DetectionDetails(LoginRequiredMixin, DetailView):
model = PredictedImage
template_name = "detection_detail.html"

View File

@ -39,6 +39,7 @@ INSTALLED_APPS = [
"django.contrib.messages",
"django.contrib.staticfiles",
"DetectionApp",
"Community",
]
MIDDLEWARE = [

View File

@ -16,8 +16,12 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("DetectionApp.urls"))
]
path("", include("DetectionApp.urls")),
path("accounts/", include("UserManagement.urls")),
path("community/", include("Community.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class UsermanagementConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "UserManagement"

View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,8 @@
from django.urls import path
from . import views
urlpatterns = [
path("login/", views.LoginView.as_view(), name="login"),
path("logout/", views.logout_view, name="logout"),
path("register/", views.SignupView.as_view(), name="signup"),
]

View File

@ -0,0 +1,46 @@
from django.shortcuts import render, redirect
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth import authenticate, login, logout
from django.views import View
class LoginView(View):
form_class = AuthenticationForm
template_name = "login_signup.html"
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {"form": form})
def post(self, request, *args, **kwargs):
form = self.form_class(data=request.POST)
if form.is_valid():
user = authenticate(
username=form.cleaned_data["username"],
password=form.cleaned_data["password"],
)
if user is not None:
login(request, user)
return redirect("detect")
return render(request, self.template_name, {"form": form})
class SignupView(View):
form_class = UserCreationForm
template_name = "login_signup.html"
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {"form": form, "signup": True})
def post(self, request, *args, **kwargs):
form = self.form_class(data=request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect("detect")
return render(request, self.template_name, {"form": form, "signup": True})
def logout_view(request):
logout(request)
return redirect("detect")

Binary file not shown.

View File

@ -0,0 +1,38 @@
.post_list{
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
}
h2{
margin-bottom:25px;
}
ul{
list-style-type: none;
}
.post_list a{
text-decoration: none;
width: 100%;
color: black;
}
.post_details{
display:flex;
width: 50%;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 25px;
}
.date_author{
display: flex;
width: 100%;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
}

View File

@ -28,6 +28,10 @@ body, html{
.footer{
display:flex;
position:fixed;
bottom: 0;
right: 0;
left:0;
flex-direction: row;
justify-content: center;
align-items: center;

View File

@ -0,0 +1,7 @@
.history_list{
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
}

View File

@ -0,0 +1,38 @@
.history_list{
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
}
h2{
margin-bottom:25px;
}
ul{
list-style-type: none;
}
.history_list a{
text-decoration: none;
width: 50%;
color: black;
}
.history_details{
display:flex;
width: 100%;
flex-direction: row;
align-items: flex-start;
justify-content: space-evenly;
margin-bottom: 25px;
}
.date_author{
display: flex;
width: 100%;
flex-direction: column;
align-items: flex-end;
justify-content: space-between;
}

View File

@ -17,6 +17,7 @@ form{
background-color: lightgray;
border: grey solid;
border-width: 2px;
margin-bottom: 59px;
}

View File

@ -14,9 +14,10 @@
</head>
<body>
<div class="top-menu">
<a href="#">Placeholder</a>
<a href="{% url 'posts' %}">Community</a>
<a href="{% url 'detect' %}">Predict</a>
{% if user.is_authenticated %}
<a href="{% url 'history' %}">History</a>
<a href="{% url 'logout' %}">Logout {{user}}</a>
{%else%}
<a href="{% url 'login' %}">Login</a>

View File

@ -0,0 +1,7 @@
{%extends 'base.html'%}
{%load static%}
{%block extracss%}
<link rel="stylesheet" href="{% static 'DetectionApp/css/detection-detail.css' %}">
{%endblock extracss%}
{%block content%}
{%endblock content%}

View File

@ -0,0 +1,40 @@
{%extends 'base.html'%}
{%load static%}
{%block extracss%}
<link rel="stylesheet" href="{% static 'DetectionApp/css/history.css' %}">
{%endblock extracss%}
{%block content%}
<div class="history_list">
<h2>History</h2>
{% for detection in page_obj %}
<div class="history_details">
<a href="{%url 'detection-details' pk=detection.id %}">
<div class="history_details">
<img src="{{detection.image.url}}" alt="upload_image" style="width:100px; height:100px;">
<div class="date_author">
<p class="date">{{detection.date_predicted.date}}</p>
<p class="author">{{detection.get_owner}}</p>
</div>
</div>
</a>
</div>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
</span>
</div>
</div>
{%endblock content%}

View File

@ -0,0 +1,21 @@
{%extends 'base.html'%}
{%load static%}
{%block extracss%}
<link rel="stylesheet" href="{% static 'Community/css/list_posts.css' %}">
{%endblock extracss%}
{%block content%}
<div class="post_list">
<h2>Posts</h2>
{% for post in object_list %}
<div class="post_details">
<a href="{%url 'post-details' pk=post.id %}">
<h3 class="title">{{ post.title }}</h3>
<div class="date_author">
<p class="date">{{post.date_pub}}</p>
<p class="author">{{post.author.username}}</p>
</div>
</a>
</div>
{% endfor %}
</div>
{%endblock content%}

View File

@ -7,7 +7,10 @@
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="side_menu">
{% if img_saved is None %}
{% if not user.is_authenticated %}
<p id="description">Please login to submit image</p>
<button onclick="location.href='{% url 'login' %}'" id='submit' method="GET" type='button'>Login</button>
{% elif img_saved is None %}
<p id="description">Choose image for analysis</p>
<input type="submit" id="submit" value="Submit">
{% else %}
@ -18,10 +21,10 @@
<div class="upload_field">
<label for="id_image", class="upload_button">
{{form.as_p}}
{% if not img_path %}
<img id="image-preview" src="{% static 'DetectionApp/images/upload_img.png' %}" alt="Image Preview" style="max-width:640px; max-height:640px;"/>
{% if not img_url %}
<img id="image-preview" src="{% static 'DetectionApp/images/upload_img.png' %}" alt="Image Preview" style="width:640px; height:460px;"/>
{%else%}
<img src="{%get_media_prefix %}{{img_path}}" alt="upload_image" width="640" height="640">
<img src="{%get_media_prefix%}{{img_url}}" alt="upload_image" style="width:640px; height:460px;">
{%endif%}
</label>
</div>