Django_rest_framework:- Need to add (POST) data into two tables(models) using 1 api_call

Submitted 5 years ago
Ticket #24
Views 451
Language/Framework Django
Priority High
Status Closed

I am creating an api for post to add a record into my table but the problem is that i have two tables named as orders and order_items and the attributes of both tables are For orders:-

order_id,customer_id,waiter_it,status,Date

For order_items:-

Order_id, Item_id, Quantity

All i need to ask is that can i add the data in both of these tables in a signle function? if it is possible than kindly guide me how if not then suggest me do i have to make POST api for both of these tables seperately:

my POST function looks like something this:

@api_view(['POST', ])
def add_order(request):

    order=Orders()
    if request.method == 'POST':
        serializer = OrdersSerializer(order, data=request.data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data)

Submitted on Jun 17, 20
add a comment

1 Answer

Acknowledged.

Submitted 5 years ago

yes you can use 2 tables in function also. PFB the some of the approaches
Approach 1:
Create new serializer in serializer.py file and use the same in views.py like below class OrderSerializer(serializers.ModelSerializer): class Meta: model = Order

class OrderItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderItem

class CombineSerializer(serializers.Serializer):
    order = OrderSerializer(many=True)
    order_item = OrderItemSerializer(many=True)

Approach 2
You can use this library to achieve this,
DjangoRestMultipleModels
Check this if it helps

- sunil 5 years ago

On it!

- moazamrana22 5 years ago

in approach 1 kindly guide me how to store the request.data in CombineSerializer: '''@api_view(['POST', ]) def add_order(request): order=Orders() oitems=OrderItems() if request.method == 'POST': serializer = #what should be written here ? '''

- moazamrana22 5 years ago

???

- moazamrana22 5 years ago

I can help you with the entire code. But I would suggest, please try some logic from your end and let us know if you still stuck, I can give you the hint :)

- sunil 5 years ago

okay! i have done pretty much work on it i have crated nested seializers but when i try to add the data into the tables. It adds the data fine accept one attribute that is menu_id From postman i had inserted the data that is :- { "order_id": 5, "waiter": 1, "customer": 1, "cheff": 2, "order_status": "Pending", "order_time": "2020-06-15T13:45:12Z", "orderitems": [ { "order_id": 3, "menu_id": 1, "quantity": 1, "order_items_id": 8 }, { "order_id": 3, "menu_id": 2, "quantity": 2, "order_items_id": 9 } ] } it returned me the data after adding it that is:- { "order_id": 6, "waiter": 1, "customer": 1, "cheff": 2, "order_status": "Pending", "order_time": "2020-06-15T13:45:12Z", "orderitems": [ { "order_id": 6, "menu_id": null, "quantity": 1, "order_items_id": 9 }, { "order_id": 6, "menu_id": null, "quantity": 2, "order_items_id": 10 } ] } i dont know what is the problem in the database too it is inserting menu_id=null

- moazamrana22 5 years ago

kindly reply fast i am close to my deadline.

- moazamrana22 5 years ago

serializers.py class OrderItemsSerializer(serializers.ModelSerializer): #order_id = serializers.IntegerField(required=True) class Meta: model=OrderItems fields=['order_id','menu_id','quantity','order_items_id']

class OrdersSerializer(serializers.ModelSerializer): orderitems=OrderItemsSerializer(many=True) class Meta: model=Orders fields=['order_id','waiter','customer','cheff','order_status','order_time','orderitems']

def create(self, validated_data):
    orderitems_data = validated_data.pop('orderitems')
    order = Orders.objects.create(**validated_data)
    for x in orderitems_data:
        OrderItems.objects.create(order=order, **x)
    return order
- moazamrana22 5 years ago

models.py ''' class Orders(models.Model): order_id = models.AutoField(primary_key=True) waiter = models.ForeignKey('Waiters', models.DO_NOTHING, blank=True, null=True) customer = models.ForeignKey(Customers, models.DO_NOTHING, blank=True, null=True) cheff = models.ForeignKey('Cheffs', models.DO_NOTHING, blank=True, null=True) order_status = models.CharField(max_length=20, blank=True, null=True) order_time = models.DateTimeField(blank=True, null=True)

def __str__(self):
    return self.order_id

class Meta:
    managed = False
    db_table = 'orders'

order_items

class OrderItems(models.Model): order = models.ForeignKey('Orders', models.DO_NOTHING, related_name='orderitems',blank=True, null=True) menu = models.ForeignKey(Menus, models.DO_NOTHING, blank=True, null=True) quantity = models.IntegerField(blank=True, null=True) order_items_id = models.AutoField(primary_key=True)

class Meta:
    managed = False
    db_table = 'order_items'

'''

