Skip to content

Commit 7fd1ec9

Browse files
authored
Merge pull request #200 from realpython/django-vue-graphql
Add source code for Building a Blog With Django, Vue, and GraphQL
2 parents 3d5aa6a + 570d137 commit 7fd1ec9

34 files changed

+19345
-0
lines changed

django-vue-graphql/README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Build a Blog Using Django, Vue, and GraphQL
2+
3+
## Starting the back-end Django application
4+
5+
In a new terminal tab:
6+
7+
1. Install the back-end requirements in the environment of your choice:
8+
```shell
9+
$ cd /path/to/repo/tutorial-drafts/articles/django-vue-graphql/source_code/backend/
10+
$ python3 -m pip install -r requirements.txt
11+
```
12+
1. Create the initial Django database by running migrations:
13+
```shell
14+
$ python manage.py migrate
15+
```
16+
1. Create a Django superuser:
17+
```shell
18+
$ python manage.py createsuperuser
19+
```
20+
1. Run the Django project (by default on port 8000):
21+
```shell
22+
$ python manage.py runserver
23+
```
24+
25+
## Starting the front-end Vue application
26+
27+
In a new terminal tab:
28+
29+
1. Install the front-end requirements:
30+
```shell
31+
$ cd /path/to/repo/tutorial-drafts/articles/django-vue-graphql/source_code/frontend/
32+
$ npm install
33+
```
34+
1. Run the Vue project (by default on port 8080):
35+
```shell
36+
$ npm run serve
37+
```
38+
39+
## Add a few posts
40+
41+
1. Visit [the Django admin](https://localhost:8000/admin)
42+
1. Log in using the superuser you created earlier
43+
1. Write a few posts, adding authors and tags as desired
44+
1. Make sure at least one post is `published` (or no posts will appear)
45+
46+
## View the blog
47+
48+
1. Visit [the blog homepage](https://localhost:8080)
49+
1. Browse the posts, tags, and authors
50+
51+
## Try the GraphQL API yourself
52+
53+
1. Visit [the GraphiQL interface](https://localhost:8000/graphql)
54+
1. View the *Docs* panel on the top right
55+
1. Create some queries—the available information should auto-populate!
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Python
2+
.python-version
3+
*.pyc
4+
5+
# SQLite
6+
db.sqlite3

django-vue-graphql/backend/backend/__init__.py

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import os
2+
3+
from django.core.asgi import get_asgi_application
4+
5+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
6+
7+
application = get_asgi_application()
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from pathlib import Path
2+
3+
4+
BASE_DIR = Path(__file__).resolve().parent.parent
5+
6+
SECRET_KEY = "gmkd4-*ew4fv!w8p!9qm(o2-qpmc$&jng-2jm!4l3$x^pn#tmu"
7+
8+
DEBUG = True
9+
10+
ALLOWED_HOSTS = ["*"]
11+
12+
INSTALLED_APPS = [
13+
"django.contrib.admin",
14+
"django.contrib.auth",
15+
"django.contrib.contenttypes",
16+
"django.contrib.sessions",
17+
"django.contrib.messages",
18+
"django.contrib.staticfiles",
19+
"graphene_django",
20+
"corsheaders",
21+
"blog",
22+
]
23+
24+
MIDDLEWARE = [
25+
"django.middleware.security.SecurityMiddleware",
26+
"django.contrib.sessions.middleware.SessionMiddleware",
27+
"django.middleware.common.CommonMiddleware",
28+
"django.middleware.csrf.CsrfViewMiddleware",
29+
"django.contrib.auth.middleware.AuthenticationMiddleware",
30+
"django.contrib.messages.middleware.MessageMiddleware",
31+
"django.middleware.clickjacking.XFrameOptionsMiddleware",
32+
"corsheaders.middleware.CorsMiddleware",
33+
]
34+
35+
ROOT_URLCONF = "backend.urls"
36+
37+
TEMPLATES = [
38+
{
39+
"BACKEND": "django.template.backends.django.DjangoTemplates",
40+
"DIRS": [],
41+
"APP_DIRS": True,
42+
"OPTIONS": {
43+
"context_processors": [
44+
"django.template.context_processors.debug",
45+
"django.template.context_processors.request",
46+
"django.contrib.auth.context_processors.auth",
47+
"django.contrib.messages.context_processors.messages",
48+
],
49+
},
50+
},
51+
]
52+
53+
WSGI_APPLICATION = "backend.wsgi.application"
54+
55+
DATABASES = {
56+
"default": {
57+
"ENGINE": "django.db.backends.sqlite3",
58+
"NAME": BASE_DIR / "db.sqlite3",
59+
}
60+
}
61+
62+
AUTH_PASSWORD_VALIDATORS = [
63+
{
64+
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
65+
},
66+
{
67+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
68+
},
69+
{
70+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
71+
},
72+
{
73+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
74+
},
75+
]
76+
77+
LANGUAGE_CODE = "en-us"
78+
79+
TIME_ZONE = "UTC"
80+
81+
USE_I18N = True
82+
83+
USE_L10N = True
84+
85+
USE_TZ = True
86+
87+
STATIC_URL = "/static/"
88+
89+
GRAPHENE = {
90+
"SCHEMA": "blog.schema.schema",
91+
}
92+
93+
CORS_ORIGIN_ALLOW_ALL = False
94+
CORS_ORIGIN_WHITELIST = ("http://localhost:8080",)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.contrib import admin
2+
from django.urls import path
3+
from django.views.decorators.csrf import csrf_exempt
4+
from graphene_django.views import GraphQLView
5+
6+
7+
urlpatterns = [
8+
path("admin/", admin.site.urls),
9+
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
10+
]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import os
2+
3+
from django.core.wsgi import get_wsgi_application
4+
5+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
6+
7+
application = get_wsgi_application()

django-vue-graphql/backend/blog/__init__.py

Whitespace-only changes.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from django.contrib import admin
2+
3+
from blog.models import Profile, Post, Tag
4+
5+
6+
@admin.register(Profile)
7+
class ProfileAdmin(admin.ModelAdmin):
8+
model = Profile
9+
10+
11+
@admin.register(Tag)
12+
class TagAdmin(admin.ModelAdmin):
13+
model = Tag
14+
15+
16+
@admin.register(Post)
17+
class PostAdmin(admin.ModelAdmin):
18+
model = Post
19+
20+
list_display = (
21+
"id",
22+
"title",
23+
"subtitle",
24+
"slug",
25+
"publish_date",
26+
"published",
27+
)
28+
list_filter = (
29+
"published",
30+
"publish_date",
31+
)
32+
list_editable = (
33+
"title",
34+
"subtitle",
35+
"slug",
36+
"publish_date",
37+
"published",
38+
)
39+
search_fields = (
40+
"title",
41+
"subtitle",
42+
"slug",
43+
"body",
44+
)
45+
prepopulated_fields = {
46+
"slug": (
47+
"title",
48+
"subtitle",
49+
)
50+
}
51+
date_hierarchy = "publish_date"
52+
save_on_top = True
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class BlogConfig(AppConfig):
5+
name = "blog"

0 commit comments

Comments
 (0)