Compare commits

...

5 commits

Author SHA1 Message Date
1e2e32e026 Merge branch 'circle'
Fix #13
2022-07-09 14:31:00 +01:00
2cb910cc30 Add circles, views to modify them and ability to add them to posts 2022-07-09 14:30:24 +01:00
ac962034df Use zimports to sort imports 2022-07-09 14:29:41 +01:00
ce230f1101 Add circles app with Circle model 2022-07-08 21:50:39 +01:00
72e80817a5 Fix null=True vs blank=True on string fields
Django documentation suggests no using null=True, but
instead defaulting to the empty string.  It's
necessary of course to allow blank=True so that
users don't have to enter the field
2022-07-08 21:49:42 +01:00
20 changed files with 237 additions and 15 deletions

View file

@ -9,3 +9,7 @@ repos:
rev: 22.6.0
hooks:
- id: black
- repo: https://github.com/sqlalchemyorg/zimports/
rev: v0.4.5
hooks:
- id: zimports

View file

@ -36,6 +36,7 @@ INSTALLED_APPS = [
"django.contrib.messages",
"django.contrib.staticfiles",
"flangr.posts",
"flangr.circles",
]
MIDDLEWARE = [

View file

7
flangr/circles/admin.py Normal file
View file

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

6
flangr/circles/apps.py Normal file
View file

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

View file

@ -0,0 +1,45 @@
# Generated by Django 4.0.5 on 2022-07-08 20:49
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="Circle",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
(
"description",
models.CharField(blank=True, default="", max_length=255),
),
("members", models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="owned_circles",
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View file

18
flangr/circles/models.py Normal file
View file

@ -0,0 +1,18 @@
from django.conf import settings
from django.db import models
# Create your models here.
class Circle(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True, default="")
members = models.ManyToManyField(settings.AUTH_USER_MODEL)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="owned_circles"
)
def __str__(self):
return f"Circle: {self.name} of user {self.owner_id}"

3
flangr/circles/tests.py Normal file
View file

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

10
flangr/circles/urls.py Normal file
View file

@ -0,0 +1,10 @@
from django.urls import path
from . import views
app_name = "circles"
urlpatterns = [
path("", views.CircleListView.as_view(), name="circle_list"),
path("circle/<int:pk>", views.CircleUpdateView.as_view(), name="circle_update"),
path("add", views.CircleCreateView.as_view(), name="circle_create"),
]

41
flangr/circles/views.py Normal file
View file

@ -0,0 +1,41 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic import CreateView
from django.views.generic import ListView
from django.views.generic import UpdateView
from .models import Circle
# Create your views here.
class CircleListView(LoginRequiredMixin, ListView):
def get_queryset(self):
return Circle.objects.filter(owner=self.request.user)
class CircleUpdateView(LoginRequiredMixin, UpdateView):
model = Circle
fields = ["name", "description", "members"]
def get_queryset(self):
return Circle.objects.filter(owner=self.request.user)
def get_success_url(self):
return reverse("circles:circle_list")
class CircleCreateView(LoginRequiredMixin, CreateView):
model = Circle
fields = ["name", "description", "members"]
def form_valid(self, form):
circle = form.save(commit=False)
circle.owner = self.request.user
circle.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse("circles:circle_list")

View file

@ -0,0 +1,23 @@
# Generated by Django 4.0.5 on 2022-07-08 20:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("posts", "0002_alter_comment_post_alter_post_img"),
]
operations = [
migrations.AlterField(
model_name="post",
name="body",
field=models.TextField(blank=True, default=""),
),
migrations.AlterField(
model_name="post",
name="title",
field=models.CharField(blank=True, default="", max_length=255),
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 4.0.5 on 2022-07-09 13:27
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("circles", "0001_initial"),
("posts", "0003_alter_post_body_alter_post_title"),
]
operations = [
migrations.RemoveField(
model_name="post",
name="public",
),
migrations.AddField(
model_name="post",
name="shared_with",
field=models.ManyToManyField(to="circles.circle"),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.0.5 on 2022-07-09 13:28
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("posts", "0004_remove_post_public_post_shared_with"),
]
operations = [
migrations.RenameField(
model_name="post",
old_name="shared_with",
new_name="circles",
),
]

View file

@ -1,8 +1,7 @@
import uuid
from django.db import models
from django.conf import settings
from django.db import models
# Create your models here.
@ -15,13 +14,14 @@ def get_img_location(instance, filename):
class Post(models.Model):
img = models.ImageField(upload_to=get_img_location)
posted = models.DateTimeField(auto_now_add=True)
public = models.BooleanField(default=False)
title = models.CharField(max_length=255, null=True)
body = models.TextField(null=True)
title = models.CharField(max_length=255, blank=True, default="")
body = models.TextField(blank=True, default="")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
circles = models.ManyToManyField("circles.Circle")
def __str__(self):
return f"Post: {self.title} at {self.posted.strftime('%Y-%m-%d %H:%S')}"

View file

@ -1,15 +1,16 @@
from django.views.generic import DetailView, CreateView
from django.views.generic.edit import ModelFormMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from django.forms import modelform_factory
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic import CreateView
from django.views.generic import DetailView
from django.views.generic.edit import ModelFormMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Comment
from .models import Post
# Create your views here.
from .models import Post, Comment
class PostDetailView(LoginRequiredMixin, DetailView, ModelFormMixin):
model = Post
@ -21,6 +22,7 @@ class PostDetailView(LoginRequiredMixin, DetailView, ModelFormMixin):
comment.post = self.object
comment.user = self.request.user
comment.save()
return HttpResponseRedirect(self.get_success_url())
def get_queryset(self):
@ -37,7 +39,7 @@ class PostDetailView(LoginRequiredMixin, DetailView, ModelFormMixin):
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ("title", "body", "img")
fields = ("title", "body", "img", "circles")
def get_success_url(self):
return reverse("posts:post_detail", kwargs={"pk": self.object.pk})
@ -46,4 +48,5 @@ class PostCreateView(LoginRequiredMixin, CreateView):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return HttpResponseRedirect(self.get_success_url())

View file

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<h1>Circle {{ object.name }}</h1>
<form action="#" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Post">
</form>
{% endblock content %}

View file

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<h1>Your Circles</h1>
<ul>
{% for circle in object_list %}
<li><a href="{% url "circles:circle_update" circle.pk %}">{{ circle.name }}</a></li>
{% endfor %}
</ul>
{% endblock content %}

View file

@ -5,6 +5,6 @@
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit", value="Post">
<input type="submit" value="Post">
</form>
{% endblock content %}

View file

@ -13,16 +13,17 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include
from django.urls import path
urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
path("posts/", include("flangr.posts.urls")),
path("circles/", include("flangr.circles.urls")),
]
if settings.DEBUG: