How to perform query on one to many relations tables using ORM and define serializers for it? - django-models

data in request
city_name = 'Nashik'
tags = ['tag 1','tag 2', 'tag 3']
I try this
ws = WorkSamplesModel.objects.filter(business_account__serviceareasmodel__city_name=city_name,
business_account__professiontagsmodel__tag_name__in=tags_list,
is_business_card_image=True).distinct()
Now I want business_title ,business_description,status,note from BusinessAccountModel and
work_sample_image, work_sample_description, is_business_card_image from WorkSampleModel and
user_name,profile_pic from UserModel
how to create serializer for it?
models
I want to find a specific BusinessAccountModel using city_name and tags
and then one WorkSamplesModel for each BusinessAccountModel.
class BusinessAccountModel(models.Model):
business_title = models.CharField(max_length=70)
business_description = models.CharField(max_length=500)
status = models.CharField(max_length=100)
note = models.CharField(max_length=200)
user = models.OneToOneField(UserModel,on_delete=models.CASCADE)
class Meta:
db_table = 'wp_business_acc'
class ProfessionTagsModel(models.Model):
tag_name = models.CharField(max_length=20)
business_account = models.ForeignKey(BusinessAccountModel,on_delete=models.CASCADE)
class Meta:
db_table = 'profession_tags'
class ServiceAreasModel(models.Model):
city_name = models.CharField(max_length=20)
business_account = models.ForeignKey(BusinessAccountModel,on_delete=models.CASCADE)
class Meta:
db_table = 'service_areas'
class WorkSamplesModel(models.Model):
work_sample_image = models.ImageField(blank=True,null=True,upload_to="work_samples")
work_sample_description = models.CharField(max_length=1000)
is_business_card_image = models.BooleanField(default=False)
business_account = models.ForeignKey(BusinessAccountModel,on_delete=models.CASCADE)
class Meta:
db_table = 'work_samples'
BusinessAccountModel - ProfessionTagsModel : 1:M
BusinessAccountModel - ServiceAreasModel : 1:M
BusinessAccountModel - WorkSamplesModel : 1:M

ws = WorkSamplesModel.objects.filter(business_account__serviceareasmodel__city_name=city_name,
business_account__professiontagsmodel__tag_name__in=tags_list,
is_business_card_image=True).distinct()
Serializer for it
class SearchWorkingProgessionalsSerializers(serializers.Serializer):
business_title = serializers.CharField(source='business_account.business_title')
business_description = serializers.CharField(source='business_account.business_description')
status = serializers.CharField(source='business_account.status')
note = serializers.CharField(source='business_account.note')
work_sample_image = serializers.ImageField()
work_sample_description = serializers.CharField(max_length=1000)

Related

Django Post request for many to many field ValueError

I am working on a post request in which the user chooses from a list of tags and makes combinations of tags. The combination of tags should then be posted. Nothing should get changed in the Tag table.
These are the models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
"""Return a human readable representation of the model instance."""
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Combination(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, null=True)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, null=True)
tag_id = models.ManyToManyField(Tag, null=True)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
def __str__(self):
return str(self.tag_id) or ''
This is the serializer for Combination.
serializers.py
class CombinationSerializer(serializers.ModelSerializer):
tag_id = TagWithIdSerializer(many=True, required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Combination
depth = 1
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag_id', 'created', 'score')
def create(self, validated_data):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
score = 0
tag_data = validated_data.pop('tag_id', None)
combination = Combination(
user=user,
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
created=datetime.now(),
score=score
)
combination.save()
for tag_object in tag_data[0]:
combination.tag_id.add(tag_object)
return combination
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag_id'] = TagWithIdSerializer(instance.tag_id.all(), many=True).data
return rep
I have tried posting the following JSON object to the database:
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [{"id": 2014077506, "name": "corwn","language": "en"}]
}
I am getting a ValueError: Field 'id' expected a number but got 'name'.
How can I fix this issue?
you need to provide tag id for each tag not all tag data,
Try like this
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [2014077506,2014077507]
}

How do i access another column from related table other than the foreign key, when creating an API view

