Random string - random username
from django .utils .crypto import get_random_string
User .objects .create_user (username = get_random_string (), email = '' , password = '123' )
$ mkdir api & cd api
$ pipenv install django djangorestframework django-cors-headers django-filter django-extensions
$ django-admin startproject api . & python manage.py startapp core
# in settings.py
ALLOWED_HOSTS = ['*' ]
# in INSTALLED_APPS
'django_extensions' ,
'rest_framework' ,
'django_filters' ,
'corsheaders' ,
'core.apps.CoreConfig' ,
# IN MIDDLEWARE SECTION
'corsheaders.middleware.CorsMiddleware' ,
# CORS CONFIG
CORS_ORIGIN_ALLOW_ALL = True
# FILTER AND PAGINATION SECTION
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS' : 'rest_framework.pagination.PageNumberPagination' ,
'PAGE_SIZE' : 24 ,
'DEFAULT_FILTER_BACKENDS' : (
'django_filters.rest_framework.DjangoFilterBackend' ,
),
}
# models.py
class Product (models .Model ):
name = models .CharField (max_length = 200 , db_index = True )
price = models .DecimalField (max_digits = 10 , decimal_places = 2 )
# serializers.py
from rest_framework import serializers
from search import models
class ProductSerializer (serializers .ModelSerializer ):
class Meta :
fields = (
'id' ,
'name' ,
'price' ,
)
model = models .Product
# filters.py
import django_filters
from search import models
class ProductFilter (django_filters .FilterSet ):
near_to = filters .CharFilter (method = 'get_nearest' )
class Meta :
model = models .Product
fields = {
'name' : ['exact' , 'icontains' ],
'price' : ['exact' , 'lte' , 'gte' , 'range' ],
}
def get_nearest (self , queryset , name , value ):
return queryset .filter (location__distance_lte = (user_location , D (km = 7 )))
# views.py
from rest_framework import viewsets
from search import models
from search import serializers
from search import filters
# Create your views here.
class ProductViewSet (viewsets .ModelViewSet ):
queryset = models .Product .objects .all ()
serializer_class = serializers .ProductSerializer
filterset_class = filters .ProductFilter
ordering_fields = ['username' , 'email' ] # ?ordering=-username # ?ordering=account,username
# core/urls
from django .urls import path
from search import views
from rest_framework .routers import DefaultRouter
router = DefaultRouter ()
router .register ('products' , views .ProductViewSet )
urlpatterns = router .urls
# api/urls
from django .contrib import admin
from django .urls import path , include
urlpatterns = [
path ('admin/' , admin .site .urls ),
path ('api/v1/' , include ('search.urls' ))
]
from rest_framework .permissions import BasePermission ,SAFE_METHODS
class IsOwnerProfileOrReadOnly (BasePermission ):
def has_object_permission (self , request , view , obj ):
if request .method in SAFE_METHODS :
return True
return obj .user == request .user
from rest_framework import viewsets , permissions
class ItemViewSet (viewsets .ModelViewSet ):
permission_classes = [permissions .IsAuthenticatedOrReadOnly , IsOwnerProfileOrReadOnly ]
# pipenv install djangorestframework-simplejwt
# settings.py
REST_FRAMEWORK = {
# ...
'DEFAULT_AUTHENTICATION_CLASSES' : (
'rest_framework_simplejwt.authentication.JWTAuthentication' ,
)
}
CORS_ORIGIN_ALLOW_ALL = True
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME' : timedelta (minutes = 50 ),
'REFRESH_TOKEN_LIFETIME' : timedelta (days = 1 ),
}
AUTH_USER_MODEL = 'account.User'
AUTHENTICATION_BACKENDS = (
'account.custom_auth_backends.EmailAuthBackend' ,
'django.contrib.auth.backends.ModelBackend' ,
)
# custom_auth_backends.py
from account import models
from django .contrib .auth .hashers import check_password
class EmailAuthBackend (object ):
def authenticate (self , request , username = None , password = None ):
try :
# Check if the user exists in Django's database
user = models .User .objects .get (email = username )
except models .User .DoesNotExist :
return None
# Check password of the user we found
if check_password (password , user .password ):
return user
return None
# Required for your backend to work properly - unchanged in most scenarios
def get_user (self , user_id ):
try :
return models .User .objects .get (pk = user_id )
except models .User .DoesNotExist :
return None
#models.py
from django .db import models
# Create your models here.
from django .db import models
from django .contrib .auth .models import AbstractUser
class User (AbstractUser ):
USER_TYPE_CHOICES = (
(1 , 'student' ),
(2 , 'teacher' ),
(3 , 'secretary' ),
(4 , 'supervisor' ),
(5 , 'admin' ),
)
user_type = models .PositiveSmallIntegerField (choices = USER_TYPE_CHOICES )
email = models .EmailField (verbose_name = 'email address' , max_length = 255 , unique = True )
phone = models .CharField (max_length = 30 )
def __str__ (self ):
return self .email
# serializers.py
from account .models import User
from rest_framework import serializers
from django .contrib .auth import authenticate
class SignUpSerializer (serializers .ModelSerializer ):
class Meta :
model = User
fields = ('id' , 'first_name' , 'last_name' , 'email' , 'password' ,)
extra_kwargs = {'password' : {'write_only' : True }}
def create (self , validated_data ):
user = User .objects .create_user (
first_name = validated_data ['first_name' ],
last_name = validated_data ['last_name' ],
username = validated_data ['first_name' ],
email = validated_data ['email' ],
password = validated_data ['password' ])
return user
class SignInSerializer (serializers .Serializer ):
email = serializers .CharField ()
password = serializers .CharField ()
def validate (self , data ):
user = authenticate (username = data ['email' ], password = data ['password' ])
if user is not None :
return user
raise serializers .ValidationError ("Unable to log in with provided credentials." )
class UserSerializer (serializers .ModelSerializer ):
class Meta :
model = User
fields = ('id' , 'email' , 'first_name' , 'last_name' , 'username' )
# views.py
from rest_framework import viewsets , permissions , generics
from rest_framework .response import Response
from rest_framework_simplejwt .tokens import RefreshToken
from rest_framework_simplejwt .serializers import TokenObtainPairSerializer
from account import serializers
from rest_framework import views , permissions , status
from rest_framework .response import Response
from account import models
from account import filters
class SignUpAPI (generics .GenericAPIView ):
serializer_class = serializers .SignUpSerializer
def post (self , request , * args , ** kwargs ):
serializer = self .get_serializer (data = request .data )
serializer .is_valid (raise_exception = True )
user = serializer .save ()
refresh = RefreshToken .for_user (user )
return Response ({
'user' : serializers .UserSerializer (user , context = self .get_serializer_context ()).data ,
'refresh' : str (refresh ),
'access' : str (refresh .access_token ),
})
class SignInAPI (generics .GenericAPIView ):
serializer_class = serializers .SignInSerializer
def post (self , request , * args , ** kwargs ):
serializer = self .get_serializer (data = request .data )
serializer .is_valid (raise_exception = True )
user = serializer .validated_data
refresh = RefreshToken .for_user (user )
return Response ({
'user' : serializers .UserSerializer (user , context = self .get_serializer_context ()).data ,
'refresh' : str (refresh ),
'access' : str (refresh .access_token ),
})
class UserAPI (generics .RetrieveAPIView ):
permission_classes = [permissions .IsAuthenticated , ]
serializer_class = serializers .UserSerializer
def get_object (self ):
return self .request .user
class UserViewSet (viewsets .ModelViewSet ):
queryset = models .User .objects .all ()
serializer_class = serializers .UserSerializer
filterset_class = filters .UserFilter
# urls.py
# ...
urlpatterns = [
path ('auth/users/me/' , views .UserAPI .as_view ()),
path ('auth/sign-up/' , views .SignUpAPI .as_view ()),
path ('auth/sign-in/' , views .SignInAPI .as_view ()),
path ('auth/refresh-token/' , TokenRefreshView .as_view ()),
]
# ...
create management/commands folder inside an app folder
add this inside a fixture.py
from django .core .management .base import BaseCommand
from search import models
from random import randrange
class Command (BaseCommand ):
help = "fake data generator"
def handle (self , * args , ** options ):
models .Product .objects .all ().delete ()
for i in range (400 ):
models .Product .objects .create (
name = "Product " + str (i ),
price = randrange (97562 ),
)
self .stdout .write (self .style .SUCCESS ("done!" ))
Custom command with param
from django .core .management .base import BaseCommand
class Command (BaseCommand ):
help = "fake data generator"
def add_arguments (self , parser ):
# Required argument
parser .add_argument ('total' , type = int , help = 'Indicates the number of item to be created' )
# Optional argument
parser .add_argument ('-p' , '--price' , type = str , help = 'Define an item price' , )
# Optional list argument
parser .add_argument ('-i' , '--items' , nargs = '+' , type = int , help = 'Item ID' )
def handle (self , * args , ** options ):
total = options ['total' ]
price = options ['price' ]
items = options ['items' ]
self .stdout .write (self .style .SUCCESS ('total "%s"' % total ))
if price :
self .stdout .write (self .style .SUCCESS ('price "%s"' % price ))
if items :
self .stdout .write (self .style .SUCCESS ('items "%s"' % items ))
class Place (models .Model ):
name = models .CharField (max_length = 50 )
address = models .CharField (max_length = 80 )
def __str__ (self ):
return "%s the place" % self .name
class Restaurant (models .Model ):
place = models .OneToOneField (
Place ,
on_delete = models .CASCADE ,
primary_key = True ,
)
serves_hot_dogs = models .BooleanField (default = False )
serves_pizza = models .BooleanField (default = False )
def __str__ (self ):
return "%s the restaurant" % self .place .name
class Waiter (models .Model ):
restaurant = models .ForeignKey (Restaurant , on_delete = models .CASCADE )
name = models .CharField (max_length = 50 )
def __str__ (self ):
return "%s the waiter at %s" % (self .name , self .restaurant )
class Reporter (models .Model ):
first_name = models .CharField (max_length = 30 )
last_name = models .CharField (max_length = 30 )
email = models .EmailField ()
def __str__ (self ):
return "%s %s" % (self .first_name , self .last_name )
class Article (models .Model ):
headline = models .CharField (max_length = 100 )
pub_date = models .DateField ()
reporter = models .ForeignKey (Reporter , on_delete = models .CASCADE )
def __str__ (self ):
return self .headline
class Meta :
ordering = ['headline' ]
class Publication (models .Model ):
title = models .CharField (max_length = 30 )
class Meta :
ordering = ['title' ]
def __str__ (self ):
return self .title
class Article (models .Model ):
headline = models .CharField (max_length = 100 )
publications = models .ManyToManyField (Publication )
class Meta :
ordering = ['headline' ]
def __str__ (self ):
return self .headline
class Person (models .Model ):
name = models .CharField (max_length = 128 )
def __str__ (self ):
return self .name
class Group (models .Model ):
name = models .CharField (max_length = 128 )
members = models .ManyToManyField (Person , through = 'Membership' )
def __str__ (self ):
return self .name
class Membership (models .Model ):
person = models .ForeignKey (Person , on_delete = models .CASCADE )
group = models .ForeignKey (Group , on_delete = models .CASCADE )
date_joined = models .DateField ()
invite_reason = models .CharField (max_length = 64 )
class Media (models .Model ):
title = models .CharField (max_length = 255 )
pub_date = models .DateTimeField ()
class Photo (Media ): # note that Photo extends Media
image = models .ImageField (upload_to = 'photos' )
class Video (Media ):
video = models .FileField (upload_to = 'videos' )
class Invoice (models .Model ):
SENT = 1
PAID = 2
VOID = 3
STATUS_CHOICES = (
(SENT , 'sent' ),
(PAID , 'paid' ),
(VOID , 'void' ),
)
user = models .ForeignKey (User , on_delete = models .CASCADE , related_name = 'invoices' )
number = models .CharField (max_length = 30 )
date = models .DateTimeField (auto_now_add = True )
status = models .PositiveSmallIntegerField (choices = STATUS_CHOICES )
amount = models .DecimalField (max_digits = 10 , decimal_places = 2 )
class User (AbstractUser ):
USER_TYPE_CHOICES = (
(1 , 'student' ),
(2 , 'teacher' ),
(3 , 'secretary' ),
(4 , 'supervisor' ),
(5 , 'admin' ),
)
user_type = models .PositiveSmallIntegerField (choices = USER_TYPE_CHOICES )
Product | Ecommerce | Shop
class Product (models .Model ):
category = models .ForeignKey (Category ,
related_name = 'products' ,
on_delete = models .CASCADE )
name = models .CharField (max_length = 200 , db_index = True )
slug = models .SlugField (max_length = 200 , db_index = True )
image = models .ImageField (upload_to = 'products/%Y/%m/%d' ,
blank = True )
description = models .TextField (blank = True )
price = models .DecimalField (max_digits = 10 , decimal_places = 2 )
available = models .BooleanField (default = True )
created = models .DateTimeField (auto_now_add = True )
updated = models .DateTimeField (auto_now = True )
class Meta :
ordering = ('name' ,)
index_together = (('id' , 'slug' ),)
def __str__ (self ):
return self .name
def get_absolute_url (self ):
return reverse ('shop:product_detail' ,
args = [self .id , self .slug ])
class Order (models .Model ):
first_name = models .CharField (_ ('first name' ), max_length = 50 )
last_name = models .CharField (_ ('last name' ), max_length = 50 )
email = models .EmailField (_ ('e-mail' ))
address = models .CharField (_ ('address' ), max_length = 250 )
postal_code = models .CharField (_ ('postal code' ), max_length = 20 )
city = models .CharField (_ ('city' ), max_length = 100 )
created = models .DateTimeField (auto_now_add = True )
updated = models .DateTimeField (auto_now = True )
paid = models .BooleanField (default = False )
braintree_id = models .CharField (max_length = 150 , blank = True )
coupon = models .ForeignKey (Coupon ,
related_name = 'orders' ,
null = True ,
blank = True ,
on_delete = models .SET_NULL )
discount = models .IntegerField (default = 0 ,
validators = [MinValueValidator (0 ),
MaxValueValidator (100 )])
class Meta :
ordering = ('-created' ,)
def __str__ (self ):
return 'Order {}' .format (self .id )
def get_total_cost (self ):
total_cost = sum (item .get_cost () for item in self .items .all ())
return total_cost - total_cost * (self .discount / Decimal ('100' ))
class OrderItem (models .Model ):
order = models .ForeignKey (Order ,
related_name = 'items' ,
on_delete = models .CASCADE )
product = models .ForeignKey (Product ,
related_name = 'order_items' ,
on_delete = models .CASCADE )
price = models .DecimalField (max_digits = 10 , decimal_places = 2 )
quantity = models .PositiveIntegerField (default = 1 )
def __str__ (self ):
return '{}' .format (self .id )
def get_cost (self ):
return self .price * self .quantity
Post | Comment
class Post (models .Model ):
STATUS_CHOICES = (
('draft' , 'Draft' ),
('published' , 'Published' ),
)
title = models .CharField (max_length = 250 )
slug = models .SlugField (max_length = 250 ,
unique_for_date = 'publish' )
author = models .ForeignKey (User ,
on_delete = models .CASCADE ,
related_name = 'blog_posts' )
body = models .TextField ()
publish = models .DateTimeField (default = timezone .now )
created = models .DateTimeField (auto_now_add = True )
updated = models .DateTimeField (auto_now = True )
status = models .CharField (max_length = 10 ,
choices = STATUS_CHOICES ,
default = 'draft' )
objects = models .Manager () # The default manager.
published = PublishedManager () # Our custom manager.
tags = TaggableManager ()
class Meta :
ordering = ('-publish' ,)
def __str__ (self ):
return self .title
def get_absolute_url (self ):
return reverse ('blog:post_detail' ,
args = [self .publish .year ,
self .publish .month ,
self .publish .day ,
self .slug ])
class Comment (models .Model ):
post = models .ForeignKey (Post ,
on_delete = models .CASCADE ,
related_name = 'comments' )
name = models .CharField (max_length = 80 )
email = models .EmailField ()
body = models .TextField ()
created = models .DateTimeField (auto_now_add = True )
updated = models .DateTimeField (auto_now = True )
active = models .BooleanField (default = True )
class Meta :
ordering = ('created' ,)
def __str__ (self ):
return 'Comment by {} on {}' .format (self .name , self .post )
class Subject (models .Model ):
title = models .CharField (max_length = 200 )
slug = models .SlugField (max_length = 200 , unique = True )
class Meta :
ordering = ['title' ]
def __str__ (self ):
return self .title
class Course (models .Model ):
owner = models .ForeignKey (User ,
related_name = 'courses_created' ,
on_delete = models .CASCADE )
subject = models .ForeignKey (Subject ,
related_name = 'courses' ,
on_delete = models .CASCADE )
title = models .CharField (max_length = 200 )
slug = models .SlugField (max_length = 200 , unique = True )
overview = models .TextField ()
created = models .DateTimeField (auto_now_add = True )
students = models .ManyToManyField (User ,
related_name = 'courses_joined' ,
blank = True )
class Meta :
ordering = ['-created' ]
def __str__ (self ):
return self .title
class Module (models .Model ):
course = models .ForeignKey (Course ,
related_name = 'modules' ,
on_delete = models .CASCADE )
title = models .CharField (max_length = 200 )
description = models .TextField (blank = True )
order = OrderField (blank = True , for_fields = ['course' ])
class Meta :
ordering = ['order' ]
def __str__ (self ):
return '{}. {}' .format (self .order , self .title )
class Content (models .Model ):
module = models .ForeignKey (Module ,
related_name = 'contents' ,
on_delete = models .CASCADE )
content_type = models .ForeignKey (ContentType ,
limit_choices_to = {'model__in' :('text' ,
'video' ,
'image' ,
'file' )},
on_delete = models .CASCADE )
object_id = models .PositiveIntegerField ()
item = GenericForeignKey ('content_type' , 'object_id' )
order = OrderField (blank = True , for_fields = ['module' ])
class Meta :
ordering = ['order' ]
class ItemBase (models .Model ):
owner = models .ForeignKey (User ,
related_name = '%(class)s_related' ,
on_delete = models .CASCADE )
title = models .CharField (max_length = 250 )
created = models .DateTimeField (auto_now_add = True )
updated = models .DateTimeField (auto_now = True )
class Meta :
abstract = True
def __str__ (self ):
return self .title
def render (self ):
return render_to_string ('courses/content/{}.html' .format (
self ._meta .model_name ), {'item' : self })
class Text (ItemBase ):
content = models .TextField ()
class File (ItemBase ):
file = models .FileField (upload_to = 'files' )
class Image (ItemBase ):
file = models .FileField (upload_to = 'images' )
class Video (ItemBase ):
url = models .URLField ()
from django .db import models
from django .utils .text import slugify
# Create your models here.
class Reservation (models .Model ):
name = models .CharField (max_length = 50 )
email = models .EmailField ()
phone = models .IntegerField ()
number_of_persons = models .IntegerField ()
Date = models .DateField ()
time = models .TimeField ()
def __str__ (self ):
return self .name
class Meals (models .Model ):
name = models .CharField (max_length = 50 )
description = models .TextField (max_length = 500 )
category = models .ForeignKey ('Category' , on_delete = models .SET_NULL , null = True )
people = models .IntegerField ()
price = models .DecimalField (max_digits = 5 , decimal_places = 2 )
preperation_time = models .IntegerField ()
image = models .ImageField (upload_to = 'meals/' )
slug = models .SlugField (blank = True , null = True )
def save (self , * args , ** kwargs ):
if not self .slug and self .name :
self .slug = slugify (self .name )
super (Meals , self ).save (* args , ** kwargs )
class Meta :
verbose_name = 'meal'
verbose_name_plural = 'meals'
def __str__ (self ):
return self .name
class Category (models .Model ):
name = models .CharField (max_length = 30 )
class Meta :
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__ (self ):
return self .name
# signals.py
from core .models import Author , Tag , Post
from django .db .models .signals import post_save , m2m_changed
from django .dispatch import receiver
@receiver (post_save , sender = Author )
def author_changed (sender , instance , ** kwargs ):
for post in instance .posts .with_documents ():
post .search_vector = post .document
post .save (update_fields = ['search_vector' ])
@receiver (m2m_changed , sender = Post .tags .through )
def post_tags_changed (sender , instance , action , ** kwargs ):
if action in ('post_add' , 'post_remove' , 'post_clear' ):
instance .save ()
# apps.py
from django .apps import AppConfig
class CoreConfig (AppConfig ):
name = 'core'
def ready (self ):
import core .signals
Custom serializers for viewsets
# mixins.py
class ReadWriteSerializerMixin (object ):
"""
Overrides get_serializer_class to choose the read serializer
for GET requests and the write serializer for POST requests.
Set read_serializer_class and write_serializer_class attributes on a
viewset.
"""
read_serializer_class = None
write_serializer_class = None
def get_serializer_class (self ):
if self .action in ["create" , "update" , "partial_update" , "destroy" ]:
return self .get_write_serializer_class ()
return self .get_read_serializer_class ()
def get_read_serializer_class (self ):
assert self .read_serializer_class is not None , (
"'%s' should either include a `read_serializer_class` attribute,"
"or override the `get_read_serializer_class()` method."
% self .__class__ .__name__
)
return self .read_serializer_class
def get_write_serializer_class (self ):
assert self .write_serializer_class is not None , (
"'%s' should either include a `write_serializer_class` attribute,"
"or override the `get_write_serializer_class()` method."
% self .__class__ .__name__
)
return self .write_serializer_class
# views.py
from .mixins import ReadWriteSerializerMixin
from .models import MyModel
from .serializers import ModelReadSerializer , ModelWriteSerializer
class MyModelViewSet (ReadWriteSerializerMixin , viewsets .ModelViewSet ):
queryset = MyModel .objects .all ()
read_serializer_class = ModelReadSerializer
write_serializer_class = ModelWriteSerializer
$ docker-compose run -rm web ./manage.py [command] [arguments]
$ docker-compose run -rm web ./manage.py test [app]
# pipenv install celery redis
# settings.py
CELERY_BROKER_URL = 'redis://redis:6379'
CELERY_RESULT_BACKEND = 'redis://redis:6379'
CELERY_ACCEPT_CONTENT = ['application/json' ]
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
# proj/celery.py
import os
from celery import Celery
os .environ .setdefault ('DJANGO_SETTINGS_MODULE' , 'proj.settings' )
app = Celery ('proj' )
app .config_from_object ('django.conf:settings' , namespace = 'CELERY' )
app .autodiscover_tasks ()
@app .task (bind = True )
def debug_task (self ):
print ('Request: {0!r}' .format (self .request ))
# app/tasks.py
from celery import shared_task
@shared_task
def hello ():
print ('Hello there!' )
@app .task
def test (arg = None ):
print (arg )
# proj/__init__.py
from .celery import app as celery_app
__all__ = ['celery_app' ]
# demo
from app .tasks import hello
hello .delay ()
# crontab
# settings.py
from celery .schedules import crontab
CELERY_BEAT_SCHEDULE = {
'hello' : {
'task' : 'app.tasks.test' ,
'schedule' : crontab (hour = 7 , minute = 30 , day_of_week = 1 ) # Executes every Monday morning at 7:30 a.m,
#'args': ('hello')
}
}
# more info
# https://www.revsys.com/tidbits/celery-and-django-and-docker-oh-my/
# dockerfile.yml
services :
db :
image : postgres:9.6.5
volumes :
- postgres_data:/var/lib/postgresql/data/
redis :
image : " redis:alpine"
web :
build : .
command : bash -c "python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000"
volumes :
- .:/code
ports :
- " 8000:8000"
depends_on :
- db
- redis
celery :
build : .
command : celery -A proj worker -l info
volumes :
- .:/code
depends_on :
- db
- redis
celery-beat :
build : .
command : celery -A proj beat -l info
volumes :
- .:/code
depends_on :
- db
- redis
volumes :
postgres_data :
# Dockerfile
# Pull base image
FROM python:3.8
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set work directory
WORKDIR /code
# Install dependencies
RUN pip install pipenv
COPY Pipfile Pipfile.lock /code/
RUN pipenv install --system
RUN apt-get update -y
RUN apt-get -y install apt-utils binutils libproj-dev gdal-bin
# Copy project
COPY . /code/
version: '3.7'
services:
db:
image: kartoza/postgis:12.0
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
- POSTGRES_MULTIPLE_EXTENSIONS=postgis,hstore,postgis_topology,pg_trgm,unaccent
ports:
- 5432:5432
restart: always
web:
build: .
command: bash -c "while !</dev/tcp/db/5432; do sleep 1; done; python manage.py makemigrations && python manage.py migrate && python manage.py runserver 0.0.0.0:8000 && pytest"
volumes:
- .:/code
ports:
- 8000:8000
depends_on:
- db
volumes:
postgres_data:
#....
DATABASES = {
'default' : {
'ENGINE' : 'django.contrib.gis.db.backends.postgis' ,
'NAME' : 'postgres' ,
'USER' : 'postgres' ,
'PASSWORD' :'postgres' ,
'HOST' : 'db' , # set in docker-compose.yml
'PORT' : 5432 , # default postgres port
'CONN_MAX_AGE' : 1000 , # pooling
}
}
$ docker-compose run --rm web python /code/manage.py createsuperuser
# settings.py
MEDIA_URL = '/media/'
#MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_ROOT = '/media'
STATIC_URL = "/static/"
STATIC_ROOT = "/static/"
# urls.py -> demo
from django .conf import settings
from django .conf .urls .static import static # new
if settings .DEBUG : # new
urlpatterns += static (settings .MEDIA_URL , document_root = settings .MEDIA_ROOT )
# models.py
class File (models .Model ):
image = models .ImageField (upload_to = 'images/' )
# serializers.py
class FileSerializer (serializers .ModelSerializer ):
class Meta :
fields = (
'id' ,
'image'
)
model = models .File
# views.py
class FileViewSet (viewsets .ModelViewSet ):
queryset = models .File .objects .all ()
serializer_class = serializers .FileSerializer
# urls.py
# ...
router .register ('files' , views .FileViewSet )
# Dockerfile
# Pull base image
FROM python:3.8
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV POSTGRES_USER postgres
ENV POSTGRES_PASS postgres
ENV BIZAO_CLIENT_ID ugyrNwqHv6bX9CB1K8tjmqtvDIYa
ENV BIZAO_CLIENT_SECRET OSQ47FxbhsWrWNfz3FP2ITWLmVsa
ENV BIZAO_TOKEN dWd5ck53cUh2NmJYOUNCMUs4dGptcXR2RElZYTpPU1E0N0Z4YmhzV3JXTmZ6M0ZQMklUV0xtVnNh
# Set work directory
WORKDIR /code
# Install dependencies
RUN pip install pipenv
COPY Pipfile Pipfile.lock /code/
RUN pipenv install --system
RUN apt-get update -y
RUN apt-get -y install apt-utils binutils libproj-dev gdal-bin
# Copy project
COPY . /code/
version : ' 3.7'
services :
db :
image : kartoza/postgis:12.0
volumes :
- adafri_postgres:/var/lib/postgresql/data/
environment :
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASS=${POSTGRES_PASS}
ports :
- 5432:5432
restart : always
web :
build : .
command : bash -c "while !</dev/tcp/db/5432; do sleep 1; done; python manage.py collectstatic --noinput && python manage.py makemigrations && python manage.py migrate && gunicorn api.wsgi:application --bind 0.0.0.0:8000"
volumes :
- .:/code
- static:/static
- media:/media
expose :
- 8000
depends_on :
- db
nginx :
image : nginx:latest
ports :
- 8000:80
volumes :
- ./nginx:/etc/nginx/conf.d
- static:/static
- media:/media
depends_on :
- web
volumes :
adafri_postgres :
static :
media :
# nginx/nginx.conf
upstream web {
server web:8000;
}
server {
listen 80;
server_name localhost;
location /static/ {
alias /static/;
}
location /media/ {
alias /media/;
}
location / {
proxy_pass http://web/;
proxy_set_header Host $http_host;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-Forwarded-Protocol "";
#proxy_set_header X-Forwarded-Ssl "";
}
}
Query for each item in a list
def get_queryset (self ):
queryset = super (MyModel , self ).get_queryset ()
states_filter = [
item .strip ()
for item in config .STATES .split (',' )
]
if not states_filter :
MyModel .objects .none ()
q = Q ()
for state in states_filter :
q = q | Q (status__iexact = state )
queryset = queryset .filter (q )
return queryset
Dynamic fields in Django Rest Framwork serializers
from django .db import models
from django .utils import timezone
class Author (models .Model ):
name = models .CharField (max_length = 40 )
dob = models .DateField (verbose_name = 'Date of birth' )
@property
def age (self ):
return timezone .now ().year - self .dob .year
class AuthorSerializer (serializers .ModelSerializer ):
age = serializers .SerializerMethodField ()
class Meta :
model = Author
fields = '__all__'
def get_age (self , instance ):
return datetime .datetime .now ().year - instance .dob .year
class AuthorSerializer (serializers .ModelSerializer ):
age = serializers .SerializerMethodField (method_name = 'calculate_age' )
class Meta :
model = Author
fields = ('id' , 'name' , 'dob' , 'age' )
def calculate_age (self , instance ):
request = self .context .get ('request' )
user = request .user
if user .is_authenticated () and user .is_staff :
return datetime .datetime .now ().year - instance .dob .year
return 'Hidden'
class Team (models .Model ):
LEADERSHIP_TEAM = 1
ACCOUNT_TEAM = 2
CREATIVE_TEAM = 3
TEAM_CHOICES = (
(LEADERSHIP_TEAM , 'Leadership' ),
(ACCOUNT_TEAM , 'Account' ),
(CREATIVE_TEAM , 'Creative' ),
)
team = models .IntegerField (choices = TEAM_CHOICES , default = LEADERSHIP_TEAM )
...
{% for member in object_list %}
{{ member.get_team_display|lower }}
{% endfor %}