├── .gitignore ├── README.md ├── config ├── __init__.py ├── environment.py ├── settings │ ├── __init__.py │ ├── base.py │ └── local.py ├── urls.py └── wsgi.py ├── manage.py ├── media └── bucky.jpg ├── requirements ├── base.txt └── local.txt ├── scripts ├── dump_database.py └── load_sample_data.sh └── v1 ├── __init__.py └── accounts ├── __init__.py ├── admin.py ├── apps.py ├── fixtures └── user.json ├── managers ├── __init__.py └── user_manager.py ├── migrations └── __init__.py ├── models ├── __init__.py ├── profile.py └── user.py ├── serializers ├── __init__.py ├── profile.py └── user.py ├── urls.py └── views ├── __init__.py ├── profile.py └── user.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Base 2 | *.sqlite3 3 | .DS_Store 4 | .idea 5 | __pycache__ 6 | node_modules 7 | 8 | # Migrations 9 | **/migrations/* 10 | !**/migrations/__init__.py 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Django Boilerplate 2 | 3 | Boilerplate for Django projects using Django REST Framework. 4 | 5 | ## Project Setup 6 | 7 | Install required packages: 8 | ``` 9 | pip3 install -r requirements/local.txt 10 | ``` 11 | 12 | Initialize database: 13 | ``` 14 | python3 manage.py makemigrations 15 | python3 manage.py migrate 16 | ``` 17 | 18 | ## Fixtures 19 | 20 | To load in sample data for all tables at once: 21 | ``` 22 | bash scripts/load_sample_data.sh 23 | ``` 24 | 25 | This will create an initial superuser account with the following credentials: 26 | ``` 27 | admin@email.com 28 | pass1234 29 | ``` 30 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/config/__init__.py -------------------------------------------------------------------------------- /config/environment.py: -------------------------------------------------------------------------------- 1 | ENVIRONMENT = 'local' 2 | SETTINGS_MODULE = 'config.settings.local' 3 | 4 | if ENVIRONMENT == 'local': 5 | SETTINGS_MODULE = 'config.settings.local' 6 | -------------------------------------------------------------------------------- /config/settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/config/settings/__init__.py -------------------------------------------------------------------------------- /config/settings/base.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 5 | SECRET_KEY = '7(ci5&0hu2r5-5@d$)j(9yssw$6+-4t!d4rp=#k&_3)4z-bm07' 6 | 7 | INSTALLED_APPS = [ 8 | 9 | # API (v1) 10 | 'v1.accounts.apps.AccountsConfig', 11 | 12 | # Base 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 | 20 | # Requirements 21 | 'corsheaders', 22 | 'rest_framework', 23 | 'rest_framework.authtoken', 24 | 25 | ] 26 | 27 | ALLOWED_HOSTS = [] 28 | AUTH_USER_MODEL = 'accounts.User' 29 | 30 | MIDDLEWARE_CLASSES = [ 31 | 'django.middleware.security.SecurityMiddleware', 32 | 'django.contrib.sessions.middleware.SessionMiddleware', 33 | 'django.middleware.common.CommonMiddleware', 34 | 'django.middleware.csrf.CsrfViewMiddleware', 35 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 36 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 37 | 'django.contrib.messages.middleware.MessageMiddleware', 38 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 39 | ] 40 | 41 | ROOT_URLCONF = 'config.urls' 42 | WSGI_APPLICATION = 'config.wsgi.application' 43 | 44 | AUTH_PASSWORD_VALIDATORS = [ 45 | {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, 46 | {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, 47 | {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, 48 | {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, 49 | ] 50 | 51 | TEMPLATES = [ 52 | { 53 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 54 | 'DIRS': [], 55 | 'APP_DIRS': True, 56 | 'OPTIONS': { 57 | 'context_processors': [ 58 | 'django.template.context_processors.debug', 59 | 'django.template.context_processors.request', 60 | 'django.contrib.auth.context_processors.auth', 61 | 'django.contrib.messages.context_processors.messages', 62 | ], 63 | }, 64 | }, 65 | ] 66 | 67 | LANGUAGE_CODE = 'en-us' 68 | TIME_ZONE = 'UTC' 69 | USE_I18N = True 70 | USE_L10N = True 71 | USE_TZ = True 72 | -------------------------------------------------------------------------------- /config/settings/local.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | 3 | 4 | DEBUG = True 5 | 6 | INTERNAL_IPS = [ 7 | '127.0.0.1', 8 | ] 9 | 10 | DATABASES = { 11 | 'default': { 12 | 'ENGINE': 'django.db.backends.sqlite3', 13 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 14 | } 15 | } 16 | 17 | INSTALLED_APPS.append('debug_toolbar') 18 | 19 | MIDDLEWARE_CLASSES.append('debug_toolbar.middleware.DebugToolbarMiddleware', ) 20 | 21 | STATIC_URL = '/static/' 22 | STATIC_ROOT = os.path.join(BASE_DIR, 'static/') 23 | 24 | MEDIA_URL = '/media/' 25 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') 26 | -------------------------------------------------------------------------------- /config/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls import include, url 3 | from django.conf.urls.static import static 4 | from django.contrib import admin 5 | from rest_framework.documentation import include_docs_urls 6 | 7 | 8 | urlpatterns = [ 9 | 10 | # Core 11 | url(r'^admin/', admin.site.urls), 12 | url(r'^docs/', include_docs_urls(title='Django REST Boilerplate')), 13 | 14 | # API (v1) 15 | url(r'^', include('v1.accounts.urls')), 16 | 17 | ] 18 | 19 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 20 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 21 | 22 | if settings.DEBUG: 23 | import debug_toolbar 24 | 25 | urlpatterns += [ 26 | url(r'^__debug__/', include(debug_toolbar.urls)), 27 | ] 28 | -------------------------------------------------------------------------------- /config/wsgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | from django.core.wsgi import get_wsgi_application 3 | from config.environment import SETTINGS_MODULE 4 | 5 | 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", SETTINGS_MODULE) 7 | application = get_wsgi_application() 8 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | from config.environment import SETTINGS_MODULE 5 | 6 | 7 | if __name__ == "__main__": 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", SETTINGS_MODULE) 9 | from django.core.management import execute_from_command_line 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /media/bucky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/media/bucky.jpg -------------------------------------------------------------------------------- /requirements/base.txt: -------------------------------------------------------------------------------- 1 | coreapi==2.3.0 2 | Django==1.11.1 3 | django-cors-headers==2.0.2 4 | djangorestframework==3.6.3 5 | Markdown==2.6.8 6 | Pillow==4.1.1 7 | Pygments==2.2.0 8 | -------------------------------------------------------------------------------- /requirements/local.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | 3 | django-debug-toolbar==1.8 4 | -------------------------------------------------------------------------------- /scripts/dump_database.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def main(): 5 | for root, dirs, files in os.walk('v1'): 6 | if root[-10:] == 'migrations': 7 | for f in [file for file in files if file[:2] == '00']: 8 | os.remove(os.path.normpath(os.path.join(root, f))) 9 | create_init_file(root) 10 | 11 | 12 | def create_init_file(root): 13 | init_file = os.path.normpath(os.path.join(root, '__init__.py')) 14 | if not os.path.exists(init_file): 15 | with open(init_file, 'wt') as f: 16 | f.write('') 17 | 18 | 19 | def remove_database(): 20 | if os.path.exists('db.sqlite3'): 21 | os.remove('db.sqlite3') 22 | print('Database removed') 23 | else: 24 | print('No database to remove') 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | remove_database() 30 | -------------------------------------------------------------------------------- /scripts/load_sample_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Accounts 4 | python3 manage.py loaddata v1/accounts/fixtures/user.json 5 | -------------------------------------------------------------------------------- /v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/__init__.py -------------------------------------------------------------------------------- /v1/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/__init__.py -------------------------------------------------------------------------------- /v1/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models.profile import Profile 3 | from .models.user import User 4 | 5 | 6 | admin.site.register(Profile) 7 | admin.site.register(User) 8 | -------------------------------------------------------------------------------- /v1/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'v1.accounts' 6 | -------------------------------------------------------------------------------- /v1/accounts/fixtures/user.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "accounts.user", 4 | "pk": 1, 5 | "fields": { 6 | "password": "pbkdf2_sha256$36000$xGbyoYnD3WAc$rhRd+45SuiqPB6kKjOIN/AJVdVeBY1JPSfzQu+tEv9g=", 7 | "last_login": "2017-05-23T14:31:38.340Z", 8 | "is_superuser": true, 9 | "date_joined": "2017-05-23T14:31:19.347Z", 10 | "email": "admin@email.com", 11 | "first_name": "", 12 | "last_name": "", 13 | "is_active": true, 14 | "is_staff": true, 15 | "groups": [], 16 | "user_permissions": [] 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /v1/accounts/managers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/managers/__init__.py -------------------------------------------------------------------------------- /v1/accounts/managers/user_manager.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import BaseUserManager 2 | 3 | 4 | class UserManager(BaseUserManager): 5 | use_in_migrations = True 6 | 7 | def _create_user(self, email, password, **kwargs): 8 | email = self.normalize_email(email) 9 | is_staff = kwargs.pop('is_staff', False) 10 | is_superuser = kwargs.pop('is_superuser', False) 11 | user = self.model( 12 | email=email, 13 | is_active=True, 14 | is_staff=is_staff, 15 | is_superuser=is_superuser, 16 | **kwargs 17 | ) 18 | user.set_password(password) 19 | user.save(using=self._db) 20 | return user 21 | 22 | def create_user(self, email, password=None, **extra_fields): 23 | return self._create_user(email, password, **extra_fields) 24 | 25 | def create_superuser(self, email, password, **extra_fields): 26 | return self._create_user(email, password, is_staff=True, is_superuser=True, **extra_fields) 27 | -------------------------------------------------------------------------------- /v1/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /v1/accounts/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/models/__init__.py -------------------------------------------------------------------------------- /v1/accounts/models/profile.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db import models 3 | 4 | 5 | class Profile(models.Model): 6 | user = models.OneToOneField(settings.AUTH_USER_MODEL) 7 | image = models.ImageField(blank=True) 8 | 9 | def __str__(self): 10 | return self.user.username 11 | -------------------------------------------------------------------------------- /v1/accounts/models/user.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin 3 | from django.db import models 4 | from v1.accounts.managers.user_manager import UserManager 5 | 6 | 7 | class User(AbstractBaseUser, PermissionsMixin): 8 | date_joined = models.DateTimeField(auto_now_add=True) 9 | email = models.EmailField(max_length=255, unique=True) 10 | first_name = models.CharField(max_length=255) 11 | last_name = models.CharField(max_length=255) 12 | is_active = models.BooleanField(default=True) 13 | is_staff = models.BooleanField(default=False) 14 | objects = UserManager() 15 | 16 | USERNAME_FIELD = 'email' 17 | 18 | class Meta: 19 | app_label = 'accounts' 20 | 21 | def __str__(self): 22 | return self.email 23 | 24 | def get_short_name(self): 25 | return self.email 26 | 27 | def get_full_name(self): 28 | return self.email 29 | 30 | def save(self, *args, **kwargs): 31 | if not self.password: 32 | self.password = str(uuid.uuid4()).replace('-', '') 33 | super(User, self).save(*args, **kwargs) 34 | -------------------------------------------------------------------------------- /v1/accounts/serializers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/serializers/__init__.py -------------------------------------------------------------------------------- /v1/accounts/serializers/profile.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from v1.accounts.models.profile import Profile 3 | 4 | 5 | class ProfileSerializer(serializers.ModelSerializer): 6 | 7 | class Meta: 8 | model = Profile 9 | fields = '__all__' 10 | -------------------------------------------------------------------------------- /v1/accounts/serializers/user.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from rest_framework import serializers 3 | 4 | User = get_user_model() 5 | 6 | 7 | class UserSerializer(serializers.ModelSerializer): 8 | 9 | class Meta: 10 | model = User 11 | exclude = ('password',) 12 | -------------------------------------------------------------------------------- /v1/accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from .views.profile import ProfileView 3 | from .views.user import UserView 4 | 5 | 6 | urlpatterns = [ 7 | 8 | # Profiles 9 | url(r'^profiles$', ProfileView.as_view()), 10 | 11 | # Users 12 | url(r'^users$', UserView.as_view()), 13 | 14 | ] 15 | -------------------------------------------------------------------------------- /v1/accounts/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azvast/django-rest-apis/8c5bbb3f580e3765ad6a7d6cfe2a5b8ca8609296/v1/accounts/views/__init__.py -------------------------------------------------------------------------------- /v1/accounts/views/profile.py: -------------------------------------------------------------------------------- 1 | from rest_framework.response import Response 2 | from rest_framework.views import APIView 3 | from v1.accounts.models.profile import Profile 4 | from v1.accounts.serializers.profile import ProfileSerializer 5 | 6 | 7 | # profiles 8 | class ProfileView(APIView): 9 | 10 | @staticmethod 11 | def get(request): 12 | """ 13 | List profiles 14 | """ 15 | 16 | profiles = Profile.objects.all() 17 | return Response(ProfileSerializer(profiles, many=True).data) 18 | -------------------------------------------------------------------------------- /v1/accounts/views/user.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from rest_framework.response import Response 3 | from rest_framework.views import APIView 4 | 5 | from v1.accounts.serializers.user import UserSerializer 6 | 7 | User = get_user_model() 8 | 9 | 10 | # users 11 | class UserView(APIView): 12 | @staticmethod 13 | def get(request): 14 | """ 15 | List users 16 | """ 17 | 18 | users = User.objects.all() 19 | return Response(UserSerializer(users, many=True).data) 20 | --------------------------------------------------------------------------------