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

Updated models.py #316

Open
wants to merge 6 commits into
base: create-market-from-sublet
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions backend/market/admin.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
from django.contrib import admin
from django.utils.html import mark_safe

from market.models import Amenity, Offer, Sublet, SubletImage
from market.models import Tag, Category, Offer, Item, Sublet, ItemImage


class SubletAdmin(admin.ModelAdmin):
class ItemAdmin(admin.ModelAdmin):
def image_tag(self, instance):
images = ['<img src="%s" height="150" />' for image in instance.images.all()]
return mark_safe("<br>".join(images))

image_tag.short_description = "Sublet Images"
image_tag.short_description = "Item Images"
readonly_fields = ("image_tag",)


admin.site.register(Offer)
admin.site.register(Amenity)
admin.site.register(Sublet, SubletAdmin)
admin.site.register(SubletImage)
admin.site.register(Tag)
admin.site.register(Category)
admin.site.register(Item, ItemAdmin)
admin.site.register(Sublet)
admin.site.register(ItemImage)
168 changes: 168 additions & 0 deletions backend/market/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Generated by Django 5.0.2 on 2024-10-25 16:41

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


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Category",
fields=[
("name", models.CharField(max_length=50, primary_key=True, serialize=False)),
],
),
migrations.CreateModel(
name="Tag",
fields=[
("name", models.CharField(max_length=255, primary_key=True, serialize=False)),
],
),
migrations.CreateModel(
name="Item",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("title", models.CharField(max_length=255)),
("description", models.TextField(blank=True, null=True)),
("external_link", models.URLField(blank=True, max_length=255, null=True)),
("price", models.IntegerField()),
("negotiable", models.BooleanField(default=True)),
("used", models.BooleanField(blank=True, null=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("expires_at", models.DateTimeField()),
(
"category",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="items",
to="market.category",
),
),
(
"favorites",
models.ManyToManyField(
blank=True, related_name="items_favorited", to=settings.AUTH_USER_MODEL
),
),
(
"seller",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
],
),
migrations.CreateModel(
name="ItemImage",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("image", models.ImageField(upload_to="marketplace/images")),
(
"item",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="images",
to="market.item",
),
),
],
),
migrations.CreateModel(
name="Offer",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("email", models.EmailField(blank=True, max_length=255, null=True)),
(
"phone_number",
phonenumber_field.modelfields.PhoneNumberField(
blank=True, max_length=128, null=True, region=None
),
),
("message", models.CharField(blank=True, max_length=255)),
("created_date", models.DateTimeField(auto_now_add=True)),
(
"item",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="offers",
to="market.item",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="offers_made_market",
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.AddField(
model_name="item",
name="buyers",
field=models.ManyToManyField(
blank=True,
related_name="items_offered",
through="market.Offer",
to=settings.AUTH_USER_MODEL,
),
),
migrations.CreateModel(
name="Sublet",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("address", models.CharField(max_length=255)),
("beds", models.IntegerField()),
("baths", models.IntegerField()),
("start_date", models.DateTimeField()),
("end_date", models.DateTimeField()),
(
"item",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="sublet",
to="market.item",
),
),
],
),
migrations.AddField(
model_name="item",
name="tags",
field=models.ManyToManyField(blank=True, related_name="items", to="market.tag"),
),
migrations.AddConstraint(
model_name="offer",
constraint=models.UniqueConstraint(fields=("user", "item"), name="unique_offer_market"),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.2 on 2024-10-25 21:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("market", "0001_initial"),
]

operations = [
migrations.RemoveField(
model_name="item",
name="used",
),
migrations.AlterField(
model_name="item",
name="price",
field=models.FloatField(),
),
]
56 changes: 35 additions & 21 deletions backend/market/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,65 @@

class Offer(models.Model):
class Meta:
constraints = [models.UniqueConstraint(fields=["user", "sublet"], name="unique_offer")]
constraints = [models.UniqueConstraint(fields=["user", "item"], name="unique_offer_market")]

user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="offers_made")
sublet = models.ForeignKey("Sublet", on_delete=models.CASCADE, related_name="offers")
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey("Item", on_delete=models.CASCADE)
email = models.EmailField(max_length=255, null=True, blank=True)
phone_number = PhoneNumberField(null=True, blank=True)
message = models.CharField(max_length=255, blank=True)
created_date = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"Offer for {self.sublet} made by {self.user}"
return f"Offer for {self.item} made by {self.user}"


