Django Rest Framework / Angular - Serialization - django

I have simple models like:
class Car(models.Model):
name = models.CharField()
type = models.ForeignKey(CarTypes)
class CarTypes(models.Model):
type_name = models.CharField()
and serializers:
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
depth = 1
class CarTypeSerializer(serializers.ModelSerializer):
class Meta:
model = CarType
DRF send list of all Car Types to my frontend/angular app which looks like:
car_types = [
{
'id': 1,
'type_name': 'Sedan'
},
{
'id': 2,
'type_name': 'Hatchback'
}
]
I am using Car data in angular form i.e administrator would like to change data about car
<form>
<input ng-model="car.name" type="text" />
<select ng-model="car.type"
ng-options="type.type_name for type in car_types track by type.id"
name="car_type">
</select>
</form>
After submit this form angular send POST to django app which looks like:
{
'id': 1,
'name': 'Audi',
'type': {
'id': 1,
'type_name': 'Sedan'
}
}
PROBLEM
This is case when i am updating Car data.
If i change car type in selectbox my DRF serializer will change name from Sedan to i.e Hatchback instead of ascribe whole object. So Car Type Sedan will be destroyed and replaced.
New Car types will looks like:
car_types = [
{
'id': 1,
'type_name': 'Hatchback'
},
{
'id': 2,
'type_name': 'Hatchback'
}
]
(Angular send correct dict with id and name. DRF accessing only name instead of id and name to car.type)
QUESTIONS
How should I serialize and deserialize data with FK ? As a PrimaryKey then in angular connect those Primary Keys with names ? I like using depth options because i received whole dict
Maybe there is function in DRF to change data before validation which allow me to change received DICT to PK ?

Related

create a django serializer to create three model instance at once

{
"product_name": "CRVRVgfhghg",
"product_price": "0.01",
"product_location": "KIKUYU,KENYA",
"product_description": "VFVFVFVFVFVF",
"product_category_name": "livestock",
"product_farmer_name": "james",
"product_category_data": {
"product_category_name": "livestock",
"product_category_description": "livestock one"
},
"product_product_file_data": {
"product_file_name": "ok"
}
}
i have three tables: product_category,product and product_product_files...what i want is to populate all the three tables at once using one view and url pattern... is there a way i can do this using serializers??
I think what you are looking for is the following documentation DRF writable nested serializers.
Looking at this you'll see that they state the following:
'By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create create() and/or update() methods in order to explicitly specify how the child relationships should be saved:'
This is the example they use:
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ['order', 'title', 'duration']
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
The data they put in then should look like this:
data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
Looking at your code-snippet I would guess these models are related in a One-to-one relationship. In this case many=False which is also the default. You could do that for both models.
I think you would be able to get to the right code with this information, if not please let me know.

Chain filtering with OR operator in the filterset - Django Rest Framework

I want to use multiple filter fields together in the filterset class which I can populate in the browsable api and make queries with OR condition. For example:
SELECT name
FROM Person
WHERE age > 17 OR address LIKE ‘%New%’
I wonder how to implement something like this as HTML controls (filterset form) in the browsable API :
f = Q(age__gt=17) | Q(address__contains='New')
qs = qs.filter(f)
This is my actual filter:
class PersonFilter(filters.FilterSet):
class Meta:
model = Person
fields = {
'name': ['exact', 'icontains'],
'age': ['gt', 'lt'],
'address': ['icontains'],
}

How to save ProductAttributesValues in Django Oscar Commerce

I'm trying to save m2m relation in Product model on Django Oscar Commerce package, the model has an many to many relation through the ProductAttributeValues model.
Making Postan POST method query to url 127.0.0.1:8000/api/products/1/update/
serializers.py:
class ProductAttributeValueSerializer(OscarModelSerializer):
class Meta:
model = ProductAttributeValue
fields = '__all__'
class ProductSerializer(OscarModelSerializer):
attribute_valuess = ProductAttributeValueSerializer(many=True, read_only=False)
class Meta:
model = catalogue_models.Product
fields = '__all__'
The json content:
{
'title': 'Producto 4',
'is_public': True,
'description': 'descripción',
'attribute_values': [
{'value_text': 'contenido', 'attribute': 1, 'product': 1},
{'value_text': 'contenido', 'attribute': 2, 'product': 1}
]
}
The postman return this json:
{
"attribute_values": [
{
"non_field_errors": [
"The fields attribute, product must make a unique set."
]
},
{
"non_field_errors": [
"The fields attribute, product must make a unique set."
]
}
]
}
Anybody could help me please ?
Thanks in advance.

How do I create new models not affecting the nested serializer

I already have a general idea of how it should be done. The only issue that I face now is how to actually send the data. I don't want to create new Projects I just want to add them to the notifications. How do I pass the data, the actual JSON?
class NotificationsScheduleSerializer(ModelSerializer):
projects = ProjectSerializer(many=True) # Thats the Many2Many Field
user = HiddenField(default=CurrentUserDefault())
class Meta:
model = NotificationsSchedule
fields = [
"pk",
"projects",
"period",
"week_day",
"created_at",
"time",
"report_type",
"user",
]
def create(self, validated_data):
breakpoint() # I don't ever get "projects" in validated_data just Empty OrderedDict
projects_data = validated_data.pop("projects", [])
notification = NotificationsSchedule.objects.create(**validated_data)
return notification
class ProjectSerializer(ModelSerializer):
class Meta:
model = Project
fields = ["pk", "name"]
I want to be able to pass something like this.
{
"projects": [290, 289],
"period": "daily",
"week_day": 2,
"time": "16:02:00",
"report_type": "word_report"
}
But it expects dict instead.
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
You have to set read_only,
projects = ProjectSerializer(many=True, read_only=True)
And when creating Notifications ,
notification = NotificationsSchedule.objects.create(**validated_data)
notification.projects.add(*self.initial_data.get("projects"))
notification.save()

Djangorestframework Modelresource add a field from an foreignkey

I have an api in django-rest framework that now returns this json data:
[
{
"id": 1,
"foreignobject": {
"id": 3
},
"otherfields": "somevalue"
}
]
But I want it to return something like this (flatten the foreigneky to its ID only):
[
{
"id": 1,
"foreignobject_id":3,
"otherfields": "somevalue"
}
]
Doing this in the model Resource, now I Have (simplified):
class ForeignKeyInDataResource(ModelResource):
model = TheOtherModel
fields = ('id',)
class SomeModelResource(ModelResource):
model = SomeModel
fields = ( 'id',('foreignobject','ForeignKeyInDataResource'),'otherfields',)
I tried already something like:
class SomeModelResource(ModelResource):
model = SomeModel
fields = ( 'id','foreignobject__id','otherfields',)
but that did not work
for the complete story, this how the view returns the data, list is a result of a query over the SomeModel:
data = Serializer(depth=2 ).serialize(list)
return Response(status.HTTP_200_OK, data)
I'm not really in a position to support REST framework 0.x anymore, but if you decide to upgrade to 2.0 this is trivial - simply declare the field on the serializer like so: foreignobject = PrimaryKeyRelatedField()
I found another option: (by reading the ModelResource documentation...)
In the Modelresource you can define a function(self,instance), which can return the id.
in the fields you can add this function!
so, this works:
class SomeModelResource(ModelResource):
model = SomeModel
fields = ( 'id','foreignobject_id','otherfields',)
def foreignobject_id(self, instance):
return instance['foreignobject']['id']