From 4a8632dd9ed82935723765acda0b5c707c137a64 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Fri, 3 Feb 2023 00:59:34 +0200 Subject: [PATCH 01/10] add src folder --- blog/__init__.py | 0 blog/admin.py | 27 --- blog/apps.py | 5 - blog/feeds.py | 32 ---- blog/forms.py | 9 - blog/migrations/0001_initial.py | 48 ------ blog/migrations/0002_comment_parent.py | 19 --- blog/migrations/0003_remove_comment_parent.py | 17 -- blog/migrations/0004_auto_20191015_0853.py | 22 --- blog/migrations/0005_auto_20211014_1338.py | 23 --- blog/migrations/__init__.py | 0 blog/models.py | 42 ----- blog/sitemaps.py | 17 -- blog/tests.py | 3 - blog/urls.py | 12 -- blog/views.py | 47 ----- manage.py | 15 -- mysite/__init__.py | 0 mysite/settings.py | 160 ------------------ mysite/urls.py | 38 ----- mysite/wsgi.py | 16 -- static/css/base.css | 27 --- templates/base.html | 76 --------- templates/index.html | 60 ------- templates/post_detail.html | 57 ------- templates/sidebar.html | 17 -- 26 files changed, 789 deletions(-) delete mode 100755 blog/__init__.py delete mode 100755 blog/admin.py delete mode 100755 blog/apps.py delete mode 100644 blog/feeds.py delete mode 100755 blog/forms.py delete mode 100755 blog/migrations/0001_initial.py delete mode 100755 blog/migrations/0002_comment_parent.py delete mode 100755 blog/migrations/0003_remove_comment_parent.py delete mode 100755 blog/migrations/0004_auto_20191015_0853.py delete mode 100644 blog/migrations/0005_auto_20211014_1338.py delete mode 100755 blog/migrations/__init__.py delete mode 100755 blog/models.py delete mode 100644 blog/sitemaps.py delete mode 100755 blog/tests.py delete mode 100755 blog/urls.py delete mode 100755 blog/views.py delete mode 100755 manage.py delete mode 100755 mysite/__init__.py delete mode 100755 mysite/settings.py delete mode 100755 mysite/urls.py delete mode 100755 mysite/wsgi.py delete mode 100755 static/css/base.css delete mode 100755 templates/base.html delete mode 100755 templates/index.html delete mode 100755 templates/post_detail.html delete mode 100755 templates/sidebar.html diff --git a/blog/__init__.py b/blog/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/blog/admin.py b/blog/admin.py deleted file mode 100755 index 8c1dbab..0000000 --- a/blog/admin.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.contrib import admin -from django_summernote.admin import SummernoteModelAdmin - -from .models import Comment, Post - - -class PostAdmin(SummernoteModelAdmin): - list_display = ("title", "slug", "status", "created_on") - list_filter = ("status", "created_on") - search_fields = ["title", "content"] - prepopulated_fields = {"slug": ("title",)} - - summernote_fields = ("content",) - - -@admin.register(Comment) -class CommentAdmin(admin.ModelAdmin): - list_display = ("name", "body", "post", "created_on", "active") - list_filter = ("active", "created_on") - search_fields = ("name", "email", "body") - actions = ["approve_comments"] - - def approve_comments(self, request, queryset): - queryset.update(active=True) - - -admin.site.register(Post, PostAdmin) diff --git a/blog/apps.py b/blog/apps.py deleted file mode 100755 index 1003897..0000000 --- a/blog/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class BlogConfig(AppConfig): - name = "blog" diff --git a/blog/feeds.py b/blog/feeds.py deleted file mode 100644 index c22cc32..0000000 --- a/blog/feeds.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.contrib.syndication.views import Feed -from django.template.defaultfilters import truncatewords -from django.urls import reverse - -from .models import Post - - -class LatestPostsFeed(Feed): - title = "My blog" - link = "" - description = "New posts of my blog." - - def items(self): - return Post.objects.filter(status=1) - - def item_title(self, item): - return item.title - - def item_description(self, item): - return truncatewords(item.content, 30) - - # Only needed if the model has no get_absolute_url method - # def item_link(self, item): - # return reverse("post_detail", args=[item.slug]) - - -from django.utils.feedgenerator import Atom1Feed - - -class AtomSiteNewsFeed(LatestPostsFeed): - feed_type = Atom1Feed - subtitle = LatestPostsFeed.description diff --git a/blog/forms.py b/blog/forms.py deleted file mode 100755 index b31cf4b..0000000 --- a/blog/forms.py +++ /dev/null @@ -1,9 +0,0 @@ -from django import forms - -from .models import Comment - - -class CommentForm(forms.ModelForm): - class Meta: - model = Comment - fields = ("name", "email", "body") diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py deleted file mode 100755 index 39ea4a9..0000000 --- a/blog/migrations/0001_initial.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 2.2.6 on 2019-10-13 10:21 - -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.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=200, unique=True)), - ('slug', models.SlugField(max_length=200, unique=True)), - ('updated_on', models.DateTimeField(auto_now=True)), - ('content', models.TextField()), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Publish')], default=0)), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_posts', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ['-created_on'], - }, - ), - migrations.CreateModel( - name='Comment', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=80)), - ('email', models.EmailField(max_length=254)), - ('body', models.TextField()), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Publish')], default=0)), - ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blog.Post')), - ], - options={ - 'ordering': ['created_on'], - }, - ), - ] diff --git a/blog/migrations/0002_comment_parent.py b/blog/migrations/0002_comment_parent.py deleted file mode 100755 index 34d10c1..0000000 --- a/blog/migrations/0002_comment_parent.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.2.6 on 2019-10-13 12:05 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('blog', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='comment', - name='parent', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='replies', to='blog.Comment'), - ), - ] diff --git a/blog/migrations/0003_remove_comment_parent.py b/blog/migrations/0003_remove_comment_parent.py deleted file mode 100755 index d5a5ab3..0000000 --- a/blog/migrations/0003_remove_comment_parent.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.6 on 2019-10-13 14:16 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('blog', '0002_comment_parent'), - ] - - operations = [ - migrations.RemoveField( - model_name='comment', - name='parent', - ), - ] diff --git a/blog/migrations/0004_auto_20191015_0853.py b/blog/migrations/0004_auto_20191015_0853.py deleted file mode 100755 index 8aaef51..0000000 --- a/blog/migrations/0004_auto_20191015_0853.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.2.6 on 2019-10-15 08:53 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('blog', '0003_remove_comment_parent'), - ] - - operations = [ - migrations.RemoveField( - model_name='comment', - name='status', - ), - migrations.AddField( - model_name='comment', - name='active', - field=models.BooleanField(default=False), - ), - ] diff --git a/blog/migrations/0005_auto_20211014_1338.py b/blog/migrations/0005_auto_20211014_1338.py deleted file mode 100644 index c2b7110..0000000 --- a/blog/migrations/0005_auto_20211014_1338.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2 on 2021-10-14 13:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('blog', '0004_auto_20191015_0853'), - ] - - operations = [ - migrations.AlterField( - model_name='comment', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='post', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - ] diff --git a/blog/migrations/__init__.py b/blog/migrations/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/blog/models.py b/blog/models.py deleted file mode 100755 index bd5695d..0000000 --- a/blog/models.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.contrib.auth.models import User -from django.db import models - -STATUS = ((0, "Draft"), (1, "Publish")) - - -class Post(models.Model): - title = models.CharField(max_length=200, unique=True) - slug = models.SlugField(max_length=200, unique=True) - author = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="blog_posts" - ) - updated_on = models.DateTimeField(auto_now=True) - content = models.TextField() - created_on = models.DateTimeField(auto_now_add=True) - status = models.IntegerField(choices=STATUS, default=0) - - class Meta: - ordering = ["-created_on"] - - def __str__(self): - return self.title - - def get_absolute_url(self): - from django.urls import reverse - - return reverse("post_detail", kwargs={"slug": str(self.slug)}) - - -class Comment(models.Model): - post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments") - name = models.CharField(max_length=80) - email = models.EmailField() - body = models.TextField() - created_on = models.DateTimeField(auto_now_add=True) - active = models.BooleanField(default=False) - - class Meta: - ordering = ["created_on"] - - def __str__(self): - return "Comment {} by {}".format(self.body, self.name) diff --git a/blog/sitemaps.py b/blog/sitemaps.py deleted file mode 100644 index 9a0a02d..0000000 --- a/blog/sitemaps.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.contrib.sitemaps import Sitemap - -from .models import Post - - -class PostSitemap(Sitemap): - changefreq = "weekly" - priority = 0.8 - - def items(self): - return Post.objects.filter(status=1) - - def lastmod(self, obj): - return obj.updated_on - - # def location(self, item): - # return reverse(item) diff --git a/blog/tests.py b/blog/tests.py deleted file mode 100755 index 7ce503c..0000000 --- a/blog/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/blog/urls.py b/blog/urls.py deleted file mode 100755 index 9bc4613..0000000 --- a/blog/urls.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.urls import include, path - -from . import views -from .feeds import AtomSiteNewsFeed, LatestPostsFeed - -urlpatterns = [ - path("feed/rss", LatestPostsFeed(), name="post_feed"), - path("feed/atom", AtomSiteNewsFeed()), - path("", views.PostList.as_view(), name="home"), - # path('/', views.PostDetail.as_view(), name='post_detail'), - path("/", views.post_detail, name="post_detail"), -] diff --git a/blog/views.py b/blog/views.py deleted file mode 100755 index 863d3b6..0000000 --- a/blog/views.py +++ /dev/null @@ -1,47 +0,0 @@ -from django.shortcuts import get_object_or_404, render -from django.views import generic - -from .forms import CommentForm -from .models import Post - - -class PostList(generic.ListView): - queryset = Post.objects.filter(status=1).order_by("-created_on") - template_name = "index.html" - paginate_by = 3 - - -# class PostDetail(generic.DetailView): -# model = Post -# template_name = 'post_detail.html' - - -def post_detail(request, slug): - template_name = "post_detail.html" - post = get_object_or_404(Post, slug=slug) - comments = post.comments.filter(active=True).order_by("-created_on") - new_comment = None - # Comment posted - if request.method == "POST": - comment_form = CommentForm(data=request.POST) - if comment_form.is_valid(): - - # Create Comment object but don't save to database yet - new_comment = comment_form.save(commit=False) - # Assign the current post to the comment - new_comment.post = post - # Save the comment to the database - new_comment.save() - else: - comment_form = CommentForm() - - return render( - request, - template_name, - { - "post": post, - "comments": comments, - "new_comment": new_comment, - "comment_form": comment_form, - }, - ) diff --git a/manage.py b/manage.py deleted file mode 100755 index 66ed3a9..0000000 --- a/manage.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) diff --git a/mysite/__init__.py b/mysite/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/mysite/settings.py b/mysite/settings.py deleted file mode 100755 index 7e6330e..0000000 --- a/mysite/settings.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -Django settings for mysite project. - -Generated by 'django-admin startproject' using Django 2.1.7. - -For more information on this file, see -https://docs.djangoproject.com/en/2.1/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/2.1/ref/settings/ -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -TEMPLATES_DIR = os.path.join(BASE_DIR, "templates") - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "0x!b#(1*cd73w$&azzc6p+essg7v=g80ls#z&xcx*mpemx&@9$" - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "django.contrib.sitemaps", - 'debug_toolbar', - "blog", - "crispy_forms", - "django_summernote", -] - - - - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - 'debug_toolbar.middleware.DebugToolbarMiddleware', - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "mysite.urls" - -# Django Debug Toolbar https://django-debug-toolbar.readthedocs.io/en/latest/installation.html -INTERNAL_IPS = [ - '127.0.0.1', -] - - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [TEMPLATES_DIR], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "mysite.wsgi.application" - - -# Database -# https://docs.djangoproject.com/en/2.1/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } -} - - -# Password validation -# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/2.1/topics/i18n/ - -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/2.1/howto/static-files/ - -STATIC_URL = "/static/" - -# Location of static files -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static"), -] - - -STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") - - -CRISPY_TEMPLATE_PACK = "bootstrap4" - - -# Media paths - -# Base url to serve media files -MEDIA_URL = "/media/" - -# Path where media is stored -MEDIA_ROOT = os.path.join(BASE_DIR, "media/") - - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -X_FRAME_OPTIONS = "SAMEORIGIN" diff --git a/mysite/urls.py b/mysite/urls.py deleted file mode 100755 index 4c3bd0e..0000000 --- a/mysite/urls.py +++ /dev/null @@ -1,38 +0,0 @@ -"""mysite URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/2.1/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -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.conf import settings -from django.conf.urls.static import static -from django.contrib import admin -from django.contrib.sitemaps.views import sitemap -from django.urls import include, path -import debug_toolbar - -from blog.sitemaps import PostSitemap - -sitemaps = { - "posts": PostSitemap, -} - -urlpatterns = [ - path("admin/", admin.site.urls), - path("", include("blog.urls"), name="blog-urls"), - path("summernote/", include("django_summernote.urls")), - path('__debug__/', include(debug_toolbar.urls)), - path("sitemap.xml", sitemap, {"sitemaps": sitemaps}, name="sitemap"), -] - -if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/mysite/wsgi.py b/mysite/wsgi.py deleted file mode 100755 index 619665f..0000000 --- a/mysite/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for mysite project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - -application = get_wsgi_application() diff --git a/static/css/base.css b/static/css/base.css deleted file mode 100755 index 62389f8..0000000 --- a/static/css/base.css +++ /dev/null @@ -1,27 +0,0 @@ -body { - font-family: "Roboto", sans-serif; - font-size: 17px; - background-color: #fdfdfd; -} - -.shadow { - box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1); -} - -.btn-danger { - color: #fff; - background-color: #f00000; - border-color: #dc281e; -} - -.masthead { - background: #3398E1; - height: auto; - padding-bottom: 15px; - box-shadow: 0 16px 48px #E3E7EB; - padding-top: 10px; -} - -.card { - box-shadow: 0 16px 48px #E3E7EB; -} diff --git a/templates/base.html b/templates/base.html deleted file mode 100755 index 1213d83..0000000 --- a/templates/base.html +++ /dev/null @@ -1,76 +0,0 @@ -{% load static %} - - - - - - - - - Django Central - - - - - - - - - - - - - - - - - {% block content %} - - {% endblock content %} - - -
-

