Add post and comment creation functionality
This commit is contained in:
parent
c6ba3dd6b0
commit
d23cdff3af
18
PlanktonDetector/Community/froms.py
Normal file
18
PlanktonDetector/Community/froms.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django import forms
|
||||
from .models import Post, Comment
|
||||
|
||||
|
||||
class PostForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = ["title", "content"]
|
||||
|
||||
|
||||
class CommentForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Comment
|
||||
fields = ["content"]
|
||||
labels = {
|
||||
"content": "Comment",
|
||||
}
|
||||
widgets = {"content": forms.Textarea(attrs={"rows": 3})}
|
@ -0,0 +1,21 @@
|
||||
# Generated by Django 4.2.7 on 2024-01-05 19:44
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("Community", "0002_post_date_pub"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="comment",
|
||||
name="date_added",
|
||||
field=models.DateField(
|
||||
auto_now_add=True, default=django.utils.timezone.now
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
@ -10,8 +10,13 @@ class Post(models.Model):
|
||||
author = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
|
||||
date_pub = models.DateField(auto_now_add=True)
|
||||
|
||||
@property
|
||||
def sorted_comments(self):
|
||||
return self.comment_set.all().order_by("-date_added")
|
||||
|
||||
|
||||
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)
|
||||
date_added = models.DateField(auto_now_add=True)
|
||||
|
@ -6,4 +6,5 @@ from . import views
|
||||
urlpatterns = [
|
||||
path("posts/", views.ListPosts.as_view(), name="posts"),
|
||||
path("posts/<int:pk>", views.PostDetails.as_view(), name="post-details"),
|
||||
path("posts/create/", views.AddPost.as_view(), name="add_post"),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
@ -1,6 +1,12 @@
|
||||
from django.shortcuts import render
|
||||
from typing import Any
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.views.generic import ListView, DetailView
|
||||
from django.views.generic.edit import FormView, FormMixin
|
||||
from .models import Post, Comment
|
||||
from .froms import PostForm, CommentForm
|
||||
|
||||
|
||||
# Create your views here.
|
||||
|
||||
@ -8,8 +14,44 @@ from .models import Post, Comment
|
||||
class ListPosts(ListView):
|
||||
model = Post
|
||||
template_name = "list_posts.html"
|
||||
paginate_by = 3
|
||||
|
||||
def get_queryset(self) -> QuerySet[Any]:
|
||||
queryset = Post.objects.all().order_by("-date_pub")
|
||||
return queryset
|
||||
|
||||
|
||||
class PostDetails(DetailView):
|
||||
class PostDetails(DetailView, FormMixin):
|
||||
model = Post
|
||||
template_name = "post_details.html"
|
||||
form_class = CommentForm
|
||||
|
||||
# def get_queryset(self) -> QuerySet[Any]:
|
||||
# queryset = Post.objects.get(pk=self.request.GET.get("pk"))
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.get_form()
|
||||
if form.is_valid():
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def form_valid(self, form) -> HttpResponse:
|
||||
post = self.get_object()
|
||||
new_comment = form.save(commit=False)
|
||||
new_comment.author = self.request.user
|
||||
new_comment.post = post
|
||||
new_comment.save()
|
||||
return redirect("post-details", pk=post.id)
|
||||
|
||||
|
||||
class AddPost(FormView):
|
||||
template_name = "add_post.html"
|
||||
form_class = PostForm
|
||||
|
||||
def form_valid(self, form) -> HttpResponse:
|
||||
new_post = form.save(commit=False)
|
||||
new_post.author = self.request.user
|
||||
new_post.save()
|
||||
return redirect("post-details", pk=new_post.id)
|
||||
|
@ -10,5 +10,5 @@ urlpatterns = [
|
||||
path(
|
||||
"detection/<int:pk>", views.DetectionDetails.as_view(), name="detection-details"
|
||||
),
|
||||
path("export_pred/<int:pk>", views.download_pred_res, name="download_predicitons"),
|
||||
path("export_pred/<int:pk>", views.download_pred_res, name="download_predicitions"),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
@ -1,8 +1,10 @@
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.urls import reverse_lazy
|
||||
from django.views import View
|
||||
|
||||
|
||||
class LoginView(View):
|
||||
form_class = AuthenticationForm
|
||||
template_name = "login_signup.html"
|
||||
@ -12,6 +14,7 @@ class LoginView(View):
|
||||
return render(request, self.template_name, {"form": form})
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
redirection_path = request.GET.get("next")
|
||||
form = self.form_class(data=request.POST)
|
||||
if form.is_valid():
|
||||
user = authenticate(
|
||||
@ -20,7 +23,10 @@ class LoginView(View):
|
||||
)
|
||||
if user is not None:
|
||||
login(request, user)
|
||||
return redirect("detect")
|
||||
if redirection_path is not None:
|
||||
return redirect(redirection_path)
|
||||
else:
|
||||
return redirect("detect/")
|
||||
return render(request, self.template_name, {"form": form})
|
||||
|
||||
|
||||
@ -37,10 +43,14 @@ class SignupView(View):
|
||||
if form.is_valid():
|
||||
user = form.save()
|
||||
login(request, user)
|
||||
return redirect("detect")
|
||||
return redirect("detect/")
|
||||
return render(request, self.template_name, {"form": form, "signup": True})
|
||||
|
||||
|
||||
def logout_view(request):
|
||||
redirection_path = request.GET.get("next")
|
||||
logout(request)
|
||||
return redirect("detect")
|
||||
if redirection_path is not None:
|
||||
return redirect(redirection_path)
|
||||
else:
|
||||
return redirect("detect/")
|
||||
|
Binary file not shown.
0
PlanktonDetector/static/Community/css/add_post.css
Normal file
0
PlanktonDetector/static/Community/css/add_post.css
Normal file
@ -27,6 +27,7 @@ ul{
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 25px;
|
||||
box-shadow: 0 2px lightgray;
|
||||
}
|
||||
|
||||
.date_author{
|
||||
@ -36,3 +37,15 @@ ul{
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#add_post{
|
||||
text-align: center;
|
||||
padding: 1px 6px 1px 6px;
|
||||
width: 10%;
|
||||
background-color: chartreuse;
|
||||
border-radius: 25px;
|
||||
border: 2px black;
|
||||
box-shadow: 0 0 0 2px black;
|
||||
font-size: 20px;
|
||||
font-family: Arial;
|
||||
}
|
@ -77,9 +77,46 @@ body, html{
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
#comment-author{
|
||||
#add_comment{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
flex-direction: row;
|
||||
width: 55%;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
margin-top:30px;
|
||||
}
|
||||
|
||||
#comment_form{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#comment_form textarea{
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#comment_form label{
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.date_author{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#submit{
|
||||
background-color: chartreuse;
|
||||
border-radius: 25px;
|
||||
border: 2px solid black;
|
||||
font-size: 20px;
|
||||
text-decoration: none;
|
||||
color:black;
|
||||
font-family: Arial;
|
||||
text-align: center;
|
||||
}
|
@ -29,17 +29,6 @@ form{
|
||||
margin: 10px 0px 15px 0px;
|
||||
}
|
||||
|
||||
#submit{
|
||||
background-color: chartreuse;
|
||||
margin-top: auto;
|
||||
height: 50px;
|
||||
width: 80%;
|
||||
border-radius: 25px;
|
||||
border: 2px white;
|
||||
box-shadow: 0 0 0 4px white;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.upload_field {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
@ -91,7 +80,26 @@ form{
|
||||
height: 50px;
|
||||
width: 60%;
|
||||
border-radius: 25px;
|
||||
border: 2px white;
|
||||
box-shadow: 0 0 0 4px white;
|
||||
border: 2px solid black;
|
||||
font-size: 25px;
|
||||
text-decoration: none;
|
||||
color:black;
|
||||
font-family: Arial;
|
||||
text-align: center;
|
||||
line-height:45px;
|
||||
}
|
||||
|
||||
#submit{
|
||||
background-color: chartreuse;
|
||||
margin-top: auto;
|
||||
height: 50px;
|
||||
width: 80%;
|
||||
border-radius: 25px;
|
||||
border: 2px solid white;
|
||||
font-size: 25px;
|
||||
text-decoration: none;
|
||||
color:black;
|
||||
font-family: Arial;
|
||||
text-align: center;
|
||||
line-height:45px;
|
||||
}
|
@ -34,9 +34,13 @@ form{
|
||||
height: 50px;
|
||||
width: 80%;
|
||||
border-radius: 25px;
|
||||
border: 2px white;
|
||||
box-shadow: 0 0 0 4px white;
|
||||
border: 2px solid white;
|
||||
font-size: 25px;
|
||||
text-decoration: none;
|
||||
color:black;
|
||||
font-family: Arial;
|
||||
text-align: center;
|
||||
line-height:45px;
|
||||
}
|
||||
|
||||
.upload_field {
|
||||
|
12
PlanktonDetector/templates/add_post.html
Normal file
12
PlanktonDetector/templates/add_post.html
Normal file
@ -0,0 +1,12 @@
|
||||
{%extends 'base.html'%}
|
||||
{%load static%}
|
||||
{%block extracss%}
|
||||
<link rel="stylesheet" href="{% static 'Community/css/add_post.css' %}">
|
||||
{%endblock extracss%}
|
||||
{%block content%}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Add post">
|
||||
</form>
|
||||
{%endblock content%}
|
@ -18,9 +18,9 @@
|
||||
<a href="{% url 'detect' %}">Predict</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'history' %}">History</a>
|
||||
<a href="{% url 'logout' %}">Logout {{user}}</a>
|
||||
<a href="{% url 'logout' %}?next={{request.path}}">Logout {{user}}</a>
|
||||
{%else%}
|
||||
<a href="{% url 'login' %}">Login</a>
|
||||
<a href="{% url 'login' %}?next={{request.path}}">Login</a>
|
||||
{%endif%}
|
||||
</div>
|
||||
{%block content%}{%endblock content%}
|
||||
|
@ -6,7 +6,10 @@
|
||||
{%block content%}
|
||||
<div class="post_list">
|
||||
<h2>Posts</h2>
|
||||
{% for post in object_list %}
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{%url 'add_post'%}" id="add_post">Add new post</a>
|
||||
{%endif%}
|
||||
{% for post in page_obj %}
|
||||
<div class="post_details">
|
||||
<a href="{%url 'post-details' pk=post.id %}">
|
||||
<h3 class="title">{{ post.title }}</h3>
|
||||
@ -17,5 +20,22 @@
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« 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 »</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{%endblock content%}
|
@ -14,12 +14,22 @@
|
||||
<p id="author">{{object.author}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="add_comment">
|
||||
<form method="POST" id="comment_form">
|
||||
{%csrf_token%}
|
||||
{{form}}
|
||||
<input type="submit" id="submit" value="Add comment">
|
||||
</form>
|
||||
</div>
|
||||
<p id="comment-label">Comments:</p>
|
||||
<div class="comments">
|
||||
{%for comments in object.comment_set.all%}
|
||||
{%for comment in object.sorted_comments%}
|
||||
<div class="single-comment">
|
||||
<p id="comment-content">{{comments.content}}</p>
|
||||
<p id="comment-author">{{comments.author}}</p>
|
||||
<p id="comment-content">{{comment.content}}</p>
|
||||
<div class="date_author">
|
||||
<p id="comment-date">{{comment.date_added}}</p>
|
||||
<p id="comment-author">{{comment.author}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{%endfor%}
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<div class="side_menu">
|
||||
{% if not user.is_authenticated %}
|
||||
<p id="description">Please login to see results</p>
|
||||
<button onclick="location.href='{% url 'login' %}'" id='submit' method="GET" type='button'>Login</button>
|
||||
<a href="{% url 'login'%}?next={{request.path}}" id="submit">Login</a>
|
||||
{% else %}
|
||||
<p id="description">Results:</p>
|
||||
{%for img in img.images.all %}
|
||||
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
{%endfor%}
|
||||
{%endfor%}
|
||||
<button onclick="location.href='{% url 'detect' %}'" id='submit' method="GET" type='button'>Submit again</button>
|
||||
<a href="{% url 'detect' %}" id="submit">Submit again</a>
|
||||
{%endif%}
|
||||
</div>
|
||||
<div class="upload_field">
|
||||
@ -29,7 +29,7 @@
|
||||
<img src="{{img.image.url}}" alt="upload_image" style="width:640px; height:460px;">
|
||||
{%endfor%}
|
||||
</label>
|
||||
<button onclick="location.href='{%url 'download_predicitons' pk=img.id%}'" id="download_json" method="GET" type="button">Export predictions</button>
|
||||
<a href="{%url 'download_predicitions' pk=img.id %}" id="download_json">Export predictions</a>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<div class="side_menu">
|
||||
{% 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>
|
||||
<a href="{% url 'login' %}?next={{request.path}}" id="submit">Login</a>
|
||||
{% else %}
|
||||
<p id="description">Choose image for analysis</p>
|
||||
<input type="submit" id="submit" value="Submit">
|
||||
@ -71,10 +71,8 @@ document.getElementById('id_image').addEventListener('change', function () {
|
||||
var user = `{{user.is_authenticated}}`
|
||||
var upload = document.getElementById("id_image")
|
||||
if (user.toLowerCase()=="false"){
|
||||
console.log('disabled');
|
||||
upload.disabled=true;
|
||||
}else if (user.toLowerCase()=="true"){
|
||||
console.log("enabled");
|
||||
upload.disabled=false;
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user