定义初始对象的 Django 序列化程序
Django Serializer defining initial object
我似乎无法弄清楚如何将初始值传递给序列化程序。我有一个多租户 django 站点,现在我正在尝试设置 API。客户端字段存在但需要隐藏且只读。我认为这就像传统 django 中的表单和视图一样工作。我通常会在视图中传递 get_initial 。我先试过了,但没用。我想我需要直接在序列化器中获取值,但我似乎无法让它工作。
型号:
class Location(ClientAwareModel):
name = models.CharField(max_length=64, blank=True)
address = models.CharField(max_length=64)
address2 = models.CharField(max_length=64, blank=True)
city = models.CharField(max_length=64)
state = USStateField()
zip_code = USZipCodeField()
class Client(models.Model):
name = models.CharField(max_length=100)
subdomain_prefix = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class ClientAwareModel(models.Model):
client = models.ForeignKey(Client, on_delete=models.PROTECT)
class Meta:
abstract = True
def hostname_from_request(request):
# split on `:` to remove port
return request.get_host().split(':')[0].lower()
def client_from_request(request):
hostname = hostname_from_request(request)
subdomain_prefix = hostname.split('.')[0]
return Client.objects.filter(subdomain_prefix=subdomain_prefix).first()
序列化器(你可以看到我所有失败的尝试都被注释掉了:
class LocationSerializer(serializers.ModelSerializer):
def get_client(self, obj):
# return client_from_request(self.request)
return client_from_request(self.context['request'])
# client = serializers.SerializerMethodField('get_client')
# client = serializers.SerializerMethodField()
# client = serializers.Field(source='get_client', read_only=True)
# client = serializers.ReadOnlyField(source='get_client')
# client = serializers.PrimaryKeyRelatedField(read_only=True, default='get_client')
client = serializers.PrimaryKeyRelatedField(read_only=True, source='get_client')
# client = serializers.HiddenField(default=get_client(self))
class Meta:
model = Location
fields = ['name', 'address', 'address2', 'city', 'state', 'zip_code', 'client']
视图集:
class LocationViewSet(viewsets.ModelViewSet):
queryset = Location.objects.all()
serializer_class = LocationSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client)
你可以看到我尝试传递值的不同方式,但无论我做什么我都得到
IntegrityError at /locations/
null value in column "client_id" violates not-null constraint
在您的视图集中,当您的 Location 模型没有 Client FK 时,您正试图通过过滤 Client 来获取 Location。
就在这里:
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client) <----
正如@gregory 在上面的评论中提到的,添加外键可以解决您的问题,然后您只需将其添加到您的序列化程序即可。
将 client
对象传递给序列化程序的一种简单方法是在 perform_create
方法中传递它,例如:
from rest_framework import serializers
class LocationViewSet(viewsets.ModelViewSet):
queryset = Location.objects.all()
serializer_class = LocationSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client)
def perform_create(self, serializer):
client = client_from_request(self.request)
if not client:
raise serializers.ValidationError("Client does not exist")
serializer.save(client=client)
并从序列化程序中删除客户端字段:
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = ['name', 'address', 'address2', 'city', 'state', 'zip_code']
我似乎无法弄清楚如何将初始值传递给序列化程序。我有一个多租户 django 站点,现在我正在尝试设置 API。客户端字段存在但需要隐藏且只读。我认为这就像传统 django 中的表单和视图一样工作。我通常会在视图中传递 get_initial 。我先试过了,但没用。我想我需要直接在序列化器中获取值,但我似乎无法让它工作。
型号:
class Location(ClientAwareModel):
name = models.CharField(max_length=64, blank=True)
address = models.CharField(max_length=64)
address2 = models.CharField(max_length=64, blank=True)
city = models.CharField(max_length=64)
state = USStateField()
zip_code = USZipCodeField()
class Client(models.Model):
name = models.CharField(max_length=100)
subdomain_prefix = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class ClientAwareModel(models.Model):
client = models.ForeignKey(Client, on_delete=models.PROTECT)
class Meta:
abstract = True
def hostname_from_request(request):
# split on `:` to remove port
return request.get_host().split(':')[0].lower()
def client_from_request(request):
hostname = hostname_from_request(request)
subdomain_prefix = hostname.split('.')[0]
return Client.objects.filter(subdomain_prefix=subdomain_prefix).first()
序列化器(你可以看到我所有失败的尝试都被注释掉了:
class LocationSerializer(serializers.ModelSerializer):
def get_client(self, obj):
# return client_from_request(self.request)
return client_from_request(self.context['request'])
# client = serializers.SerializerMethodField('get_client')
# client = serializers.SerializerMethodField()
# client = serializers.Field(source='get_client', read_only=True)
# client = serializers.ReadOnlyField(source='get_client')
# client = serializers.PrimaryKeyRelatedField(read_only=True, default='get_client')
client = serializers.PrimaryKeyRelatedField(read_only=True, source='get_client')
# client = serializers.HiddenField(default=get_client(self))
class Meta:
model = Location
fields = ['name', 'address', 'address2', 'city', 'state', 'zip_code', 'client']
视图集:
class LocationViewSet(viewsets.ModelViewSet):
queryset = Location.objects.all()
serializer_class = LocationSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client)
你可以看到我尝试传递值的不同方式,但无论我做什么我都得到
IntegrityError at /locations/
null value in column "client_id" violates not-null constraint
在您的视图集中,当您的 Location 模型没有 Client FK 时,您正试图通过过滤 Client 来获取 Location。
就在这里:
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client) <----
正如@gregory 在上面的评论中提到的,添加外键可以解决您的问题,然后您只需将其添加到您的序列化程序即可。
将 client
对象传递给序列化程序的一种简单方法是在 perform_create
方法中传递它,例如:
from rest_framework import serializers
class LocationViewSet(viewsets.ModelViewSet):
queryset = Location.objects.all()
serializer_class = LocationSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
client = client_from_request(self.request)
return super().get_queryset().filter(client=client)
def perform_create(self, serializer):
client = client_from_request(self.request)
if not client:
raise serializers.ValidationError("Client does not exist")
serializer.save(client=client)
并从序列化程序中删除客户端字段:
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = ['name', 'address', 'address2', 'city', 'state', 'zip_code']