Copyright © Django Central

-
- - - - - - - - - - diff --git a/templates/index.html b/templates/index.html deleted file mode 100755 index 760ca1a..0000000 --- a/templates/index.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "base.html" %} - -{% block content %} - - -
-
-
-
-
-
-

Welcome to my awesome Blog

-

We Love Django As much as you do   -

-
-
-
-
- -
- -
-
- - -
- {% for post in post_list %} -
-
-

{{ post.title }}

-

{{ post.author }} | {{ post.created_on}}

- -

{{post.content|safe|slice:":200" }}

- Read More → -
- -
- {% endfor %} - -
- {% block sidebar %} - {% include 'sidebar.html' %} - {% endblock sidebar %} -
-
- {% if is_paginated %} - - - - - {% endif %} -{%endblock%} diff --git a/templates/post_detail.html b/templates/post_detail.html deleted file mode 100755 index e672195..0000000 --- a/templates/post_detail.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends 'base.html' %} {% block content %} - {% load crispy_forms_tags %} - -
-
-
-
-

{% block title %} {{ post.title }} {% endblock title %}

-

{{ post.author }} | {{ post.created_on }}

-

{{ post.content | safe }}

-
-
- {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %} - -
-
- - {% with comments.count as total_comments %} -

{{ total_comments }} comments

