-
Notifications
You must be signed in to change notification settings - Fork 2
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
base: create-market-from-sublet
Are you sure you want to change the base?
Conversation
… in views to use a more abstract filtering method
There was a problem hiding this 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)
@@ -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: |
There was a problem hiding this comment.
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
|
||
|
||
# Browse images | ||
class SubletImageURLSerializer(serializers.ModelSerializer): | ||
class ItemImageURLSerializer(serializers.ModelSerializer): | ||
image_url = serializers.SerializerMethodField("get_image_url") |
There was a problem hiding this comment.
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
backend/market/views.py
Outdated
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 = [] |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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)
backend/market/views.py
Outdated
|
||
queryset = queryset.filter(**filters) | ||
|
||
# Apply tag filtering iteratively if "tags" parameter is provided |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why r tags special
There was a problem hiding this comment.
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.
backend/market/views.py
Outdated
@@ -57,167 +68,163 @@ def get_queryset(self): | |||
return Offer.objects.filter(user=user) | |||
|
|||
|
|||
class Properties(viewsets.ModelViewSet): | |||
def apply_filters( |
There was a problem hiding this comment.
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
- Make a (static) function that does this for Items and does it cleanly and well without extra accessories (in the Item view)
- 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
There was a problem hiding this 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] |
There was a problem hiding this comment.
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!
backend/market/serializers.py
Outdated
] | ||
read_only_fields = ["id", "created_at", "seller", "buyers", "images"] |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
backend/market/serializers.py
Outdated
instance = super().create(validated_data) | ||
instance.save() | ||
return instance |
There was a problem hiding this comment.
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
backend/market/serializers.py
Outdated
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): |
There was a problem hiding this comment.
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?
backend/market/serializers.py
Outdated
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): |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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)
Codecov ReportAttention: Patch coverage is
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. 🚨 Try these New Features:
|
Made two routes for Item/Sublet, also made sure other routes work