Skip to content

Commit 38db5e5

Browse files
committed
Basic backend with graphql
0 parents  commit 38db5e5

19 files changed

+523
-0
lines changed

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.sqlite3
2+
**/__pycache__
3+
.direnv/

backend/__init__.py

Whitespace-only changes.

backend/asgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for backend 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/4.2/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", "backend.settings")
15+
16+
application = get_asgi_application()

backend/settings.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""
2+
Django settings for backend project.
3+
4+
Generated by 'django-admin startproject' using Django 4.2.9.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/4.2/topics/settings/
8+
9+
For the full list of settings and their values, see
10+
https://docs.djangoproject.com/en/4.2/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/4.2/howto/deployment/checklist/
21+
22+
# SECURITY WARNING: keep the secret key used in production secret!
23+
SECRET_KEY = "django-insecure-1mf!ukyj51be^arlbdizd6lq1qq=37r#bwhxe(3en$@3xmx2y$"
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+
"graphene_django",
41+
"corsheaders",
42+
"blog",
43+
]
44+
45+
MIDDLEWARE = [
46+
"django.middleware.security.SecurityMiddleware",
47+
"django.contrib.sessions.middleware.SessionMiddleware",
48+
"django.middleware.common.CommonMiddleware",
49+
"django.middleware.csrf.CsrfViewMiddleware",
50+
"django.contrib.auth.middleware.AuthenticationMiddleware",
51+
"django.contrib.messages.middleware.MessageMiddleware",
52+
"django.middleware.clickjacking.XFrameOptionsMiddleware",
53+
"corsheaders.middleware.CorsMiddleware",
54+
]
55+
56+
ROOT_URLCONF = "backend.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 = "backend.wsgi.application"
75+
76+
CORS_ORIGIN_ALLOW_ALL = False
77+
CORS_ORIGIN_WHITELIST = ("http://localhost:8080",)
78+
79+
# Database
80+
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
81+
82+
DATABASES = {
83+
"default": {
84+
"ENGINE": "django.db.backends.sqlite3",
85+
"NAME": BASE_DIR / "db.sqlite3",
86+
}
87+
}
88+
89+
GRAPHENE = {
90+
"SCHEMA": "blog.schema.schema",
91+
}
92+
93+
94+
# Password validation
95+
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
96+
97+
AUTH_PASSWORD_VALIDATORS = [
98+
{
99+
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
100+
},
101+
{
102+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
103+
},
104+
{
105+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
106+
},
107+
{
108+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
109+
},
110+
]
111+
112+
113+
# Internationalization
114+
# https://docs.djangoproject.com/en/4.2/topics/i18n/
115+
116+
LANGUAGE_CODE = "en-us"
117+
118+
TIME_ZONE = "UTC"
119+
120+
USE_I18N = True
121+
122+
USE_TZ = True
123+
124+
125+
# Static files (CSS, JavaScript, Images)
126+
# https://docs.djangoproject.com/en/4.2/howto/static-files/
127+
128+
STATIC_URL = "static/"
129+
130+
# Default primary key field type
131+
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
132+
133+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