- -

- {% endwith %} {% for comment in comments %} -

- -
-

- {{ comment.name }} - - {{ comment.created_on }} - -

- {{ comment.body | linebreaks }} -
- - {% endfor %} -
-
-
-
- {% if new_comment %} - - {% else %} -

Leave a comment

-
- {{ comment_form | crispy }} - {% csrf_token %} - -
- {% endif %} -
-
-
-
- -{% endblock content %} diff --git a/templates/sidebar.html b/templates/sidebar.html deleted file mode 100755 index ec832f7..0000000 --- a/templates/sidebar.html +++ /dev/null @@ -1,17 +0,0 @@ -{% block sidebar %} - - - - -
-
-
About Us
-
-

This awesome blog is made with our Favourite full stack Framework Django, - follow up the tutorial to learn how we made it

- Know more -
-
-
- -{% endblock sidebar %} From 88410ebb2a0f9f8d7018fb38e3fcc3b7646ed22a Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Fri, 3 Feb 2023 01:01:24 +0200 Subject: [PATCH 02/10] add src folder --- .idea/.gitignore | 3 + .idea/Django_blog.iml | 10 ++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + src/blog/__init__.py | 0 src/blog/admin.py | 27 +++ src/blog/apps.py | 5 + src/blog/feeds.py | 32 ++++ src/blog/forms.py | 9 + src/blog/migrations/0001_initial.py | 48 ++++++ src/blog/migrations/__init__.py | 0 src/blog/models.py | 42 +++++ src/blog/sitemaps.py | 17 ++ src/blog/tests.py | 3 + src/blog/urls.py | 12 ++ src/blog/views.py | 47 +++++ src/manage.py | 15 ++ src/mysite/__init__.py | 0 src/mysite/settings.py | 160 ++++++++++++++++++ src/mysite/urls.py | 38 +++++ src/mysite/wsgi.py | 16 ++ src/static/css/base.css | 27 +++ src/templates/base.html | 76 +++++++++ src/templates/index.html | 60 +++++++ src/templates/post_detail.html | 57 +++++++ src/templates/sidebar.html | 17 ++ 28 files changed, 748 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/Django_blog.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 src/blog/__init__.py create mode 100644 src/blog/admin.py create mode 100644 src/blog/apps.py create mode 100644 src/blog/feeds.py create mode 100644 src/blog/forms.py create mode 100644 src/blog/migrations/0001_initial.py create mode 100644 src/blog/migrations/__init__.py create mode 100644 src/blog/models.py create mode 100644 src/blog/sitemaps.py create mode 100644 src/blog/tests.py create mode 100644 src/blog/urls.py create mode 100644 src/blog/views.py create mode 100644 src/manage.py create mode 100644 src/mysite/__init__.py create mode 100644 src/mysite/settings.py create mode 100644 src/mysite/urls.py create mode 100644 src/mysite/wsgi.py create mode 100644 src/static/css/base.css create mode 100644 src/templates/base.html create mode 100644 src/templates/index.html create mode 100644 src/templates/post_detail.html create mode 100644 src/templates/sidebar.html diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..eaf91e2 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Django_blog.iml b/.idea/Django_blog.iml new file mode 100644 index 0000000..858c4d5 --- /dev/null +++ b/.idea/Django_blog.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..61c90c4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d417121 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..c8397c9 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/blog/__init__.py b/src/blog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/blog/admin.py b/src/blog/admin.py new file mode 100644 index 0000000..8c1dbab --- /dev/null +++ b/src/blog/admin.py @@ -0,0 +1,27 @@ +from django.contrib import admin +from django_summernote.admin import SummernoteModelAdmin + +from .models import Comment, Post + + +class PostAdmin(SummernoteModelAdmin): + list_display = ("title", "slug", "status", "created_on") + list_filter = ("status", "created_on") + search_fields = ["title", "content"] + prepopulated_fields = {"slug": ("title",)} + + summernote_fields = ("content",) + + +@admin.register(Comment) +class CommentAdmin(admin.ModelAdmin): + list_display = ("name", "body", "post", "created_on", "active") + list_filter = ("active", "created_on") + search_fields = ("name", "email", "body") + actions = ["approve_comments"] + + def approve_comments(self, request, queryset): + queryset.update(active=True) + + +admin.site.register(Post, PostAdmin) diff --git a/src/blog/apps.py b/src/blog/apps.py new file mode 100644 index 0000000..1003897 --- /dev/null +++ b/src/blog/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class BlogConfig(AppConfig): + name = "blog" diff --git a/src/blog/feeds.py b/src/blog/feeds.py new file mode 100644 index 0000000..c22cc32 --- /dev/null +++ b/src/blog/feeds.py @@ -0,0 +1,32 @@ +from django.contrib.syndication.views import Feed +from django.template.defaultfilters import truncatewords +from django.urls import reverse + +from .models import Post + + +class LatestPostsFeed(Feed): + title = "My blog" + link = "" + description = "New posts of my blog." + + def items(self): + return Post.objects.filter(status=1) + + def item_title(self, item): + return item.title + + def item_description(self, item): + return truncatewords(item.content, 30) + + # Only needed if the model has no get_absolute_url method + # def item_link(self, item): + # return reverse("post_detail", args=[item.slug]) + + +from django.utils.feedgenerator import Atom1Feed + + +class AtomSiteNewsFeed(LatestPostsFeed): + feed_type = Atom1Feed + subtitle = LatestPostsFeed.description diff --git a/src/blog/forms.py b/src/blog/forms.py new file mode 100644 index 0000000..b31cf4b --- /dev/null +++ b/src/blog/forms.py @@ -0,0 +1,9 @@ +from django import forms + +from .models import Comment + + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ("name", "email", "body") diff --git a/src/blog/migrations/0001_initial.py b/src/blog/migrations/0001_initial.py new file mode 100644 index 0000000..0a1d71c --- /dev/null +++ b/src/blog/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.12 on 2023-02-02 22:55 + +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=200, unique=True)), + ('slug', models.SlugField(max_length=200, unique=True)), + ('updated_on', models.DateTimeField(auto_now=True)), + ('content', models.TextField()), + ('created_on', models.DateTimeField(auto_now_add=True)), + ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Publish')], default=0)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_posts', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-created_on'], + }, + ), + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=80)), + ('email', models.EmailField(max_length=254)), + ('body', models.TextField()), + ('created_on', models.DateTimeField(auto_now_add=True)), + ('active', models.BooleanField(default=False)), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blog.post')), + ], + options={ + 'ordering': ['created_on'], + }, + ), + ] diff --git a/src/blog/migrations/__init__.py b/src/blog/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/blog/models.py b/src/blog/models.py new file mode 100644 index 0000000..bd5695d --- /dev/null +++ b/src/blog/models.py @@ -0,0 +1,42 @@ +from django.contrib.auth.models import User +from django.db import models + +STATUS = ((0, "Draft"), (1, "Publish")) + + +class Post(models.Model): + title = models.CharField(max_length=200, unique=True) + slug = models.SlugField(max_length=200, unique=True) + author = models.ForeignKey( + User, on_delete=models.CASCADE, related_name="blog_posts" + ) + updated_on = models.DateTimeField(auto_now=True) + content = models.TextField() + created_on = models.DateTimeField(auto_now_add=True) + status = models.IntegerField(choices=STATUS, default=0) + + class Meta: + ordering = ["-created_on"] + + def __str__(self): + return self.title + + def get_absolute_url(self): + from django.urls import reverse + + return reverse("post_detail", kwargs={"slug": str(self.slug)}) + + +class Comment(models.Model): + post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments") + name = models.CharField(max_length=80) + email = models.EmailField() + body = models.TextField() + created_on = models.DateTimeField(auto_now_add=True) + active = models.BooleanField(default=False) + + class Meta: + ordering = ["created_on"] + + def __str__(self): + return "Comment {} by {}".format(self.body, self.name) diff --git a/src/blog/sitemaps.py b/src/blog/sitemaps.py new file mode 100644 index 0000000..9a0a02d --- /dev/null +++ b/src/blog/sitemaps.py @@ -0,0 +1,17 @@ +from django.contrib.sitemaps import Sitemap + +from .models import Post + + +class PostSitemap(Sitemap): + changefreq = "weekly" + priority = 0.8 + + def items(self): + return Post.objects.filter(status=1) + + def lastmod(self, obj): + return obj.updated_on + + # def location(self, item): + # return reverse(item) diff --git a/src/blog/tests.py b/src/blog/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/src/blog/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/blog/urls.py b/src/blog/urls.py new file mode 100644 index 0000000..9bc4613 --- /dev/null +++ b/src/blog/urls.py @@ -0,0 +1,12 @@ +from django.urls import include, path + +from . import views +from .feeds import AtomSiteNewsFeed, LatestPostsFeed + +urlpatterns = [ + path("feed/rss", LatestPostsFeed(), name="post_feed"), + path("feed/atom", AtomSiteNewsFeed()), + path("", views.PostList.as_view(), name="home"), + # path('/', views.PostDetail.as_view(), name='post_detail'), + path("/", views.post_detail, name="post_detail"), +] diff --git a/src/blog/views.py b/src/blog/views.py new file mode 100644 index 0000000..863d3b6 --- /dev/null +++ b/src/blog/views.py @@ -0,0 +1,47 @@ +from django.shortcuts import get_object_or_404, render +from django.views import generic + +from .forms import CommentForm +from .models import Post + + +class PostList(generic.ListView): + queryset = Post.objects.filter(status=1).order_by("-created_on") + template_name = "index.html" + paginate_by = 3 + + +# class PostDetail(generic.DetailView): +# model = Post +# template_name = 'post_detail.html' + + +def post_detail(request, slug): + template_name = "post_detail.html" + post = get_object_or_404(Post, slug=slug) + comments = post.comments.filter(active=True).order_by("-created_on") + new_comment = None + # Comment posted + if request.method == "POST": + comment_form = CommentForm(data=request.POST) + if comment_form.is_valid(): + + # Create Comment object but don't save to database yet + new_comment = comment_form.save(commit=False) + # Assign the current post to the comment + new_comment.post = post + # Save the comment to the database + new_comment.save() + else: + comment_form = CommentForm() + + return render( + request, + template_name, + { + "post": post, + "comments": comments, + "new_comment": new_comment, + "comment_form": comment_form, + }, + ) diff --git a/src/manage.py b/src/manage.py new file mode 100644 index 0000000..66ed3a9 --- /dev/null +++ b/src/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) diff --git a/src/mysite/__init__.py b/src/mysite/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/mysite/settings.py b/src/mysite/settings.py new file mode 100644 index 0000000..7e6330e --- /dev/null +++ b/src/mysite/settings.py @@ -0,0 +1,160 @@ +""" +Django settings for mysite project. + +Generated by 'django-admin startproject' using Django 2.1.7. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.1/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +TEMPLATES_DIR = os.path.join(BASE_DIR, "templates") + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "0x!b#(1*cd73w$&azzc6p+essg7v=g80ls#z&xcx*mpemx&@9$" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.sitemaps", + 'debug_toolbar', + "blog", + "crispy_forms", + "django_summernote", +] + + + + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + 'debug_toolbar.middleware.DebugToolbarMiddleware', + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "mysite.urls" + +# Django Debug Toolbar https://django-debug-toolbar.readthedocs.io/en/latest/installation.html +INTERNAL_IPS = [ + '127.0.0.1', +] + + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [TEMPLATES_DIR], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "mysite.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/2.1/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/2.1/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.1/howto/static-files/ + +STATIC_URL = "/static/" + +# Location of static files +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "static"), +] + + +STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") + + +CRISPY_TEMPLATE_PACK = "bootstrap4" + + +# Media paths + +# Base url to serve media files +MEDIA_URL = "/media/" + +# Path where media is stored +MEDIA_ROOT = os.path.join(BASE_DIR, "media/") + + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +X_FRAME_OPTIONS = "SAMEORIGIN" diff --git a/src/mysite/urls.py b/src/mysite/urls.py new file mode 100644 index 0000000..4c3bd0e --- /dev/null +++ b/src/mysite/urls.py @@ -0,0 +1,38 @@ +"""mysite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +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.conf import settings +from django.conf.urls.static import static +from django.contrib import admin +from django.contrib.sitemaps.views import sitemap +from django.urls import include, path +import debug_toolbar + +from blog.sitemaps import PostSitemap + +sitemaps = { + "posts": PostSitemap, +} + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", include("blog.urls"), name="blog-urls"), + path("summernote/", include("django_summernote.urls")), + path('__debug__/', include(debug_toolbar.urls)), + path("sitemap.xml", sitemap, {"sitemaps": sitemaps}, name="sitemap"), +] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/src/mysite/wsgi.py b/src/mysite/wsgi.py new file mode 100644 index 0000000..619665f --- /dev/null +++ b/src/mysite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mysite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +application = get_wsgi_application() diff --git a/src/static/css/base.css b/src/static/css/base.css new file mode 100644 index 0000000..62389f8 --- /dev/null +++ b/src/static/css/base.css @@ -0,0 +1,27 @@ +body { + font-family: "Roboto", sans-serif; + font-size: 17px; + background-color: #fdfdfd; +} + +.shadow { + box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1); +} + +.btn-danger { + color: #fff; + background-color: #f00000; + border-color: #dc281e; +} + +.masthead { + background: #3398E1; + height: auto; + padding-bottom: 15px; + box-shadow: 0 16px 48px #E3E7EB; + padding-top: 10px; +} + +.card { + box-shadow: 0 16px 48px #E3E7EB; +} diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..1213d83 --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,76 @@ +{% load static %} + + + + + + + + + Django Central + + + + + + + + + + + + + + + + + {% block content %} + + {% endblock content %} + + +
+

