Skip to content

Commit

Permalink
ingridients + tags
Browse files Browse the repository at this point in the history
  • Loading branch information
rotem123456 committed Jul 28, 2024
1 parent 600c340 commit 34dfb59
Show file tree
Hide file tree
Showing 11 changed files with 475 additions and 10 deletions.
4 changes: 3 additions & 1 deletion app/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ class UserAdmin(BaseUserAdmin):


admin.site.register(models.User, UserAdmin)
admin.site.register(models.Recipe)
admin.site.register(models.Recipe)
admin.site.register(models.Tag) #make sure the Tag field is editable through the admin page
admin.site.register(models.Ingridient)
28 changes: 28 additions & 0 deletions app/core/migrations/0005_auto_20240724_1123.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.2.25 on 2024-07-24 11:23

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0004_recipe_time_minutes'),
]

operations = [
migrations.CreateModel(
name='Tag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='recipe',
name='tags',
field=models.ManyToManyField(to='core.Tag'),
),
]
28 changes: 28 additions & 0 deletions app/core/migrations/0006_auto_20240728_0930.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.2.25 on 2024-07-28 09:30

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0005_auto_20240724_1123'),
]

operations = [
migrations.CreateModel(
name='Ingridient',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='recipe',
name='ingridients',
field=models.ManyToManyField(to='core.Ingridient'),
),
]
24 changes: 23 additions & 1 deletion app/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,28 @@ class Recipe(models.Model):
time_minutes = models.IntegerField(default = 0)
description = models.TextField(blank = True)
link = models.CharField(max_length=255, blank=True)

tags = models.ManyToManyField('Tag')
ingridients = models.ManyToManyField('ingridient')
def __str__(self):
return self.title

class Tag(models.Model):
"""Tag for filtering recipes"""
name = models.CharField(max_length = 255)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.name

class Ingridient(models.Model):
"""Ingridient for recipes"""
name = models.CharField(max_length=255)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)

def __str__(self):
return self.name
20 changes: 20 additions & 0 deletions app/core/tests/test_modesl.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
from django.contrib.auth import get_user_model
from decimal import Decimal
from core import models
def create_user(email = 'user@example.com',password='testpassword'):
"""Create and return a new user"""
return get_user_model().objects.create_user(email,password)

class ModelTest(TestCase):
"""Test models."""

Expand Down Expand Up @@ -66,3 +70,19 @@ def test_create_recipie(self):
)

self.assertEqual(str(recipe),recipe.title)

def test_create_tag(self):
"""Test creating a test is succesfull"""
user = create_user()
tag = models.Tag.objects.create(user=user, name='Tag1')
self.assertEqual(str(tag),tag.name)

def test_create_ingredient(self):
"""Test creating an ingridient is succesfull"""
user = create_user()
ingridient = models.Ingridient.objects.create(
user=user,
name = 'Ingredient1'
)

self.assertEqual(str(ingridient),ingridient.name)
55 changes: 53 additions & 2 deletions app/recipe/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,71 @@
"""
from rest_framework import serializers

from core.models import Recipe
from core.models import (
Recipe,
Tag,
Ingridient
)
class IngridientSerializer(serializers.ModelSerializer):
"""serialzer for ingredient"""
class Meta:
model = Ingridient
fields = ['id','name']
read_only_fields = ['id']

class TagSerializer(serializers.ModelSerializer):
"""Serializer for tags"""


class Meta:
model = Tag
fields = ['id','name']
read_only_fields = ['id']


class RecipeSerializer(serializers.ModelSerializer):
"""Serializer for recipes."""
tags = TagSerializer(many=True,required = False)

class Meta:
model = Recipe
fields = ['id', 'title', 'time_minutes', 'price', 'link']
fields = ['id', 'title', 'time_minutes', 'price', 'link','tags']
read_only_fields = ['id']

def _get_or_create_tags(self,tags,recipe):
"""Handle getting or creating tags as needed"""
auth_user = self.context['request'].user
for tag in tags:
tag_obj,created = Tag.objects.get_or_create(
user=auth_user,
**tag,
)
recipe.tags.add(tag_obj)

def create(self,validated_data):
"""Crate a recipe"""
tags = validated_data.pop('tags',[])
recipe = Recipe.objects.create(**validated_data)
self._get_or_create_tags(tags,recipe)
return recipe

def update(self,instance,validated_data):
"""update recipe"""
tags = validated_data.pop('tags',None)
if tags is not None:
instance.tags.clear()
self._get_or_create_tags(tags, instance)

for attr,value in validated_data.items():
setattr(instance,attr,value)
instance.save()
return instance

class RecipeDetailSerializer(RecipeSerializer):
"""Serializer for recipe detail view."""

class Meta(RecipeSerializer.Meta):
fields = RecipeSerializer.Meta.fields + ['description']



96 changes: 96 additions & 0 deletions app/recipe/tests/test_ingridients.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Tests for the ingredients API.
"""
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.test import TestCase

