Issue
I'm using multiple databases.
And every database has the same models.
for example there is a concrete model A
class AModel(models.Model):
name = models.CharField("A name", max_length=10, unique=True)
and a drf ModelSerializer
class AModelSerializer(serilaizers.ModelSerializer):
class Meta:
model = AModel # from above
fields = ['name']
And a proxy model which has a custom manager which uses a specific database
class CustomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().using("test")
class ProxyModel(AModel):
objects = CustomManager()
class Meta:
proxy = True
and even if I dynamically change ModelSerializer's Meta.model to ProxyModel in init, name field's UniqueValidator queryset still refers to A.objects.all() not A.objects.using('test')
What I figured out is ModelSerializer only refers concrete model fields, the model it is defined and their model's default manager, which in turn AModel.name, AModel and AModel's default manager in this case.
Actually I solved it before using defining concrete models from an abstract model for each databases. and then set ModelSerializer model to abstract class, and then change ModelSerializer's Meta.model to a concrete model. So as I told it refers correct concrete model.
but it seems error prone cause some of the code should be hard coded. and I hope to solve this problem more generically.
Give me any idea.
and if i found a solution. I'll share it to here.
Solution
I solved the problem with customizing a ModelSerializer.
from rest_framework import serializers, validators
from rest_framework.fields import empty
from rest_framework.relations import PrimaryKeyRelatedField
class GlobalModelSerializer(serializers.ModelSerializer):
site = serializers.CharField(source="_state.db", read_only=True)
queryset = None
def __init__(self, instance=None, data=empty, **kwargs):
super().__init__(instance=instance, data=data, **kwargs)
if data is empty:
return
site = data.get("site") or instance._state.db
self.queryset = self.Meta.model.objects.using("test")
for field in self.fields.values():
if type(field) in [PrimaryKeyRelatedField]:
field.queryset = field.queryset.using(site)
continue
for validator in field.validators:
if type(validator) not in [validators.UniqueValidator]:
continue
validator.queryset = validator.queryset.using(site)
The concept is straightforward but may have a potential issue. Before validators' queryset is being queried, change it to something I want.
Answered By - Amugae
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.