Добавление портфолио в тестовом виде

This commit is contained in:
VladislavOstapov 2023-04-04 23:35:51 +03:00
parent f200ec0bef
commit 9982c3b529
4 changed files with 122 additions and 13 deletions

View File

@ -37,6 +37,14 @@ class AccessTokenAdmin(admin.ModelAdmin):
class OrderAdmin(admin.ModelAdmin):
list_display = ['owner', 'phone', 'name', 'create_time', 'moderated', 'published']
readonly_fields = ['create_time']
@admin.register(Portfolio)
class PortfolioAdmin(admin.ModelAdmin):
list_display = ['id', 'account', 'title', 'actual_date', 'actual_price']
readonly_fields = ['actual_date', 'actual_price']
#
#
# @admin.register(OrderImage)

View File

@ -74,16 +74,14 @@ def __make_error(ex: Exception):
def make_error_object(ex: Exception | list):
try:
data = {
"status": "error"
}
if type(ex) == list:
data["error"] = {
"status": "error",
"error": {
"code": API_ERROR_MULTIPLY_ERRORS[0],
"message": API_ERROR_MULTIPLY_ERRORS[1],
} if type(ex) == list else __make_error(ex)
}
if type(ex) == list:
data["related"] = [__make_error(e) for e in ex]
else:
data["error"] = __make_error(ex)
return data
except BaseException as err:

View File

@ -1,4 +1,8 @@
import random
import time
from datetime import date as dt
import traceback
from .api_media_utils import *
from .api_utils import *
from .models import *
@ -39,7 +43,7 @@ class ApiAccount:
return True
@staticmethod
def __make_user_json(user: Account, self_using=False):
def make_user_json(user: Account, self_using=False):
obj = {
"id": user.id,
"name": user.name,
@ -165,7 +169,7 @@ class ApiAccount:
if user is None:
return make_error_object(Exception(API_ERROR_NOT_FOUND, {"user": user_id}))
return api_make_response(ApiAccount.__make_user_json(user))
return api_make_response(ApiAccount.make_user_json(user))
@staticmethod
@api_method("account.edit",
@ -281,7 +285,7 @@ class ApiAccount:
await sync_to_async(user.executoraccount.save)()
return api_make_response(ApiAccount.__make_user_json(user))
return api_make_response(ApiAccount.make_user_json(user))
@staticmethod
@api_method("account.changePhone",
@ -801,6 +805,78 @@ class ApiMedia:
return api_make_response(res)
class ApiPortfolio:
# portfel.get(user_id=None, portfel_id=None, count=20, offset=0, order_by={date,-date, .... })
# portfel.create(поля портфолио)
# portfel.delete(portfel_id)
@staticmethod
@api_method("portfolio.create",
doc="Создания объекта портфолио",
params=[
ApiParamAccessToken(),
ApiParamStr(name="title", min_length=5, max_length=200,
description="Название выполненного заказа, 5-200 символов"),
ApiParamInt(name="date", required=False,
description="Дата в формате UNIX time, потом будет нормальный объект даты,"
"если не передать то будет вставлена текущая дата"),
ApiParamFloat(name="price", description="Цена заказа, актуальная на момент выполнения")
], returns="<code>id</code> созданного объекта")
async def create(access_token, title, date, price):
# проверка на роль, нужна сразу
if access_token.user.role != Account.ROLE_EXECUTOR:
raise Exception(API_ERROR_NOT_ALLOWED, "you must have executor role")
try:
p = await Portfolio.objects.acreate(account=access_token.user, title=title, actual_price=price,
actual_date=(dt.fromtimestamp(date) if date is not None else None))
return api_make_response({"portfolio_id": p.id})
except Exception:
traceback.print_exc()
raise Exception(API_ERROR_INTERNAL_ERROR)
@staticmethod
@api_method("portfolio.get",
doc="Получение портфолио или ленты портфолио",
params=[
ApiParamAccessToken(),
ApiParamInt(name="owner_id", required=False, value_min=0, default=None,
description="ID пользователя, портфолио которого нужно вернуть."),
ApiParamInt(name="portfolio_id", required=False, value_min=0, default=None,
description="ID портфолио, которое нужно вернуть."),
ApiParamInt(name="count", required=False, value_min=1, value_max=100, default=20,
description="Количество объектов, по умолчанию 20"),
ApiParamInt(name="offset", required=False, value_min=0, default=0,
description="Количество объектов")
], returns="")
async def get(access_token, owner_id, portfolio_id, count, offset):
res = Portfolio.objects.order_by('actual_date')
res = res.select_related('account', 'account__accountavatar', 'account__accountavatar__photo',
'account__accountavatar__profile_background',
'account__executoraccount')
if owner_id is not None:
res = res.filter(account_id=owner_id)
if portfolio_id is not None:
res = res.filter(id=portfolio_id)
res = res[offset:offset + count]
# выполняем fetch
objects = [{
"owner": ApiAccount.make_user_json(item.account),
"id": item.id,
"title": item.title,
"actual_date": int(time.mktime(item.actual_date.timetuple())),
"actual_price": item.actual_price,
"photos": [random.randint(1, 10) for _ in range(random.randint(1, 5))]
} async for item in res]
return api_make_response(objects)
class DatabaseApi:
# TODO переместить сюда форму заказа, список городов
# def get_order_form

View File

@ -402,6 +402,33 @@ class Order(models.Model):
else:
return q[0]
class Portfolio(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name="Аккаунт")
title = models.CharField(max_length=200, verbose_name="Название")
actual_date = models.DateField(verbose_name="Дата выполнения", default=datetime.now)
actual_price = models.DecimalField(max_digits=12, decimal_places=2, blank=False, verbose_name="Цена")
def __str__(self):
return f"{self.id}: \"{self.title}\""
class PortfolioPhoto(models.Model):
portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE, verbose_name="Портфолио")
photo = models.ForeignKey(Media, on_delete=models.SET_NULL, null=True, verbose_name="Аватар")
is_preview = models.BooleanField(verbose_name="Это главная фотография")
class Meta:
constraints = [
models.UniqueConstraint(
fields=['portfolio', 'photo'], name='unique_portfoliophoto_photo'
)
]
# TODO добавить проверку того, чтобы нельзя было приложить медиа другого юзера
# def _upload_image_filename(instance, filename):
# name, ext = os.path.splitext(filename)
# fn = sha256((str(datetime.now()) + name).encode('utf-8')).hexdigest() + ext