From 769bc3418b0ee02c5edeec1c9e1e4de4d838dbc2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 16 May 2021 19:43:41 -0500 Subject: [PATCH] {Modified} project --- config/config/settings.py | 14 +++ config/photoapp/forms.py | 22 +++++ config/photoapp/migrations/0001_initial.py | 31 +++++++ config/photoapp/urls.py | 28 ++++++ config/photoapp/views.py | 101 ++++++++++++++++++++- 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 config/photoapp/forms.py create mode 100644 config/photoapp/migrations/0001_initial.py diff --git a/config/config/settings.py b/config/config/settings.py index 5617ab3..2f4b48a 100644 --- a/config/config/settings.py +++ b/config/config/settings.py @@ -37,6 +37,12 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + + # 3rd party apps + 'taggit', + + # Custom apps + 'photoapp', ] MIDDLEWARE = [ @@ -114,6 +120,14 @@ USE_TZ = True +# Django taggit + +TAGGIT_CASE_INSENSITIVE = True + +# Django Authentication +LOGIN_URL = 'users:login' +LOGIN_REDIRECT_URL = 'photo:list' + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ diff --git a/config/photoapp/forms.py b/config/photoapp/forms.py new file mode 100644 index 0000000..6dcc2a6 --- /dev/null +++ b/config/photoapp/forms.py @@ -0,0 +1,22 @@ +'''Photo app Forms''' + +from django import forms +from django.forms import fields + +from .models import Photo + +class CreatePhotoForm(forms.ModelForm): + + class Meta: + model = Photo + + fields = ('title', 'description', 'image', 'tags') + + +class UpdatePhotoForm(forms.ModelForm): + + class Meta: + model = Photo + + fields = ('title', 'description') + \ No newline at end of file diff --git a/config/photoapp/migrations/0001_initial.py b/config/photoapp/migrations/0001_initial.py new file mode 100644 index 0000000..233becc --- /dev/null +++ b/config/photoapp/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.3 on 2021-05-16 21:29 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import taggit.managers + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('taggit', '0003_taggeditem_add_unique_index'), + ] + + operations = [ + migrations.CreateModel( + name='Photo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=45)), + ('description', models.CharField(max_length=250)), + ('created', models.DateTimeField(auto_now_add=True)), + ('image', models.ImageField(upload_to='photos/')), + ('submitter', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')), + ], + ), + ] diff --git a/config/photoapp/urls.py b/config/photoapp/urls.py index e69de29..1c5900b 100644 --- a/config/photoapp/urls.py +++ b/config/photoapp/urls.py @@ -0,0 +1,28 @@ +'''Photoapp URL patterns''' + +from django.urls import path + +from .views import ( + PhotoListView, + PhotoTagListView, + PhotoDetailView, + PhotoCreateView, + PhotoUpdateView, + PhotoDeleteView +) + +appname = 'photo' + +urlpatterns = [ + path('', PhotoListView.as_view(), name='list'), + + path('tag//', PhotoTagListView.as_view(), name='tag'), + + path('photo//', PhotoDetailView.as_view(), name='detail'), + + path('photo/create/', PhotoCreateView.as_view(), name='create'), + + path('photo//update/', PhotoUpdateView.as_view(), name='update'), + + path('photo//delete/', PhotoDeleteView.as_view(), name='delete'), +] diff --git a/config/photoapp/views.py b/config/photoapp/views.py index 91ea44a..67daab1 100644 --- a/config/photoapp/views.py +++ b/config/photoapp/views.py @@ -1,3 +1,100 @@ -from django.shortcuts import render +'''Photo app generic views''' -# Create your views here. +from django.shortcuts import get_object_or_404 + +from django.http import HttpResponseNotAllowed + +from django.urls.resolvers import get_resolver + +from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView + +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin + +from django.urls import reverse_lazy + +from .models import Photo + +from .forms import CreatePhotoForm, UpdatePhotoForm + +class PhotoListView(ListView): + + model = Photo + + template_name = 'photoapp/list.html' + + context_object_name = 'photos' + + +class PhotoTagListView(ListView): + + model = Photo + + template_name = 'photoapp/taglist.html' + + context_object_name = 'photos' + + + # Custom function + def get_tag(self): + return self.kwargs.get('tag') + + def get_queryset(self): + return Photo.objects.filter(tag__slug_in=[self.get_tag()]) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["tag"] = self.get_tag() + return context + + +class PhotoDetailView(DetailView): + + model = Photo + + context_object_name = 'photo' + + template_name = 'photoapp/detail.html' + + +class PhotoCreateView(LoginRequiredMixin, CreateView): + + model = Photo + + form = CreatePhotoForm + + success_url = reverse_lazy('photo:list') + + def form_valid(self, form): + + form.user = self.request.user + form.save() + # Without this next line the tags won't be saved. + form.save_m2m() + return super().form_valid(form) + +class UserIsSubmitter(UserPassesTestMixin): + + # Custom method + def get_photo(self): + return get_object_or_404(Photo, pk=self.kwargs.get('pk')) + + def test_func(self): + + if self.request.user.is_authenticated(): + return self.request.user is self.get_photo().submitter + else: + raise HttpResponseNotAllowed('Sorry you are not allowed here') + +class PhotoUpdateView(UserIsSubmitter, UpdateView): + + model = Photo + + form = UpdatePhotoForm + + success_url = reverse_lazy('photo:list') + +class PhotoDeleteView(UserIsSubmitter, DeleteView): + + model = Photo + + success_url = reverse_lazy('photo:list') \ No newline at end of file