├── myblog ├── accounts │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── admin.py │ ├── apps.py │ ├── views.py │ ├── urls.py │ └── templates │ │ └── accounts │ │ └── signup.html ├── blogs │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ └── 0001_initial.py │ ├── tests.py │ ├── admin.py │ ├── apps.py │ ├── templates │ │ └── blogs │ │ │ ├── post_confirm_delete.html │ │ │ ├── post_form.html │ │ │ ├── post_detail.html │ │ │ └── post_list.html │ ├── models.py │ ├── urls.py │ └── views.py ├── myblog │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── templates │ ├── registration │ │ ├── logged_out.html │ │ └── login.html │ ├── 404.html │ ├── 403.html │ └── base.html ├── manage.py └── static │ └── css │ └── style.css ├── README.md └── .gitignore /myblog/accounts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myblog/blogs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myblog/myblog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myblog/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myblog/blogs/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myblog/blogs/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /myblog/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /myblog/accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /myblog/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /myblog/blogs/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Post 3 | 4 | admin.site.register(Post) 5 | -------------------------------------------------------------------------------- /myblog/blogs/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BlogsConfig(AppConfig): 5 | name = 'blogs' 6 | -------------------------------------------------------------------------------- /myblog/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /myblog/templates/registration/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Logout{% endblock %} 4 | 5 | {% block content %} 6 |

Logged Out

7 |

Thanks for spending some quality time with the Web site today.

8 |

Log in again

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /myblog/accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import UserCreationForm 2 | from django.urls import reverse_lazy 3 | from django.views import generic 4 | 5 | 6 | class SignUpView(generic.CreateView): 7 | form_class = UserCreationForm 8 | success_url = reverse_lazy('login') 9 | template_name = 'accounts/signup.html' 10 | -------------------------------------------------------------------------------- /myblog/accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | # set the application namespace 6 | # https://docs.djangoproject.com/en/2.0/intro/tutorial03/ 7 | app_name = 'accounts' 8 | 9 | urlpatterns = [ 10 | # ex: /accounts/signup/ 11 | path('signup/', views.SignUpView.as_view(), name='signup'), 12 | ] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django2 Tutorial - Simple Blog App with Auth - 2 | 3 | ## Django2 でユーザー認証(ログイン認証)を実装するチュートリアル 4 | 1. [環境構築とアプリ雛形の作成](https://it-engineer-lab.com/archives/506) 5 | 1. [サインアップとログイン・ログアウト](https://it-engineer-lab.com/archives/554) 6 | 1. [ブログアプリへの実装](https://it-engineer-lab.com/archives/737) 7 | 8 | ## デモサイト 9 | [https://tutorialauth.it-engineer-lab.com/](https://tutorialauth.it-engineer-lab.com/) -------------------------------------------------------------------------------- /myblog/accounts/templates/accounts/signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Sign up{% endblock %} 4 | 5 | {% block content %} 6 |

Sign up

