Django ViewSet, get data from model without foreign key - python

My Models
def ModelA(models.Model):
id = models.CharField(primary_key=True, max_length=50)
val_a = models.CharField(db_index=True, max_length=100)
val_b = models.CharField(db_index=True, max_length=100)
modelB = models.ForeignKey(modelB, on_delete=models.CASCADE, db_constraint=False)
def ModelB(models.Model):
id = models.CharField(primary_key=True, max_length=50)
val_c = models.CharField(db_index=True, max_length=100)
val_d = models.CharField(db_index=True, max_length=100)
def ModelC(PostgresModel):
id = models.CharField(primary_key=True, max_length=50)
val_e = models.CharField(db_index=True, max_length=100)
modelB = models.OneToOneField(ModelB, on_delete=models.CASCADE, null=False, blank=False)
My ViewSet
class ModelAViewSet(ListDataResponseMixin, APIKeyViewSet):
endpoint_permissions = [APILicenseKeyPermission.Codes.A]
queryset = ModelA.objects.all()
serializer_class = ModelASerializer
filterset_class = ModelAFilter
filter_backends = [DjangoFilterBackend]
My Serializer
class ModelASerializer(serializers.ModelSerializer):
class Meta:
model = ModelA
fields = (
"id",
"val_a",
"val_b"
)
When querying ModelA I would like to get val_e from ModelC. I am learning django, and previously when I needed to do something like this, I would use select_related, however, since there is no clear path from ModelA -> ModelC using foreign keys, I am not sure how to proceed. (My base models cannot change). How would I modify my ViewSet to include the needed ModelC data in my queryset? And then for my ModelASerializer I would like to just be able to add in val_e.

You can simply use a CharField, like this:
class ModelASerializer(serializers.ModelSerializer):
val_e = serializers.CharField(source='modelB.modelc.val_e')
class Meta:
model = ModelA
fields = (
"id",
"val_a",
"val_b",
"val_e"
)
This is possible because ModelA has a ForeignKey to ModelB and ModelB has One To One relation to ModelC. More information on source can be found in documentation.

Related

Django Restful framework post to create foreign key if not already exists

