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 django.contrib import admin
from . import models
# Register your models here. # Register your models here.
admin.site.register(models.UploadImage)

View File

@ -1,9 +1,11 @@
from django import forms from django import forms
from .models import DetectImage from .models import UploadImage
class DetectForm(forms.ModelForm): class DetectForm(forms.ModelForm):
class Meta: class Meta:
model = DetectImage model = UploadImage
fields = "__all__" fields = [
labels={"image":""} "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.db import models
from django.core.validators import FileExtensionValidator from django.core.validators import FileExtensionValidator
from django.contrib.auth.models import User
# Create your models here. # Create your models here.
class DetectImage(models.Model): class UploadImage(models.Model):
image = models.ImageField( image = models.ImageField(
upload_to="plankton/%Y/%m/%d/", upload_to="plankton/%Y/%m/%d/",
validators=[FileExtensionValidator(allowed_extensions=["jpg", "png"])], 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 = [ urlpatterns = [
path("detect/", views.DetectView.as_view(), name="detect"), path("detect/", views.DetectView.as_view(), name="detect"),
path("login/", views.LoginView.as_view(), name="login"), path("history/", views.ListHistory.as_view(), name="history"),
path("logout/", views.logout_view, name="logout"), path(
path("register/", views.SignupView.as_view(), name="signup"), "detection/<int:pk>", views.DetectionDetails.as_view(), name="detection-details"
),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + 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.shortcuts import render, redirect
from django.views import View from django.views import View
from .forms import DetectForm from .forms import DetectForm
from django.conf import settings from django.views.generic import ListView, DetailView
from ultralytics import YOLO from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.utils.decorators import method_decorator
from django.contrib.auth import authenticate, login, logout from .models import UploadImage, PredictedImage
from .utils import predict_image
# Create your views here. from django.contrib.auth.mixins import LoginRequiredMixin
MODEL = YOLO("best.pt")
class DetectView(View): class DetectView(View):
@ -18,68 +19,49 @@ class DetectView(View):
form = self.form_class() form = self.form_class()
return render(request, "upload.html", {"form": form}) return render(request, "upload.html", {"form": form})
@method_decorator(login_required)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES) form = self.form_class(request.POST, request.FILES)
if form.is_valid(): if form.is_valid():
image = form.save() image = form.save(commit=False)
MODEL.predict( image.owner = request.user
image.image.path, image.save()
save=True, prediciton_results = predict_image(image)
project=settings.MEDIA_ROOT, image.predicted_image_url = (
name=f"{image.image.name}_predicted", f"{image.image.name}_predicted/{image.image.name.split('/')[-1]}"
imgsz=[640, 640], )
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( return render(
request, request,
"upload.html", "upload.html",
{ {
"img_saved": saved, "img_saved": True,
"img_path": f"{image.image.name}_predicted/{image.image.name.split('/')[-1]}", "img_url": image.predicted_image_url,
}, },
) )
else: else:
return render(request, "upload.html", {"form": form}) return render(request, "upload.html", {"form": form})
class LoginView(View): class ListHistory(LoginRequiredMixin, ListView):
form_class = AuthenticationForm model = PredictedImage
template_name = "login_signup.html" queryset = PredictedImage.objects.all()
template_name = "history.html"
paginate_by = 4
def get(self, request, *args, **kwargs): def get_queryset(self) -> QuerySet[Any]:
form = self.form_class() queryset = PredictedImage.objects.filter(
return render(request, self.template_name, {"form": form}) original_image__owner=self.request.user
).order_by("-date_predicted")
def post(self, request, *args, **kwargs): return queryset
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): class DetectionDetails(LoginRequiredMixin, DetailView):
form_class = UserCreationForm model = PredictedImage
template_name = "login_signup.html" template_name = "detection_detail.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")

View File

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

View File

@ -16,8 +16,12 @@ Including another URLconf
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls), 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{ .footer{
display:flex; display:flex;
position:fixed;
bottom: 0;
right: 0;
left:0;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: 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; background-color: lightgray;
border: grey solid; border: grey solid;
border-width: 2px; border-width: 2px;
margin-bottom: 59px;
} }

View File

@ -14,9 +14,10 @@
</head> </head>
<body> <body>
<div class="top-menu"> <div class="top-menu">
<a href="#">Placeholder</a> <a href="{% url 'posts' %}">Community</a>
<a href="{% url 'detect' %}">Predict</a> <a href="{% url 'detect' %}">Predict</a>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<a href="{% url 'history' %}">History</a>
<a href="{% url 'logout' %}">Logout {{user}}</a> <a href="{% url 'logout' %}">Logout {{user}}</a>
{%else%} {%else%}
<a href="{% url 'login' %}">Login</a> <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"> <form method="POST" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="side_menu"> <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> <p id="description">Choose image for analysis</p>
<input type="submit" id="submit" value="Submit"> <input type="submit" id="submit" value="Submit">
{% else %} {% else %}
@ -18,10 +21,10 @@
<div class="upload_field"> <div class="upload_field">
<label for="id_image", class="upload_button"> <label for="id_image", class="upload_button">
{{form.as_p}} {{form.as_p}}
{% if not img_path %} {% if not img_url %}
<img id="image-preview" src="{% static 'DetectionApp/images/upload_img.png' %}" alt="Image Preview" style="max-width:640px; max-height:640px;"/> <img id="image-preview" src="{% static 'DetectionApp/images/upload_img.png' %}" alt="Image Preview" style="width:640px; height:460px;"/>
{%else%} {%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%} {%endif%}
</label> </label>
</div> </div>