mirror of
https://github.com/Rushilwiz/rounded.git
synced 2025-04-09 22:00:18 -04:00
feat(backend): added database models and API views
This commit is contained in:
parent
495cbfc407
commit
acba7b111d
16
server/Pipfile
Normal file
16
server/Pipfile
Normal file
|
@ -0,0 +1,16 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
django = "*"
|
||||
gunicorn = "*"
|
||||
python-dotenv = "*"
|
||||
djangorestframework = "*"
|
||||
django-cors-headers = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
92
server/Pipfile.lock
generated
Normal file
92
server/Pipfile.lock
generated
Normal file
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "6b09e5def16da359280b38cfa9690ef7fb07897b5befd3c0f5b16de35d664690"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
"sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
|
||||
"sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.5.0"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:07c8638e7a7f548dc0acaaa7825d84b7bd42b10e8d22268b3d572946f1e9b687",
|
||||
"sha256:4e8177858524417563cc0430f29ea249946d831eacb0068a1455686587df40b5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.4"
|
||||
},
|
||||
"django-cors-headers": {
|
||||
"hashes": [
|
||||
"sha256:a22be2befd4069c4fc174f11cf067351df5c061a3a5f94a01650b4e928b0372b",
|
||||
"sha256:eb98389bf7a2afc5d374806af4a9149697e3a6955b5a2dc2bf049f7d33647456"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.11.0"
|
||||
},
|
||||
"djangorestframework": {
|
||||
"hashes": [
|
||||
"sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee",
|
||||
"sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.13.1"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
|
||||
"sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.1.0"
|
||||
},
|
||||
"python-dotenv": {
|
||||
"hashes": [
|
||||
"sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f",
|
||||
"sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.20.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7",
|
||||
"sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"
|
||||
],
|
||||
"version": "==2022.1"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
|
||||
"sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.2"
|
||||
},
|
||||
"tzdata": {
|
||||
"hashes": [
|
||||
"sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9",
|
||||
"sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==2022.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
0
server/api/__init__.py
Normal file
0
server/api/__init__.py
Normal file
9
server/api/admin.py
Normal file
9
server/api/admin.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from . import models
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(models.Consumer)
|
||||
admin.site.register(models.Foundation)
|
||||
admin.site.register(models.Wallet)
|
||||
admin.site.register(models.FoundationOrder)
|
6
server/api/apps.py
Normal file
6
server/api/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'api'
|
67
server/api/migrations/0001_initial.py
Normal file
67
server/api/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Generated by Django 4.0.4 on 2022-04-16 20:35
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Consumer',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('access_token', models.CharField(max_length=100)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Consumers',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Foundation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('description', models.TextField()),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Foundations',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Wallet',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('address', models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Wallets',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FoundationOrder',
|
||||
fields=[
|
||||
('price', models.DecimalField(decimal_places=2, max_digits=9)),
|
||||
('uuid', models.UUIDField(primary_key=True, serialize=False, unique=True)),
|
||||
('consumer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='foundation_orders', to='api.consumer')),
|
||||
('foundation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='foundation_orders', to='api.foundation')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Foundation Orders',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='foundation',
|
||||
name='wallet',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='api.wallet'),
|
||||
),
|
||||
]
|
20
server/api/migrations/0002_consumer_wallet.py
Normal file
20
server/api/migrations/0002_consumer_wallet.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 4.0.4 on 2022-04-16 20:37
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('api', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='consumer',
|
||||
name='wallet',
|
||||
field=models.OneToOneField(default=None, on_delete=django.db.models.deletion.CASCADE, to='api.wallet'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
19
server/api/migrations/0003_alter_consumer_wallet.py
Normal file
19
server/api/migrations/0003_alter_consumer_wallet.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 4.0.4 on 2022-04-16 21:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('api', '0002_consumer_wallet'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='consumer',
|
||||
name='wallet',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='api.wallet'),
|
||||
),
|
||||
]
|
0
server/api/migrations/__init__.py
Normal file
0
server/api/migrations/__init__.py
Normal file
50
server/api/models.py
Normal file
50
server/api/models.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
class Wallet (models.Model):
|
||||
address = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return self.address[0:4]
|
||||
# return f'{self.consumer.user.username}\'s wallet'
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Wallets"
|
||||
|
||||
class Consumer (models.Model):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
wallet = models.OneToOneField(Wallet, null=True, blank=True, on_delete=models.CASCADE)
|
||||
access_token = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.user.username}\'s profile'
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Consumers"
|
||||
|
||||
class Foundation (models.Model):
|
||||
wallet = models.OneToOneField(Wallet, on_delete=models.CASCADE)
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=100)
|
||||
description = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.user.username}\'s foundation'
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Foundations"
|
||||
|
||||
class FoundationOrder (models.Model):
|
||||
consumer = models.ForeignKey(Consumer, related_name='foundation_orders', on_delete=models.CASCADE)
|
||||
foundation = models.ForeignKey(Foundation, related_name='foundation_orders', on_delete=models.CASCADE)
|
||||
|
||||
price = models.DecimalField(max_digits=9, decimal_places=2)
|
||||
uuid = models.UUIDField(primary_key=True, unique=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Foundation Orders"
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.consumer.user.username}\'s Order to {self.foundation.name} for {self.price}'
|
62
server/api/serializers.py
Normal file
62
server/api/serializers.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
from operator import mod
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework import serializers
|
||||
|
||||
from . import models
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'email', 'first_name', 'last_name')
|
||||
|
||||
class ConsumerCreateSerializer(serializers.ModelSerializer):
|
||||
password = serializers.CharField(write_only=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
user = User.objects.create_user(**validated_data)
|
||||
user.set_password(validated_data['password'])
|
||||
user.save()
|
||||
|
||||
consumer = models.Consumer.objects.create(user=user)
|
||||
consumer.save()
|
||||
|
||||
return user
|
||||
|
||||
class Meta:
|
||||
model = models.User
|
||||
fields = ('username', 'password', 'email', 'first_name', 'last_name')
|
||||
|
||||
class FoundationSerializer(serializers.ModelSerializer):
|
||||
user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.Foundation
|
||||
fields = ('user', 'name', 'description')
|
||||
|
||||
|
||||
class ConsumerOrderSerializer(serializers.ModelSerializer):
|
||||
foundation = FoundationSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.FoundationOrder
|
||||
fields = ('price', 'uuid', 'foundation')
|
||||
|
||||
|
||||
class ConsumerSerializer(serializers.ModelSerializer):
|
||||
user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.Consumer
|
||||
fields = ('user', 'access_token', 'foundation_orders')
|
||||
|
||||
class FoundationOrderSerializer(serializers.ModelSerializer):
|
||||
consumer = ConsumerSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.FoundationOrder
|
||||
fields = ('price', 'uuid', 'consumer')
|
||||
|
||||
class FoundationOrderCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = models.FoundationOrder
|
||||
fields = ('price', 'uuid', 'foundation')
|
3
server/api/tests.py
Normal file
3
server/api/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
10
server/api/urls.py
Normal file
10
server/api/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('profile/create', views.ConsumerCreate.as_view()),
|
||||
path('profile/', views.ConsumerDetail.as_view()),
|
||||
path('foundation/', views.FoundationViewSet.as_view({'get': 'list', 'post': 'create'})),
|
||||
path('foundation/<int:pk>/', views.FoundationViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
|
||||
]
|
38
server/api/views.py
Normal file
38
server/api/views.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
from .models import *
|
||||
from .serializers import *
|
||||
|
||||
from rest_framework import status, permissions
|
||||
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.generics import CreateAPIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
# Create your views here.
|
||||
class FoundationViewSet(ModelViewSet):
|
||||
queryset = models.Foundation.objects.all()
|
||||
serializer_class = FoundationSerializer
|
||||
|
||||
class ConsumerOrderViewSet(ModelViewSet):
|
||||
queryset = ''
|
||||
serializerClass = ConsumerOrderSerializer
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
queryset = request.user.consumer.foundation_orders.all()
|
||||
serializer = ConsumerOrderSerializer(queryset, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ConsumerCreate(CreateAPIView):
|
||||
model = User
|
||||
permission_classes = [permissions.AllowAny]
|
||||
serializer_class = ConsumerCreateSerializer
|
||||
|
||||
class ConsumerDetail(APIView):
|
||||
def get(self, request, format=None):
|
||||
profile = request.user.consumer
|
||||
serializer = ConsumerSerializer(profile)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
2
server/config/.env.sample
Normal file
2
server/config/.env.sample
Normal file
|
@ -0,0 +1,2 @@
|
|||
SECRET_KEY=notsosecret
|
||||
DEBUG=True
|
|
@ -12,6 +12,10 @@ https://docs.djangoproject.com/en/4.0/ref/settings/
|
|||
|
||||
from pathlib import Path
|
||||
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
@ -20,26 +24,36 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-ioum!dn#uh5t3yn_15j)4qtjp6wyl24-xx*mv6d1kl&wk_-mx1'
|
||||
SECRET_KEY = str(os.getenv('SECRET_KEY'))
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
DEBUG = str(os.getenv("DEBUG")).lower() == "true"
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
if DEBUG:
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
else:
|
||||
ALLOWED_HOSTS = ["api.roundedapp.tech"]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'api',
|
||||
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'corsheaders',
|
||||
'rest_framework'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
|
@ -68,17 +82,30 @@ TEMPLATES = [
|
|||
]
|
||||
|
||||
WSGI_APPLICATION = 'config.wsgi.application'
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL=True
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
if DEBUG:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
}
|
||||
else:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'rounded',
|
||||
'USER': 'rounded',
|
||||
'PASSWORD': 'rounded',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '5432',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Password validation
|
||||
|
@ -116,6 +143,8 @@ USE_TZ = True
|
|||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
||||
|
|
|
@ -14,8 +14,9 @@ Including another URLconf
|
|||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from django.urls import include, path
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('api/', include('api.urls')),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue
Block a user