├── .gitignore ├── README.md ├── main ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ └── __init__.py ├── models.py ├── static │ ├── css │ │ └── styles.css │ └── js │ │ └── main.js ├── templates │ ├── components │ │ └── response.html │ ├── homepage.html │ ├── layouts │ │ └── page.html │ ├── login.html │ ├── navbar.html │ ├── new-question.html │ ├── question.html │ └── register.html ├── tests.py ├── urls.py └── views.py ├── manage.py ├── mywebsite ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | .vscode 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | .DS_Store 104 | *.sqlite3 105 | media/ 106 | *.pyc 107 | *.db 108 | *.pid 109 | 110 | # Ignore Django Migrations in Development if you are working on team 111 | 112 | # Only for Development only 113 | **/migrations/** 114 | !**/migrations 115 | !**/migrations/__init__.py 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to create a Q&A website using Django Python | Django portfolio website 2 | 3 | Find full tutorial here 👉 [Youtube](https://youtu.be/PR9Ws30iIU8) 4 | 5 | Hello everyone, in this video we build a Q&A website using Django, you'll learn a lot of the basic stuff to help you started in your own projects. The idea of this project is that you can use it to create your own version of this project and add that to your portfolio. 6 | 7 | This video cover these topics: 8 | - Django forms 9 | - Django templates 10 | - Django Models & Django databases 11 | - Django QuerySet 12 | - Django ORM 13 | - Relationships in Django 14 | - Django authentication 15 | 16 | Follow me: 17 | https://www.instagram.com/codingvenue/ 18 | -------------------------------------------------------------------------------- /main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingvenue/questions-and-answers-website-django/79738ae6acd5907683f6b77ae738abebc10cad80/main/__init__.py -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | # Register your models here. 5 | admin.site.register(models.Question) 6 | admin.site.register(models.Response) 7 | -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | name = 'main' 6 | -------------------------------------------------------------------------------- /main/forms.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import UserCreationForm, AuthenticationForm 2 | from django.contrib.auth.models import User 3 | from .models import Question, Response 4 | from django import forms 5 | 6 | class RegisterUserForm(UserCreationForm): 7 | class Meta: 8 | model = User 9 | fields = ['username', 'email', 'password1', 'password2'] 10 | widgets = { 11 | 'email': forms.EmailInput(attrs={ 12 | 'required': True, 13 | 'placeholder': 'lisa@example.com', 14 | 'autofocus': True 15 | }), 16 | 'username': forms.TextInput(attrs={ 17 | 'placeholder': 'lisamora', 18 | }) 19 | } 20 | 21 | def __init__(self, *args, **kwargs): 22 | super(RegisterUserForm, self).__init__(*args, **kwargs) 23 | self.fields['password1'].widget.attrs = {'placeholder': 'password'} 24 | self.fields['password2'].widget.attrs = {'placeholder': 'confirm password'} 25 | 26 | class LoginForm(AuthenticationForm): 27 | class Meta: 28 | fields = '__all__' 29 | 30 | class NewQuestionForm(forms.ModelForm): 31 | class Meta: 32 | model = Question 33 | fields = ['title', 'body'] 34 | widgets = { 35 | 'title': forms.TextInput(attrs={ 36 | 'autofocus': True, 37 | 'placeholder': 'How to create a Q&A website with Django?' 38 | }) 39 | } 40 | 41 | class NewResponseForm(forms.ModelForm): 42 | class Meta: 43 | model = Response 44 | fields = ['body'] 45 | 46 | class NewReplyForm(forms.ModelForm): 47 | class Meta: 48 | model = Response 49 | fields = ['body'] 50 | widgets = { 51 | 'body': forms.Textarea(attrs={ 52 | 'rows': 2, 53 | 'placeholder': 'What are your thoughts?' 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingvenue/questions-and-answers-website-django/79738ae6acd5907683f6b77ae738abebc10cad80/main/migrations/__init__.py -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | # Create your models here. 5 | class Question(models.Model): 6 | author = models.ForeignKey(User, null=False, on_delete=models.CASCADE) 7 | title = models.CharField(max_length=200, null=False) 8 | body = models.TextField(null=False) 9 | created_at = models.DateTimeField(auto_now_add=True) 10 | updated_at = models.DateTimeField(auto_now=True) 11 | 12 | def __str__(self): 13 | return self.title 14 | 15 | def get_responses(self): 16 | return self.responses.filter(parent=None) 17 | 18 | class Response(models.Model): 19 | user = models.ForeignKey(User, null=False, on_delete=models.CASCADE) 20 | question = models.ForeignKey(Question, null=False, on_delete=models.CASCADE, related_name='responses') 21 | parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE) 22 | body = models.TextField(null=False) 23 | created_at = models.DateTimeField(auto_now_add=True) 24 | updated_at = models.DateTimeField(auto_now=True) 25 | 26 | def __str__(self): 27 | return self.body 28 | 29 | def get_responses(self): 30 | return Response.objects.filter(parent=self) 31 | -------------------------------------------------------------------------------- /main/static/css/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | font-family: Segoe UI; 4 | background-color: #7ef29d; 5 | } 6 | 7 | *, *::after, *::before { 8 | box-sizing: border-box; 9 | } 10 | 11 | a { 12 | text-decoration: none; 13 | } 14 | 15 | ul { 16 | list-style: none; 17 | padding: 0; 18 | } 19 | 20 | blockquote { 21 | border-left: 6px solid lightgray; 22 | padding-left: 6px; 23 | margin-left: 15px; 24 | } 25 | 26 | .main { 27 | max-width: 800px; 28 | margin: 60px auto; 29 | padding: 24px; 30 | border-radius: 20px; 31 | background-color: white; 32 | 33 | box-shadow: 5px 10px #888888; 34 | } 35 | 36 | .navbar { 37 | display: flex; 38 | flex-direction: row; 39 | justify-content: space-between; 40 | padding: 0 24px; 41 | 42 | border-bottom: 1px solid lightgray; 43 | } 44 | 45 | .user-menu ul li a, 46 | .main-menu ul li a { 47 | color: black; 48 | font-weight: 700; 49 | } 50 | 51 | .user-menu ul li a:hover, 52 | .main-menu ul li a:hover { 53 | text-decoration: underline; 54 | } 55 | 56 | .user-menu ul li { 57 | display: inline; 58 | margin-left: 12px; 59 | } 60 | 61 | .page { 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .new-question-page, 67 | .login-page, 68 | .register-page { 69 | margin: 0 auto; 70 | min-width: 50%; 71 | max-width: 50%; 72 | } 73 | 74 | .title { 75 | margin: 20px auto 30px auto; 76 | font-weight: 900; 77 | } 78 | 79 | .question-list-item { 80 | margin-bottom: 20px; 81 | } 82 | 83 | .question-list-item a:hover { 84 | text-decoration: underline; 85 | color: black; 86 | } 87 | 88 | .question-list-item-title { 89 | color: black; 90 | font-size: 18px; 91 | font-weight: 900; 92 | margin: 0 93 | } 94 | 95 | .question-list-item-author { 96 | color: lightgray; 97 | margin: 0; 98 | } 99 | 100 | .register-form { 101 | width: 100%; 102 | } 103 | 104 | .fieldWrapper { 105 | display: flex; 106 | flex-direction: column; 107 | margin-bottom: 20px; 108 | } 109 | 110 | .fieldWrapper label { 111 | font-size: 12px; 112 | font-weight: 600; 113 | text-transform: uppercase; 114 | margin-bottom: 10px; 115 | } 116 | 117 | .fieldWrapper input { 118 | margin-bottom: 6px; 119 | border: 1px solid lightgray; 120 | min-height: 40px; 121 | } 122 | 123 | .error { 124 | font-size: 14px; 125 | color: red; 126 | } 127 | 128 | .errorlist { 129 | margin: 0; 130 | } 131 | 132 | .non_form_errors { 133 | margin-bottom: 20px; 134 | } 135 | 136 | .submit-button { 137 | display: block; 138 | width: 120px; 139 | height: 40px; 140 | border: none; 141 | border-radius: 20px; 142 | background-color: black; 143 | color: white; 144 | margin: 0 auto; 145 | cursor: pointer; 146 | } 147 | 148 | .question-title { 149 | font-weight: 900; 150 | margin: 20px auto 0 auto; 151 | } 152 | 153 | .question-body { 154 | margin-bottom: 6px; 155 | } 156 | 157 | .question-author { 158 | font-size: 14px; 159 | color: lightgray; 160 | } 161 | 162 | .responses-container { 163 | border-top: 1px solid lightgray; 164 | margin-top: 30px; 165 | } 166 | 167 | .responses-container-heading { 168 | color: lightgray; 169 | } 170 | 171 | .no-responses-text { 172 | color: lightgray; 173 | } 174 | 175 | .response-body { 176 | margin: 0; 177 | } 178 | 179 | .response-author { 180 | color: lightgray; 181 | font-style: italic; 182 | } 183 | 184 | .reply-button { 185 | background-color: transparent; 186 | border: none; 187 | padding: 0; 188 | text-transform: lowercase; 189 | color: lightgray; 190 | cursor: pointer; 191 | } 192 | 193 | .response-form { 194 | margin-top: 20px; 195 | border-top: 1px solid lightgray; 196 | padding: 30px; 197 | } 198 | 199 | .reply-form-container { 200 | display: none; 201 | } 202 | 203 | .reply-form-container.enabled { 204 | display: block; 205 | } 206 | 207 | .reply-form textarea { 208 | width: 100%; 209 | } 210 | 211 | .reply-form-cancel-button { 212 | font-weight: 600; 213 | color: orange; 214 | background-color: transparent; 215 | border: none; 216 | padding: 4px 12px; 217 | cursor: pointer; 218 | } 219 | 220 | .reply-form-submit-button { 221 | font-weight: 600; 222 | color: white; 223 | background-color: orange; 224 | border: none; 225 | padding: 4px 12px; 226 | border-radius: 4px; 227 | cursor: pointer; 228 | } 229 | -------------------------------------------------------------------------------- /main/static/js/main.js: -------------------------------------------------------------------------------- 1 | function handleReplyButton(responseId) { 2 | const replyFormContainer = document.getElementById(`reply-form-container-${responseId}`); 3 | if (replyFormContainer) { 4 | replyFormContainer.className = 'reply-form-container enabled' 5 | } 6 | } 7 | 8 | function handleCancelReply(responseId) { 9 | const replyFormContainer = document.getElementById(`reply-form-container-${responseId}`); 10 | if (replyFormContainer) { 11 | replyFormContainer.className = 'reply-form-container' 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /main/templates/components/response.html: -------------------------------------------------------------------------------- 1 |
2 |

