Advanced_Django_Blog
Advanced_Django_Blog copied to clipboard
A Blog project built using Django Web Framework, Django REST Framework, Graphene Django, Cookiecutter Django, Vue.js 3, Quasar Framework, Tanstack Vue Query, Vue Apollo and Vue-multiselect
Advanced Django Blog
A blog project built using
Django Web Framework, Django REST Framework, Graphene Django, Cookiecutter Django, HTMX, Vue.js 3, Quasar Framework, Tanstack Vue Query, Vue Apollo, Vue-multiselect,
[!CAUTION] Currently vue-frontend GraphQL implementation is not working correctly if you are using a chromium based web browser (like Google Chrome for example). but, it is working very well if you are using Firefox web browser.
Project Goals
-
Authenticated users can:
-
Access a GraphQL endpoint and run several Quries and CRUD Mutations.
-
Access a Rest API endpoint and run CRUD operations.
-
Create, Read, Update and Delete (CRUD) blog posts on the website.
-
Add comments on blog posts, but the comments will not be visiable until the website admin approves it.
-
Like Blog posts and Add them to their favorite list (using HTMX).
-
Access their profile which lists all their blog posts and their favorite posts.
-
-
All users can read or search for the posts on the blog.
-
Users can access separate frontend project built using Vue.js 3, Tanstack-Vue-Query, Vue-Apollo and Quasar Framework which connects with django through Django Rest Framework using Session Authentication.
-
The frontend vue.js app also allows users to perform CRUD operations through connecting to a REST API and a GraphQL endpoints.
Currently in Vue frontend users can:
-
Register for an account and log in to their account (users will be authenticated using Django Rest Framework Session Authentication).
-
Add tags to blog using a Rest API endpoint and GraphQL endpoint.
-
Perform CRUD operations to blog posts using both REST API and GraphQL.
-
Perform CRUD operations to add comments to blog posts using both REST API and GraphQL.
-
Add and remove posts to and form their favorite posts list.
-
Access pages that show their added blog posts and their favorite posts.
-
Search for blog posts by title and limiting the results using both REST API and GraphQL
Project preview
Project Description:
This project is a Django project called blog_backend and it has four registered apps and one third-party app.
-
The
blogapp which contains an app-level templates and urls, used for most of the functionalities of our app, like, models, forms, views, urls, and custom template tags. -
The
apiapp which contains the Django Rest Framework integration used to build a REST API. -
The
graphql_appwhich contains the Graphene Django integration used to build a GraphQL endpoint. -
The
usersapp which usesdjango.contrib.auth.urlsto allow users register and login to their accounts. -
crispy formsthird-party app which beautify django forms design.
What could you learn from this project?
-
Create Django models and define relationships between the database fields.
-
Use both Django Class-based and Function-based views.
-
Create custom Django template tags, (In this project I created a simple custom template tag that return the number of comments on each blog post).
-
How to use page pagination on your website.
-
How to associate each blog post to its author.
-
How to protect your post so that only you who can modify or delete it.
-
Throw a 403 forbidden page to any user who try to guess the URL to change something they are not authorized to change.
-
Create a search form on your website.
-
And many more.
To get started with this project without Docker:
-
Make sure that both PostgreSQL database and Mailpit Email client are installed and running in your system.
-
Create a PostgreSQL database, This project uses PostgreSQL version 14.
-
Export database default url using the following terminal command, In this example PostgreSQL is installed locally, database name is django-blog-backend, and database admin credentials are => username: admin / password: 1234:
export DATABASE_URL=postgres://admin:[email protected]:5432/django-blog-backend
-
Open the terminal or CMD to create a virtual environment like Python virtual environment (venv) or pipenv and activate it.
-
python -m venv venvCreate the venv -
source venv/bin/activateOn Linux -
venv/Scripts/activateOn Windows -
source venv/Scripts/activateGit Bash on Windows
-
-
Change directory to django_blog_backend
cd django_blog_backend -
Install local.txt requirements file:
python -m pip install -r requirements/local.txt -
Create the database by running the following commands:
python manage.py makemigrationspython manage.py migrate -
Create a super user:
python manage.py createsuperuser -
Run the project:
python manage.py runserver -
Before logging in to the Django website make sure that Mailpit email client is running in your system to recieve an email activation link.
To get started with this project with Docker:
-
Make sure that Docker and docker-compose are installed in your system.
-
Clone the repository: git clone https://github.com/MoustafaShaaban/Advanced_Django_Blog.git
-
Change directory to docker_blog_backend directory
cd docker_blog_backend -
Build the docker image to develop the project locally using docker-compose:
docker-compose -f docker-compose.local.yml build
- Create the database by running the following commands:
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate
- Create a super user:
docker-compose -f docker-compose.local.yml run --rm django python manage.py createsuperuser
- Run the test using pytest:
docker compose -f docker-compose.local.yml run --rm django test docker_blog_backend/blog
- Now run the project:
docker-compose -f docker-compose.local.yml up
-
Open the web browser and go to
http://localhost:8000/to see the results. -
Start a new terminal and change directory to vue-frontend directory and install the requirements:
cd vue-frontend
npm install
- Run the Vue.js 3 frontend project:
npm run dev
For more information about the available commands in this project check the Cookiecutter Django Documentation
References:
GraphQL Queries and Mutations Examples:
query ReturnAllPosts {
allPosts {
id
title
content
updatedAt
comments {
id
comment
user {
username
}
}
tag {
id
name
}
}
}
query returnPostBySlug($slug: String!) {
postBySlug(slug: $slug) {
id
title
content
author {
username
avatar
}
updatedAt
comments {
id
comment
user {
username
}
}
tag {
id
name
}
}
}
and in the variables:
{
"slug: "post-1"
}
query ReturnMyPost {
myPostsWithFilters {
edges {
node {
id
title
content
updatedAt
comments {
id
comment
user {
username
}
}
tag {
id
name
}
}
}
}
}
query PostByTitle {
allPostsWithFilters(title: "Post Number 1") {
edges {
node {
id
title
updatedAt
content
comments {
id
comment
}
}
}
}
}
query AllComments {
allComments {
id
user {
name
}
comment
post {
id
title
content
updatedAt
}
}
}
query AllTags {
allTags {
id
name
slug
}
}
mutation createTag {
createTag(input: {
name: "Python"
}) {
tag {
id
name
}
}
}
mutation UpdateTag {
updateTag(id: 1, name: "Python") {
tag {
id
name
}
}
}
mutation DeleteTag {
deleteTag(id: 6) {
success
}
}
mutation CreatePost {
createPost(input: {
title: "Post number 1",
content: "Post number 1 content",
tags: [
{ slug: "python" }
]
}) {
post {
id
content
}
}
}
mutation CreateComment {
createComment(inputs: {
postSlug: "post-1",
comment: "Great post",
}) {
post {
title,
comments {
comment
user {
username
}
}
}
}
}
query PostsByAuthor {
postsByAuthor(author: "admin") {
id
title
updatedAt
tag {
name
}
content
comments {
id
user {
username
}
comment
}
}
}
query PostsByTag {
postsByTag(tag: "Python") {
id
title
updatedAt
tag {
name
}
content
comments {
id
user {
username
}
comment
}
}
}
query PostsByTitle {
postByTitle(title: "Post number 1") {
id
title
updatedAt
tag {
name
}
content
comments {
id
user {
username
}
comment
}
}
}
query PostsByTitleWithDjangoFilters {
allPostsWithFilters(title_Icontains: "Post number") {
edges {
node {
id
title
updatedAt
tag {
name
}
content
comments {
id
user {
username
}
comment
}
}
}
}
}
query PostsByTitleWithDjangoFilters {
allPostsWithFilters(title_Istartswith: "Post number") {
edges {
node {
id
title
updatedAt
tag {
name
}
content
comments {
id
user {
username
}
comment
}
}
}
}
}