├── .gitignore
├── .idea
├── .gitignore
├── QuotesApp.iml
├── dataSources.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── LICENSE
├── QuotesApp
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
├── README.md
├── db.sqlite3
├── manage.py
├── quotes
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_quote_category.py
│ ├── 0003_alter_quote_category.py
│ ├── 0004_comment_like.py
│ ├── 0005_alter_quote_category.py
│ └── __init__.py
├── models.py
├── serializers.py
├── static
│ └── images
│ │ └── favicon.ico
├── templates
│ └── quotes
│ │ ├── category.html
│ │ ├── comment_item.html
│ │ ├── index.html
│ │ ├── quote_detail.html
│ │ └── search.html
├── tests.py
├── urls.py
└── views.py
├── readme-images
├── api.png
├── category.png
├── details.png
├── homepage.png
└── results.png
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /.env
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/QuotesApp.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/dataSources.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | sqlite.xerial
6 | true
7 | true
8 | $PROJECT_DIR$/QuotesApp/settings.py
9 | org.sqlite.JDBC
10 | jdbc:sqlite:$PROJECT_DIR$/db.sqlite3
11 | $ProjectFileDir$
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Son Nguyen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/QuotesApp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoangsonww/Django-Quote-Application/572085c3a1d17e6c741bc1694711a92a899b68ab/QuotesApp/__init__.py
--------------------------------------------------------------------------------
/QuotesApp/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for QuotesApp 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/5.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', 'QuotesApp.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/QuotesApp/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for QuotesApp project.
3 |
4 | Generated by 'django-admin startproject' using Django 5.0.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/5.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/5.0/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 | from decouple import config
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/5.0/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = config('DJANGO_SECRET_KEY')
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = False
28 |
29 | ALLOWED_HOSTS = ['*']
30 |
31 | CORS_ALLOWED_ORIGINS = ['*']
32 |
33 | # Application definition
34 |
35 | INSTALLED_APPS = [
36 | 'django.contrib.admin',
37 | 'django.contrib.auth',
38 | 'django.contrib.contenttypes',
39 | 'django.contrib.sessions',
40 | 'django.contrib.messages',
41 | 'django.contrib.staticfiles',
42 | 'rest_framework',
43 | 'quotes',
44 | ]
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | ]
55 |
56 | ROOT_URLCONF = 'QuotesApp.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': [],
62 | 'APP_DIRS': True,
63 | 'OPTIONS': {
64 | 'context_processors': [
65 | 'django.template.context_processors.debug',
66 | 'django.template.context_processors.request',
67 | 'django.contrib.auth.context_processors.auth',
68 | 'django.contrib.messages.context_processors.messages',
69 | ],
70 | },
71 | },
72 | ]
73 |
74 | WSGI_APPLICATION = 'QuotesApp.wsgi.application'
75 |
76 | ADMIN_SITE_HEADER = "Quotes Application Administration"
77 |
78 |
79 | # Database
80 | # https://docs.djangoproject.com/en/5.0/ref/settings/#databases
81 |
82 | DATABASES = {
83 | 'default': {
84 | 'ENGINE': 'django.db.backends.sqlite3',
85 | 'NAME': BASE_DIR / 'db.sqlite3',
86 | }
87 | }
88 |
89 |
90 | # Password validation
91 | # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
92 |
93 | AUTH_PASSWORD_VALIDATORS = [
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
99 | },
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
102 | },
103 | {
104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
105 | },
106 | ]
107 |
108 |
109 | # Internationalization
110 | # https://docs.djangoproject.com/en/5.0/topics/i18n/
111 |
112 | LANGUAGE_CODE = 'en-us'
113 |
114 | TIME_ZONE = 'UTC'
115 |
116 | USE_I18N = True
117 |
118 | USE_TZ = True
119 |
120 |
121 | # Static files (CSS, JavaScript, Images)
122 | # https://docs.djangoproject.com/en/5.0/howto/static-files/
123 |
124 | STATIC_URL = 'static/'
125 |
126 | # Default primary key field type
127 | # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
128 |
129 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
130 |
--------------------------------------------------------------------------------
/QuotesApp/urls.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.urls import path, include
3 |
4 | urlpatterns = [
5 | path('admin/', admin.site.urls),
6 | path('', include('quotes.urls')),
7 | ]
8 |
--------------------------------------------------------------------------------
/QuotesApp/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for QuotesApp 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/5.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', 'QuotesApp.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Django Quotes App
2 |
3 | This is a simple Django-powered web application (backend) that displays inspirational quotes, allows users to like, comment, and search for quotes. It includes a user interface for viewing quotes, an admin interface for managing quotes, and a REST API using Django REST Framework for interacting with quotes programmatically.
4 |
5 | ## Table of Contents
6 | - [Live Deployment](#live-deployment)
7 | - [User Interface](#user-interface)
8 | - [Features](#features)
9 | - [Project Structure](#project-structure)
10 | - [How to Run Locally](#how-to-run-locally)
11 | - [User Guide](#user-guide)
12 | - [REST API Usage](#rest-api-usage)
13 | - [Contributing](#contributing)
14 | - [License](#license)
15 | - [Contact](#contact)
16 |
17 | ## Live Deployment
18 |
19 | You can view the live deployment of this project [here](https://django-quote-application.onrender.com).
20 |
21 | The Django backend is deployed on Render, and the UI is composed of HTML and CSS templates, which are served statically. There is no "real frontend" used in this project, so you can create your own frontend using JavaScript frameworks like React, Vue, or Angular.
22 |
23 | ## User Interface
24 |
25 | ### Homepage
26 |
27 |
28 |
29 |
30 |
31 | ### Category Page
32 |
33 |
34 |
35 |
36 |
37 | ### Search Results
38 |
39 |
40 |
41 |
42 |
43 | ### Quote Details
44 |
45 |
46 |
47 |
48 |
49 | ## Features
50 |
51 | * **Quote of the Day:** A random quote is displayed on the homepage.
52 | * **Liking and Commenting:** Authenticated users can like and comment on quotes.
53 | * **Category Filtering:** Filter quotes by category.
54 | * **Search:** Easily search for quotes by keywords.
55 | * **Responsive Design:** Looks great on desktops, tablets, and mobile devices.
56 | * **Admin Interface:** Add, update, and delete quotes using our admin interface.
57 | * **REST API:** Interact with quotes programmatically using our API endpoints.
58 |
59 | **Note:** Only authenticated users can like and comment on quotes. You can create a superuser account using the Django admin interface or use the admin interface to create user accounts to test these features.
60 |
61 | ## Project Structure
62 |
63 | The project consists of the following main components:
64 |
65 | - **`quotes/`:**
66 | - `models.py`: Contains the database models for quotes and categories.
67 | - `views.py`: Defines the views for rendering different pages.
68 | - `urls.py`: Maps URLs to views.
69 | - `templates/quotes/`: Contains HTML templates for rendering pages.
70 | - `category.html`: Displays quotes in a specific category.
71 | - `quote-detail.html`: Shows the details of a quote.
72 | - `index.html`: The main homepage with the quote of the day.
73 | - `search.html`: Displays search results.
74 | - `static/images/`: Contains images used in the project.
75 | - `__init__.py`: Makes the directory a Python package.
76 | - `admin.py`: Registers models for the admin interface.
77 | - `apps.py`: Configuration for the quotes app.
78 | - `tests.py`: Contains test cases for the application.
79 | - `urls.py`: URL patterns for the quotes app.
80 | - `serializers.py`: Serializers for converting model instances to JSON.
81 | - **`QuotesApp/`:**
82 | - `settings.py`: Contains the project settings and configurations.
83 | - `urls.py`: Defines the URL patterns for the entire project.
84 | - `wsgi.py`: WSGI configuration for deployment.
85 | - `asgi.py`: ASGI configuration for deployment.
86 | - `__init__.py`: Makes the directory a Python package.
87 | - **`db.sqlite3`:** The default SQLite database file.
88 | - **`manage.py`:** A command-line utility for interacting with the project.
89 |
90 | ## How to Run Locally
91 |
92 | ### Prerequisites
93 |
94 | * Python (3.7+)
95 | * Django (4.x)
96 | * Django REST Framework
97 | * Virtual Python Environment (recommended)
98 | * Git
99 |
100 | ### Steps
101 |
102 | 1. **Clone the repository:** Clone the repository using the Code button in the repository's main GitHub page.
103 |
104 | 2. **Create a virtual environment (optional):**
105 |
106 | ```bash
107 | python -m venv venv
108 | source venv/bin/activate # On Windows, use `venv\Scripts\activate`
109 | ```
110 |
111 | 3. **Apply migrations:**
112 |
113 | ```bash
114 | python manage.py makemigrations
115 | python manage.py migrate
116 | ```
117 |
118 | 4. **Create a superuser (for admin access):**
119 |
120 | ```bash
121 | python manage.py createsuperuser
122 | ```
123 |
124 | 5. **Start the development server:**
125 |
126 | ```bash
127 | # Run the server
128 | python manage.py runserver
129 | # Go to the admin interface (http://127.0.0.1:8000/admin/)
130 | # Create quotes and add them to different categories
131 | # Go to the homepage to see the quotes (http://127.0.0.1:8000/)
132 | ```
133 |
134 | **Important**: Remember to change the Django production secret key and set `DEBUG` to `True` in `QuotesApp/settings.py` order to run the server:
135 | ```python
136 | SECRET_KEY = 'your_secret_key'
137 |
138 | DEBUG = True
139 | ```
140 |
141 | ## User Guide
142 |
143 | ### Homepage:
144 |
145 | * The main page displays a random quote of the day.
146 | * Like and comment on the quote if you're logged in.
147 | * Use the search bar to find specific quotes.
148 | * Use the category filter to see quotes in a specific category.
149 |
150 | ### Searching:
151 |
152 | * Enter your search query in the search bar.
153 | * The results page will show all quotes containing your keywords.
154 | * Click on a quote to view its details and comments.
155 |
156 | ### Categories:
157 |
158 | * Choose a category from the dropdown on the main page.
159 | * You'll see a list of quotes that belong to that category.
160 |
161 | ### Liking and Commenting:
162 |
163 | * If you like a quote, click the "Like" button. You can unlike it by clicking again.
164 | * To comment, type your comment in the text area and click "Submit."
165 |
166 | ### Adding Quotes (Admin):
167 |
168 | * Go to the admin interface (http://127.0.0.1.8000/admin/).
169 | * Log in with the superuser credentials you created earlier.
170 | * Click on "Quotes" and then "Add Quote."
171 | * Fill in the quote text, author, and category.
172 | * Click "Save" to add the quote to the database.
173 |
174 | ## REST API Usage
175 |
176 | The app also includes a REST API built with Django REST Framework. Here are some of the available endpoints:
177 |
178 | | Endpoint | Method | Description | Authentication Required |
179 | |:-----------------------------------|:------:|:-----------------------------------|:-----------------------:|
180 | | `/api/quotes/` | GET | Get a list of all quotes. | No |
181 | | `/api/quotes//` | GET | Get a specific quote by ID. | No |
182 | | `/api/quotes/` | POST | Create a new quote. | Yes |
183 | | `/api/quotes//` | PUT | Update a specific quote. | Yes |
184 | | `/api/quotes//` | DELETE | Delete a specific quote. | Yes |
185 | | `/api/quotes//comments/` | GET | Get comments for a specific quote. | No |
186 | | `/api/quotes//comments/` | POST | Add a comment to a specific quote. | Yes |
187 |
188 | **Example Usage (with curl):**
189 |
190 | ```bash
191 | # Get all quotes
192 | curl http://127.0.0.1:8000/api/quotes/
193 |
194 | # Get a specific quote
195 | curl http://127.0.0.1:8000/api/quotes/1/
196 | ```
197 |
198 | For example, running `curl http://127.0.0.1:800/api/quotes/` will return this output:
199 |
200 | ```json
201 | [{"id":1,"text":"heheheheh","author":"hehe","category":"General","like_set":[]},{"id":2,"text":"ggegegege","author":"gegegeg","category":"Inspirational","like_set":[23]}]
202 | ```
203 |
204 | You can also go to the API endpoints directly in your browser to see the JSON responses, such as:
205 |
206 |