├── main ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ ├── 0001_initial.cpython-310.pyc │ │ ├── 0003_contact.cpython-310.pyc │ │ ├── 0002_blog_slug.cpython-310.pyc │ │ ├── 0005_blog_mini_description.cpython-310.pyc │ │ └── 0004_alter_blog_description.cpython-310.pyc │ ├── 0007_alter_blog_description.py │ ├── 0002_blog_slug.py │ ├── 0004_alter_blog_description.py │ ├── 0008_alter_blog_description.py │ ├── 0005_blog_mini_description.py │ ├── 0006_alter_blog_author.py │ ├── 0003_contact.py │ └── 0001_initial.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-310.pyc │ ├── urls.cpython-310.pyc │ ├── admin.cpython-310.pyc │ ├── forms.cpython-310.pyc │ ├── models.cpython-310.pyc │ ├── views.cpython-310.pyc │ └── __init__.cpython-310.pyc ├── apps.py ├── admin.py ├── urls.py ├── models.py ├── forms.py └── views.py ├── authors ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-310.pyc │ ├── 0002_userprofuile_education_userprofuile_work.py │ ├── 0003_userprofuile_currently_hacking_on_and_more.py │ └── 0001_initial.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-310.pyc │ ├── urls.cpython-310.pyc │ ├── admin.cpython-310.pyc │ ├── forms.cpython-310.pyc │ ├── models.cpython-310.pyc │ ├── views.cpython-310.pyc │ └── __init__.cpython-310.pyc ├── admin.py ├── apps.py ├── signals.py ├── models.py ├── urls.py ├── forms.py └── views.py ├── blog_project ├── __init__.py ├── __pycache__ │ ├── urls.cpython-310.pyc │ ├── wsgi.cpython-310.pyc │ ├── __init__.cpython-310.pyc │ └── settings.cpython-310.pyc ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── Procfile ├── db.sqlite3 ├── templates ├── authors │ ├── password_change_success.html │ ├── login.html │ ├── delete_user_confirm.html │ ├── edit_user_profile.html │ ├── register.html │ ├── password_change.html │ ├── dashboard.html │ ├── edit_public_details.html │ └── profile.html ├── main │ ├── update_blog.html │ ├── create_blog.html │ ├── delete_blog.html │ ├── contact_us.html │ ├── blog_home.html │ └── blog_detail.html ├── containers │ ├── _sideNavBar.html │ └── _navbar.html └── base.html ├── requirements.txt ├── manage.py ├── readme.md └── .gitignore /main/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /authors/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog_project/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /authors/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: python manage.py migrate 2 | web: gunicorn blog_project.wsgi -------------------------------------------------------------------------------- /authors/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /main/__pycache__/apps.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/apps.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/urls.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/urls.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/apps.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/apps.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/urls.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/urls.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/admin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/admin.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/forms.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/forms.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/models.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/models.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/views.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/views.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/admin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/admin.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/forms.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/forms.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/models.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/models.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/views.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/views.cpython-310.pyc -------------------------------------------------------------------------------- /main/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /authors/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /blog_project/__pycache__/urls.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/blog_project/__pycache__/urls.cpython-310.pyc -------------------------------------------------------------------------------- /blog_project/__pycache__/wsgi.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/blog_project/__pycache__/wsgi.cpython-310.pyc -------------------------------------------------------------------------------- /authors/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import UserProfuile 3 | 4 | # Register your models here. 5 | admin.site.register(UserProfuile) 6 | -------------------------------------------------------------------------------- /blog_project/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/blog_project/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /blog_project/__pycache__/settings.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/blog_project/__pycache__/settings.cpython-310.pyc -------------------------------------------------------------------------------- /main/migrations/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /authors/migrations/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/authors/migrations/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'main' 7 | -------------------------------------------------------------------------------- /main/migrations/__pycache__/0001_initial.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/0001_initial.cpython-310.pyc -------------------------------------------------------------------------------- /main/migrations/__pycache__/0003_contact.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/0003_contact.cpython-310.pyc -------------------------------------------------------------------------------- /main/migrations/__pycache__/0002_blog_slug.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/0002_blog_slug.cpython-310.pyc -------------------------------------------------------------------------------- /main/migrations/__pycache__/0005_blog_mini_description.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/0005_blog_mini_description.cpython-310.pyc -------------------------------------------------------------------------------- /main/migrations/__pycache__/0004_alter_blog_description.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashpatel-py/django_blog_youtube/HEAD/main/migrations/__pycache__/0004_alter_blog_description.cpython-310.pyc -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Blog, BlogComment, Contact 3 | 4 | # Register your models here. 5 | admin.site.register(Blog) 6 | admin.site.register(BlogComment) 7 | admin.site.register(Contact) -------------------------------------------------------------------------------- /authors/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AuthorsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'authors' 7 | 8 | def ready(self): 9 | import authors.signals 10 | -------------------------------------------------------------------------------- /templates/authors/password_change_success.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Password changed successfully{% endblock title %} 4 | 5 | {% block content %} 6 |

Your password has been updated successfully - {{user.username}}

7 | {% endblock content %} -------------------------------------------------------------------------------- /templates/authors/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Login{% endblock title %} 4 | 5 | {% block content %} 6 |

Login

7 | 8 |
9 | {% csrf_token %} 10 | 11 | {{form}} 12 | 13 | 14 |
15 | {% endblock content %} -------------------------------------------------------------------------------- /authors/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import post_save 2 | from django.contrib.auth import get_user_model 3 | from django.dispatch import receiver 4 | from .models import UserProfuile 5 | 6 | user = get_user_model() 7 | 8 | 9 | @receiver(post_save, sender=user) 10 | def create_user_profile(sender, instance, created, **kwargs): 11 | if created: 12 | UserProfuile.objects.create(user=instance) 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.5.2 2 | autopep8==1.6.0 3 | bleach==5.0.1 4 | crispy-bootstrap5==0.6 5 | Django==4.0.6 6 | django-ckeditor==6.5.0 7 | django-crispy-forms==1.14.0 8 | django-js-asset==2.0.0 9 | fontawesomefree==6.1.1 10 | gunicorn==20.1.0 11 | Pillow==9.2.0 12 | pycodestyle==2.8.0 13 | six==1.16.0 14 | sqlparse==0.4.2 15 | toml==0.10.2 16 | tzdata==2022.1 17 | webencodings==0.5.1 18 | whitenoise==6.2.0 19 | -------------------------------------------------------------------------------- /templates/authors/delete_user_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Delete {{ user.username }}'s Account{% endblock title %} 4 | 5 | {% block content %} 6 |

Delete user confirm page