{{response.body}}

3 | by {{response.user.username}} 4 | 5 | {% if user.is_authenticated %} 6 | 7 | {% endif %} 8 | 9 |
10 |
11 | {% csrf_token %} 12 | 13 | 14 | {{reply_form.body}} 15 | 16 | 17 |
18 |
19 | 20 | {% for children in response.get_responses %} 21 | {% include 'components/response.html' with response=children %} 22 | {% endfor %} 23 | 24 |
25 | -------------------------------------------------------------------------------- /main/templates/homepage.html: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/page.html' %} 2 | 3 | {% block content %} 4 |
5 |

All questions

6 | 7 | {% for question in questions %} 8 |
9 | 10 |

11 | {{question.title}} 12 |

13 |

14 | by {{question.author.username}} 15 |

16 |
17 |
18 | {% endfor %} 19 |
20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /main/templates/layouts/page.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | {% include 'navbar.html' %} 13 | {% block content %} 14 | {% endblock %} 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /main/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/page.html' %} 2 | 3 | {% block content %} 4 |
5 |

Login

6 | 7 | 8 |
9 | {% csrf_token %} 10 |
11 | 12 | {{form.username}} 13 | {{form.username.errors}} 14 |
15 |
16 | 17 | {{form.password}} 18 | {{form.password.errors}} 19 |
20 | {% if form.non_field_errors %} 21 |
22 | {{form.non_field_errors.as_ul}} 23 |
24 | {% endif %} 25 | 26 |
27 | 28 |
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /main/templates/navbar.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /main/templates/new-question.html: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/page.html' %} 2 | 3 | {% block content %} 4 |
5 |