class Amenity(models.Model):
class Category(models.Model):
name = models.CharField(max_length=50, primary_key=True)

def __str__(self):
return self.name



class Tag(models.Model):
name = models.CharField(max_length=255, primary_key=True)

def __str__(self):
return self.name


class Sublet(models.Model):
subletter = models.ForeignKey(User, on_delete=models.CASCADE)
sublettees = models.ManyToManyField(
User, through=Offer, related_name="sublets_offered", blank=True
class Item(models.Model):
seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name="items_listed")
buyers = models.ManyToManyField(
User, through=Offer, related_name="items_offered", blank=True
)
favorites = models.ManyToManyField(User, related_name="sublets_favorited", blank=True)
amenities = models.ManyToManyField(Amenity, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
favorites = models.ManyToManyField(User, related_name="items_favorited", blank=True)

title = models.CharField(max_length=255)
address = models.CharField(max_length=255, null=True, blank=True)
beds = models.IntegerField(null=True, blank=True)
baths = models.DecimalField(max_digits=3, decimal_places=1, null=True, blank=True)
description = models.TextField(null=True, blank=True)
external_link = models.URLField(max_length=255, null=True, blank=True)
price = models.IntegerField()
price = models.FloatField()
negotiable = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField()
start_date = models.DateField()
end_date = models.DateField()

def __str__(self):
return f"{self.title} by {self.subletter}"
return f"{self.title} by {self.seller}"


class Sublet(models.Model):
item = models.OneToOneField(Item, on_delete=models.CASCADE)
address = models.CharField(max_length=255)
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's keep the same requirements for the model and same model fields.

Copy link
Author

Choose a reason for hiding this comment

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

What do you mean by this? Are you asking me to remove related_name again?

beds = models.IntegerField()
baths = models.IntegerField()
start_date = models.DateTimeField()
end_date = models.DateTimeField()


class SubletImage(models.Model):
sublet = models.ForeignKey(Sublet, on_delete=models.CASCADE, related_name="images")
image = models.ImageField(upload_to="sublet/images")
# TODO: Verify that this S2 bucket exists. Check if we need to make it manually or will Django make it for us?
class ItemImage(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
image = models.ImageField(upload_to="marketplace/images")
Copy link
Contributor

Choose a reason for hiding this comment

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

add a TODO here so we are reminded to verify this in production

Copy link
Author

Choose a reason for hiding this comment

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

What exactly do you want us to verify? Is it the image routes?
So i can leave a more specific TODO

Copy link
Contributor

Choose a reason for hiding this comment

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

make sure that this s3 bucket exists/if we need to make it manually or django will make it for us

22 changes: 10 additions & 12 deletions backend/market/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,30 @@ def has_permission(self, request, view):
return request.user.is_superuser


class SubletOwnerPermission(permissions.BasePermission):
class ItemOwnerPermission(permissions.BasePermission):
"""
Custom permission to allow the owner of a Sublet to edit or delete it.
Custom permission to allow the owner of a Item to edit or delete it.
"""

def has_permission(self, request, view):
return request.user.is_authenticated

def has_object_permission(self, request, view, obj):
# Check if the user is the owner of the Sublet.
if request.method in permissions.SAFE_METHODS:
return True
return obj.subletter == request.user
# Check if the user is the owner of the Item.
return request.method in permissions.SAFE_METHODS or obj.seller == request.user


class SubletImageOwnerPermission(permissions.BasePermission):
class ItemImageOwnerPermission(permissions.BasePermission):
"""
Custom permission to allow the owner of a SubletImage to edit or delete it.
Custom permission to allow the owner of a ItemImage to edit or delete it.
"""

def has_permission(self, request, view):
return request.user.is_authenticated

def has_object_permission(self, request, view, obj):
# Check if the user is the owner of the Sublet.
return request.method in permissions.SAFE_METHODS or obj.sublet.subletter == request.user
# Check if the user is the owner of the Item.
return request.method in permissions.SAFE_METHODS or obj.item.seller == request.user


class OfferOwnerPermission(permissions.BasePermission):
Expand All @@ -51,7 +49,7 @@ def has_permission(self, request, view):

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
# Check if the user owns the sublet when getting list
return obj.subletter == request.user
# Check if the user owns the item when getting list
return obj.seller == request.user
# This is redundant, here for safety
return obj.user == request.user
Loading
Loading