7 | 8 |
9 | {% csrf_token %} 10 | 11 | 12 |
13 | {% endblock content %} -------------------------------------------------------------------------------- /templates/main/update_blog.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Update Blog{% endblock title %} 4 | 5 | {% block content %} 6 |
7 | {% csrf_token %} 8 | {{form.media}} 9 | {{form.as_p}} 10 | 11 | 12 |
13 | 14 | 18 | {% endblock content %} -------------------------------------------------------------------------------- /blog_project/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for blog_project project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blog_project.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /blog_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for blog_project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blog_project.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /templates/main/create_blog.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Create new blog{% endblock title %} 4 | 5 | {% block content %} 6 | 7 |
8 | {% csrf_token %} 9 | {{ form.media }} 10 | {{form.as_p}} 11 | 12 |
13 | 14 | 18 | 19 | {% endblock content %} -------------------------------------------------------------------------------- /main/migrations/0007_alter_blog_description.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-08-14 08:01 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('main', '0006_alter_blog_author'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='blog', 15 | name='description', 16 | field=models.TextField(), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /main/migrations/0002_blog_slug.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.1 on 2022-02-09 05:19 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('main', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='blog', 15 | name='slug', 16 | field=models.CharField(blank=True, max_length=1000, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /main/migrations/0004_alter_blog_description.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.1 on 2022-04-23 14:53 2 | 3 | import ckeditor.fields 4 | from django.db import migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('main', '0003_contact'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='blog', 16 | name='description', 17 | field=ckeditor.fields.RichTextField(), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /main/migrations/0008_alter_blog_description.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-08-14 08:55 2 | 3 | import ckeditor.fields 4 | from django.db import migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('main', '0007_alter_blog_description'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='blog', 16 | name='description', 17 | field=ckeditor.fields.RichTextField(), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /main/migrations/0005_blog_mini_description.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.1 on 2022-04-24 08:50 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('main', '0004_alter_blog_description'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='blog', 15 | name='mini_description', 16 | field=models.TextField(default=''), 17 | preserve_default=False, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /main/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from main import views 3 | 4 | urlpatterns = [ 5 | path('', views.blog_home.as_view(), name="home"), 6 | path('blog_detail/', views.blog_detail, name="blog_detail"), 7 | path('contact_us/', views.contactUs.as_view(), name="contact_us"), 8 | 9 | path('create_new_blog/', views.CreateBlog.as_view(), name="create-blog"), 10 | 11 | path('update_blog//', views.UpdateBlogView.as_view(), name="UpdateBlogView"), 12 | 13 | path('delete_blog//', views.DeleteBlogView.as_view(), name="DeleteBlogView") 14 | ] 15 | -------------------------------------------------------------------------------- /templates/authors/edit_user_profile.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Edit profile{% endblock title %} 4 | 5 | {% block content %} 6 |

Update user

7 | 8 |
9 |
10 | {% include 'containers/_sideNavBar.html' %} 11 |
12 |
13 |
14 | {% csrf_token %} 15 | 16 | {{form}} 17 | 18 |
19 | 20 |
21 |
22 |
23 | {% endblock content %} -------------------------------------------------------------------------------- /authors/migrations/0002_userprofuile_education_userprofuile_work.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-07-16 12:19 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authors', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofuile', 15 | name='education', 16 | field=models.TextField(blank=True), 17 | ), 18 | migrations.AddField( 19 | model_name='userprofuile', 20 | name='work', 21 | field=models.TextField(blank=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /main/migrations/0006_alter_blog_author.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-07-24 07:13 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ('main', '0005_blog_mini_description'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='blog', 18 | name='author', 19 | field=models.ForeignKey(default='', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 20 | preserve_default=False, 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blog_project.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /templates/main/delete_blog.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Delete blog{% endblock title %} 4 | 5 | {% block content %} 6 | {% if user.is_authenticated %} 7 | {% if user.id == blog.author.id %} 8 |

Delete: {{blog.name}}

9 | 10 |
11 | {% csrf_token %} 12 | Are you sure you want to delete this blog ?? 13 |
14 | 15 |
16 | {% else %} 17 | You are not allowed hare? 18 | {% endif %} 19 | {% else %} 20 | You are not logged in please create or login in website 21 | {% endif %} 22 | {% endblock content %} -------------------------------------------------------------------------------- /authors/migrations/0003_userprofuile_currently_hacking_on_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-07-22 14:34 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authors', '0002_userprofuile_education_userprofuile_work'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofuile', 15 | name='currently_hacking_on', 16 | field=models.TextField(blank=True), 17 | ), 18 | migrations.AddField( 19 | model_name='userprofuile', 20 | name='currently_learning', 21 | field=models.TextField(blank=True), 22 | ), 23 | migrations.AddField( 24 | model_name='userprofuile', 25 | name='skills_language', 26 | field=models.TextField(blank=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /main/migrations/0003_contact.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.1 on 2022-02-09 18:00 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('main', '0002_blog_slug'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='Contact', 15 | fields=[ 16 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('first_name', models.CharField(max_length=200)), 18 | ('last_name', models.CharField(max_length=200)), 19 | ('e_mail', models.EmailField(max_length=250)), 20 | ('phone_number', models.IntegerField()), 21 | ('contact_message', models.TextField()), 22 | ('timestamp', models.DateTimeField(auto_now_add=True)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /authors/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | # from django.contrib.auth.models import User 3 | from django.contrib.auth import get_user_model # current user model 4 | 5 | User = get_user_model() 6 | 7 | 8 | class UserProfuile(models.Model): 9 | user = models.OneToOneField(User, on_delete=models.CASCADE) 10 | bio = models.TextField(blank=True) 11 | location = models.CharField(max_length=50, blank=True) 12 | dob = models.DateField(null=True, blank=True) 13 | profile_image = models.ImageField(upload_to="profile/", blank=True) 14 | currently_learning = models.TextField(blank=True) 15 | skills_language = models.TextField(blank=True) 16 | currently_hacking_on = models.TextField(blank=True) 17 | website = models.URLField(blank=True) 18 | github = models.URLField(blank=True) 19 | twitter = models.URLField(blank=True) 20 | education = models.TextField(blank=True) 21 | work = models.TextField(blank=True) 22 | 23 | def __str__(self): 24 | return f"{self.user.username}'s profile" 25 | -------------------------------------------------------------------------------- /authors/urls.py: -------------------------------------------------------------------------------- 1 | from unicodedata import name 2 | from django.urls import path 3 | from authors import views 4 | 5 | urlpatterns = [ 6 | path('create-new-account/', views.signUp.as_view(), name="register"), 7 | path('user-profile//', views.profile.as_view(), name="profile"), 8 | # path('user-profile//', views.profile, name="profile"), 9 | path('login/', views.logIn.as_view(), name="login"), 10 | path('logout/', views.logOut.as_view(), name="logout"), 11 | path('change_password/', views.PasswordChangeView.as_view(template_name = "authors/password_change.html"), name="change-password"), 12 | path('password_success/', views.password_success, name="password_success"), 13 | path('edit_profile/', views.UpdateUserView.as_view(), name="edit_user"), 14 | path('delete_user//', views.DeleteUser.as_view(), name="delete_user"), 15 | path('update_public_details/', views.UpdatePublicDetails.as_view(), name="user_public_details"), 16 | path('dashboard/', views.Dashboard.as_view(), name="dashboard") 17 | ] 18 | -------------------------------------------------------------------------------- /templates/main/contact_us.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Contact Us{% endblock title %} 4 | 5 | {% block content %} 6 |

Contact to DE Blog

7 |
8 | {% csrf_token %} 9 |
10 | 11 | {{form.first_name}} 12 |
13 |
14 | 15 | {{form.last_name}} 16 |
17 |
18 | 19 | {{form.e_mail}} 20 |
21 |
22 | 23 | {{form.phone_number}} 24 |
25 |
26 | 27 | {{form.contact_message}} 28 |
29 |
30 | 31 |
32 |
33 | {% endblock content %} -------------------------------------------------------------------------------- /blog_project/urls.py: -------------------------------------------------------------------------------- 1 | """blog_project URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | from main import views 20 | from django.conf import settings 21 | from django.conf.urls.static import static 22 | 23 | urlpatterns = [ 24 | path('admin/', admin.site.urls), 25 | path("", include("main.urls")), 26 | path("authors/", include("authors.urls")), 27 | path("ckeditor/", include('ckeditor_uploader.urls')) 28 | ] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT) 29 | -------------------------------------------------------------------------------- /authors/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-07-14 11:40 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='UserProfuile', 19 | fields=[ 20 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('bio', models.TextField(blank=True)), 22 | ('location', models.CharField(blank=True, max_length=50)), 23 | ('dob', models.DateField(blank=True, null=True)), 24 | ('profile_image', models.ImageField(blank=True, upload_to='profile/')), 25 | ('website', models.URLField(blank=True)), 26 | ('github', models.URLField(blank=True)), 27 | ('twitter', models.URLField(blank=True)), 28 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 29 | ], 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /templates/containers/_sideNavBar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/authors/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Create new account{% endblock title %} 4 | 5 | {% block content %} 6 |

Register

7 | 8 |
9 | {% csrf_token %} 10 |
11 |
12 | 13 | {{form.first_name}} 14 |
15 |
16 | 17 | {{form.last_name}} 18 |
19 |
20 | 21 | {{form.username}} 22 |
23 |
24 | 25 | {{form.email}} 26 |
27 |
28 | 29 | {{form.password1}} 30 |
31 |
32 | 33 | {{form.password2}} 34 |
35 |
36 | 37 |
38 | {% endblock content %} -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DW Blog Django 2 | 3 | [![Youtube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UCKspdO30Fea8ZCxwg-0svOg) 4 | [![Python](https://img.shields.io/badge/Python-FFD43B?style=for-the-badge&logo=python&logoColor=blue)](https://www.youtube.com/channel/UCKspdO30Fea8ZCxwg-0svOg) 5 | [![Django](https://img.shields.io/badge/django-darkgreen?style=for-the-badge&logo=django&logoColor=white)](https://code.visualstudio.com/download) 6 | [![Django Rest framework](https://img.shields.io/badge/djangorest-ff1709?style=for-the-badge&logo=django&logoColor=white)](https://code.visualstudio.com/download) 7 | ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white) 8 | [![VS Code](https://img.shields.io/badge/Visual_Studio_Code-0078D4?style=for-the-badge&logo=visual%20studio%20code&logoColor=white)](https://code.visualstudio.com/download) 9 | 10 | Django tutorial for this project is available on [YouTube](https://youtube.com/playlist?list=PLKnjLEpehhFnb210PantMg9sdQNrygxUL) 11 | 12 | ## Steps to run the project 13 | 14 | 1. Clone the repository 15 | 2. Create a virtual environment using command `python3 -m venv env` 16 | 3. Install the dependencies using command `pip install -r requirements.txt` 17 | 4. Type `source env/bin/activate` 18 | 5. Run the server using command `python manage.py makemigrations` 19 | 6. Then run the server using command `python manage.py migrate` 20 | 7. Finally run the server using command `python manage.py runserver` 21 | -------------------------------------------------------------------------------- /main/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.1 on 2022-02-04 11:16 2 | 3 | import datetime 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Blog', 20 | fields=[ 21 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('name', models.CharField(max_length=100)), 23 | ('description', models.TextField(help_text='Write your blog')), 24 | ('post_date', models.DateField(default=datetime.date.today)), 25 | ('author', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), 26 | ], 27 | ), 28 | migrations.CreateModel( 29 | name='BlogComment', 30 | fields=[ 31 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 32 | ('description', models.TextField(help_text='Write your comment')), 33 | ('comment_date', models.DateTimeField(auto_now_add=True)), 34 | ('author', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), 35 | ('blog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.blog')), 36 | ], 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from datetime import date 4 | from django.template.defaultfilters import slugify 5 | from ckeditor.fields import RichTextField 6 | 7 | # Create your models here. 8 | class Blog(models.Model): 9 | name = models.CharField(max_length=100) 10 | author = models.ForeignKey(User, on_delete=models.CASCADE) 11 | description = RichTextField() 12 | mini_description = models.TextField() 13 | post_date = models.DateField(default=date.today) 14 | slug = models.CharField(max_length=1000, null=True, blank=True) 15 | 16 | def __str__(self): 17 | return self.name + " ==> " + str(self.author) 18 | 19 | def save(self, *args, **kwargs): 20 | if not self.slug: 21 | self.slug = slugify(self.name + "-" + str(self.post_date)) 22 | return super().save(*args, **kwargs) 23 | 24 | class BlogComment(models.Model): 25 | description = models.TextField(help_text="Write your comment") 26 | author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) 27 | comment_date = models.DateTimeField(auto_now_add=True) 28 | blog = models.ForeignKey(Blog, on_delete=models.CASCADE) 29 | 30 | def __str__(self): 31 | return str(self.blog) 32 | 33 | class Contact(models.Model): 34 | first_name = models.CharField(max_length=200) 35 | last_name = models.CharField(max_length=200) 36 | e_mail = models.EmailField(max_length=250) 37 | phone_number = models.IntegerField() 38 | contact_message = models.TextField() 39 | timestamp = models.DateTimeField(auto_now_add=True, blank=True) 40 | 41 | def __str__(self): 42 | return str(self.first_name + " " + self.last_name) -------------------------------------------------------------------------------- /templates/authors/password_change.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Chnage password{% endblock title %} 4 | 5 | {% block content %} 6 |

Update user

7 | 8 |
9 |
10 | {% include 'containers/_sideNavBar.html' %} 11 |
12 |
13 |
14 | {% csrf_token %} 15 |
16 |
17 | 18 | {{form.old_password}} 19 |
20 | 21 |
22 | 23 | {{form.new_password1}} 24 |
25 |
26 | 27 | {{form.new_password2}} 28 |
29 |
30 | 31 |

Rules

32 |
    33 |
  • 1. Your password can’t be too similar to your other personal information.
  • 34 |
  • 2. Your password must contain at least 8 characters.
  • 35 |
  • 3. Your password can’t be a commonly used password.
  • 36 |
  • 4. Your password can’t be entirely numeric.
  • 37 |
38 | 39 | 40 |
41 |
42 |
43 | {% endblock content %} -------------------------------------------------------------------------------- /templates/main/blog_home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Blog Home{% endblock title %} 4 | 5 | {% block content %} 6 |

Blog Home

7 |
8 | {% if object_list %} 9 | {% for data in object_list %} 10 |
11 |
12 |
13 |
{{ data.name }}
14 | {{data.author}} 15 |

16 | {{data.mini_description| truncatechars:200}} 17 |

18 | Read More 19 |
20 |
21 |
22 | {% endfor %} 23 | {% else %} 24 |

No blog found

25 | {% endif %} 26 |
27 | 28 |
29 | 54 |
55 | {% endblock content %} -------------------------------------------------------------------------------- /main/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import BlogComment, Contact, Blog 3 | from ckeditor.widgets import CKEditorWidget 4 | 5 | class ContactForm(forms.ModelForm): 6 | class Meta: 7 | model = Contact 8 | fields = "__all__" 9 | # fields = ("first_name", "last_name", "e_mail") 10 | # exclude = ("first_name",) 11 | 12 | widgets = { 13 | "first_name": forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter your first name'}), 14 | "last_name": forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter your last name'}), 15 | "e_mail": forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Enter your email'}), 16 | "phone_number": forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Enter your phone number'}), 17 | "contact_message": forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Enter your message'}) 18 | } 19 | 20 | class CreateBlogForm(forms.ModelForm): 21 | description = forms.CharField(widget=CKEditorWidget()) 22 | class Meta: 23 | model = Blog 24 | exclude = ('post_date', 'slug') 25 | widgets = { 26 | 'author': forms.TextInput(attrs={'value': '', 'id':'author', 'type':'hidden'}), 27 | 'mini_description': forms.Textarea(attrs={'class': 'form-control'}) 28 | } 29 | 30 | class UpdateBlogForm(forms.ModelForm): 31 | description = forms.CharField(widget=CKEditorWidget()) 32 | class Meta: 33 | model = Blog 34 | exclude = ('post_date', 'slug') 35 | widgets = { 36 | 'author': forms.TextInput(attrs={'value': '', 'id':'author', 'type':'hidden'}), 37 | 'mini_description': forms.Textarea(attrs={'class': 'form-control'}) 38 | } 39 | 40 | 41 | class CommentBlogForm(forms.ModelForm): 42 | class Meta: 43 | model = BlogComment 44 | fields = "__all__" 45 | 46 | widgets = { 47 | 'author': forms.TextInput(attrs={'value': '', 'id':'author', 'type':'hidden'}), 48 | 'blog': forms.TextInput(attrs={'value': '', 'id':'blog', 'type':'hidden'}), 49 | 'description': forms.Textarea(attrs={'class': 'form-control'}), 50 | } -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | {% block extrahead %} 4 | 5 | {{ block.super }} 6 | {% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | DW - {% block title %}{% endblock title %} 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% include 'containers/_navbar.html' %} 27 | 28 |
29 | {% for message in messages %} 30 | 38 | {% endfor %} 39 | {% block content %} 40 | {% endblock content %} 41 |
42 | 43 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect, render 2 | from .models import Blog, BlogComment, Contact 3 | from .forms import ContactForm, CreateBlogForm, UpdateBlogForm, CommentBlogForm 4 | from django.contrib import messages 5 | from django.views import generic 6 | from django.contrib.messages.views import SuccessMessageMixin 7 | from django.contrib.auth.mixins import LoginRequiredMixin 8 | 9 | class blog_home(generic.ListView): 10 | model = Blog 11 | paginate_by = 10 12 | template_name = "main/blog_home.html" 13 | 14 | def blog_detail(request, slug): 15 | blog = Blog.objects.get(slug=slug) 16 | all_comments = BlogComment.objects.filter(blog = blog.id) 17 | all_blogs = Blog.objects.all().order_by('-post_date')[:10] 18 | 19 | form = CommentBlogForm() 20 | if request.method == "POST": 21 | form = CommentBlogForm(request.POST) 22 | if form.is_valid(): 23 | form.save() 24 | messages.success(request, "Your comment on this blog has been posted") 25 | return redirect("/blog_detail/"+blog.slug) 26 | else: 27 | form = CommentBlogForm() 28 | 29 | context = { 30 | 'blog':blog, 31 | 'all_blogs': all_blogs, 32 | 'form': form, 33 | 'all_comments': all_comments 34 | } 35 | return render(request, "main/blog_detail.html", context) 36 | 37 | class contactUs(SuccessMessageMixin, generic.CreateView): 38 | form_class = ContactForm 39 | template_name = "main/contact_us.html" 40 | success_url = "/" 41 | success_message = "Your query has been submited successfully, we will contact you soon." 42 | 43 | def form_invalid(self, form): 44 | messages.add_message(self.request, messages.ERROR, "Please submit the form carefully") 45 | return redirect('home') 46 | 47 | class CreateBlog(LoginRequiredMixin, SuccessMessageMixin, generic.CreateView): 48 | form_class = CreateBlogForm 49 | template_name = "main/create_blog.html" 50 | login_url = 'login' 51 | success_url = "/" 52 | success_message = "Your blog has been created" 53 | 54 | class UpdateBlogView(LoginRequiredMixin, SuccessMessageMixin, generic.UpdateView): 55 | model = Blog 56 | form_class = UpdateBlogForm 57 | template_name = "main/update_blog.html" 58 | login_url = 'login' 59 | success_url = "/" 60 | success_message = "Your blog has been updated" 61 | 62 | class DeleteBlogView(LoginRequiredMixin, SuccessMessageMixin, generic.DeleteView): 63 | model = Blog 64 | template_name = "main/delete_blog.html" 65 | login_url = 'login' 66 | success_url = "/" 67 | success_message = "Your blog has been deleted" -------------------------------------------------------------------------------- /templates/main/blog_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load humanize %} 3 | 4 | {% block title %}{{blog.name}}{% endblock title %} 5 | 6 | {% block content %} 7 | 8 |
9 |
10 |

{{ blog.name }}

11 | Author: {{blog.author}} 12 |
13 | {{ blog.post_date }} 14 |
15 | 16 |
17 | {% if user.is_authenticated %} 18 | {% if user.id == blog.author.id %} 19 | Edit Blog 20 | Delete Blog 21 | {% endif %} 22 | {% endif %} 23 |
24 | 25 |
26 |

{{blog.description|safe}}

27 |
28 | 29 |
30 |

Comments ({{all_comments.count}})

31 | 32 | {% for comment in all_comments %} 33 |
34 |
35 | {{ comment.author }}
36 | {{ comment.comment_date| timesince }} ago 37 |
38 | 39 |
40 |
41 |

{{ comment.description }}

42 |
43 |
44 |
45 | {% endfor %} 46 |
47 | 48 |
49 | {% if user.is_authenticated %} 50 | {% if blog.author.id == user.id %} 51 |

You are not allowed to post comment on your own blog

52 | {% else %} 53 |

Write your comment...

54 |
55 | {% csrf_token %} 56 | {{form.as_p}} 57 | 58 |
59 | {% endif %} 60 | {% else %} 61 |

Please Login to comment on this post Login

62 | {% endif %} 63 |
64 |
65 |
66 |
    67 | {% for blogs in all_blogs %} 68 |
  • 69 | {{blogs.name}} 70 |
  • 71 | {% endfor %} 72 |
73 |
74 |
75 |
76 | 77 | 83 | {% endblock content %} -------------------------------------------------------------------------------- /templates/authors/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Dashboard{% endblock title %} 4 | 5 | {% block content %} 6 |

Dashboard

7 | 8 |
9 |
10 |
11 |
12 |
{{ user_related_data.count }}
13 |
Total Post
14 |
15 |
16 |
17 |
18 |
19 |
20 |
{{ user_comments.count }}
21 |
Total Reaction
22 |
23 |
24 |
25 |
26 | 27 |
28 |

Posts

29 | 30 |
31 |
32 | {% for post_data in page_obj %} 33 |
34 |
35 |
36 |
37 |
38 |

{{post_data.name}}

39 |
40 | 41 |
42 |

{{post_data.post_date|timesince}}

43 |
44 |
45 |
{{post_data.mini_description |truncatewords:50}}
46 |
47 |
48 | 56 |
57 | {% endfor %} 58 |
59 |
60 |
61 | 86 |
87 |
88 | {% endblock content %} -------------------------------------------------------------------------------- /templates/containers/_navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/authors/edit_public_details.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load crispy_forms_tags %} 3 | 4 | {% block title %}Edit profile{% endblock title %} 5 | 6 | {% block content %} 7 |

Update, {{user.username}}

8 | 9 |
10 |
11 | {% include 'containers/_sideNavBar.html' %} 12 |
13 |
14 |
15 | {% csrf_token %} 16 | 17 |
18 |
19 |

General Info

20 |
21 |
22 |
23 | {{form.user}} 24 |
25 |
26 | {{form.bio|as_crispy_field}} 27 |
28 |
29 |
30 | {{form.location|as_crispy_field}} 31 |
32 |
33 | {{form.dob|as_crispy_field}} 34 |
35 |
36 | {{form.profile_image|as_crispy_field}} 37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 |

Education/Work

45 |
46 |
47 |
48 |
49 | {{form.education|as_crispy_field}} 50 |
51 |
52 | {{form.work|as_crispy_field}} 53 |
54 |
55 |
56 |
57 | 58 |
59 |
60 |

Socual Links

61 |
62 |
63 |
64 |
65 | {{form.website|as_crispy_field}} 66 |
67 |
68 | {{form.github|as_crispy_field}} 69 |
70 |
71 | {{form.twitter|as_crispy_field}} 72 |
73 |
74 |
75 |
76 |
77 |
78 |

Skills/Languages

79 |
80 |
81 |
82 |
83 | {{form.skills_language|as_crispy_field}} 84 |
85 |
86 |
87 |
88 |
89 |
90 |

Currently learning/Currently hacking on

91 |
92 |
93 |
94 |
95 | {{form.currently_learning|as_crispy_field}} 96 |
97 |
98 | {{form.currently_hacking_on|as_crispy_field}} 99 |
100 |
101 |
102 |
103 | 104 |
105 |
106 |
107 | {% endblock content %} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/django 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=django 3 | 4 | ### Django ### 5 | *.log 6 | *.pot 7 | *.pyc 8 | __pycache__/ 9 | local_settings.py 10 | db.sqlite3 11 | db.sqlite3-journal 12 | media 13 | 14 | # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ 15 | # in your Git repository. Update and uncomment the following line accordingly. 16 | # /staticfiles/ 17 | 18 | ### Django.Python Stack ### 19 | # Byte-compiled / optimized / DLL files 20 | *.py[cod] 21 | *$py.class 22 | 23 | # C extensions 24 | *.so 25 | 26 | # Distribution / packaging 27 | .Python 28 | build/ 29 | develop-eggs/ 30 | dist/ 31 | downloads/ 32 | eggs/ 33 | .eggs/ 34 | lib/ 35 | lib64/ 36 | parts/ 37 | sdist/ 38 | var/ 39 | wheels/ 40 | share/python-wheels/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | MANIFEST 45 | 46 | # PyInstaller 47 | # Usually these files are written by a python script from a template 48 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 49 | *.manifest 50 | *.spec 51 | 52 | # Installer logs 53 | pip-log.txt 54 | pip-delete-this-directory.txt 55 | 56 | # Unit test / coverage reports 57 | htmlcov/ 58 | .tox/ 59 | .nox/ 60 | .coverage 61 | .coverage.* 62 | .cache 63 | nosetests.xml 64 | coverage.xml 65 | *.cover 66 | *.py,cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | cover/ 70 | 71 | # Translations 72 | *.mo 73 | 74 | # Django stuff: 75 | 76 | # Flask stuff: 77 | instance/ 78 | .webassets-cache 79 | 80 | # Scrapy stuff: 81 | .scrapy 82 | 83 | # Sphinx documentation 84 | docs/_build/ 85 | 86 | # PyBuilder 87 | .pybuilder/ 88 | target/ 89 | 90 | # Jupyter Notebook 91 | .ipynb_checkpoints 92 | 93 | # IPython 94 | profile_default/ 95 | ipython_config.py 96 | 97 | # pyenv 98 | # For a library or package, you might want to ignore these files since the code is 99 | # intended to run in multiple environments; otherwise, check them in: 100 | # .python-version 101 | 102 | # pipenv 103 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 104 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 105 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 106 | # install all needed dependencies. 107 | #Pipfile.lock 108 | 109 | # poetry 110 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 111 | # This is especially recommended for binary packages to ensure reproducibility, and is more 112 | # commonly ignored for libraries. 113 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 114 | #poetry.lock 115 | 116 | # pdm 117 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 118 | #pdm.lock 119 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 120 | # in version control. 121 | # https://pdm.fming.dev/#use-with-ide 122 | .pdm.toml 123 | 124 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 125 | __pypackages__/ 126 | 127 | # Celery stuff 128 | celerybeat-schedule 129 | celerybeat.pid 130 | 131 | # SageMath parsed files 132 | *.sage.py 133 | 134 | # Environments 135 | .env 136 | .venv 137 | env/ 138 | venv/ 139 | ENV/ 140 | env.bak/ 141 | venv.bak/ 142 | 143 | # Spyder project settings 144 | .spyderproject 145 | .spyproject 146 | 147 | # Rope project settings 148 | .ropeproject 149 | 150 | # mkdocs documentation 151 | /site 152 | 153 | # mypy 154 | .mypy_cache/ 155 | .dmypy.json 156 | dmypy.json 157 | 158 | # Pyre type checker 159 | .pyre/ 160 | 161 | # pytype static type analyzer 162 | .pytype/ 163 | 164 | # Cython debug symbols 165 | cython_debug/ 166 | 167 | # PyCharm 168 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 169 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 170 | # and can be added to the global gitignore or merged into this file. For a more nuclear 171 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 172 | #.idea/ 173 | 174 | # End of https://www.toptal.com/developers/gitignore/api/django -------------------------------------------------------------------------------- /authors/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, UserChangeForm 3 | from django.contrib.auth.models import User 4 | from .models import UserProfuile 5 | 6 | class UserPublicDetailsForm(forms.ModelForm): 7 | def __init__(self, *args, **kwargs): 8 | super().__init__(*args, **kwargs) 9 | 10 | self.fields['user'].widget.attrs.update({ 11 | 'hidden': "hidden" 12 | }) 13 | 14 | self.fields['user'].widget.attrs.update({ 15 | 'hidden': "hidden" 16 | }) 17 | 18 | self.fields['bio'].widget.attrs.update({ 19 | "rows": "3" 20 | }) 21 | 22 | self.fields['currently_hacking_on'].widget.attrs.update({ 23 | "rows": "2" 24 | }) 25 | 26 | self.fields['currently_learning'].widget.attrs.update({ 27 | "rows": "2" 28 | }) 29 | 30 | self.fields['skills_language'].widget.attrs.update({ 31 | "rows": "2", 32 | "placeholder": "eg: django, python, java, javascript" 33 | }) 34 | 35 | self.fields['education'].widget.attrs.update({ 36 | "rows": "3" 37 | }) 38 | self.fields['work'].widget.attrs.update({ 39 | "rows": "3" 40 | }) 41 | 42 | class Meta: 43 | model = UserProfuile 44 | fields = "__all__" 45 | 46 | class LoginUserForm(AuthenticationForm): 47 | def __init__(self, *args, **kwargs): 48 | super().__init__(*args, **kwargs) 49 | 50 | self.fields['username'].widget.attrs.update({ 51 | 'class': 'form-control', 52 | 'placeholder': 'Enter your username' 53 | }) 54 | 55 | self.fields['password'].widget.attrs.update({ 56 | 'class': 'form-control', 57 | 'placeholder': 'Enter your password' 58 | }) 59 | class Meta: 60 | fields = ['username', 'password'] 61 | 62 | class SignupForm(UserCreationForm): 63 | def __init__(self, *args, **kwargs): 64 | super().__init__(*args, **kwargs) 65 | 66 | self.fields['username'].widget.attrs.update({ 67 | 'class': 'form-control', 68 | 'placeholder': 'Enter your username' 69 | }) 70 | 71 | self.fields['first_name'].widget.attrs.update({ 72 | 'class': 'form-control', 73 | 'placeholder': 'Enter your first name' 74 | }) 75 | 76 | self.fields['last_name'].widget.attrs.update({ 77 | 'class': 'form-control', 78 | 'placeholder': 'Enter your last name' 79 | }) 80 | 81 | self.fields['email'].widget.attrs.update({ 82 | 'class': 'form-control', 83 | 'placeholder': 'Enter your email-id' 84 | }) 85 | 86 | self.fields['password1'].widget.attrs.update({ 87 | 'class': 'form-control', 88 | 'placeholder': 'Enter your password' 89 | }) 90 | self.fields['password2'].widget.attrs.update({ 91 | 'class': 'form-control', 92 | 'placeholder': 'Confirm your password' 93 | }) 94 | username = forms.CharField(max_length=150) 95 | first_name = forms.CharField(max_length=150) 96 | last_name = forms.CharField(max_length=150) 97 | email = forms.EmailField(max_length=150) 98 | password1 = forms.CharField(widget=forms.PasswordInput) 99 | password2 = forms.CharField(widget=forms.PasswordInput) 100 | class Meta: 101 | model = User 102 | fields = ['username', 'first_name', 'last_name', 'email', 'password1', 'password2'] 103 | 104 | 105 | class PasswordChangingForm(PasswordChangeForm): 106 | old_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Old Password'})) 107 | new_password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'New Passowrd'})) 108 | new_password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Conform new password'})) 109 | class Meta: 110 | model = User 111 | fields = ['old_password', 'new_password1', 'new_password2'] 112 | 113 | 114 | class EditUserProfileForm(UserChangeForm): 115 | email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': "Enter uour username"})) 116 | 117 | first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Enter your first name"})) 118 | 119 | last_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Enter your last name"})) 120 | 121 | username = forms.CharField(max_length=150, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Enter your last name"})) 122 | class Meta: 123 | model = User 124 | fields = ['username', 'first_name', "last_name", 'email'] -------------------------------------------------------------------------------- /authors/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect, render 2 | from django.core.paginator import Paginator 3 | from django.contrib import messages 4 | from django.urls import reverse_lazy 5 | from .forms import SignupForm, LoginUserForm, PasswordChangingForm, EditUserProfileForm, UserPublicDetailsForm 6 | from django.contrib.auth import authenticate, login, logout 7 | from django.contrib.auth.views import PasswordChangeView 8 | from main.models import Blog, BlogComment 9 | from django.views import generic 10 | from django.contrib.messages.views import SuccessMessageMixin 11 | from django.contrib.auth.models import User 12 | from django.contrib.auth.mixins import LoginRequiredMixin 13 | from .models import UserProfuile 14 | 15 | 16 | class signUp(SuccessMessageMixin, generic.CreateView): 17 | form_class = SignupForm 18 | template_name = "authors/register.html" 19 | success_url = reverse_lazy('login') 20 | success_message = "User has been created, please login with your username and password" 21 | 22 | def form_invalid(self, form): 23 | messages.add_message(self.request, messages.ERROR, 24 | "Please enter details properly") 25 | return redirect('home') 26 | 27 | 28 | class logIn(generic.View): 29 | form_class = LoginUserForm 30 | template_name = "authors/login.html" 31 | 32 | def get(self, request): 33 | form = self.form_class 34 | return render(request, self.template_name, {'form': form}) 35 | 36 | def post(self, request): 37 | if request.method == "POST": 38 | form = LoginUserForm(request, data=request.POST) 39 | if form.is_valid(): 40 | username = form.cleaned_data.get('username') 41 | password = form.cleaned_data.get('password') 42 | 43 | user = authenticate(username=username, password=password) 44 | 45 | if user is not None: 46 | login(request, user) 47 | messages.success( 48 | request, f"You are logged in as {username}") 49 | return redirect('home') 50 | else: 51 | messages.error(request, "Error") 52 | else: 53 | messages.error(request, "Username or password incorrect") 54 | form = LoginUserForm() 55 | return render(request, "authors/login.html", {"form": form}) 56 | 57 | 58 | class logOut(LoginRequiredMixin, generic.View): 59 | login_url = 'login' 60 | 61 | def get(self, request): 62 | logout(request) 63 | messages.success(request, "User logged out") 64 | return redirect('home') 65 | 66 | 67 | class profile(LoginRequiredMixin, generic.View): 68 | model = Blog 69 | login_url = 'login' 70 | template_name = "authors/profile.html" 71 | 72 | def get(self, request, user_name): 73 | user_related_data = Blog.objects.filter(author__username=user_name)[:6] 74 | user_profile_data = UserProfuile.objects.get(user=request.user.id) 75 | context = { 76 | "user_related_data": user_related_data, 77 | 'user_profile_data': user_profile_data 78 | } 79 | return render(request, self.template_name, context) 80 | 81 | 82 | class PasswordChangeView(LoginRequiredMixin, PasswordChangeView): 83 | form_class = PasswordChangingForm 84 | login_url = 'login' 85 | success_url = reverse_lazy('password_success') 86 | 87 | 88 | def password_success(request): 89 | return render(request, "authors/password_change_success.html") 90 | 91 | 92 | class UpdateUserView(LoginRequiredMixin, SuccessMessageMixin, generic.UpdateView): 93 | form_class = EditUserProfileForm 94 | login_url = 'login' 95 | template_name = "authors/edit_user_profile.html" 96 | success_url = reverse_lazy('home') 97 | success_message = "User updated" 98 | 99 | def get_object(slef): 100 | return slef.request.user 101 | 102 | def form_invalid(self, form): 103 | messages.add_message(self.request, messages.ERROR, 104 | "Please submit the form carefully") 105 | return redirect('home') 106 | 107 | 108 | class DeleteUser(LoginRequiredMixin, SuccessMessageMixin, generic.DeleteView): 109 | model = User 110 | login_url = 'login' 111 | template_name = 'authors/delete_user_confirm.html' 112 | success_message = "User has been deleted" 113 | success_url = reverse_lazy('home') 114 | 115 | 116 | class UpdatePublicDetails(LoginRequiredMixin, SuccessMessageMixin, generic.UpdateView): 117 | login_url = "login" 118 | form_class = UserPublicDetailsForm 119 | template_name = "authors/edit_public_details.html" 120 | success_url = reverse_lazy('home') 121 | success_message = "User updated" 122 | 123 | def get_object(slef): 124 | return slef.request.user.userprofuile 125 | 126 | def form_invalid(self, form): 127 | messages.add_message(self.request, messages.ERROR, "Please submit the form carefully") 128 | return redirect('home') 129 | 130 | class Dashboard(LoginRequiredMixin ,generic.View): 131 | login_url = "login" 132 | 133 | def get(self, request): 134 | user_related_data = Blog.objects.filter(author__username = request.user.username) 135 | user_comments = BlogComment.objects.filter(author__username = request.user.username) 136 | 137 | paginator = Paginator(user_related_data, 10) 138 | page_number = request.GET.get('page') 139 | page_obj = paginator.get_page(page_number) 140 | 141 | context = { 142 | 'user_related_data': user_related_data, 143 | 'page_obj': page_obj, 144 | 'user_comments': user_comments 145 | } 146 | return render(request, "authors/dashboard.html", context) -------------------------------------------------------------------------------- /templates/authors/profile.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load humanize %} 3 | 4 | {% block title %}{{user.username}}'s Profile{% endblock title %} 5 | 6 | {% block content %} 7 |

Hello, {{user.username}}!!

8 | 9 |
10 |
11 | {% if user_profile_data.profile_image %} 12 | {{user.username}}'s profile image 14 | {% else %} 15 | {{user.username}}'s profile image 17 | {% endif %} 18 | 19 |

{{user.first_name}} {{user.last_name}} (@{{user.username}})

20 | 21 | {% if user_profile_data.bio %} 22 |

{{user_profile_data.bio}}

23 | {% else %} 24 |

404 dio not found

25 | {% endif %} 26 | 27 |
28 | {% if user_profile_data.location %} 29 | 30 | {{user_profile_data.location}} 31 | {% endif %} 32 | 33 | {% if user_profile_data.dob %} 34 | {{user_profile_data.dob}} 35 | {% endif %} 36 | 37 | {% if user.email %} 38 | {{user.email}} 39 | {% endif %} 40 | 41 | {% if user_profile_data.website %} 42 | 43 | {% endif %} 44 | 45 | {% if user_profile_data.github %} 46 | 47 | {% endif %} 48 | 49 | {% if user_profile_data.twitter %} 50 | 51 | {% endif %} 52 |
53 |
54 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 | {% if user_profile_data.currently_learning %} 76 |
77 |
78 |

Currently learning

79 |
80 |
81 |

{{user_profile_data.currently_learning}}

82 |
83 |
84 | {% endif %} 85 | 86 | {% if user_profile_data.skills_language %} 87 |
88 |
89 |

Skills/Languages

90 |
91 |
92 |

{{user_profile_data.skills_language}}

93 |
94 |
95 | {% endif %} 96 | 97 | {% if user_profile_data.currently_hacking_on %} 98 |
99 |
100 |

Currently hacking on

101 |
102 |
103 |

{{user_profile_data.currently_hacking_on}}

104 |
105 |
106 | {% endif %} 107 |
108 |
109 |

{{user_related_data.count}} - Posts

110 |
111 |
112 |
113 | 114 |
115 | {% for post_data in user_related_data %} 116 |
117 |
118 |
119 |
120 |
121 |

{{post_data.name}}

122 |
123 | 124 |
125 |

{{post_data.post_date|timesince}}

126 |
127 |
128 |
{{post_data.mini_description |truncatewords:50}}
129 |
130 |
131 | 139 |
140 | {% endfor %} 141 | 142 |
143 | 144 | View all blogs 145 |
146 |
147 |
148 | {% endblock content %} -------------------------------------------------------------------------------- /blog_project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for blog_project project. 3 | 4 | Generated by 'django-admin startproject' using Django 4.0.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/4.0/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | from django.contrib.messages import constants as messages 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'django-insecure-f!#otb52&gq31q^@e99_=4o=2e%tyww##pjspp)sc@tuugdv4f' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = ['*',] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'main', 36 | 'authors', 37 | 'fontawesomefree', 38 | 'ckeditor', 39 | 'ckeditor_uploader', 40 | 'crispy_forms', 41 | "crispy_bootstrap5", 42 | "django.contrib.humanize", 43 | 'django.contrib.admin', 44 | 'django.contrib.auth', 45 | 'django.contrib.contenttypes', 46 | 'django.contrib.sessions', 47 | 'django.contrib.messages', 48 | 'django.contrib.staticfiles', 49 | ] 50 | 51 | MIDDLEWARE = [ 52 | 'django.middleware.security.SecurityMiddleware', 53 | "whitenoise.middleware.WhiteNoiseMiddleware", 54 | 'django.contrib.sessions.middleware.SessionMiddleware', 55 | 'django.middleware.common.CommonMiddleware', 56 | 'django.middleware.csrf.CsrfViewMiddleware', 57 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 58 | 'django.contrib.messages.middleware.MessageMiddleware', 59 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 60 | ] 61 | 62 | ROOT_URLCONF = 'blog_project.urls' 63 | 64 | CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" 65 | CRISPY_TEMPLATE_PACK = "bootstrap5" 66 | 67 | TEMPLATES = [ 68 | { 69 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 70 | 'DIRS': ['templates'], 71 | 'APP_DIRS': True, 72 | 'OPTIONS': { 73 | 'context_processors': [ 74 | 'django.template.context_processors.debug', 75 | 'django.template.context_processors.request', 76 | 'django.contrib.auth.context_processors.auth', 77 | 'django.contrib.messages.context_processors.messages', 78 | ], 79 | }, 80 | }, 81 | ] 82 | 83 | WSGI_APPLICATION = 'blog_project.wsgi.application' 84 | 85 | 86 | # Database 87 | # https://docs.djangoproject.com/en/4.0/ref/settings/#databases 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': BASE_DIR / 'db.sqlite3', 93 | } 94 | } 95 | 96 | 97 | # Password validation 98 | # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators 99 | 100 | AUTH_PASSWORD_VALIDATORS = [ 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 109 | }, 110 | { 111 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 112 | }, 113 | ] 114 | 115 | 116 | # Internationalization 117 | # https://docs.djangoproject.com/en/4.0/topics/i18n/ 118 | 119 | LANGUAGE_CODE = 'en-us' 120 | 121 | TIME_ZONE = 'UTC' 122 | 123 | USE_I18N = True 124 | 125 | USE_TZ = True 126 | 127 | 128 | # CKEDITOR CONF 129 | CKEDITOR_UPLOAD_PATH = "uploads/" 130 | 131 | CKEDITOR_CONFIGS = { 132 | 'awesome_ckeditor': { 133 | 'toolbar': 'Basic', 134 | }, 135 | } 136 | 137 | CKEDITOR_CONFIGS = { 138 | 'default': { 139 | 'skin': 'moono', 140 | # 'skin': 'office2013', 141 | 'toolbar_Basic': [ 142 | ['Source', '-', 'Bold', 'Italic'] 143 | ], 144 | 'toolbar_YourCustomToolbarConfig': [ 145 | {'name': 'document', 'items': ['Source', '-', 'Save', 'NewPage', 'Preview', 'Print', '-', 'Templates']}, 146 | {'name': 'clipboard', 'items': ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']}, 147 | {'name': 'editing', 'items': ['Find', 'Replace', '-', 'SelectAll']}, 148 | {'name': 'forms', 149 | 'items': ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 150 | 'HiddenField']}, 151 | '/', 152 | {'name': 'basicstyles', 153 | 'items': ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']}, 154 | {'name': 'paragraph', 155 | 'items': ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 156 | 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 157 | 'Language']}, 158 | {'name': 'links', 'items': ['Link', 'Unlink', 'Anchor']}, 159 | {'name': 'insert', 160 | 'items': ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']}, 161 | '/', 162 | {'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']}, 163 | {'name': 'colors', 'items': ['TextColor', 'BGColor']}, 164 | {'name': 'tools', 'items': ['Maximize', 'ShowBlocks']}, 165 | {'name': 'about', 'items': ['About']}, 166 | '/', # put this to force next toolbar on new line 167 | {'name': 'yourcustomtools', 'items': [ 168 | # put the name of your editor.ui.addButton here 169 | 'Preview', 170 | 'Maximize', 171 | 172 | ]}, 173 | ], 174 | 'toolbar': 'YourCustomToolbarConfig', # put selected toolbar config here 175 | # 'toolbarGroups': [{ 'name': 'document', 'groups': [ 'mode', 'document', 'doctools' ] }], 176 | # 'height': 291, 177 | # 'width': '100%', 178 | # 'filebrowserWindowHeight': 725, 179 | # 'filebrowserWindowWidth': 940, 180 | # 'toolbarCanCollapse': True, 181 | # 'mathJaxLib': '//cdn.mathjax.org/mathjax/2.2-latest/MathJax.js?config=TeX-AMS_HTML', 182 | 'tabSpaces': 4, 183 | 'extraPlugins': ','.join([ 184 | 'uploadimage', # the upload image feature 185 | # your extra plugins here 186 | 'div', 187 | 'autolink', 188 | 'autoembed', 189 | 'embedsemantic', 190 | 'autogrow', 191 | # 'devtools', 192 | 'widget', 193 | 'lineutils', 194 | 'clipboard', 195 | 'dialog', 196 | 'dialogui', 197 | 'elementspath' 198 | ]), 199 | } 200 | } 201 | 202 | 203 | # Static files (CSS, JavaScript, Images) 204 | # https://docs.djangoproject.com/en/4.0/howto/static-files/ 205 | 206 | STATIC_URL = 'static/' 207 | STATICFILES_DIRS = [ 208 | BASE_DIR / "blog_project/static", 209 | ] 210 | STATIC_ROOT = BASE_DIR / "static" 211 | 212 | # Media conf 213 | MEDIA_URL = '/media/' 214 | MEDIA_ROOT = BASE_DIR / 'media' 215 | 216 | # Default primary key field type 217 | # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field 218 | 219 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 220 | 221 | 222 | MESSAGE_TAGS = { 223 | messages.ERROR: "danger" 224 | } 225 | 226 | STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" --------------------------------------------------------------------------------