Copyright © Django Central

+
+ + + + + + + + + + diff --git a/src/templates/index.html b/src/templates/index.html new file mode 100644 index 0000000..760ca1a --- /dev/null +++ b/src/templates/index.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} + +{% block content %} + + +
+
+
+
+
+
+

Welcome to my awesome Blog

+

We Love Django As much as you do   +

+
+
+
+
+ +
+ +
+
+ + +
+ {% for post in post_list %} +
+
+

{{ post.title }}

+

{{ post.author }} | {{ post.created_on}}

+ +

{{post.content|safe|slice:":200" }}

+ Read More → +
+ +
+ {% endfor %} + +
+ {% block sidebar %} + {% include 'sidebar.html' %} + {% endblock sidebar %} +
+
+ {% if is_paginated %} + +
    + {% if page_obj.has_previous %} +
  • « PREV
  • + {% endif %} + {% if page_obj.has_next %} +
  • NEXT »
  • + + {% endif %} +
+ + + {% endif %} +{%endblock%} diff --git a/src/templates/post_detail.html b/src/templates/post_detail.html new file mode 100644 index 0000000..e672195 --- /dev/null +++ b/src/templates/post_detail.html @@ -0,0 +1,57 @@ +{% extends 'base.html' %} {% block content %} + {% load crispy_forms_tags %} + +
+
+
+
+

