Skip to content

Commit 969bd41

Browse files
committed
update
1 parent ba803bc commit 969bd41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+633
-0
lines changed

aplikacija/api/__init__.py

Whitespace-only changes.
152 Bytes
Binary file not shown.
141 Bytes
Binary file not shown.
264 Bytes
Binary file not shown.
253 Bytes
Binary file not shown.
425 Bytes
Binary file not shown.
412 Bytes
Binary file not shown.
969 Bytes
Binary file not shown.
832 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5.11 KB
Binary file not shown.
710 Bytes
Binary file not shown.
483 Bytes
Binary file not shown.
2.55 KB
Binary file not shown.
1.53 KB
Binary file not shown.

aplikacija/api/admin.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.
4+
from api.models import Recipe
5+
6+
admin.site.register(Recipe)

aplikacija/api/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class ApiConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'api'
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Generated by Django 4.1.3 on 2022-11-10 20:11
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = [
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='Recipe',
19+
fields=[
20+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('created', models.DateTimeField(auto_now_add=True)),
22+
('name', models.CharField(blank=True, default='', max_length=100)),
23+
('description', models.TextField(blank=True, default='')),
24+
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recipes', to=settings.AUTH_USER_MODEL)),
25+
],
26+
options={
27+
'ordering': ['created'],
28+
},
29+
),
30+
]

aplikacija/api/migrations/__init__.py

Whitespace-only changes.
Binary file not shown.
Binary file not shown.

aplikacija/api/models.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from django.db import models
2+
from django.contrib.auth.models import User
3+
4+
# Create your models here.
5+
6+
class Recipe(models.Model):
7+
created = models.DateTimeField(auto_now_add=True)
8+
name = models.CharField(max_length=100, blank=True, default='')
9+
description = models.TextField(blank=True, default='')
10+
owner = models.ForeignKey('auth.User', related_name='recipes', on_delete=models.CASCADE)
11+
12+
class Meta:
13+
ordering = ['created']
14+
15+
def __str__(self):
16+
return self.name

aplikacija/api/permissions.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from rest_framework import permissions
2+
3+
class IsOwnerOrReadOnly(permissions.BasePermission):
4+
def has_object_permission(self, request, view, obj):
5+
if request.method in permissions.SAFE_METHODS:
6+
return True
7+
8+
return obj.owner == request.user
9+
10+
class IsUserOrReadOnly(permissions.BasePermission):
11+
def has_object_permission(self, request, view, obj):
12+
if request.method in permissions.SAFE_METHODS:
13+
return True
14+
15+
return obj.id == request.user.id

aplikacija/api/serializers.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from rest_framework import serializers
2+
from django.contrib.auth.models import User
3+
from api.models import Recipe
4+
5+
6+
class RecipeSerializer(serializers.ModelSerializer):
7+
owner = serializers.ReadOnlyField(source='owner.username')
8+
9+
class Meta:
10+
model = Recipe
11+
fields = ['id', 'name', 'description', 'owner']
12+
13+
class UserSerializer(serializers.ModelSerializer):
14+
recipes = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
15+
16+
class Meta:
17+
model = User
18+
fields = ['id', 'username', 'password', 'first_name', 'recipes']
19+
write_only_fields = ('password',)
20+
read_only_fields = ('id',)
21+
22+
def create(self, validated_data):
23+
user = User.objects.create(
24+
username=validated_data['username'],
25+
first_name=validated_data['first_name'],
26+
)
27+
28+
user.set_password(validated_data['password'])
29+
user.save()
30+
31+
return user