7 |
8 |
9 | {% csrf_token %} 10 | {{ form.as_p }} 11 | 12 |
13 |
14 | {% endblock %} -------------------------------------------------------------------------------- /myblog/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}404 Page Not Found{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |

404 Page Not Found

9 |

The requested URL {{ request.get_full_path }} was not found on this server.

10 |
11 |
12 |
13 |

< Back

14 |
15 | {% endblock %} -------------------------------------------------------------------------------- /myblog/myblog/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for myblog 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/2.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", "myblog.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /myblog/templates/403.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}403 Forbidden{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |

403 Forbidden

9 |
10 |

Sorry, it appears the page you were looking for is forbidden and not accessible.

11 | {% if exception %} 12 |

{{ exception }}

13 | {% endif %} 14 |
15 |
16 |

< Back

17 |
18 | {% endblock %} -------------------------------------------------------------------------------- /myblog/blogs/templates/blogs/post_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Delete Post{% endblock %} 4 | 5 | {% block content %} 6 |

Delete Post

7 |
8 |

Are you sure you want to delete "{{ object.title }}" ?

9 |
{% csrf_token %} 10 | 11 |
12 |
13 |
14 |

< Back

15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /myblog/blogs/templates/blogs/post_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}{{ object|yesno:'Edit,Add New'}} Post{% endblock %} 4 | 5 | {% block content %} 6 | {# https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#yesno #} 7 |

{{ object|yesno:'Edit,Add New'}} Post

8 |
9 |
{% csrf_token %} 10 | {{ form.as_p }} 11 | 12 |
13 |
14 | {% endblock %} -------------------------------------------------------------------------------- /myblog/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myblog.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /myblog/blogs/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.urls import reverse 3 | 4 | 5 | class Post(models.Model): 6 | title = models.CharField(max_length=255) 7 | text = models.TextField() 8 | author = models.ForeignKey( 9 | 'auth.User', 10 | on_delete=models.CASCADE, 11 | ) 12 | created_at = models.DateTimeField(auto_now_add=True) 13 | updated_at = models.DateTimeField(auto_now=True) 14 | 15 | def __str__(self): 16 | return self.title 17 | 18 | def get_absolute_url(self): 19 | # https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/ 20 | # return reverse('blogs:detail', kwargs={'pk': self.pk}) 21 | return reverse('blogs:index') 22 | -------------------------------------------------------------------------------- /myblog/blogs/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | # set the application namespace 6 | # https://docs.djangoproject.com/en/2.0/intro/tutorial03/ 7 | app_name = 'blogs' 8 | 9 | urlpatterns = [ 10 | # ex: / 11 | path('', views.IndexView.as_view(), name='index'), 12 | 13 | # ex: /post/create/ 14 | path('post/create/', views.CreateView.as_view(), name='create'), 15 | 16 | # ex: /post/1/ 17 | path('post//', views.DetailView.as_view(), name='detail'), 18 | 19 | # ex: /post/1/update/ 20 | path('post//update/', views.UpdateView.as_view(), name='update'), 21 | 22 | # ex: /post/1/delete 23 | path('post//delete/', views.DeleteView.as_view(), name='delete'), 24 | 25 | # ex: /post/help/ 26 | path('post/help/', views.help, name='help'), 27 | ] 28 | -------------------------------------------------------------------------------- /myblog/blogs/templates/blogs/post_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Sign up{% endblock %} 4 | 5 | {% block content %} 6 |

{{ object.title }}

7 |
8 | {{ object.text|linebreaksbr }} 9 |

Author: {{ object.author }}

10 |
11 | 14 | {# ownership #} 15 | {% if request.user.id == object.author_id %} 16 |
17 | Edit 18 | Delete 19 |
20 | {% endif %} 21 |
22 |

< Back

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

Login

7 |
8 | {% if form.errors %} 9 |

Your username and password didn't match. Please try again.

10 | {% endif %} 11 | 12 | {% if next %} 13 | {% if user.is_authenticated %} 14 |

Your account doesn't have access to this page. To proceed, 15 | please login with an account that has access.

16 | {% else %} 17 |

Please login to see this page.

18 | {% endif %} 19 | {% endif %} 20 | 21 |
22 | {% csrf_token %} 23 | {{ form.as_p }} 24 | 25 | 26 |
27 |
28 | {% endblock %} -------------------------------------------------------------------------------- /myblog/blogs/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.1 on 2018-01-07 02:02 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='Post', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('title', models.CharField(max_length=255)), 22 | ('text', models.TextField()), 23 | ('created_at', models.DateTimeField(auto_now_add=True)), 24 | ('updated_at', models.DateTimeField(auto_now=True)), 25 | ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /myblog/myblog/urls.py: -------------------------------------------------------------------------------- 1 | """myblog URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.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 | from django.contrib import admin 17 | from django.urls import include, path 18 | 19 | urlpatterns = [ 20 | # https://docs.djangoproject.com/en/2.0/topics/auth/default/#module-django.contrib.auth.views 21 | path('', include('blogs.urls')), 22 | path('accounts/', include('accounts.urls')), 23 | path('accounts/', include('django.contrib.auth.urls')), 24 | path('admin/', admin.site.urls), 25 | ] 26 | -------------------------------------------------------------------------------- /myblog/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% if request.path != '/' %}{% block title %}{% endblock %} | {% endif %}Blog App with Auth | Django2 Tutorial 10 | 11 | 12 |
13 |
14 |

Blog App

15 | 26 |
27 |
28 | {% block content %}{% endblock %} 29 |
30 |
31 | 32 | -------------------------------------------------------------------------------- /myblog/blogs/templates/blogs/post_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Index{% endblock %} 4 | 5 | {% block content %} 6 | 7 | {% if user.is_authenticated %} 8 |

Username

9 |

{{ user }}

10 | {% endif %} 11 | 12 |

Articles

13 |
14 |
    15 | {% for post in object_list %} 16 |
  • 17 |

    {{ post.title }}

    18 |

    {{ post.text }}

    19 |
  • 20 | {% empty %} 21 |
  • 22 |

    No articles yet.

    23 |

    Add New Post

  • 24 | {% endfor %} 25 |
26 |
27 | 28 | {% if is_paginated %} 29 |
30 |
    31 |
  • 32 | {% if page_obj.has_previous %} 33 | << Prev 34 | {% else %} 35 | << Prev 36 | {% endif %} 37 |
  • 38 |
  • 39 | {% if page_obj.has_next %} 40 | Next >> 41 | {% else %} 42 | Next >> 43 | {% endif %} 44 |
  • 45 |
46 |
47 | {% endif %} 48 | {% endblock %} -------------------------------------------------------------------------------- /myblog/blogs/views.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse, reverse_lazy 2 | from django.http import HttpResponse 3 | from django.views import generic 4 | from django.shortcuts import redirect 5 | from django.core.exceptions import PermissionDenied 6 | from django.contrib.auth.mixins import LoginRequiredMixin 7 | from django.contrib.auth.decorators import login_required 8 | from .models import Post 9 | 10 | """ 11 | Django Auth 12 | 13 | The LoginRequired mixin 14 | https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-loginrequired-mixin 15 | 16 | The login_required decorator 17 | https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-login-required-decorator 18 | @login_required 19 | """ 20 | 21 | 22 | class IndexView(generic.ListView): 23 | model = Post 24 | paginate_by = 5 25 | ordering = ['-updated_at'] 26 | # template_name = 'blogs/post_list.html' 27 | 28 | 29 | class DetailView(generic.DetailView): 30 | model = Post 31 | # template_name = 'blogs/post_confirm_delete.html' 32 | 33 | 34 | class CreateView(LoginRequiredMixin, generic.edit.CreateView): # The LoginRequired mixin 35 | model = Post 36 | fields = ['title', 'text'] # '__all__' 37 | 38 | # template_name = 'blogs/post_form.html' 39 | 40 | def form_valid(self, form): 41 | # This method is called when valid form data has been POSTed. 42 | # It should return an HttpResponse. 43 | # https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user 44 | form.instance.author = self.request.user 45 | return super(CreateView, self).form_valid(form) 46 | 47 | 48 | class UpdateView(LoginRequiredMixin, generic.edit.UpdateView): # The LoginRequired mixin 49 | model = Post 50 | fields = ['title', 'text'] # '__all__' 51 | 52 | # template_name = 'blogs/post_form.html' 53 | 54 | def dispatch(self, request, *args, **kwargs): 55 | # ownership validation 56 | obj = self.get_object() 57 | if obj.author != self.request.user: 58 | raise PermissionDenied('You do not have permission to edit.') 59 | 60 | return super(UpdateView, self).dispatch(request, *args, **kwargs) 61 | 62 | 63 | class DeleteView(LoginRequiredMixin, generic.edit.DeleteView): # The LoginRequired mixin 64 | model = Post 65 | success_url = reverse_lazy('blogs:index') 66 | 67 | # blogs/post_confirm_delete.html 68 | 69 | def dispatch(self, request, *args, **kwargs): 70 | # ownership validation 71 | obj = self.get_object() 72 | if obj.author != self.request.user: 73 | raise PermissionDenied('You do not have permission to delete.') 74 | 75 | return super(DeleteView, self).dispatch(request, *args, **kwargs) 76 | 77 | 78 | @login_required 79 | def help(request): 80 | return HttpResponse("Member Only Help Page") 81 | -------------------------------------------------------------------------------- /myblog/static/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: 'Open Sans', sans-serif; 5 | } 6 | 7 | div, p, ul, ol, li, dl, dt, dd, h1, h2, h3, h4, h5, h6 label, input, textarea, select, button { 8 | margin: 0; 9 | padding: 0; 10 | color: #555555; 11 | font-size: 1rem; 12 | line-height: 1.8; 13 | box-sizing: border-box; 14 | } 15 | 16 | h1, h2, h3 { 17 | font-size: 1.2rem; 18 | } 19 | 20 | a { 21 | color: #6495ed; 22 | text-decoration: none; 23 | } 24 | 25 | a.act { 26 | color: #ff5252; 27 | font-weight: bold; 28 | } 29 | 30 | li { 31 | list-style: none; 32 | } 33 | 34 | section { 35 | margin: 0 0 8px; 36 | } 37 | 38 | .container { 39 | margin: 0 auto; 40 | width: 100%; 41 | max-width: 600px; 42 | } 43 | 44 | .error-msg, .errorlist * { 45 | color: #ff0000; 46 | } 47 | 48 | header { 49 | width: 100%; 50 | display: table; 51 | margin: 0 0 8px; 52 | padding: 8px 0; 53 | border-bottom: 1px solid #cccccc; 54 | } 55 | 56 | header a { 57 | color: #888888; 58 | } 59 | 60 | header .site-name { 61 | padding-left: 8px; 62 | display: table-cell; 63 | vertical-align: middle; 64 | } 65 | 66 | header nav { 67 | padding-right: 8px; 68 | display: table-cell; 69 | vertical-align: middle; 70 | text-align: right; 71 | } 72 | 73 | header nav li { 74 | text-align: right; 75 | display: inline-block; 76 | padding-right: 24px; 77 | } 78 | 79 | header nav li:last-child { 80 | padding-right: 0; 81 | } 82 | 83 | header .site-name a { 84 | font-size: 1.4rem; 85 | } 86 | 87 | .content { 88 | padding: 0 8px; 89 | } 90 | 91 | /** 92 | * index 93 | */ 94 | .user-name { 95 | margin-bottom: 24px; 96 | color: #993333; 97 | } 98 | 99 | .post-list ul { 100 | width: 100%; 101 | } 102 | 103 | .post-list ul li { 104 | margin-bottom: 8px; 105 | padding-bottom: 8px; 106 | border-bottom: 1px dotted #cccccc; 107 | } 108 | 109 | .post-list, .pagination { 110 | 111 | } 112 | 113 | .pagination ul { 114 | width: 100%; 115 | display: table; 116 | } 117 | 118 | .pagination li { 119 | display: table-cell; 120 | width: 50%; 121 | } 122 | 123 | .pagination li:last-child { 124 | text-align: right; 125 | } 126 | 127 | /** 128 | * detail 129 | */ 130 | .post-text { 131 | margin-bottom: 8px; 132 | padding-bottom: 8px; 133 | border-bottom: 1px dotted #cccccc; 134 | } 135 | 136 | .post-date { 137 | margin-bottom: 8px; 138 | padding-bottom: 8px; 139 | border-bottom: 1px dotted #cccccc; 140 | } 141 | 142 | .post-date span { 143 | padding: 0 16px; 144 | } 145 | 146 | .post-edit { 147 | margin-bottom: 8px; 148 | padding-bottom: 8px; 149 | border-bottom: 1px dotted #cccccc; 150 | } 151 | 152 | .post-edit a:first-child { 153 | margin-right: 24px; 154 | } 155 | 156 | /** 157 | * Create, Update 158 | */ 159 | .common-form label { 160 | display: block; 161 | } 162 | 163 | .common-form p { 164 | margin-bottom: 8px; 165 | } 166 | 167 | .common-form input, .common-form textarea { 168 | padding: 4px; 169 | width: 100%; 170 | margin-bottom: 8px; 171 | } 172 | 173 | .common-form select { 174 | padding: 4px; 175 | margin-bottom: 8px; 176 | } 177 | 178 | .common-form .submit { 179 | margin-top: 8px; 180 | margin-bottom: 8px; 181 | padding: 8px 36px; 182 | border: none; 183 | color: #ffffff; 184 | text-align: center; 185 | text-decoration: none; 186 | display: inline-block; 187 | background-color: #4CAF50; 188 | border-radius: 2px; 189 | } 190 | 191 | .common-form .delete { 192 | background-color: #f44336; 193 | } -------------------------------------------------------------------------------- /myblog/myblog/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for myblog project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.0.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = 'knt5e_sj_95sr3g7oa#cdvq3eqjgp)u^^4j*a(e)6&a5$b4j=u' 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = True 26 | 27 | ALLOWED_HOSTS = ['*'] 28 | 29 | # Application definition 30 | 31 | INSTALLED_APPS = [ 32 | 'accounts.apps.AccountsConfig', 33 | 'blogs.apps.BlogsConfig', 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | ] 41 | 42 | MIDDLEWARE = [ 43 | 'django.middleware.security.SecurityMiddleware', 44 | 'django.contrib.sessions.middleware.SessionMiddleware', 45 | 'django.middleware.common.CommonMiddleware', 46 | 'django.middleware.csrf.CsrfViewMiddleware', 47 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 48 | 'django.contrib.messages.middleware.MessageMiddleware', 49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 50 | ] 51 | 52 | ROOT_URLCONF = 'myblog.urls' 53 | 54 | TEMPLATES = [ 55 | { 56 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 57 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], # './templates', 58 | 'APP_DIRS': True, 59 | 'OPTIONS': { 60 | 'context_processors': [ 61 | 'django.template.context_processors.debug', 62 | 'django.template.context_processors.request', 63 | 'django.contrib.auth.context_processors.auth', 64 | 'django.contrib.messages.context_processors.messages', 65 | ], 66 | }, 67 | }, 68 | ] 69 | 70 | WSGI_APPLICATION = 'myblog.wsgi.application' 71 | 72 | # Database 73 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 74 | 75 | DATABASES = { 76 | 'default': { 77 | 'ENGINE': 'django.db.backends.sqlite3', 78 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 79 | } 80 | } 81 | 82 | # Password validation 83 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 84 | 85 | AUTH_PASSWORD_VALIDATORS = [ 86 | { 87 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 88 | }, 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 97 | }, 98 | ] 99 | 100 | # Internationalization 101 | # https://docs.djangoproject.com/en/2.0/topics/i18n/ 102 | 103 | LANGUAGE_CODE = 'en-us' 104 | 105 | TIME_ZONE = 'UTC' 106 | 107 | USE_I18N = True 108 | 109 | USE_L10N = True 110 | 111 | USE_TZ = True 112 | 113 | # Static files (CSS, JavaScript, Images) 114 | # https://docs.djangoproject.com/en/2.0/howto/static-files/ 115 | STATIC_URL = '/static/' 116 | STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] # './static' 117 | 118 | # Auth 119 | # https://docs.djangoproject.com/en/2.0/ref/settings/#login-redirect-url 120 | LOGIN_REDIRECT_URL = '/' 121 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | myenv/ 2 | .idea/ 3 | 4 | # Created by https://www.gitignore.io/api/python 5 | 6 | ### Python ### 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | 109 | # End of https://www.gitignore.io/api/python 110 | 111 | 112 | # Created by https://www.gitignore.io/api/django 113 | 114 | ### Django ### 115 | *.log 116 | *.pot 117 | *.pyc 118 | __pycache__/ 119 | local_settings.py 120 | db.sqlite3 121 | media 122 | 123 | # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ 124 | # in your Git repository. Update and uncomment the following line accordingly. 125 | # /staticfiles/ 126 | 127 | # End of https://www.gitignore.io/api/django 128 | 129 | 130 | 131 | # Created by https://www.gitignore.io/api/pycharm 132 | 133 | ### PyCharm ### 134 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 135 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 136 | 137 | # User-specific stuff: 138 | .idea/**/workspace.xml 139 | .idea/**/tasks.xml 140 | .idea/dictionaries 141 | 142 | # Sensitive or high-churn files: 143 | .idea/**/dataSources/ 144 | .idea/**/dataSources.ids 145 | .idea/**/dataSources.xml 146 | .idea/**/dataSources.local.xml 147 | .idea/**/sqlDataSources.xml 148 | .idea/**/dynamic.xml 149 | .idea/**/uiDesigner.xml 150 | 151 | # Gradle: 152 | .idea/**/gradle.xml 153 | .idea/**/libraries 154 | 155 | # CMake 156 | cmake-build-debug/ 157 | 158 | # Mongo Explorer plugin: 159 | .idea/**/mongoSettings.xml 160 | 161 | ## File-based project format: 162 | *.iws 163 | 164 | ## Plugin-specific files: 165 | 166 | # IntelliJ 167 | /out/ 168 | 169 | # mpeltonen/sbt-idea plugin 170 | .idea_modules/ 171 | 172 | # JIRA plugin 173 | atlassian-ide-plugin.xml 174 | 175 | # Cursive Clojure plugin 176 | .idea/replstate.xml 177 | 178 | # Ruby plugin and RubyMine 179 | /.rakeTasks 180 | 181 | # Crashlytics plugin (for Android Studio and IntelliJ) 182 | com_crashlytics_export_strings.xml 183 | crashlytics.properties 184 | crashlytics-build.properties 185 | fabric.properties 186 | 187 | ### PyCharm Patch ### 188 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 189 | 190 | # *.iml 191 | # modules.xml 192 | # .idea/misc.xml 193 | # *.ipr 194 | 195 | # Sonarlint plugin 196 | .idea/sonarlint 197 | 198 | # End of https://www.gitignore.io/api/pycharm 199 | 200 | --------------------------------------------------------------------------------