{% block title %} {{ post.title }} {% endblock title %}

+

{{ post.author }} | {{ post.created_on }}

+

{{ post.content | safe }}

+
+
+ {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %} + +
+
+ + {% with comments.count as total_comments %} +

{{ total_comments }} comments

+ +

+ {% endwith %} {% for comment in comments %} +

+ +
+

+ {{ comment.name }} + + {{ comment.created_on }} + +

+ {{ comment.body | linebreaks }} +
+ + {% endfor %} +
+
+
+
+ {% if new_comment %} + + {% else %} +

Leave a comment

+
+ {{ comment_form | crispy }} + {% csrf_token %} + +
+ {% endif %} +
+
+
+
+ +{% endblock content %} diff --git a/src/templates/sidebar.html b/src/templates/sidebar.html new file mode 100644 index 0000000..ec832f7 --- /dev/null +++ b/src/templates/sidebar.html @@ -0,0 +1,17 @@ +{% block sidebar %} + + + + +
+
+
About Us
+
+

This awesome blog is made with our Favourite full stack Framework Django, + follow up the tutorial to learn how we made it

+ Know more +
+
+
+ +{% endblock sidebar %} From 8e5b9fc8ca4626f9662d08243bee902b1214fde0 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Sun, 5 Feb 2023 00:23:51 +0200 Subject: [PATCH 03/10] use post tag in url --- .idea/Django_blog.iml | 1 + src/blog/migrations/0001_initial.py | 48 ----------------------------- src/blog/models.py | 1 + src/blog/urls.py | 2 ++ src/blog/views.py | 10 +++++- src/mysite/settings.py | 2 ++ src/templates/post_detail.html | 5 +-- 7 files changed, 18 insertions(+), 51 deletions(-) delete mode 100644 src/blog/migrations/0001_initial.py diff --git a/.idea/Django_blog.iml b/.idea/Django_blog.iml index 858c4d5..d289905 100644 --- a/.idea/Django_blog.iml +++ b/.idea/Django_blog.iml @@ -2,6 +2,7 @@ + diff --git a/src/blog/migrations/0001_initial.py b/src/blog/migrations/0001_initial.py deleted file mode 100644 index 0a1d71c..0000000 --- a/src/blog/migrations/0001_initial.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 3.2.12 on 2023-02-02 22:55 - -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=200, unique=True)), - ('slug', models.SlugField(max_length=200, unique=True)), - ('updated_on', models.DateTimeField(auto_now=True)), - ('content', models.TextField()), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Publish')], default=0)), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_posts', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ['-created_on'], - }, - ), - migrations.CreateModel( - name='Comment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=80)), - ('email', models.EmailField(max_length=254)), - ('body', models.TextField()), - ('created_on', models.DateTimeField(auto_now_add=True)), - ('active', models.BooleanField(default=False)), - ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blog.post')), - ], - options={ - 'ordering': ['created_on'], - }, - ), - ] diff --git a/src/blog/models.py b/src/blog/models.py index bd5695d..47d4de7 100644 --- a/src/blog/models.py +++ b/src/blog/models.py @@ -14,6 +14,7 @@ class Post(models.Model): content = models.TextField() created_on = models.DateTimeField(auto_now_add=True) status = models.IntegerField(choices=STATUS, default=0) + tag = models.CharField(unique=False, max_length=50) class Meta: ordering = ["-created_on"] diff --git a/src/blog/urls.py b/src/blog/urls.py index 9bc4613..e8b9b51 100644 --- a/src/blog/urls.py +++ b/src/blog/urls.py @@ -1,6 +1,7 @@ from django.urls import include, path from . import views +from blog.views import PostTag from .feeds import AtomSiteNewsFeed, LatestPostsFeed urlpatterns = [ @@ -9,4 +10,5 @@ path("", views.PostList.as_view(), name="home"), # path('/', views.PostDetail.as_view(), name='post_detail'), path("/", views.post_detail, name="post_detail"), + path("tag//", PostTag.as_view(), name="post_detail"), ] diff --git a/src/blog/views.py b/src/blog/views.py index 863d3b6..f051bbb 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -1,4 +1,4 @@ -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, render, redirect from django.views import generic from .forms import CommentForm @@ -15,6 +15,14 @@ class PostList(generic.ListView): # model = Post # template_name = 'post_detail.html' +class PostTag(generic.ListView): + queryset = Post.objects.filter(status=1).order_by("-created_on") + template_name = "index.html" + + def get(self, request, *args, **kwargs): + print(args, kwargs) + return redirect("__debug__/") + def post_detail(request, slug): template_name = "post_detail.html" diff --git a/src/mysite/settings.py b/src/mysite/settings.py index 7e6330e..9a52a3c 100644 --- a/src/mysite/settings.py +++ b/src/mysite/settings.py @@ -17,6 +17,8 @@ TEMPLATES_DIR = os.path.join(BASE_DIR, "templates") + + # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ diff --git a/src/templates/post_detail.html b/src/templates/post_detail.html index e672195..1fab24c 100644 --- a/src/templates/post_detail.html +++ b/src/templates/post_detail.html @@ -8,6 +8,9 @@

{% block title %} {{ post.title }} {% endblock title %}

{{ post.author }} | {{ post.created_on }}

{{ post.content | safe }}

+
+

Tag

+

{{post.tag}}

{% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %} @@ -17,11 +20,9 @@

{% block title %} {{ post.title }} {% endblock title %}

{% with comments.count as total_comments %}

{{ total_comments }} comments

-

{% endwith %} {% for comment in comments %}

-

{{ comment.name }} From 8829e92d26f566f2d4d1e05bde3cd6ce01326d01 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:54:58 +0200 Subject: [PATCH 04/10] filter post according to tag in url --- src/blog/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blog/views.py b/src/blog/views.py index f051bbb..66dd5a1 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -21,7 +21,8 @@ class PostTag(generic.ListView): def get(self, request, *args, **kwargs): print(args, kwargs) - return redirect("__debug__/") + post_list = Post.objects.filter(tag=kwargs['tag']) + return render(request, self.template_name, context={'post_list': post_list}) def post_detail(request, slug): From 01f351eb0ec3003da164df09865db4210fafb9d7 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:15:15 +0200 Subject: [PATCH 05/10] add all posts url --- .idea/Django_blog.iml | 2 +- .idea/misc.xml | 2 +- src/blog/urls.py | 5 +++-- src/blog/views.py | 13 ++++++++----- src/mysite/urls.py | 1 - 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.idea/Django_blog.iml b/.idea/Django_blog.iml index d289905..a05f1a4 100644 --- a/.idea/Django_blog.iml +++ b/.idea/Django_blog.iml @@ -5,7 +5,7 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 61c90c4..98b7183 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/src/blog/urls.py b/src/blog/urls.py index e8b9b51..778b5f3 100644 --- a/src/blog/urls.py +++ b/src/blog/urls.py @@ -1,14 +1,15 @@ from django.urls import include, path from . import views -from blog.views import PostTag +from blog.views import PostTag, AllPosts from .feeds import AtomSiteNewsFeed, LatestPostsFeed urlpatterns = [ path("feed/rss", LatestPostsFeed(), name="post_feed"), path("feed/atom", AtomSiteNewsFeed()), path("", views.PostList.as_view(), name="home"), + path("articles/", views.AllPosts.as_view(), name="articles"), # path('/', views.PostDetail.as_view(), name='post_detail'), path("/", views.post_detail, name="post_detail"), - path("tag//", PostTag.as_view(), name="post_detail"), + path("articles//", PostTag.as_view()) ] diff --git a/src/blog/views.py b/src/blog/views.py index 66dd5a1..ea8997f 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -16,25 +16,23 @@ class PostList(generic.ListView): # template_name = 'post_detail.html' class PostTag(generic.ListView): - queryset = Post.objects.filter(status=1).order_by("-created_on") template_name = "index.html" def get(self, request, *args, **kwargs): - print(args, kwargs) - post_list = Post.objects.filter(tag=kwargs['tag']) - return render(request, self.template_name, context={'post_list': post_list}) + posts = Post.objects.filter(tag=kwargs['tag']) + return render(request, self.template_name, {"post_list": posts}) def post_detail(request, slug): template_name = "post_detail.html" post = get_object_or_404(Post, slug=slug) + print("post objects-->", post) comments = post.comments.filter(active=True).order_by("-created_on") new_comment = None # Comment posted if request.method == "POST": comment_form = CommentForm(data=request.POST) if comment_form.is_valid(): - # Create Comment object but don't save to database yet new_comment = comment_form.save(commit=False) # Assign the current post to the comment @@ -54,3 +52,8 @@ def post_detail(request, slug): "comment_form": comment_form, }, ) + +class AllPosts(generic.ListView): + template_name = "index.html" + queryset = Post.objects.filter(status=1).order_by("-created_on") + paginate_by = 3 diff --git a/src/mysite/urls.py b/src/mysite/urls.py index 4c3bd0e..dd9f6dc 100644 --- a/src/mysite/urls.py +++ b/src/mysite/urls.py @@ -19,7 +19,6 @@ from django.contrib.sitemaps.views import sitemap from django.urls import include, path import debug_toolbar - from blog.sitemaps import PostSitemap sitemaps = { From 067a3b525ab1d67f3ebdc6b3bda35543a212fcc6 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:24:41 +0200 Subject: [PATCH 06/10] add all post h3 to template if url is /articles/ --- src/blog/views.py | 2 ++ src/templates/index.html | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/blog/views.py b/src/blog/views.py index ea8997f..d1a775f 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -20,6 +20,7 @@ class PostTag(generic.ListView): def get(self, request, *args, **kwargs): posts = Post.objects.filter(tag=kwargs['tag']) + return render(request, self.template_name, {"post_list": posts}) @@ -53,6 +54,7 @@ def post_detail(request, slug): }, ) + class AllPosts(generic.ListView): template_name = "index.html" queryset = Post.objects.filter(status=1).order_by("-created_on") diff --git a/src/templates/index.html b/src/templates/index.html index 760ca1a..6be1901 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -9,8 +9,13 @@

+ {% if request.get_full_path == "/" %}

Welcome to my awesome Blog

We Love Django As much as you do   + {% elif request.get_full_path == "/articles/"%} + +

All posts

+ {% endif %}

From 5965036c7fc6e4bf3464b5b528569223e4941aba Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:26:19 +0200 Subject: [PATCH 07/10] change articles to posts --- src/blog/urls.py | 2 +- src/blog/views.py | 2 +- src/templates/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/blog/urls.py b/src/blog/urls.py index 778b5f3..bec07d6 100644 --- a/src/blog/urls.py +++ b/src/blog/urls.py @@ -8,7 +8,7 @@ path("feed/rss", LatestPostsFeed(), name="post_feed"), path("feed/atom", AtomSiteNewsFeed()), path("", views.PostList.as_view(), name="home"), - path("articles/", views.AllPosts.as_view(), name="articles"), + path("posts/", views.AllPosts.as_view(), name="articles"), # path('/', views.PostDetail.as_view(), name='post_detail'), path("/", views.post_detail, name="post_detail"), path("articles//", PostTag.as_view()) diff --git a/src/blog/views.py b/src/blog/views.py index d1a775f..95fdb87 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -20,7 +20,7 @@ class PostTag(generic.ListView): def get(self, request, *args, **kwargs): posts = Post.objects.filter(tag=kwargs['tag']) - + return render(request, self.template_name, {"post_list": posts}) diff --git a/src/templates/index.html b/src/templates/index.html index 6be1901..96019e3 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -12,7 +12,7 @@ {% if request.get_full_path == "/" %}

Welcome to my awesome Blog

We Love Django As much as you do   - {% elif request.get_full_path == "/articles/"%} + {% elif request.get_full_path == "/posts/"%}

All posts

{% endif %} From 0c12a331d7358dee481d65c67c4386a19b5683cb Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Tue, 7 Feb 2023 19:56:12 +0200 Subject: [PATCH 08/10] finishing urls for /, /posts/, posts/tag --- src/blog/urls.py | 2 +- src/blog/views.py | 12 ++++++++---- src/templates/index.html | 17 ++++++++++------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/blog/urls.py b/src/blog/urls.py index bec07d6..4c3df10 100644 --- a/src/blog/urls.py +++ b/src/blog/urls.py @@ -11,5 +11,5 @@ path("posts/", views.AllPosts.as_view(), name="articles"), # path('/', views.PostDetail.as_view(), name='post_detail'), path("/", views.post_detail, name="post_detail"), - path("articles//", PostTag.as_view()) + path("posts//", PostTag.as_view()) ] diff --git a/src/blog/views.py b/src/blog/views.py index 95fdb87..bfe9b2e 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -17,11 +17,15 @@ class PostList(generic.ListView): class PostTag(generic.ListView): template_name = "index.html" + paginate_by = 3 - def get(self, request, *args, **kwargs): - posts = Post.objects.filter(tag=kwargs['tag']) - - return render(request, self.template_name, {"post_list": posts}) + def get_queryset(self): + posts = Post.objects.filter(tag=self.kwargs['tag']) + return posts + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + context['tag'] = self.kwargs['tag'] + return context def post_detail(request, slug): diff --git a/src/templates/index.html b/src/templates/index.html index 96019e3..03836ee 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -9,24 +9,27 @@
- {% if request.get_full_path == "/" %} + + {% if "/posts/"|add:tag|add:"/" in request.path %} + +

Tag: {{tag}}

+ + {% elif "/posts/" in request.path %} +

all posts

+ + {% else %}

Welcome to my awesome Blog

-

We Love Django As much as you do   - {% elif request.get_full_path == "/posts/"%} +

We Love Django As much as you do  

-

All posts

{% endif %} -

-
-
{% for post in post_list %} From 68f32733eaac32eee05ee0690a7fca0f44f42294 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:13:33 +0200 Subject: [PATCH 09/10] finish post tag --- src/blog/urls.py | 2 +- src/static/css/base.css | 6 ++++++ src/templates/index.html | 6 +++--- src/templates/post_detail.html | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/blog/urls.py b/src/blog/urls.py index 4c3df10..1decfb6 100644 --- a/src/blog/urls.py +++ b/src/blog/urls.py @@ -11,5 +11,5 @@ path("posts/", views.AllPosts.as_view(), name="articles"), # path('/', views.PostDetail.as_view(), name='post_detail'), path("/", views.post_detail, name="post_detail"), - path("posts//", PostTag.as_view()) + path("posts//", PostTag.as_view(), name="post_tag") ] diff --git a/src/static/css/base.css b/src/static/css/base.css index 62389f8..59c6963 100644 --- a/src/static/css/base.css +++ b/src/static/css/base.css @@ -4,6 +4,12 @@ body { background-color: #fdfdfd; } +.post-tag { + color: black; + text-decoration: none; +} + + .shadow { box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1); } diff --git a/src/templates/index.html b/src/templates/index.html index 03836ee..cc148c6 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -12,10 +12,10 @@ {% if "/posts/"|add:tag|add:"/" in request.path %} -

Tag: {{tag}}

+

Tag: {{tag}}

{% elif "/posts/" in request.path %} -

all posts

+

all posts

{% else %}

Welcome to my awesome Blog

@@ -35,9 +35,9 @@

Welcome to my awesome Blog

{% for post in post_list %}
+ {{ post.tag }}

{{ post.title }}

{{ post.author }} | {{ post.created_on}}

-

{{post.content|safe|slice:":200" }}

Read More →
diff --git a/src/templates/post_detail.html b/src/templates/post_detail.html index 1fab24c..3a3124a 100644 --- a/src/templates/post_detail.html +++ b/src/templates/post_detail.html @@ -9,8 +9,8 @@

{% block title %} {{ post.title }} {% endblock title %}

{{ post.author }} | {{ post.created_on }}

{{ post.content | safe }}


-

Tag

-

{{post.tag}}

+

Tag

+ {{ post.tag }}
{% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %} From af42c741157f3a3141bed544de1dccfbf4cdee03 Mon Sep 17 00:00:00 2001 From: Mohamed Talaat <102768699+MohamedTalaat-Coder@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:17:36 +0200 Subject: [PATCH 10/10] finish post tag --- src/blog/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/blog/views.py b/src/blog/views.py index bfe9b2e..5dcfe29 100644 --- a/src/blog/views.py +++ b/src/blog/views.py @@ -31,7 +31,6 @@ def get_context_data(self, *args, **kwargs): def post_detail(request, slug): template_name = "post_detail.html" post = get_object_or_404(Post, slug=slug) - print("post objects-->", post) comments = post.comments.filter(active=True).order_by("-created_on") new_comment = None # Comment posted