aplikacija/api/tests.py

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import json
2+
from django.contrib.auth.models import User
3+
from django.urls import reverse
4+
from rest_framework import status
5+
from rest_framework.authtoken.models import Token
6+
from rest_framework.test import APITestCase
7+
8+
from api.serializers import UserSerializer, RecipeSerializer
9+
from api.views import UserDetail
10+
from api.models import Recipe
11+
12+
from django.contrib import auth
13+
14+
class CreateUserTestCase(APITestCase):
15+
16+
# User - Create 😊
17+
def test_registration(self):
18+
data = {"username": "branko", "email": "branko@hr.com", "first_name": "Branko", "password": "brankobranko"}
19+
response = self.client.post("/api/users/new/", data)
20+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
21+
22+
# User - Login 😊
23+
def test_login(self):
24+
data = {"username": "leon", "password": "leonleon"}
25+
response = self.client.post("/api-auth/login/", data)
26+
self.assertEqual(response.status_code, status.HTTP_200_OK)
27+
28+
29+
class UserListTestCase(APITestCase):
30+
31+
# Users- Read List 😊
32+
def test_userList(self):
33+
response = self.client.get("/api/users/")
34+
self.assertEqual(response.status_code, status.HTTP_200_OK)
35+
36+
class RecipeListTestCase(APITestCase):
37+
38+
# Recipes - Read List 😊
39+
def test_recipesList(self):
40+
response = self.client.get("/api/recipes/")
41+
self.assertEqual(response.status_code, status.HTTP_200_OK)
42+
43+
44+
class CreateUserTestCase(APITestCase):
45+
46+
# what needs to be done before test function is run 😊
47+
def setUp(self):
48+
data = {"username": "branko", "email": "branko@hr.com", "first_name": "Branko", "password": "brankobranko"}
49+
self.client.post("/api/users/new/", data)
50+
data = {"username": "Branko", "password": "brankobranko"}
51+
self.client.post("/api-auth/login/", data)
52+
53+
54+
# Recipe - Create 😊
55+
def test_recipeCreate(self):
56+
user = User.objects.create(username='testuser')
57+
user.set_password('12345')
58+
user.save()
59+
recipe_det = Recipe.objects.create(name = "špagete", description = "ukusne špagete", owner = user)
60+
response = self.client.get(reverse("recipe-detail", kwargs={'pk': recipe_det.id}), format="json")
61+
self.assertEqual(response.status_code, status.HTTP_200_OK)
62+
63+
64+
65+
class DetailTestCase(APITestCase):
66+
67+
def setUp(self):
68+
data = {"username": "branko", "email": "branko@hr.com", "first_name": "Branko", "password": "brankobranko"}
69+
self.client.post("/api/users/new/", data)
70+
data = {"username": "Branko", "password": "brankobranko"}
71+
self.client.post("/api-auth/login/", data)
72+
73+
# User - Read detail 😊
74+
def test_userDetail(self):
75+
user_det = User.objects.get()
76+
response = self.client.get(reverse("user-detail", kwargs={'pk': user_det.id}), format="json")
77+
self.assertEqual(response.status_code, status.HTTP_200_OK)
78+
79+
# User - Update
80+
def test_userUpdate(self):
81+
user_det = User.objects.get()
82+
data_change = {"first_name": "Brankec"}
83+
response = self.client.put(reverse("user-detail", kwargs={'pk': user_det.id}), data_change, format="json")
84+
self.assertEqual(response.status_code, status.HTTP_200_OK)
85+
86+
# User - Delete
87+
def test_userDelete(self):
88+
user_det = User.objects.get()
89+
response = self.client.delete(reverse("user-detail", kwargs={'pk': user_det.id}), format="json", follow= True)
90+
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
91+
92+
# Recipe - Read detail 😊
93+
def test_recipeDetail(self):
94+
user = User.objects.create(username='testuser')
95+
user.set_password('12345')
96+
user.save()
97+
recipe_det = Recipe.objects.create(name = "špagete", description = "ukusne špagete", owner = user)
98+
response = self.client.get(reverse("recipe-detail", kwargs={'pk': recipe_det.id}), format="json")
99+
self.assertEqual(response.status_code, status.HTTP_200_OK)
100+
101+
# Recipe - Update 😊 - treba popraviti
102+
def test_recipeUpdate(self):
103+
user = User.objects.create(username='testuser')
104+
user.set_password('12345')
105+
user.save()
106+
recipe_det = Recipe.objects.create(name = "špagete", description = "ukusne špagete", owner = user)
107+
recipe_det_up = Recipe.objects.update(name = "špagete1", description = "ukusne špagete", owner = user)
108+
self.assertEqual(recipe_det_up, 1) # uspješan update
109+
recipe_obj = Recipe.objects.get(id = 1)
110+
self.assertEqual(recipe_obj.name, "špagete1")
111+
response = self.client.get(reverse("recipe-detail", kwargs={'pk': recipe_det.id}), format="json")
112+
self.assertEqual(response.status_code, status.HTTP_200_OK)
113+
114+
# Recipe - Delete
115+
def test_recipeDelete(self):
116+
user = User.objects.create(username='testuser')
117+
user.set_password('12345')
118+
user.save()
119+
recipe_det = Recipe.objects.create(name = "špagete", description = "ukusne špagete", owner = user)
120+
recipe_det.delete
121+
response = self.client.delete(reverse("recipe-detail", kwargs={'pk': recipe_det.id}), format="json")
122+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
123+
124+
# Nested - Read - 😊
125+
def test_recipesOfUserList(self):
126+
user_det = User.objects.get()
127+
response = self.client.get(reverse("user-recipe", kwargs={'user_pk': user_det.id}), format="json")
128+
self.assertEqual(response.status_code, status.HTTP_200_OK)

