Skip to content

Commit 8d39457

Browse files
committed
first commit
0 parents  commit 8d39457

26 files changed

+1889
-0
lines changed

.gitignore

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Created by .ignore support plugin (hsz.mobi)
2+
### Python template
3+
# Byte-compiled / optimized / DLL files
4+
__pycache__/
5+
*.py[cod]
6+
*$py.class
7+
8+
# C extensions
9+
*.so
10+
11+
# Distribution / packaging
12+
.Python
13+
build/
14+
develop-eggs/
15+
dist/
16+
downloads/
17+
eggs/
18+
.eggs/
19+
lib/
20+
lib64/
21+
parts/
22+
sdist/
23+
var/
24+
wheels/
25+
pip-wheel-metadata/
26+
share/python-wheels/
27+
*.egg-info/
28+
.installed.cfg
29+
*.egg
30+
MANIFEST
31+
32+
# PyInstaller
33+
# Usually these files are written by a python script from a template
34+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
35+
*.manifest
36+
*.spec
37+
38+
# Installer logs
39+
pip-log.txt
40+
pip-delete-this-directory.txt
41+
42+
# Unit test / coverage reports
43+
htmlcov/
44+
.tox/
45+
.nox/
46+
.coverage
47+
.coverage.*
48+
.cache
49+
nosetests.xml
50+
coverage.xml
51+
*.cover
52+
*.py,cover
53+
.hypothesis/
54+
.pytest_cache/
55+
56+
# Translations
57+
*.mo
58+
*.pot
59+
60+
# Django stuff:
61+
*.log
62+
local_settings.py
63+
db.sqlite3
64+
db.sqlite3-journal
65+
66+
# Flask stuff:
67+
instance/
68+
.webassets-cache
69+
70+
# Scrapy stuff:
71+
.scrapy
72+
73+
# Sphinx documentation
74+
docs/_build/
75+
76+
# PyBuilder
77+
target/
78+
79+
# Jupyter Notebook
80+
.ipynb_checkpoints
81+
82+
# IPython
83+
profile_default/
84+
ipython_config.py
85+
86+
# pyenv
87+
.python-version
88+
89+
# pipenv
90+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
92+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
93+
# install all needed dependencies.
94+
#Pipfile.lock
95+
96+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
97+
__pypackages__/
98+
99+
# Celery stuff
100+
celerybeat-schedule
101+
celerybeat.pid
102+
103+
# SageMath parsed files
104+
*.sage.py
105+
106+
# Environments
107+
.env
108+
.venv
109+
env/
110+
venv/
111+
ENV/
112+
env.bak/
113+
venv.bak/
114+
115+
# Spyder project settings
116+
.spyderproject
117+
.spyproject
118+
119+
# Rope project settings
120+
.ropeproject
121+
122+
# mkdocs documentation
123+
/site
124+
125+
# mypy
126+
.mypy_cache/
127+
.dmypy.json
128+
dmypy.json
129+
130+
# Pyre type checker
131+
.pyre/
132+
133+
.idea
134+
.python-version
135+
.vscode

.isort.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[settings]
2+
known_third_party = django,gql,graphql,jwt,pydantic

.pre-commit-config.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
repos:
2+
- repo: https://github.com/asottile/seed-isort-config
3+
rev: v1.9.3
4+
hooks:
5+
- id: seed-isort-config
6+
language_version: python3.7
7+
- repo: https://github.com/pre-commit/mirrors-isort
8+
rev: v4.3.21
9+
hooks:
10+
- id: isort
11+
args: [-rc]
12+
language_version: python3.7
13+
- repo: https://github.com/ambv/black
14+
rev: stable
15+
hooks:
16+
- id: black
17+
language_version: python3.7
18+
args: [--line-length=100, --skip-string-normalization]
19+
- repo: https://github.com/pre-commit/pre-commit-hooks
20+
rev: v1.2.3
21+
hooks:
22+
- id: flake8
23+
args: [--max-line-length=120, --ignore=W293]

