register at elephantsql.com for a free postgres database on cloud
----------------------------------------
#update database
#django/settings
DATABASES = {'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'pupssizu',
'USER': 'pupssizu',
'PASSWORD': 'xxxxx',
'HOST': 'raja.db.elephantsql.com',
'PORT': '5432',
}
}
----------------------------
#pgadmin connect cloud database
pgAdmin 4 create server
lots of database on elephantSQL, locate my database
---------------------------
#django/models
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class Album(models.Model):
artist = models.CharField(max_length=50)
album_title = models.CharField(max_length=50)
genre = models.CharField(max_length=50)
album_logo = models.TextField(default='iVBOR...')
date_posted = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
price = models.DecimalField(decimal_places=2,max_digits=5, default=10)
#form submitted without action redirect to detail
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.pk})
#query album.objects.get(pk=1)
def __str__(self):
return self.album_title + ' - ' + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=50)
song_title = models.CharField(max_length=50)
is_favorite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
# form submitted without action redirect to detail
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.album.id})
class ShoppingItem(models.Model):
shopper = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
album = models.ForeignKey(Album, on_delete=models.CASCADE, blank=True, default=1)
quantity = models.PositiveIntegerField(blank=True, default=0)
def __str__(self):
return 'shopper ' + str(self.shopper) + ' - album ' + str(self.album) + ' - quantity '+str(self.quantity)
class OrderHistory(models.Model):
order = models.CharField(max_length=50)
shopper = models.ForeignKey(User, on_delete=models.CASCADE)
total = models.DecimalField(decimal_places=2,max_digits=7, default=0)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.order)+ ' ' + str(self.shopper) + ' bought ' + str(self.total) + ' on ' + str(self.date)
#powershell python manage.py migrate
------------------------------------
#django create super user#django/models
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class Album(models.Model):
artist = models.CharField(max_length=50)
album_title = models.CharField(max_length=50)
genre = models.CharField(max_length=50)
album_logo = models.TextField(default='iVBOR...')
date_posted = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
price = models.DecimalField(decimal_places=2,max_digits=5, default=10)
#form submitted without action redirect to detail
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.pk})
#query album.objects.get(pk=1)
def __str__(self):
return self.album_title + ' - ' + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=50)
song_title = models.CharField(max_length=50)
is_favorite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
# form submitted without action redirect to detail
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.album.id})
class ShoppingItem(models.Model):
shopper = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
album = models.ForeignKey(Album, on_delete=models.CASCADE, blank=True, default=1)
quantity = models.PositiveIntegerField(blank=True, default=0)
def __str__(self):
return 'shopper ' + str(self.shopper) + ' - album ' + str(self.album) + ' - quantity '+str(self.quantity)
class OrderHistory(models.Model):
order = models.CharField(max_length=50)
shopper = models.ForeignKey(User, on_delete=models.CASCADE)
total = models.DecimalField(decimal_places=2,max_digits=7, default=0)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.order)+ ' ' + str(self.shopper) + ' bought ' + str(self.total) + ' on ' + str(self.date)
#powershell python manage.py migrate
------------------------------------
https://docs.djangoproject.com/en/1.8/intro/tutorial02/
super user chuanshuo created
-----------------------------#django/admin
from django.contrib import admin
from .models import Album, Song, ShoppingItem, OrderHistory
admin.site.register(Album)
admin.site.register(Song)
admin.site.register(ShoppingItem)
admin.site.register(OrderHistory)
-----------------------------------------
#install django-rest-auth
https://django-rest-auth.readthedocs.io/en/latest/installation.html
# django-rest-auth configuration
#django settings
OLD_PASSWORD_FIELD_ENABLED = True
LOGIN_URL = 'http://localhost:3000/login'
#django urls
path('rest-auth/',include('rest_auth.urls')),
path('', include('django.contrib.auth.urls')),
-----------------------------------
#create registration template
https://chuanshuoge2.blogspot.com/2019/05/django-33-reset-password-by-email.html
https://chuanshuoge2.blogspot.com/2019/07/django-53-react-redux-reset-password-by.html
----------------------------------------------
#email setting
#django settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'zchen2014chuanshuo@gmail.com'
EMAIL_HOST_PASSWORD = 'xxxx'
---------------------------------------
#enable cors
#power shell
pip install django-cors-headers
#django setting
INSTALLED_APPS = (
...
'corsheaders',
)
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
)
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
https://chuanshuoge2.blogspot.com/2019/06/django-40-django-react-redux-ftech-token.html
-------------------------------------
#create rest api
#power shell
pip install djangorestframework
pip install django-filter
#django settings
INSTALLED_APPS = [
...
'rest_framework',
]
#django urls
path('api/', include('music.api.urls')),
------------------------------------------
#django rest framework token authentication
#django settings
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
'django_filters',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
}
#powershell
python manage.py migrate
https://chuanshuoge2.blogspot.com/2019/05/django-38-rest-framework-authentication.html
--------------------------
#django/api/urls
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview
from rest_framework.authtoken import views
app_name = 'musicAPI'
urlpatterns = [
path('album_list/', apiview.AlbumList.as_view(), name='AlbumList'),
path('shoppingItems/', apiview.ShoppingItemsList.as_view(), name='ShoppingItems'),
path('user_list/', apiview.UserList.as_view(), name='UserList'),
path('user_register/', apiview.UserRegister.as_view(), name='UserRegister'),
path('song_list/', apiview.SongList.as_view(), name='SongList'),
path('cart_checkout/', apiview.CartCheckout.as_view(), name='CartCheckout'),
path('order_history/', apiview.OrderHistoryList.as_view(), name='OrderHistory'),
path('album_detail/<int:pk>/', apiview.AlbumDetail.as_view(), name='AlbumDetail'),
path('shoppingItem/<int:pk>/', apiview.ShoppingItemDetail.as_view(), name='ShoppingItemDetail'),
path('orderDetail/<int:pk>/', apiview.OrderHistoryDetail.as_view(), name='OrderDetail'),
path('api-token-auth/', views.obtain_auth_token, name='AuthToken'),
path('update_password/', apiview.UpdatePassword.as_view(), name='UpdatePassword'),
]
urlpatterns = format_suffix_patterns(urlpatterns)
-------------------------------------------
#django/api/serializers
from rest_framework import serializers
from music.models import Album, Song, ShoppingItem, OrderHistory
from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password
class MusicSerializer(serializers.ModelSerializer):
class Meta:
model = Album
fields = '__all__'
def __init__(self, *args, **kwargs):
super(MusicSerializer, self).__init__(*args, **kwargs)
self.fields['album_logo'] = serializers.CharField(required=True)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
class SongSerializer(serializers.ModelSerializer):
class Meta:
model = Song
fields = ('id', 'album', 'file_type', 'song_title', 'is_favorite')
class PasswordSerializer(serializers.Serializer):
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
def validate_new_password(self, value):
validate_password(value)
return value
class ShoppingItemsSerializer(serializers.ModelSerializer):
class Meta:
model = ShoppingItem
fields = ('id', 'shopper', 'album', 'quantity')
class OrderHistorySerializer(serializers.ModelSerializer):
class Meta:
model = OrderHistory
fields = ('id', 'order', 'shopper', 'total', 'date')
-----------------------------------------
#django/api/apiview
from music.models import Album, Song, ShoppingItem, OrderHistory
from music.api.serializers import MusicSerializer, UserSerializer, SongSerializer, PasswordSerializer, ShoppingItemsSerializer, OrderHistorySerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework.decorators import authentication_classes, permission_classes
from django.contrib.auth.password_validation import validate_password
from django.core import exceptions
from django.forms.models import model_to_dict
from django.conf import settings
import stripe
class AlbumList(APIView):
def get(self, request, format=None):
username = request.GET.get('author')
data_length = request.GET.get('data_length')
#filter by author
if username==None:
albums = Album.objects.all()
else:
author_id = get_object_or_404(User, username=username).pk
albums = Album.objects.filter(author=author_id).order_by('-date_posted')
#filter by data length
if data_length!=None:
try:
int(data_length)
except ValueError:
return Response('data length is invvalid', status=status.HTTP_406_NOT_ACCEPTABLE)
else:
albums = albums[:int(data_length)]
serializer = MusicSerializer(albums, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = MusicSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class AlbumDetail(APIView):
def get_object(self, pk):
try:
return Album.objects.get(pk=pk)
except Album.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
album = self.get_object(pk)
serializer = MusicSerializer(album)
return Response(serializer.data)
def put(self, request, pk, format=None):
album = self.get_object(pk)
#only owner can edit
if album.author != request.user:
return Response({"detail": "You do not have permission to perform this action."},
status= status.HTTP_403_FORBIDDEN)
serializer = MusicSerializer(album, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
album = self.get_object(pk)
# only owner can delete
if album.author != request.user:
return Response({"detail": "You do not have permission to perform this action."},
status=status.HTTP_403_FORBIDDEN)
album.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class UserList(APIView):
def get(self, request, format=None):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
@authentication_classes([])
@permission_classes([])
class UserRegister(APIView):
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
#email has to be unique
email = request.POST.get('email')
unique_email = User.objects.filter(email=email).count()
if(unique_email > 0):
return Response({'email': 'email already exist'}, status=status.HTTP_406_NOT_ACCEPTABLE)
#validate password
password = request.POST.get('password')
try:
validate_password(password)
except exceptions.ValidationError as e:
return Response(e.messages, status=status.HTTP_406_NOT_ACCEPTABLE)
else:
pass
#register new user
serializer.save()
#set password for new user
username = serializer.data.get('username')
newUser = User.objects.get(username=username)
newUser.set_password(password)
#save password for new user
newUser.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class SongList(APIView):
def get(self, request, format=None):
songs = Song.objects.all()
serializer = SongSerializer(songs, many=True)
return Response(serializer.data)
class UpdatePassword(APIView):
def get_object(self, queryset=None):
return self.request.user
def put(self, request, *args, **kwargs):
currentUser = self.get_object()
serializer = PasswordSerializer(data=request.data)
if serializer.is_valid():
# Check old password
old_password = serializer.data.get("old_password")
if not currentUser.check_password(old_password):
return Response({"old_password": ["Wrong password."]},
status=status.HTTP_400_BAD_REQUEST)
# set_password also hashes the password that the user will get
currentUser.set_password(serializer.data.get("new_password"))
currentUser.save()
return Response(status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ShoppingItemsList(APIView):
def get(self, request, format=None):
#for privacy, only return shoppers items
shoppingItems = ShoppingItem.objects.filter(shopper=request.user)
serializer = ShoppingItemsSerializer(shoppingItems, many=True)
return Response(serializer.data)
def post(self, request, format=None):
#customer has item in cart
try:
revisitedItem = ShoppingItem.objects.get(shopper=request.user, album=request.data.get('album'))
revisitedItem.quantity= int(request.data.get('quantity')) + revisitedItem.quantity
serializer = ShoppingItemsSerializer(data=model_to_dict( revisitedItem ))
if serializer.is_valid():
# update database
revisitedItem.save()
return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#customer select new item
except exceptions.ObjectDoesNotExist:
serializer = ShoppingItemsSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ShoppingItemDetail(APIView):
def get_object(self, pk):
try:
return ShoppingItem.objects.get(pk=pk)
except ShoppingItem.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
shoppingItem = self.get_object(pk)
serializer = ShoppingItemsSerializer(shoppingItem)
return Response(serializer.data)
def put(self, request, pk, format=None):
shoppintItem = self.get_object(pk)
#only owner can edit
if shoppintItem.shopper != request.user:
return Response({"detail": "You do not have permission to perform this action."},
status= status.HTTP_403_FORBIDDEN)
serializer = ShoppingItemsSerializer(shoppintItem, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
shoppingItem = self.get_object(pk)
# only owner can delete
if shoppingItem.shopper != request.user:
return Response({"detail": "You do not have permission to perform this action."},
status=status.HTTP_403_FORBIDDEN)
shoppingItem.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class CartCheckout(APIView):
def post(self, request, format=None):
stripe.api_key = settings.STRIPE_SECRET_KEY
token = request.data.get('token')
cart = request.data.get('cart')
try:
customer=stripe.Customer.create(email=token['email'],source=token['id'])
charge=stripe.Charge.create(
amount=int(cart['price']*100),
currency='cad',
receipt_email= token['email'],
customer=customer.id,
metadata=cart['items'],
)
return Response(charge, status=status.HTTP_202_ACCEPTED)
except Exception as e:
return Response(e, status=status.HTTP_400_BAD_REQUEST)
class OrderHistoryList(APIView):
def get(self, request, format=None):
orders = OrderHistory.objects.filter(shopper=request.user)
serializer = OrderHistorySerializer(orders, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = OrderHistorySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class OrderHistoryDetail(APIView):
def get_object(self, pk):
try:
return OrderHistory.objects.get(pk=pk)
except OrderHistory.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
stripe.api_key = settings.STRIPE_SECRET_KEY
order = self.get_object(pk)
try:
#order is a model boject, request is a python dictionary
charge=stripe.Charge.retrieve(order.order)
return Response(charge, status=status.HTTP_200_OK)
except Exception as e:
return Response(e, status=status.HTTP_400_BAD_REQUEST)
-------------------------------------------------------
#stripe
#power shell
pip install stripe
#django settings
STRIPE_SECRET_KEY = 'sk_test_xxxxxx'
https://chuanshuoge2.blogspot.com/2019/07/django-62-stripe-checkout.html
No comments:
Post a Comment