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

Submitted 3 years, 10 months ago
Ticket #24
Views 304
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 3 years, 10 months 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 3 years, 10 months ago

On it!

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

???

- moazamrana22 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

kindly reply fast i am close to my deadline.

- moazamrana22 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

that was the heading of ticket

- moazamrana22 3 years, 10 months ago

i still have issue in POST api

- moazamrana22 3 years, 10 months ago

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

- bhavana 3 years, 10 months ago

Thanks for your concern i am waiting..!

- moazamrana22 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

Thanks for sharing :)

- bhavana 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

actually i am new with it

- moazamrana22 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

ok just print(x)

- bhavana 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- bhavana 3 years, 10 months ago

i think this will remove the OrderItem

- bhavana 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

i mean one order item only

- bhavana 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- bhavana 3 years, 10 months ago

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

- bhavana 3 years, 10 months 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 3 years, 10 months ago

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

- bhavana 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- bhavana 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months 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 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

not sure something else you are doing wrong.

- bhavana 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months 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 3 years, 10 months ago

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

- Vengat 3 years, 10 months ago

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

- moazamrana22 3 years, 10 months ago

You are Welcome :)

- bhavana 3 years, 10 months ago


Latest Blogs