README.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Django Graphql
2+
3+
## gqlgen
4+
5+
gqlgen is a generator tool for GraphQL.
6+
7+
```shell script
8+
Usage: gqlgen [OPTIONS] COMMAND [ARGS]...
9+
10+
Options:
11+
--help Show this message and exit.
12+
13+
Commands:
14+
all Generate all schema types
15+
field-resolver Generate field resolver.
16+
type Generate one type
17+
type-resolver Generate all schema types
18+
19+
```
20+
21+
22+
## How to use
23+
24+
```python
25+
# urls.py
26+
from django.contrib import admin
27+
from django.urls import path
28+
29+
from djgql.views import GraphQLView
30+
31+
urlpatterns = [
32+
path('admin/', admin.site.urls),
33+
path('graphql/', GraphQLView.as_view())
34+
]
35+
```
36+
37+
```python
38+
# settings.py
39+
GRAPHQL_SCHEMA_FILE = os.path.join(BASE_DIR, 'starwar.gql')
40+
GRAPHQL = {
41+
'SCHEMA': 'starwar.schema.schema',
42+
'ENABLE_PLAYGROUND': True
43+
}
44+
```
45+
46+
```python
47+
import typing
48+
from enum import Enum
49+
50+
from django.conf import settings
51+
from gql import query, gql, type_resolver, enum_type, field_resolver
52+
from gql.build_schema import build_schema_from_file
53+
from pydantic import BaseModel
54+
55+
type_defs = gql("""
56+
type Query {
57+
hello(name: String!): String!
58+
}
59+
""")
60+
61+
62+
@enum_type
63+
class Episode(Enum):
64+
NEWHOPE = 1
65+
EMPIRE = 2
66+
JEDI = 3
67+
68+
69+
class Character(BaseModel):
70+
id: typing.Text
71+
name: typing.Optional[typing.Text]
72+
friends: typing.Optional[typing.List[typing.Optional['Character']]]
73+
appears_in: typing.Optional[typing.List[typing.Optional[Episode]]]
74+
75+
76+
class Human(Character):
77+
id: typing.Text
78+
name: typing.Optional[typing.Text]
79+
friends: typing.Optional[typing.List[typing.Optional[Character]]]
80+
appears_in: typing.Optional[typing.List[typing.Optional[Episode]]]
81+
home_planet: typing.Optional[typing.Text]
82+
83+
84+
class Droid(Character):
85+
id: typing.Text
86+
name: typing.Optional[typing.Text]
87+
friends: typing.Optional[typing.List[typing.Optional[Character]]]
88+
appears_in: typing.Optional[typing.List[typing.Optional[Episode]]]
89+
primary_function: typing.Optional[typing.Text]
90+
91+
92+
@query
93+
def hero(parent, info, episode: typing.Optional[Episode]) -> typing.Optional[Character]:
94+
return Human(id='test')
95+
96+
97+
@field_resolver('Human', 'name')
98+
def human_name(parent, info):
99+
return 'Jack'
100+
101+
102+
@type_resolver('Character')
103+
def resolve_character_type(obj, info, type_):
104+
if isinstance(obj, Human):
105+
return 'Human'
106+
if isinstance(obj, Droid):
107+
return 'Droid'
108+
return None
109+
110+
111+
schema = build_schema_from_file(settings.GRAPHQL_SCHEMA_FILE)
112+
```

djgql/__init__.py

Whitespace-only changes.

djgql/auth/__init__.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
def get_authorization_header(request):
2+
"""
3+
Return request's 'Authorization:' header, as a bytestring.
4+
5+
Hide some test client ickyness where the header can be unicode.
6+
"""
7+
auth = request.META.get('HTTP_AUTHORIZATION', b'')
8+
if isinstance(auth, str):
9+
auth = auth.encode()
10+
return auth
11+
12+
13+
class BaseAuthentication:
14+
"""
15+
All authentication classes should extend BaseAuthentication.
16+
"""
17+
18+
def authenticate(self, request):
19+
"""
20+
Authenticate the request and return a two-tuple of (user, token).
21+
"""
22+
raise NotImplementedError(".authenticate() must be overridden.")
23+
24+
def authenticate_header(self, request):
25+
"""
26+
Return a string to be used as the value of the `WWW-Authenticate`
27+
header in a `401 Unauthenticated` response, or `None` if the
28+
authentication scheme should return `403 Permission Denied` responses.
29+
"""
30+
pass

djgql/auth/backends.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from django.contrib.auth import get_user_model
2+
3+
from djgql.settings import api_settings
4+
5+
UserModel = get_user_model()
6+
7+
get_user_from_cache = api_settings.USER_CACHE_GETTER
8+
set_user_to_cache = api_settings.USER_CACHE_SETTER
9+
10+
11+
class CacheBackend:
12+
"""
13+
Authenticates against settings.AUTH_USER_MODEL.
14+
"""
15+
16+
def authenticate(self, request, username=None, password=None, **kwargs):
17+
if username is None:
18+
username = kwargs.get(UserModel.USERNAME_FIELD)
19+
20+
user = get_user_from_cache(username)
21+
if user:
22+
if user.check_password(password) and self.user_can_authenticate(user):
23+
user = None
24+
return user
25+
26+
try:
27+
user = UserModel._default_manager.get_by_natural_key(username)
28+
except UserModel.DoesNotExist:
29+
# Run the default password hasher once to reduce the timing
30+
# difference between an existing and a nonexistent user (#20760).
31+
UserModel().set_password(password)
32+
else:
33+
if user.check_password(password) and self.user_can_authenticate(user):
34+
set_user_to_cache(user)
35+
return user
36+
37+
def user_can_authenticate(self, user):
38+
"""
39+
Reject users with is_active=False. Custom user models that don't have
40+
that attribute are allowed.
41+
"""
42+
is_active = getattr(user, 'is_active', None)
43+
return is_active or is_active is None

0 commit comments

Comments
 (0)