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

Minghan market two routes #318

Open
wants to merge 16 commits into
base: create-market-from-sublet
Choose a base branch
from

Conversation

minghansun1
Copy link

Made two routes for Item/Sublet, also made sure other routes work

Copy link
Contributor

@vcai122 vcai122 left a comment

Choose a reason for hiding this comment

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

Okay, code is looking a lot cleaner, really great work!

I left a decent amount of comments all just pushing you towards cleaner code and to understand what Django is actually doing, it's tough thinking about this stuff but you are doing a great job.

Also, I am mentioning a decent amount of stuff that was just code you moved over. For now since they work and are tested lets just leave a TODO to fix in a later PR (perhaps after you get everything in and working)

backend/market/models.py Outdated Show resolved Hide resolved
@@ -51,7 +62,7 @@ def has_permission(self, request, view):

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
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 this method might be wrong? If the type of obj is an Offer, then .subletter does not exist right? Let's ask @dr-Jess

backend/market/serializers.py Outdated Show resolved Hide resolved
backend/market/serializers.py Outdated Show resolved Hide resolved


# Browse images
class SubletImageURLSerializer(serializers.ModelSerializer):
class ItemImageURLSerializer(serializers.ModelSerializer):
image_url = serializers.SerializerMethodField("get_image_url")
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 you don't need the "get_image_url", that is the default method it tries to look for I believe

sublet_id = int(self.kwargs["sublet_id"])
self.get_queryset() # check if sublet exists
item_id = int(self.kwargs["item_id"])
self.get_queryset() # check if item exists
img_serializers = []
Copy link
Contributor

Choose a reason for hiding this comment

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

change this to list comprehension


# Serialize and return the queryset
serializer = SubletSerializerSimple(queryset, many=True)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)


class CreateImages(generics.CreateAPIView):
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at this code we are not really leveraging the fact that it is a CreateAPIView at all... let's pin this and put a TODO about this

@@ -230,77 +237,75 @@ def destroy(self, request, *args, **kwargs):


class Favorites(mixins.DestroyModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
Copy link
Contributor

Choose a reason for hiding this comment

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

This is sus, we are not leveraging the viewset/serializer at all, put another pin here (or fix if you want this fix looks simpler)


queryset = queryset.filter(**filters)

# Apply tag filtering iteratively if "tags" parameter is provided
Copy link
Contributor

Choose a reason for hiding this comment

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

why r tags special

Copy link
Author

@minghansun1 minghansun1 Nov 17, 2024

Choose a reason for hiding this comment

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

Tags are filtered by tags__name, which is different from the param name that the frontend passes in to filter with tags. This is because frontend thinks they're filtering based on tags, when filtering is actually being done on the name field of the Tag model.

@@ -57,167 +68,163 @@ def get_queryset(self):
return Offer.objects.filter(user=user)


class Properties(viewsets.ModelViewSet):
def apply_filters(
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 passing this should be called create_filters and we shouldn't be passing in a queryset.
Also filter_mappings, is_sublet, and tag_field is a bit contrived.

You should

  1. Make a (static) function that does this for Items and does it cleanly and well without extra accessories (in the Item view)
  2. Make a function that does this cleanly and well for sublet (in the sublet view) that uses the Item function for help to make it more concise

Copy link
Contributor

@vcai122 vcai122 left a comment

Choose a reason for hiding this comment

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

One last round I think. Mainly has to due with verifying if we need the manual permissions check. Your code is look really good, I can see the effort you put in to make it clean. Awesome job!

class Meta:
model = Tag
fields = "__all__"
read_only_fields = [field.name for field in model._meta.fields]
Copy link
Contributor

Choose a reason for hiding this comment

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

nice! I assume you tried "all" first and it didn't work.

Let's leave a TODO here about extracting out this pattern. For context I'm thinking about building out a small "core" library soon, so we can include a "ReadOnlySerializer" in there that we can just inherit from to make this easier!

]
read_only_fields = ["id", "created_at", "seller", "buyers", "images"]
Copy link
Contributor

Choose a reason for hiding this comment

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

If I'm interpreting correct, this leaves

  • title, description, external_link, price, negotiable, expires_at as changeable?
  • id, created_at are auto generated on create, seller is manually added below, and buyers, and images can be empty, so create still works

Copy link
Author

Choose a reason for hiding this comment

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

I added favorites to read-only fields since it should only be changed through the favorites route.

instance = super().create(validated_data)
instance.save()
return instance
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: don't need to set instance before returning

validated_data["seller"] = self.context["request"].user
category_name = validated_data.pop("category")
category_instance = Category.objects.get(name=category_name)
validated_data["category"] = category_instance
instance = super().create(validated_data)
instance.save()
return instance

# delete_images is a list of image ids to delete
def update(self, instance, validated_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 don't see anything being altered? We are talking about the update function right?

or self.context["request"].user.is_superuser
):
instance = super().update(instance, validated_data)
instance.save()
return instance
else:
raise serializers.ValidationError("You do not have permission to update this sublet.")
raise serializers.ValidationError("You do not have permission to update this item.")

def destroy(self, instance):
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you remove this and test?

I feel like we do not actually need this given that you wrote the permission classes above (get_object_permissions should be responsible for controlling who can change the object)

fields = ["id", "item", "address", "beds", "baths", "start_date", "end_date"]
read_only_fields = ["id"]

def create(self, validated_data):
Copy link
Contributor

Choose a reason for hiding this comment

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

gotcha, this looks good then!

instance = super().create(validated_data)
return instance

def update(self, instance, validated_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 we can use the item serializer for update just like you did above?

Also if you find that we don't need this explicit permission check on the serializer, lets remove it

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

instance.save()
return instance

def destroy(self, instance):
Copy link
Contributor

Choose a reason for hiding this comment

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

a little bit. Doesn't seem terrible because our end user is in the same room as us (ios/android developers), so we have the liberty of assuming they aren't clueless, and we would be removing room for error in our code.

but i could go either way. I did see you overode delete on models which is good if we want to go the delete sublet route as that would ensure deletion on admin portal will also delete the item. So you have no need to double delete as you are here. Also clean up this method lol (and remove permission checking if you verify we don't need)

Copy link

codecov bot commented Nov 23, 2024

Codecov Report

Attention: Patch coverage is 54.39560% with 83 lines in your changes missing coverage. Please review.

Project coverage is 86.68%. Comparing base (316e43a) to head (15274d4).

Files with missing lines Patch % Lines
backend/market/views.py 32.92% 55 Missing ⚠️
backend/market/serializers.py 65.30% 17 Missing ⚠️
backend/market/models.py 80.64% 6 Missing ⚠️
backend/market/permissions.py 44.44% 5 Missing ⚠️
Additional details and impacted files
@@                      Coverage Diff                      @@
##           create-market-from-sublet     #318      +/-   ##
=============================================================
+ Coverage                      79.94%   86.68%   +6.74%     
=============================================================
  Files                             68       68              
  Lines                           3032     3035       +3     
=============================================================
+ Hits                            2424     2631     +207     
+ Misses                           608      404     -204     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.


🚨 Try these New Features:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants