Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/api products catalogue #65

Merged
merged 22 commits into from
Jan 13, 2024
Merged

Feature/api products catalogue #65

merged 22 commits into from
Jan 13, 2024

Conversation

knop-k
Copy link
Contributor

@knop-k knop-k commented Dec 18, 2023

Hi all!
I am just starting my adventure with DRF so please give me constructive comments on what I could improve/add/change.
I have prepared an API for the product:

  • list view
  • detail view
  • update
  • delete

In Additionally:
added filtering and pagination

Feel free to ask questions and comment

@jacoor
Copy link
Contributor

jacoor commented Dec 19, 2023

Please fix linting before we review it.

from .api_views import ProductViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be a good idea to remove the trailing slashes. My front-end friend recently pointed out that it was easier for them that way.
router = DefaultRouter(trailing_slash=False)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont have preference @knop-k. Your call.

Comment on lines +1 to +5
from .models import Product
from .serializers import ProductSerializer
from .filters import ProductFilter
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8 import order rules not followed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not followed in the whole project. Good pointing out, we need to add something to guard id. Right now, let's ignore.

Comment on lines +1 to +2
from django_filters import rest_framework as filters
from .models import Product
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8 import order rules not followed

Comment on lines +7 to +9
class Meta:
model = Product
fields = ['id', 'category', 'name', 'price', 'short_description', 'full_description', 'parent_product']
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a suggestion: you can add read_only_fields to Meta (with e.g. id field)

Comment on lines +1 to +5
import pytest
from django.urls import reverse
from apps.products_catalogue.models import Category, Product
# pylama:ignore=W0404, W0611
from apps.users.conftest import api_client, login_url, login_data, user_instance, user_instance_token
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8 import order rules not followed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not followed in the whole project. Good pointing out, we need to add something to guard id. Right now, let's ignore.

Copy link
Contributor

@jacoor jacoor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, needs small tweaks in tests.

from .api_views import ProductViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont have preference @knop-k. Your call.

Comment on lines +1 to +5
from .models import Product
from .serializers import ProductSerializer
from .filters import ProductFilter
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not followed in the whole project. Good pointing out, we need to add something to guard id. Right now, let's ignore.

Comment on lines +1 to +5
import pytest
from django.urls import reverse
from apps.products_catalogue.models import Category, Product
# pylama:ignore=W0404, W0611
from apps.users.conftest import api_client, login_url, login_data, user_instance, user_instance_token
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not followed in the whole project. Good pointing out, we need to add something to guard id. Right now, let's ignore.

Dshop/apps/products_catalogue/tests/test_api_products.py Outdated Show resolved Hide resolved
Dshop/apps/products_catalogue/tests/test_api_products.py Outdated Show resolved Hide resolved
Dshop/apps/products_catalogue/filters.py Show resolved Hide resolved
Copy link
Contributor

@jacoor jacoor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small changes. Looks good, almost there.

results = response.data.get('results', [])
assert len(results) == 1

for product_data in results:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why using loop if there is only one product?

Suggested change
for product_data in results:
product_data = results[0]
  • fix indentation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, it checks that fields are there, but not fields values. Would be good to add values check too.
What I would to is prob create

def assert_active_object(data):
# copy all fields values and compare to data[x] ie:
    fields_values = {  
     "name": "main product"
     # ... more fields
     }
     for key, value in data.items():
         assert fields_values[key] == value

And use that function whenever you need to compare active_object with response.

Copy link
Contributor Author

@knop-k knop-k Dec 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacoor What do you think of this approach:

def assert_active_object(data):
    fields_values = {
        "name": "main product",
        "price": "11.00",
        "short_description": "short desc",
        "full_description": "full_description",
    }
    for key, value in data.items():
        if key in fields_values:
            assert fields_values[key] == value

because I don't want to check for example id or category

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late response.
For id it would be good to check if field is there, and for category too. Would be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jacoor , I added this to test

@knop-k knop-k requested a review from a team January 6, 2024 10:23
"full_description": "full_description",
}
for key, value in data.items():
if key in fields_values:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this if.
The goal of the test is to FAIL if something is missing, this is so called "silent failure" - test passes, you expect all good but no, field is not there.
Example: data = {}
Test will pass.

assert 'parent_product' in product_data
product_data = results[0]

assert 'id' in product_data, "Field 'id' is missing in product data"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would add this assertion to assert_active_object function. This way we will have one assertion in test, which is good practice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also enough will be to do

product_data['category'] is not None

As this will cover both cases: missing category or category being None. I would remove error message as in this case it might be confusing.
Tests should be short and concise, as this makes them easier to maintain.

@knop-k knop-k requested a review from a team January 8, 2024 14:47
@knop-k knop-k merged commit 6b067fd into dev Jan 13, 2024
2 checks passed
@knop-k knop-k deleted the feature/api_products_catalogue branch January 13, 2024 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants