Django Rest Framework many to many with extra fields serialization - django

class Item(models.Model):
name = models.CharField(max_length=20)
class Meals(models.Model):
name = models.CharField(max_length=50)
ingredients = models.ManyToManyField(Item, through='MealRecipe')
class Menu(models.Model):
name = models.CharField(max_length=50)
meals = models.ManyToManyField(Meals,through='CompMenu')
class CompMenu(models.Model):
TYPE_COMP = (
('B', 'Breakfast'),
('L', 'Lunch'),
('D', 'Dinner')
)
menu = models.ForeignKey(Menu)
meal = models.ForeignKey(Meals)
type = models.CharField(max_length=1, choices=TYPE_COMP)
class MealRecipe(models.Model):
meal = models.ForeignKey(Meal)
item = models.ForeignKey(Item)
qty = models.IntegerField()
If i need to serialze queryset how can i do it, there is no documentation about it, i need a JSON with Item_id, Item_name, MealRecipe_qty. Do i have to serialze all models ? I need this to manipualte the recipe quantities on the front end based on the selected menu.
receipes = MealRecipe.objects.filter(meal__in=meals_of_menu)
for receipe in receipes:
name = receipe.item.name
qty = receipe.qty
OR
MealRecipe.objects.filter(meal__menu=some_menu_instance).distinct()
I cannot figure out how to pass the result o this query to the front end

For your requirements of Item_id, Item_name, MealRecipe_qty, you will need to serialize the MealRecipe model and the Item model.
Also give a related name to item in MealRecipe model
class MealRecipe(models.Model):
meal = models.ForeignKey(Meal)
item = models.ForeignKey(Item,related_name='qty')
qty = models.IntegerField()
And your serializers will be
class MealRecipeSerializer(serializers.ModelSerializer):
class Meta:
model = MealRecipe
fields = ('qty')
class ItemSerializer(serializers.ModelSerializer):
qty = MealRecipeSerializer()
class Meta:
model = Item
fields = ('id','name','qty')
Also if you are passing a queryset to a serializer do it as, MealRecipeSerializer(many=True)

Related

How to fix "the `.create()` method does not support writable nested fields by default" in Django API

I have a problem with creating new ratings for cars.
When i try to send a post request from Postman in order to create/add a new rating for a specific car i get the error:
The `.create()` method does not support writable nested fields by default.
These are my models:
class Car(models.Model):
name = models.CharField(max_length=50)
symbol = models.CharField(max_length = 5)
def __str__(self):
return self.name
class Type(models.Model):
name = models.CharField(max_length = 50)
fuel = models.CharField(max_length = 1)##1 or 2 for fuel type
car = models.ManyToManyField(Car)
def __str__(self):
return self.name
class Rating(models.Model):
rating = models.IntegerField(validators=[
MaxValueValidator(10),
MinValueValidator(0)
])
car = models.ForeignKey(Car, on_delete=models.CASCADE)
type = models.ForeignKey(Type, on_delete=models.CASCADE)
def __int__(self):
return self.rating
My serializers:
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
fields = ('id','name')
class TypeSerializer(serializers.ModelSerializer):
car = CarSerializer(many=True)
class Meta:
model = Type
fields = ('id','name', 'fuel', 'car')
#depth=2
class RatingSerializer(serializers.ModelSerializer):
type = TypeSerializer()
class Meta:
model = Rating
fields = ('id','rating', 'car', 'type')
def create(self, validated_data):
type_data = validated_data.pop('type')
rating = Rating.objects.create(**validated_data)
for t_data in type_data:
Type.objects.create(rating=rating, **t_data)
return rating
When i try to do a post request to rating such as :
{"rating":5, "car": 2,"type":{"id":1,"name":"OffRoad","fuel":"1","car":[{"id":2,"name":"Ford"}] } }
I get:
The `.create()` method does not support writable nested fields by default.
Please help if you can, ive been trying to fix this all day. Thank you!

Django Rest Framework get attributes from foreign key's class

here's my models:
class Recruteur(models.Model):
entrepriseName = models.CharField(max_length=50)
emplacement = models.CharField(max_length=50)
class Offre(models.Model):
title = models.CharField(max_length=100, blank=True, default=0)
idRecruteur = models.ForeignKey(Recruteur,verbose_name = "idRecruteur", on_delete=models.CASCADE, default=None)
and here's my api.py:
class VilleViewSet(ModelViewSet):
queryset = Offre.objects.values('idRecruteur__emplacement').distinct()
serializer_class = VilleSerializer
serializers.py:
class EmplacementSerializer(serializers.ModelSerializer):
class Meta:
model = Recruteur
fields = ('emplacement',)
class VilleSerializer(serializers.ModelSerializer):
emplacements = EmplacementSerializer(source='idRecruteur', read_only=True)
class Meta:
model = Offre
fields = ( 'emplacements',)
i was expecting a result like this
but i got nothing instead ..
Any ideas why?
You get nothing, because there is no emplacements field in Offre model. I guess, what you want is to get serialized Recruteur record, that is referenced by idRecruteur field. Try this:
class VilleSerializer(serializers.ModelSerializer):
idRecruteur = EmplacementSerializer(read_only=True)
class Meta:
model = Offre
fields = ( 'idRecruteur',)

Fetch data from multiple tables in django views

In Django views, I want to fetch all details(Workeraccount.location,Workeravail.date, Workerprofile.*) for any particular wid=1.
SQL Query:
select * from Workeraccount,Workeravail,Workerprofile where Workerprofile.wid=1 and Workerprofile.wid=Workeravail.wid and Workeraccount.wid=Workerprofile.wid;
The corresponding models are as follows:
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True)
location = models.ForeignKey(Location, db_column='location')
class Meta:
managed = False
db_table = 'workerAccount'
class Workeravail(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid')
date = models.DateField()
class Meta:
managed = False
db_table = 'workerAvail'
class Workerprofile(models.Model):
wid = models.SmallIntegerField(primary_key=True)
fname = models.CharField(max_length=30)
mname = models.CharField(max_length=30, blank=True, null=True)
lname = models.CharField(max_length=30)
gender = models.CharField(max_length=1)
age = models.IntegerField()
class Meta:
managed = False
db_table = 'workerProfile'`
You can do this:
workprofile = Workerprofile.objects.filter(id=1).first()
all_worker_avails = workprofile.workeravail_set.all()
all_workeraccounts = workprofile.workeraccount_set.all()
As Workeraccount and Workeravail are related through Workerprofile, you can get one queryset easily - you will need two separate ones.
You can also do the following:
all_worker_avails = Workeravail.objects.filter(wid=workprofile)
...
Here is how you can do it with only one database call:
workprofile = Workerprofile.objects.get(pk=1)
.select_related('workeravail_set', 'workerprofile_set')
This will fetch all the data for you at once, which can then be used with:
workprofile.workerprofile_set.location #Gets the Workeraccount.location
workprofile.workeravail_set.date #Gets the Workeravail.date
workprofile.fname #Example of Workerprofile.*
As an aside, if you want a shorter way to reference the foreign objects than the "*_set" method, you can set a related_name like
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True, related_name='waccount')
...
And then replace workeraccount_set with waccount

Relation in Django REST Framework?

I am using serializers.GeoFeatureModelSerializer to serialize Model. I have a queryset
that is creating Left Outer Join. I want to serialize related Model fields
Here is my Model
class LookupTiming(models.Model):
day = models.CharField(max_length=7)
time_1 = models.TimeField()
time_2 = models.TimeField()
class Meta:
db_table = u'lookup_timing'
class Streets(models.Model):
name = models.CharField(max_length=50)
geometry = models.GeometryField(null=True, blank=True)
objects = models.GeoManager()
class Meta:
db_table = u'streets'
def __unicode__(self):
return '%s' % self.name
class StreetTimings(models.Model):
street= models.ForeignKey(Streets)
lookuptiming = models.ForeignKey(LookupTiming)
class Meta:
db_table = u'street_timings'
queryset =
Streets.objects.filter(streettimings_lookuptiming_isnull=True)
Serializer Class
class StreetSerializer(gis_serializer.GeoFeatureModelSerializer):
class Meta:
model = Streets
geo_field = "geometry"
id_field = False
fields = ('id', 'streettimings__lookuptiming__day', other fields)
Updated
I want to show following fields on response
Streets (id)
LookupTiming (day)
I want output like this query simple is that
SELECT "streets"."id", "lookuptiming"."day" FROM "streets"
LEFT OUTER JOIN "streettimings" ON ( "streets"."id" = "streettimings"."street_id" )
LEFT OUTER JOIN "lookuptiming" ON ( "streettimings"."lookuptiming_id" = "lookuptiming"."id" )
How can i do this?
Thank you

django accessing foreign key in model

i have the following models
class SchoolClass(models.Model):
id = models.AutoField(primary_key = True)
class_name = models.TextField()
level = models.IntegerField()
taught_by = models.ManyToManyField(User,related_name="teacher_teaching",through='TeachSubject')
attended_by = models.ManyToManyField(User,related_name='student_attending')
def __unicode__(self):
return self.class_name
class Meta:
db_table = 'classes'
class Relationship(models.Model):
rChoices = (
(1,'Mother'),
(2,'Father'),
(3,'Guardian'),
)
parent = models.ForeignKey(User,related_name='parent')
student = models.ForeignKey(User,related_name='child')
relationship = models.IntegerField(choices= rChoices)
#add in __unicode__ for admin name
class Meta:
unique_together = ('parent','student')
db_table = 'relationship
I have the the pk of the class, and I want to find out who are the parents of the students in the selected class.
My feeble attempt is:
selected_class = SchoolClass.objects.get(pk=class_id)
studs = selected_class.attended_by.all().select_related()
r = Relationship.objects.filter(student__in=students)
parents = [.parent for p in r]
Now, I am just curious if there is a shorter or more efficient way of doing this(i'm sure missed something in the docs) ?
This should work
parents = Relationship.objects.filter(student__schoolclass__id=class_id).values_list('parent', flat=True)
"To refer to a "reverse" relationship, just use the lowercase name of the model". (docs)