Im using django for a web app and i am creating REST API views. Is there a way i can access two tables in one view? If not, how can can i retrieve a non-foreign key column from a related record. The below code is retrieving a vase record based on a URL parameter. I want to access the artistName which is stored in artist table (a one-to-many with Vase table), not artist_id which is stored in Vase
class FilterVases(generics.ListAPIView):
serializer_class = VaseSerializer
def get_queryset(self):
queryset = Vase.objects.all()
artist_id = self.request.query_params.get('artist_id')
if artist_id is not None:
queryset = queryset.filter(artist_id=artist_id)
vaseID = self.request.query_params.get('vaseID')
if vaseID is not None:
queryset = queryset.filter(vaseID=vaseID)
return queryset
edited to add
This is models for Artist and Vase:
class Artist(models.Model) :
artistID = models.CharField(max_length=10)
artistName = models.CharField(max_length=100)
class Vase(models.Model):
vaseID = models.CharField(max_length=10)
vaseRef = models.CharField(max_length=255,blank=True,null=True)
inscription = models.CharField(max_length=255,blank=True,null=True)
fabric = models.CharField(max_length=100, blank=True,null=True)
subject = models.CharField(max_length=255,blank=True,null=True)
technique = models.CharField(max_length=100,blank=True,null=True)
height = models.FloatField(max_length=100,blank=True,null=True)
diameter = models.FloatField(max_length=100,blank=True,null=True)
shape = models.ForeignKey(Shape, on_delete=models.CASCADE)
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
provenance = models.ForeignKey(Provenance, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
In the Vase model add this:
def artist_name(self):
return self.artist.artistName
Hence, it will look like:
class Vase(models.Model):
vaseID = models.CharField(max_length=10)
vaseRef = models.CharField(max_length=255,blank=True,null=True)
inscription = models.CharField(max_length=255,blank=True,null=True)
fabric = models.CharField(max_length=100, blank=True,null=True)
subject = models.CharField(max_length=255,blank=True,null=True)
technique = models.CharField(max_length=100,blank=True,null=True)
height = models.FloatField(max_length=100,blank=True,null=True)
diameter = models.FloatField(max_length=100,blank=True,null=True)
shape = models.ForeignKey(Shape, on_delete=models.CASCADE)
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
provenance = models.ForeignKey(Provenance, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
def artist_name(self):
return self.artist.artistName
In the VaseSerializer add the 'artist_name' to the fields Meta.
If you want to add this custom fields to all Vase Model fields, refer to this topic Django Rest framework, how to include '__all__' fields and a related field in ModelSerializer ?
class VaseSerializer(serializers.ModelSerializer):
class Meta:
model = models.Vase
fields = '__all__'
extra_fields = ['artist_name']
def get_field_names(self, declared_fields, info):
expanded_fields = super(VaseSerializer, self).get_field_names(
declared_fields, info)
if getattr(self.Meta, 'extra_fields', None):
return expanded_fields + self.Meta.extra_fields
else:
return expanded_fields
Below should your view:
class FilterVases(generics.ListAPIView):
serializer_class = VaseSerializer
def get_queryset(self):
queryset = Vase.objects.all()
query_artist = self.request.query_params.get('artist_name')
if query_artist is not None:
try:
artist = Artist.objects.get(artistName=query_artist)
queryset = queryset.filter(artist=artist)
except:
pass
vaseID = self.request.query_params.get('vaseID')
if vaseID is not None:
queryset = queryset.filter(vaseID=vaseID)
return queryset

Django rest framework + multiple database + POST data

I'm preparing API and I'm using multiple database ("oracle" and "sqlserver").
I want to POST data (json) into sqlserver.
Here is part of my code.
models.py (every table is in sqlserver database)
class QtOfferParam(models.Model):
ext_id = models.IntegerField(primary_key=True)
dealer_code = models.CharField(max_length=10, db_column="dealer_code")
dealer_name = models.CharField(max_length=30, db_column="dealer_name")
dealer_user = models.CharField(max_length=30, db_column="dealer_user")
class Meta:
db_table = 'ZZ_QT_OFFER_PARAM'
class QtParameterValues(models.Model):
ext_id = models.ForeignKey(QtOfferParam, to_field="ext_id", db_column="ext_id", on_delete=models.PROTECT, related_name="parameterValues", primary_key=True)
parameter = models.CharField(max_length=200, null=True, db_column="parameter")
value_p = models.CharField(max_length=10, null=True, db_column="value_p")
class Meta:
db_table = 'ZZ_QT_PARAMETER_VALUE'
class QtOptions(models.Model):
ext_id = models.ForeignKey(QtOfferParam, to_field="ext_id", db_column="ext_id", on_delete=models.PROTECT, related_name="options", primary_key=True)
f_amount = models.FloatField(db_column="FINANCED_AMOUNT")
installment_amount = models.FloatField(db_column="INSTALLMENT_AMOUNT")
total_amount = models.FloatField(db_column="TOTAL_AMOUNT")
total_amount_in_percentage = models.FloatField(db_column="TOTAL_AMOUNT_IN_PERCENTAGE")
class Meta:
db_table = 'ZZ_QT_OPTIONS'
serializers.py (i added " using='sqlserver' ")
class ReqSerializer(serializers.HyperlinkedModelSerializer):
dealer = DealerField(source='*')
parameterValues = ParametersSgSerializer(many=True)
options = OptionsSgSerializer(many=True)
class Meta:
model = QtOfferParam
fields = ['ext_id', 'dealer', 'parameterValues', 'options']
def create(self, validated_data):
parameters_data = validated_data.pop('parameterValues')
options_data = validated_data.pop('options')
req_id = QtOfferParam.objects.using('sqlserver').create(**validated_data)
for parameters_data in parameters_data:
parameters_data['ext_id'] = req_id
QtParameterValues.objects.using('sqlserver').create(**parameters_data)
for options_data in options_data:
options_data['ext_id'] = req_id
QtOptions.objects.using('sqlserver').create(**options_data)
return req_id
views.py
class testView(viewsets.ModelViewSet):
queryset = QtOfferParam.objects.using('sqlserver').all()
serializer_class = ReqSerializer
when I GET data everything is OK. The data are from sql server, but if I try POST new json i get error from oracle database:
ORA-00942: table or view does not exist
Where i need to add database to save data in sqlserver?

Foreign key return object instead of integer

in "models.py"
class Run(models.Model):
number = models.IntegerField(choices=((int(x), x) for x in range(1, 50)))
type = models.CharField(max_length=10, choices=((str(x), x) for x in ['bit', 'casing']))
run_date = models.DateTimeField(default=timezone.now)
well = models.ForeignKey(Well, related_name='run', on_delete=models.CASCADE)
created_by = models.ForeignKey(User, related_name='run_created_by', null=True, on_delete=models.SET_NULL)
description = models.CharField(max_length=255)
class Meta:
verbose_name = "Run Information"
verbose_name_plural = "Run Information"
def __int__(self):
return self.number
class BitRun(models.Model):
number = models.PositiveSmallIntegerField(choices=((int(x), x) for x in range(1, 50)))
od = models.DecimalField(max_digits=5, decimal_places=3)
inner_diameter = models.DecimalField(max_digits=5, decimal_places=3)
tfa = models.DecimalField(max_digits=5, decimal_places=3)
bottom_depth = models.DecimalField(max_digits=7, decimal_places=2)
top_depth = models.DecimalField(max_digits=7, decimal_places=2)
run = models.ForeignKey(Run, related_name='bit_number', on_delete=models.CASCADE)
well = models.ForeignKey(Well, related_name='well_name', on_delete=models.CASCADE)
class Meta:
verbose_name = "Bit Record"
verbose_name_plural = "Bit Records"
in "admin.py"
class BitRunAdmin(admin.ModelAdmin):
ordering = ('number',)
list_display = ('well', 'run', 'od', 'tfa')
list_filter = ['well']
search_fields = ['well']
I see run object(1) instead of the actual fields value.
Can someone please point what i am doing wrong in the code?
Thank you
add __str__ representation for each model.
def __str__(self):
rerurn f"{self.field_name}"
field_name must be the name of field you want to see.

ndb badrequesterror only in production

I get the following error only on production: BadRequestError: BLOB, ENITY_PROTO or TEXT properties must be in a raw_property field
It happens when I put() a instance of the Receipt class (extends ndb.Model)
Below, I attach the model and the handler where the code breaks (only in production)
class Receipt(RModel):
ownerId = ndb.IntegerProperty()
houseId = ndb.IntegerProperty()
renterId = ndb.IntegerProperty()
year = ndb.IntegerProperty()
month_number = ndb.IntegerProperty()
code = ndb.StringProperty()
description = ndb.StringProperty()
value = ndb.StringProperty()
owner = ndb.ComputedProperty(lambda self: Owner.get_by_id(self.ownerId))
house = ndb.ComputedProperty(lambda self: House.get_by_id(self.houseId))
renter = ndb.ComputedProperty(lambda self: Renter.get_by_id(self.renterId))
month = ndb.ComputedProperty(lambda self: month_number_to_string(self.month_number))
class RModel(ndb.Model):
created = ndb.DateTimeProperty(auto_now_add = True)
changed = ndb.DateTimeProperty(auto_now_add = True)
creatorId = ndb.IntegerProperty()
changerId = ndb.IntegerProperty()
#def to_dict(self):
# return ndb.to_dict(self, {'id':self.key().id()})
def set_attributes(self, **attrs):
props = self.properties()
for prop in props.values():
if prop.name in attrs:
prop.__set__(self, attrs[prop.name])
class ReceiptNew(BaseHandler):
def Get(self):
user_id = self.get_user_id()
owner = Owner.get_by_id(user_id)
receipt = Receipt(value="")
houses = list(House.gql("where ownerId = :1", owner.key.id()))
renters = list(Renter.gql("where ownerId = :1", owner.key.id()))
context = {'receipt': receipt, 'houses': houses, 'renters': renters, 'new': True}
self.render_response('receipt-edit.html', **context)
def post(self):
user_id = self.get_user_id()
owner = Owner.get_by_id(user_id)
data = {
'year': self.request.get('year'),
'month': self.request.get('month'),
'house': self.request.get('house'),
'renter': self.request.get('renter'),
'value': self.request.get('value'),
'paid': self.request.get('paid')
}
receipt = Receipt()
receipt.year = int(data.get('year'))
receipt.month_number = int(data.get('month'))
receipt.houseId = int(data.get('house'))
receipt.renterId = int(data.get('renter'))
receipt.value = data.get('value')
receipt.ownerId = owner.key.id()
receipt.put() ##### CODE BREAKS HERE, ONLY IN PRODUCTION
self.redirect('/receipts')
You can't use ComputedProperty to store an entire entity, you need to use KeyProperty.

Resources