New question

6 | 7 | 8 |
9 | {% csrf_token %} 10 |
11 | 12 | {{form.title}} 13 | {{form.title.errors}} 14 |
15 |
16 | 17 | {{form.body}} 18 | {{form.body.errors}} 19 |
20 | 21 |
22 | 23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /main/templates/question.html: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/page.html' %} 2 | 3 | {% block content %} 4 |
5 | 6 |

{{question.title}}

7 |

{{question.body}}

8 | author : {{question.author.username}} 9 | 10 |
11 |

Responses

12 | 13 | {% if not question.responses.all %} 14 |

No responses yet

15 | {% else %} 16 | {% for response in question.get_responses %} 17 | {% include 'components/response.html' with response=response %} 18 | {% endfor %} 19 | {% endif %} 20 |
21 | 22 | {% if user.is_authenticated %} 23 |
24 | {% csrf_token %} 25 |
26 | 27 | {{response_form.body}} 28 |
29 | 30 |
31 | {% endif %} 32 | 33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /main/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/page.html' %} 2 | 3 | {% block content %} 4 |
5 |

Register

6 | 7 | 8 |
9 | {% csrf_token %} 10 |
11 | 12 | {{form.email}} 13 | {{form.email.errors}} 14 |
15 |
16 | 17 | {{form.username}} 18 | {{form.username.errors}} 19 |
20 |
21 | 22 | {{form.password1}} 23 | {{form.password1.errors}} 24 |
25 |
26 | 27 | {{form.password2}} 28 | {{form.password2.errors}} 29 |
30 | {% if form.non_field_errors %} 31 |
32 | {{form.non_field_errors.as_ul}} 33 |
34 | {% endif %} 35 | 36 |
37 | 38 |
39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /main/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('register', views.registerPage, name='register'), 6 | path('login', views.loginPage, name='login'), 7 | path('logout', views.logoutPage, name='logout'), 8 | path('', views.homePage, name='index'), 9 | path('new-question', views.newQuestionPage, name='new-question'), 10 | path('question/', views.questionPage, name='question'), 11 | path('reply', views.replyPage, name='reply') 12 | ] 13 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth import login, logout 3 | from django.contrib.auth.decorators import login_required 4 | from .models import Question, Response 5 | from .forms import RegisterUserForm, LoginForm, NewQuestionForm, NewResponseForm, NewReplyForm 6 | 7 | # Create your views here. 8 | 9 | def registerPage(request): 10 | form = RegisterUserForm() 11 | 12 | if request.method == 'POST': 13 | try: 14 | form = RegisterUserForm(request.POST) 15 | if form.is_valid(): 16 | user = form.save() 17 | login(request, user) 18 | return redirect('index') 19 | except Exception as e: 20 | print(e) 21 | raise 22 | 23 | context = { 24 | 'form': form 25 | } 26 | return render(request, 'register.html', context) 27 | 28 | def loginPage(request): 29 | form = LoginForm() 30 | 31 | if request.method == 'POST': 32 | try: 33 | form = LoginForm(data=request.POST) 34 | if form.is_valid(): 35 | user = form.get_user() 36 | login(request, user) 37 | return redirect('index') 38 | except Exception as e: 39 | print(e) 40 | raise 41 | 42 | context = {'form': form} 43 | return render(request, 'login.html', context) 44 | 45 | @login_required(login_url='register') 46 | def logoutPage(request): 47 | logout(request) 48 | return redirect('login') 49 | 50 | @login_required(login_url='register') 51 | def newQuestionPage(request): 52 | form = NewQuestionForm() 53 | 54 | if request.method == 'POST': 55 | try: 56 | form = NewQuestionForm(request.POST) 57 | if form.is_valid(): 58 | question = form.save(commit=False) 59 | question.author = request.user 60 | question.save() 61 | except Exception as e: 62 | print(e) 63 | raise 64 | 65 | context = {'form': form} 66 | return render(request, 'new-question.html', context) 67 | 68 | def homePage(request): 69 | questions = Question.objects.all().order_by('-created_at') 70 | context = { 71 | 'questions': questions 72 | } 73 | return render(request, 'homepage.html', context) 74 | 75 | def questionPage(request, id): 76 | response_form = NewResponseForm() 77 | reply_form = NewReplyForm() 78 | 79 | if request.method == 'POST': 80 | try: 81 | response_form = NewResponseForm(request.POST) 82 | if response_form.is_valid(): 83 | response = response_form.save(commit=False) 84 | response.user = request.user 85 | response.question = Question(id=id) 86 | response.save() 87 | return redirect('/question/'+str(id)+'#'+str(response.id)) 88 | except Exception as e: 89 | print(e) 90 | raise 91 | 92 | question = Question.objects.get(id=id) 93 | context = { 94 | 'question': question, 95 | 'response_form': response_form, 96 | 'reply_form': reply_form, 97 | } 98 | return render(request, 'question.html', context) 99 | 100 | 101 | @login_required(login_url='register') 102 | def replyPage(request): 103 | if request.method == 'POST': 104 | try: 105 | form = NewReplyForm(request.POST) 106 | if form.is_valid(): 107 | question_id = request.POST.get('question') 108 | parent_id = request.POST.get('parent') 109 | reply = form.save(commit=False) 110 | reply.user = request.user 111 | reply.question = Question(id=question_id) 112 | reply.parent = Response(id=parent_id) 113 | reply.save() 114 | return redirect('/question/'+str(question_id)+'#'+str(reply.id)) 115 | except Exception as e: 116 | print(e) 117 | raise 118 | 119 | return redirect('index') 120 | -------------------------------------------------------------------------------- /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', 'mywebsite.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 | -------------------------------------------------------------------------------- /mywebsite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingvenue/questions-and-answers-website-django/79738ae6acd5907683f6b77ae738abebc10cad80/mywebsite/__init__.py -------------------------------------------------------------------------------- /mywebsite/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for mywebsite 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/3.1/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', 'mywebsite.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /mywebsite/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for mywebsite project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.3. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '+q*p#-#2)u*p9t68n#tb)rn^$w7$wd8u)4qu^((61=2&lu8s8_' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 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 | 'main' 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'mywebsite.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [], 59 | 'APP_DIRS': True, 60 | 'OPTIONS': { 61 | 'context_processors': [ 62 | 'django.template.context_processors.debug', 63 | 'django.template.context_processors.request', 64 | 'django.contrib.auth.context_processors.auth', 65 | 'django.contrib.messages.context_processors.messages', 66 | ], 67 | }, 68 | }, 69 | ] 70 | 71 | WSGI_APPLICATION = 'mywebsite.wsgi.application' 72 | 73 | 74 | # Database 75 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 76 | 77 | DATABASES = { 78 | 'default': { 79 | 'ENGINE': 'django.db.backends.sqlite3', 80 | 'NAME': BASE_DIR / 'db.sqlite3', 81 | } 82 | } 83 | 84 | 85 | # Password validation 86 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 87 | 88 | AUTH_PASSWORD_VALIDATORS = [ 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 100 | }, 101 | ] 102 | 103 | 104 | # Internationalization 105 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 106 | 107 | LANGUAGE_CODE = 'en-us' 108 | 109 | TIME_ZONE = 'UTC' 110 | 111 | USE_I18N = True 112 | 113 | USE_L10N = True 114 | 115 | USE_TZ = True 116 | 117 | 118 | # Static files (CSS, JavaScript, Images) 119 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 120 | 121 | STATIC_URL = '/static/' 122 | -------------------------------------------------------------------------------- /mywebsite/urls.py: -------------------------------------------------------------------------------- 1 | """mywebsite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/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 path, include 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path('', include('main.urls')) 22 | ] 23 | -------------------------------------------------------------------------------- /mywebsite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mywebsite 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/3.1/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', 'mywebsite.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.1 2 | Django==3.1.3 3 | pytz==2020.4 4 | sqlparse==0.4.1 5 | --------------------------------------------------------------------------------