【发布时间】:2022-01-10 11:57:00
【问题描述】:
在 django 项目上工作时,我有点卡在通过 API 表示数据的问题上。事实上,在设计模型时,数据模型非常简单:我有一对多的关系 A--> B 因此我为对象 B 添加了一个 FK。
对象 B 有一个布尔属性“活动”。
我想进行 API 调用以列出所有具有至少一个关联对象 B 且 active = true 的 A 对象。
API 可能是这样的:
/api/objectA/?ObjectB.active=True
这是我的代码:
型号:
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver
class Startup(models.Model):
header = models.CharField("Header", max_length=255)
title = models.CharField("Title", max_length=255)
description = models.CharField("description", max_length=255)
# TODO Change this to options instead of array
tags = ArrayField(models.CharField(max_length=10, blank=True), size=5)
# TODO Images to be stored in aws only url will be in DB
card_image = models.ImageField(upload_to='media/images/cards')
logo_image = models.ImageField(upload_to='media/images/logos')
main_img = models.ImageField(upload_to='media/images/main', null=True)
createdAt = models.DateTimeField("Created At", auto_now_add=True)
def __str__(self):
return self.title
class Investment(models.Model):
# TODO change the name of Investment to fund round in back and front
# TODO all price to be checked for max digits and decimal places
startup = models.ForeignKey(Startup, related_name='startup_investments', on_delete=models.CASCADE, default="1")
# Use the related_name as a serializer bale for investments inside startup serializer
Investment_title = models.CharField("Investment_title", max_length=255, default="Missing Title")
collected_amount = models.DecimalField(max_digits=12, decimal_places=2)
goal_percentage = models.IntegerField(default=0)
number_of_investors = models.IntegerField(default=0)
days_left = models.IntegerField()
active = models.BooleanField(default=False)
# TODO Need to update this to prevent linking to a non existing startup
createdAt = models.DateTimeField("Created At", auto_now_add=True)
def clean(self):
"""Validate that the startup does not have already an active Investment """
if self.active:
qs = Investment.objects.filter(active=True).filter(startup=self.startup)
if self.pk is not None:
qs = qs.exclude(pk=self.pk)
if qs:
raise ValidationError(message="An active investment already exists for this startup")
def __str__(self):
return self.Investment_title
序列化器:
from rest_framework import serializers
from .models import Startup, Investment
class InvestmentSerializer(serializers.ModelSerializer):
class Meta:
model = Investment
fields = ('id', 'Investment_title', 'collected_amount', 'goal_percentage', 'number_of_investors',
'days_left', 'active')
class StartupSerializer(serializers.ModelSerializer):
startup_investments = InvestmentSerializer(many=True, read_only=True)
class Meta:
model = Startup
fields = ('id', 'header', 'title', 'description', 'tags', 'card_image',
'logo_image', 'main_img', 'startup_investments')
观看次数:
from django_filters import rest_framework as filters
from rest_framework.viewsets import ModelViewSet
from rest_framework_extensions.mixins import NestedViewSetMixin
from .serializers import *
class StartUpViewSet(NestedViewSetMixin, ModelViewSet):
"""
Class that provides List, Retrieve, Create, Update, Partial Update and Destroy actions for startups.
It also include a filter by startup status
"""
model = Startup
queryset = Startup.objects.all()
serializer_class = StartupSerializer
class InvestmentViewSet(NestedViewSetMixin, ModelViewSet):
"""
Class that provides List, Retrieve, Create, Update, Partial Update and Destroy actions for Investments.
It also include a active and investment title
"""
model = Investment
serializer_class = InvestmentSerializer
queryset = Investment.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filterset_fields = ('active', 'Investment_title')
路由器:
router = ExtendedSimpleRouter()
(
router.register(r'api/investments', views.InvestmentViewSet, basename='investment'),
router.register(r'api/startups', views.StartUpViewSet, basename='startup')
.register(r'investments', views.InvestmentViewSet, basename='startups_investment',
parents_query_lookups=['startup']),
)
感谢您的帮助。
【问题讨论】:
-
我猜你已经设置了一个 APIView 一个序列化器并且你正在处理一个查询集。在这种情况下,你必须使用对象 A 上的注释和组来创建一个查询集
-
感谢 marco by annotate 你的意思是添加一个动作? @动作?
-
不,我的意思是在视图中你必须设置一个 get_queryset 来查询你的模型,在查询中你必须使用一种叫做 annotate 的方法,在 Django 中也用于对某些数据进行分组字段..如果您发布一些代码,它会更容易修复
-
当然很抱歉应该早点这样做,我已经编辑了我的问题!
标签: django api django-rest-framework