from rest_framework import status
from rest_framework.test import APIClient

from core.models import Ingridient

from recipe.serializers import IngridientSerializer


INGRIDIENTS_URL = reverse('recipe:ingridient-list')

def detail_url(ingridient_id):
"""Create and return an ingridient detail url"""
return reverse('recipe:ingridient-detail',args = [ingridient_id])

def create_user(email = 'user@example.com', password = 'testpass123'):
"""Create and return and email"""
return get_user_model().objects.create_user(
email = email,
password = password,
)

class PublicIngredientsApiTests(TestCase):
"""Test unauthenticated API requests."""

def setUp(self):
self.client = APIClient()


def test_auth_required(self):
"""Test auth is required for retrieving an ingridient"""
res = self.client.get(INGRIDIENTS_URL)

self.assertEqual(res.status_code,status.HTTP_401_UNAUTHORIZED)


class PrivateIngredientsApiTests(TestCase):
"""Test authenticated API requests"""

def setUp(self):
self.user = create_user()
self.client = APIClient()
self.client.force_authenticate(self.user)

def test_retrieve_ingridients(self):
"""Test retrieving a list of ingredients"""
Ingridient.objects.create(user=self.user,name = 'Kale')
Ingridient.objects.create(user=self.user,name = 'Vanila')

res = self.client.get(INGRIDIENTS_URL)

ingredients = Ingridient.objects.all().order_by('-name')
serializer = IngridientSerializer(ingredients, many=True)
self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.data, serializer.data)

def test_ingredients_limited_to_user(self):
"""List of ingredients is limited to authenticated user"""
user2 = create_user(email = 'user2@example.com')
Ingridient.objects.create(user=user2,name = 'salt')
Ingredient = Ingridient.objects.create(user=self.user,name = 'Pepper')

res = self.client.get(INGRIDIENTS_URL)

self.assertEqual(res.status_code,status.HTTP_200_OK)
self.assertEqual(len(res.data),1)
self.assertEqual(res.data[0]['name'],Ingredient.name)
self.assertEqual(res.data[0]['id'],Ingredient.id)

def test_update_ingridient(self):
"""Test updating an ingridient"""
ing = Ingridient.objects.create(user=self.user,name = 'Sugar')
payload = {'name':'Sugar_updated'}
url = detail_url(ing.id)
res = self.client.patch(url,payload)

self.assertEqual(res.status_code,status.HTTP_200_OK)
ing.refresh_from_db()
self.assertEqual(ing.name,payload['name'])

def test_delete_ingridient(self):
"""Test deleting an ingredient."""
ing = Ingridient.objects.create(user=self.user,name = 'lettuce')
url = detail_url(ing.id)
res = self.client.delete(url)

self.assertEqual(res.status_code, status.HTTP_204_NO_CONTENT)
ings = Ingridient.objects.filter(user=self.user)
self.assertFalse(ings.exists())

Loading

0 comments on commit 34dfb59

Please sign in to comment.