backend/urls.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
URL configuration for backend project.
3+
4+
The `urlpatterns` list routes URLs to views. For more information please see:
5+
https://docs.djangoproject.com/en/4.2/topics/http/urls/
6+
Examples:
7+
Function views
8+
1. Add an import: from my_app import views
9+
2. Add a URL to urlpatterns: path('', views.home, name='home')
10+
Class-based views
11+
1. Add an import: from other_app.views import Home
12+
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
13+
Including another URLconf
14+
1. Import the include() function: from django.urls import include, path
15+
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
16+
"""
17+
from django.contrib import admin
18+
from django.urls import path
19+
20+
from django.views.decorators.csrf import csrf_exempt
21+
from graphene_django.views import GraphQLView
22+
23+
urlpatterns = [
24+
path("admin/", admin.site.urls),
25+
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
26+
]

backend/wsgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
WSGI config for backend 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/4.2/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", "backend.settings")
15+
16+
application = get_wsgi_application()

blog/__init__.py

Whitespace-only changes.

blog/admin.py

+52
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

blog/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class BlogConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "blog"

blog/migrations/0001_initial.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Generated by Django 4.2.9 on 2024-01-19 19:05
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+
initial = True
10+
11+
dependencies = [
12+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name="Tag",
18+
fields=[
19+
(
20+
"id",
21+
models.BigAutoField(
22+
auto_created=True,
23+
primary_key=True,
24+
serialize=False,
25+
verbose_name="ID",
26+
),
27+
),
28+
("name", models.CharField(max_length=50, unique=True)),
29+
],
30+
),
31+
migrations.CreateModel(
32+
name="Profile",
33+
fields=[
34+
(
35+
"id",
36+
models.BigAutoField(
37+
auto_created=True,
38+
primary_key=True,
39+
serialize=False,
40+
verbose_name="ID",
41+
),
42+
),
43+
("website", models.URLField(blank=True)),
44+
("bio", models.CharField(blank=True, max_length=240)),
45+
(
46+
"user",
47+
models.OneToOneField(
48+
on_delete=django.db.models.deletion.PROTECT,
49+
to=settings.AUTH_USER_MODEL,
50+
),
51+
),
52+
],
53+
),
54+
migrations.CreateModel(
55+
name="Post",
56+
fields=[
57+
(
58+
"id",
59+
models.BigAutoField(
60+
auto_created=True,
61+
primary_key=True,
62+
serialize=False,
63+
verbose_name="ID",
64+
),
65+
),
66+
("title", models.CharField(max_length=255, unique=True)),
67+
("subtitle", models.CharField(blank=True, max_length=255)),
68+
("slug", models.SlugField(max_length=255, unique=True)),
69+
("body", models.TextField()),
70+
("meta_description", models.CharField(blank=True, max_length=150)),
71+
("date_created", models.DateTimeField(auto_now_add=True)),
72+
("date_modified", models.DateTimeField(auto_now=True)),
73+
("publish_date", models.DateTimeField(blank=True, null=True)),
74+
("published", models.BooleanField(default=False)),
75+
(
76+
"author",
77+
models.ForeignKey(
78+
on_delete=django.db.models.deletion.PROTECT, to="blog.profile"
79+
),
80+
),
81+
("tags", models.ManyToManyField(blank=True, to="blog.tag")),
82+
],
83+
options={
84+
"ordering": ["-publish_date"],
85+
},
86+
),
87+
]

blog/migrations/__init__.py

Whitespace-only changes.

blog/models.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from django.db import models
2+
from django.conf import settings
3+
4+
5+
class Profile(models.Model):
6+
user = models.OneToOneField(
7+
settings.AUTH_USER_MODEL,
8+
on_delete=models.PROTECT,
9+
)
10+
website = models.URLField(blank=True)
11+
bio = models.CharField(max_length=240, blank=True)
12+
13+
def __str__(self):
14+
return self.user.get_username()
15+
16+
17+
class Tag(models.Model):
18+
name = models.CharField(max_length=50, unique=True)
19+
20+
def __str__(self):
21+
return self.name
22+
23+
24+
class Post(models.Model):
25+
class Meta:
26+
ordering = ["-publish_date"]
27+
28+
title = models.CharField(max_length=255, unique=True)
29+
subtitle = models.CharField(max_length=255, blank=True)
30+
slug = models.SlugField(max_length=255, unique=True)
31+
body = models.TextField()
32+
meta_description = models.CharField(max_length=150, blank=True)
33+
date_created = models.DateTimeField(auto_now_add=True)
34+
date_modified = models.DateTimeField(auto_now=True)
35+
publish_date = models.DateTimeField(blank=True, null=True)
36+
published = models.BooleanField(default=False)
37+
38+
author = models.ForeignKey(Profile, on_delete=models.PROTECT)
39+
tags = models.ManyToManyField(Tag, blank=True)

0 commit comments

Comments
 (0)