- moazamrana22 5 years ago

seems like you are talking about different issue right. Initially this ticket raised for different issue, i hope that has been resolved. Now you are talking about different issue.

- sunil 5 years ago

Need to add (POST) data into two tables(models) using 1 api_call

- moazamrana22 5 years ago

that was the heading of ticket

- moazamrana22 5 years ago

i still have issue in POST api

- moazamrana22 5 years ago

Hi Moazamranna,
I will review the code and get back to you

- bhavana 5 years ago

Thanks for your concern i am waiting..!

- moazamrana22 5 years ago

May i know the API you are calling from POSTMAN?. Also can you add print statement
in your views.py & serializer.py and see what is there is menu_id when you calling.

- bhavana 5 years ago

okay! http://127.0.0.1:8000/api/order this is the url that i called through postman url(r'^order',OrderListView.as_view()) this is the url in api/urls.py and i'll print the value in serializer then get back to you

- moazamrana22 5 years ago

class OrderListView(generics.ListCreateAPIView): queryset = Orders.objects.all() serializer_class = OrdersSerializer this is views.py

- moazamrana22 5 years ago

Thanks for sharing :)

- bhavana 5 years ago

Can you help me with accessing menu_id in views.py and serializer.py ??

- moazamrana22 5 years ago

actually i am new with it

- moazamrana22 5 years ago

The attribute menu_id in the orderItems is actually a foreign key is that can be a problem ??

- moazamrana22 5 years ago

Its ok no worries !!!
for x in orderitems_data: print(x.menu_id) OrderItems.objects.create(order=order, **x) return order
Try like this

- bhavana 5 years ago

but still you can insert foreign key data into the Table.
Because you are just sending the hardcoded data from POSTMAN right
So it ideally it should insert the foreign key data as well.

- bhavana 5 years ago

AttributeError: 'collections.OrderedDict' object has no attribute 'menu_id' it throws the above error

- moazamrana22 5 years ago

ok just print(x)

- bhavana 5 years ago

OrderedDict([('quantity', 1)]) OrderedDict([('quantity', 2)])

- moazamrana22 5 years ago

the json object i had inserted was this -->> { "order_id": 7, "waiter": 1, "customer": 1, "cheff": 2, "order_status": "Pending", "order_time": "2020-06-15T13:45:12Z", "orderitems": [ { "order_id": 3, "menu_id": 1, "quantity": 1, "order_items_id": 8 }, { "order_id": 3, "menu_id": 2, "quantity": 2, "order_items_id": 9 } ] }

- moazamrana22 5 years ago

why you have this line orderitems_data = validated_data.pop('orderitems')

- bhavana 5 years ago

i think this will remove the OrderItem

- bhavana 5 years ago

wasn't it for storing the poped value in orderitems_data ? i don't know i am very new to django rest_framework + django itself i had followed some tutorials .

- moazamrana22 5 years ago

from the orderitems it is just having the value of quantity the same that i had provided and order_id and order_items_id are auto increment on the database thats why there value is generated automatically

- moazamrana22 5 years ago

validated_data is a dictionary and .pop(key) searches for the key specified and returns and removes it if it is found, otherwise an exception is thrown.

- bhavana 5 years ago

i think you should focus on Django & Python project. Once you familiar with that, move on to Rest framework. That is my suggestion friend.

- bhavana 5 years ago

Then why the value of quantity is still stored in it ?

- moazamrana22 5 years ago

Is there any other way i can recreate the create method i mean with some other logic ? to store the values in orders and orderitems tables.

- moazamrana22 5 years ago

I have to do it for my FYP , though thanks for your suggestion.

- moazamrana22 5 years ago

Not sure what was the wrong in your code. lets try this, remove the for loop in OrderSerailizer
and just have this OrderItems.objects.create(order=order, **orderitem_data)

- bhavana 5 years ago

it throws this error ''' TypeError: create() argument after ** must be a mapping, not list '''

- moazamrana22 5 years ago

can you try pass only order_item from POST call . Also put back the for loop and send me the code after the execution

- bhavana 5 years ago

i mean one order item only

- bhavana 5 years ago