aplikacija/api/urls.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Kreirano
2+
from django.urls import path, re_path
3+
from rest_framework.urlpatterns import format_suffix_patterns
4+
from api import views
5+
6+
urlpatterns = [
7+
path('users/', views.UserList.as_view()),
8+
path('users/<int:pk>/', views.UserDetail.as_view(), name='user-detail'),
9+
path('users/new/', views.CreateUserView.as_view()),
10+
path('recipes/', views.RecipeList.as_view()),
11+
path('recipes/<int:pk>/', views.RecipeDetail.as_view(), name='recipe-detail'),
12+
# Get list of recipes from specific user
13+
# re_path supports regex expressions, path doesnt
14+
re_path(r'^users/(?P<user_pk>\d+)/recipes/?$', views.UserRecipesViewSet.as_view({'get': 'list'}), name='user-recipe'),
15+
16+
]
17+
18+
urlpatterns = format_suffix_patterns(urlpatterns)

aplikacija/api/views.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from rest_framework import generics
2+
from api import serializers
3+
from django.contrib.auth.models import User
4+
from api.models import Recipe
5+
from rest_framework import permissions
6+
from api.permissions import IsOwnerOrReadOnly,IsUserOrReadOnly
7+
from rest_framework import status, viewsets, mixins
8+
from rest_framework.exceptions import NotFound
9+
10+
class UserList(generics.ListAPIView):
11+
queryset = User.objects.all()
12+
serializer_class = serializers.UserSerializer
13+
14+
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
15+
queryset = User.objects.all()
16+
serializer_class = serializers.UserSerializer
17+
permission_classes = [IsUserOrReadOnly]
18+
19+
class CreateUserView(generics.CreateAPIView):
20+
model = User
21+
permission_classes = [
22+
permissions.AllowAny # Or anon users can't register
23+
]
24+
serializer_class = serializers.UserSerializer
25+
26+
class RecipeList(generics.ListCreateAPIView):
27+
queryset = Recipe.objects.all()
28+
serializer_class = serializers.RecipeSerializer
29+
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
30+
31+
def perform_create(self, serializer):
32+
serializer.save(owner=self.request.user)
33+
34+
class RecipeDetail(generics.RetrieveUpdateDestroyAPIView):
35+
queryset = Recipe.objects.all()
36+
serializer_class = serializers.RecipeSerializer
37+
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
38+
IsOwnerOrReadOnly]
39+
40+
class UserRecipesViewSet(viewsets.ModelViewSet):
41+
queryset = Recipe.objects.all().select_related(
42+
'owner'
43+
)
44+
serializer_class = serializers.RecipeSerializer
45+
46+
def get_queryset(self, *args, **kwargs):
47+
user_id = self.kwargs.get("user_pk")
48+
try:
49+
owner = User.objects.get(id=user_id)
50+
except User.DoesNotExist:
51+
raise NotFound('A user with this id does not exist')
52+
return self.queryset.filter(owner=owner)

aplikacija/aplikacija/__init__.py

Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

aplikacija/aplikacija/asgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for aplikacija project.
3+
4+
It exposes the ASGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.asgi import get_asgi_application
13+
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aplikacija.settings')
15+
16+
application = get_asgi_application()

0 commit comments

Comments
 (0)