class ModelA(models.Model):
name = models.CharField(max_length=100)
code = models.CharField(max_length=100, default='')
class ModelB(models.Model):
name = models.CharField(max_length=100)
code = models.CharField(max_length=100, default='')
class ModelC(models.Model):
name = models.CharField(max_length=100)
modelA = models.ForeignKey(ModelA, on_delete=models.CASCADE)
modelB = models.ForeignKey(ModelB, on_delete=models.CASCADE)
These are the models.
class ModelASerializer(serializers.ModelSerializer):
class Meta:
model = ModelA
fields = "__all__"
class ModelBSerializer(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = "__all__"
class ModelC(serializers.ModelSerializer):
modelA = ModelASerializer()
modelB = ModelBSerializer()
class Meta:
model = ModelC
fields = "__all__"
These are my serializers.
Right now I have no problem with a GET request. What I want to achieve is that when I do a post request for ModelC and if ModelA and ModelB do not already exist then create them. Right now I am able to do post with existing modelA and modelB by removing the nested serializer.
Thanks for everyone's help.

Many to Many model with a dropdown in Django Rest Framework?

I am trying to create a Many to Many relation with a model in between, I have a Client model, and a Zone model, each client may have access to different zones, and each zone may have multiple clients.
Therefore I created a model called Access Permission, that stores said relation, and I want to show a dropdown selector in the post form that shows the existing clients and zones, or to ask for the Id of an existing object, instead of showing the form to create new ones.
These are my models:
class Zone(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class Client(models.Model):
name = models.TextField()
birthDate = models.DateField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class AccessPermission(models.Model):
idClient = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
idZone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
And these my current serializers:
class ZoneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Zone
fields = ('name',)
class ClientSerializer(serializers.HyperlinkedModelSerializer):
zones = ZonesSerializer(source='accesspermission_set', many=True, read_only=True)
class Meta:
model = Client
fields = ('name', 'birthDate', 'zones')
class AccessPermissionSerializer(serializers.ManyRelatedField):
idClient = ClientSerializer(many=False)
idZone = ZoneSerializer(many=False)
class Meta:
model = AccessPermission
fields = ('idClient', 'idZone')
Is there any way to ask for the Id of an existing object, or show the existing ones, instead of the fields to create new ones?
You can do it like:
models
class AccessPermission(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
zone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
serializers
class AccessPermissionSerializer(serializers.ManyRelatedField):
id = serializers.IntegerField(read_only=True)
client_id = serializers.PrimaryKeyRelatedField(
queryset=Client.objects.all(), source='client', allow_null=False, required=True
)
zone_id = serializers.PrimaryKeyRelatedField(
queryset=Zone.objects.all(), source='zone', allow_null=False, required=True
)
class Meta:
model = AccessPermission
fields = (
'id', 'client_id', 'zone_id'
)

Django Rest Framework M2M Through Model field not resolving

Here are my models
# Models
class Category(models.Model):
parent = models.ForeignKey('Category', null=True, blank=True, related_name="children")
name = models.CharField(max_length=64)
alternate_naming = models.ManyToManyField('businesses.Office', through='CategoryOfficeNaming', blank=True)
class CategoryOfficeNaming(models.Model):
category = models.ForeignKey('Category')
office = models.ForeignKey('businesses.Office')
name = models.CharField(max_length=64)
And here are my serializers
# Serializers
class CategoryOfficeNamingSerializer(serializers.ModelSerializer):
class Meta:
model = CategoryOfficeNaming
fields = (
'office',
'name',
)
class CategorySerializer(serializers.ModelSerializer):
# We need special recursive serialization here for Category (parent) -> Category (child) relationship
children = serializers.ListSerializer(read_only=True, child=RecursiveField())
alternate_naming = CategoryOfficeNamingSerializer(many=True)
class Meta:
model = Category
fields = (
'children',
'name',
'alternate_naming',
)
I get an error when trying serialize a Category:
AttributeError at /api/categories/
'Office' object has no attribute 'category'
It seems like the Serializer (alternate_naming) points to an Office instance instead of using the through model (CategoryOfficeNaming) -- why is that? I'm probably doing something silly!
A, ha!
It turns out I was misunderstanding when to use through tables a bit. Instead of using a through table, I ended up with this structure and I got something that works for this situation:
Models:
# Models
class Category(models.Model):
parent = models.ForeignKey('Category', null=True, blank=True, related_name="children")
name = models.CharField(max_length=64)
class CategoryOfficeNaming(models.Model):
category = models.ForeignKey('Category', related_name="alternate_namings")
office = models.ForeignKey('businesses.Office')
name = models.CharField(max_length=64)
Serializers:
# Serializers
class CategoryOfficeNamingSerializer(serializers.ModelSerializer):
class Meta:
model = CategoryOfficeNaming
fields = (
'office',
'name',
)
class CategorySerializer(serializers.ModelSerializer):
# We need special recursive serialization here for Category (parent) -> Category (child) relationship
children = serializers.ListSerializer(read_only=True, child=RecursiveField())
alternate_namings = CategoryOfficeNamingSerializer(many=True)
class Meta:
model = Category
fields = (
'children',
'name',
'alternate_namings',
)

Django's double-underscore notation not working here

I have combined these two answers: one and two In the attempt to select only certain fields from nested objects without any success at all, the result is returning ALL fields from all tables.
serializers:
class NameTestTypeSerializer(serializers.ModelSerializer):
class Meta:
model = TestTypeModel
fields = 'name'
class ExecutedTestSerializer(serializers.ModelSerializer):
test_type = NameTestTypeSerializer
class Meta:
model = ExecutedTestModel
fields = ('id', 'result', 'test_type')
depth = 1
models:
class TestTypeModel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(null=False, max_length=255, unique=True)
........
class Meta:
db_table = 'TestType'
class ExecutedTestModel(models.Model):
id = models.AutoField(primary_key=True)
test_type = models.ForeignKey(TestTypeModel, to_field='id')
result = models.IntegerField(null=False)
class Meta:
db_table = 'ExecutedTest'
viewset:
class ExecutedTestViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticatedOrReadOnly,)
serializer_class = ExecutedTestSerializer
def get_queryset(self):
queryset = ExecutedTestModel.objects.all().select_related('test_type').defer('test_type__executable' )
return queryset
How did you check that executable is fetched? In django you can access deferred fields, they are loaded from db on demand.
I believe the problem isn't in underscore notation, instead it is in the definition of the serializers.

django rest serialize level 2 field

Hi I need to add a field in a serializer of a 2 level reference item.
I have the following model:
model.py:
class Company(models.Model):
companyName = models.CharField(max_length=50, blank=True)
class Poll(models.Model):
questionString = models.CharField(max_length=500, blank=True)
companyId = models.ForeignKey(Company, null=True, db_column='companyId', blank=True)
class PossibleAnswer(models.Model):
answerString = models.CharField(max_length=100, blank=True)
pollId = models.ForeignKey(Poll, null=True, db_column='pollId', blank=True,related_name='answers')
token = models.CharField(max_length=10, blank=True)
serializers.py:
class PossibleAnswerSerializer(serializers.ModelSerializer):
#companyId = serializers.RelatedField()
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I want to make a Serializer for the PossibleAnswer object that has a field named company. How to make a this reference? Something similar to: pollId__companyId in a django query set filter.
Another solution...
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.SerializerMethodField()
def get_companyId(self, obj):
return obj.pollId.companyId
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId',)
I the field is read-only you can easily achieve this with a serializers.Field, which accept dotted paths to the source.
Your Serializer would be:
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.Field(source='pollId.companyId')
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I too agree with Erik, that naming model attributes with Id is a bad idea even though the DB representation is only the ID.

Categories

Resources