{ "order_id": 13, "waiter": 1, "customer": 1, "cheff": 2, "order_status": "Pending", "order_time": "2020-06-15T13:45:12Z", "orderitems": [ { "order_id": 13, "menu_id": null, "quantity": 1, "order_items_id": 15 } ] }

- moazamrana22 5 years ago

still sending the menu_id=null actually it is getting the value of quantity only

- moazamrana22 5 years ago

from orderitems only the value of quantity is being passed in orderitems_data

- moazamrana22 5 years ago

Add this in OrderItem serilizer and try this
def validate_menu_id(self, data): menu_id= self.initial_data.get('menu_id') print(menu_id) return data

- bhavana 5 years ago

basically we are trying to see whether we are getting data in OrderItemSerializer or not

- bhavana 5 years ago

try this, i will come back in few mins :)

- bhavana 5 years ago

N.p i had written this function but it is not printing any thing i think it should be called somewhere ? talking about validate_menu_id

- moazamrana22 5 years ago

where did you check the output in POSTMAN or django server?

- bhavana 5 years ago

i had checked output for the print command in the terminal and for the json object in the POSTMAN

- moazamrana22 5 years ago

ok try something in your django shell
from rest_framework.renderers import JSONRenderer data = { "order_id": 7, "waiter": 1, "customer": 1, "cheff": 2, "order_status": "Pending", "order_time": "2020-06-15T13:45:12Z", "orderitems": [ { "order_id": 3, "menu_id": 1, "quantity": 1, "order_items_id": 8 }, { "order_id": 3, "menu_id": 2, "quantity": 2, "order_items_id": 9 } ] } json = JSONRenderer().render(serializer.data) json

- bhavana 5 years ago

okay just need to tell you that i had printed the validated_data['order_items'] in the first line of create method and it printed only quantity which means it only saves the quantity from the input

- moazamrana22 5 years ago

''' def create(self, validated_data): print(validated_data['orderitems']) '''

- moazamrana22 5 years ago

something which made me worried is that do i need add the serializer of menu in the nested serialization ? because menu_id is a foreign key which comes from menu table just need to know about this !

- moazamrana22 5 years ago

hmm correct you dont have menu_id column at all in your model right?..

- bhavana 5 years ago

class OrderItemSerializer(serializers.ModelSerializer): menu_name = serializers.RelatedField(source='menu', queryset=Menu.objects.all())

class Meta:
    model = Item
    fields = ['order_id','menu_name','quantity','order_items_id']

If you want to retrieve all ForeignKey columns then use above method

- bhavana 5 years ago

I think this will work i had updated the orderItemsSerializer as you told me now it is returning me the data in jason form like this { "waiter": 2, "customer": 1, "cheff": 1, "order_status": "Pending", "order_time": "2019-06-15T13:45:12Z", "orderitems": [ { "order_id": 50, "menu_id": 2, "quantity": 9, "order_items_id": 2 }, { "order_id": 50, "menu_id": 1, "quantity": 2, "order_items_id": 2 } ] } First it ignores the order_id and the second issue is it is not updating the database

- moazamrana22 5 years ago

i think it is not enetering in the ceate method in the mother serializer that is:- ''' class OrdersSerializer(serializers.ModelSerializer): orderitems=OrderItemsSerializer(many=True) class Meta: model=Orders fields=['order_id','waiter','customer','cheff','order_status','order_time','orderitems'] def create(self, validated_data): print(validated_data['orderitems']) orderitems_data = validated_data.pop('orderitems') order = Orders.objects.create(*validated_data) for x in orderitems_data: #print(x) OrderItems.objects.create(order=order, *x) return order '''

- moazamrana22 5 years ago

it is because it is not printing the validated data in the terminal that i had in the create method

- moazamrana22 5 years ago

plus implementing the above orderitemsSerializer it had blocked my get api' just want to tell you that menu_id was included in the OrdersItems model as a foreign key

- moazamrana22 5 years ago

not sure something else you are doing wrong.

- bhavana 5 years ago

i think there is some another issue or the communication gap :p BTW thank you i am going to close the ticket.

- moazamrana22 5 years ago

Thank you. You just need to play around with the examples which we shared, if you adjust your code it should work. Nothing sooper dooper :)

- bhavana 5 years ago

Looks like quite long conversation. Hopefully it helped you to move forward. Thanks all Techions !!!

- Vengat 5 years ago

Yes! helped me clear many concepts Thanks to you Miss Bhavna.

- moazamrana22 5 years ago

You are Welcome :)

- bhavana 5 years ago


Latest Blogs