Hỏi cách dùng parser cho JSON lồng nhau (Nested JSON)

Hi cả nhà,
Mình đang học làm API bằng flask-restplus, mình đang gặp vấn đề khi dùng parser (reqparse). Nếu input đầu vào là 1 json đơn thuần thì mình làm được rồi

from flask_restplus import fields
from rest_api_demo.api.restplus import api

# Model
book_model = api.model('Book', {
    'id': fields.Integer(description='The unique identifier of a book'),
    'title': fields.String(required=True, description='Book title')
})

.....
# Parser
from flask_restx import reqparse

book_parser = reqparse.RequestParser(bundle_errors=True)
book_parser .add_argument('id', required=True, type=int, location="json",help ="The unique identifier of a book")
book_parser .add_argument('title', required=True, type=int, location="json",help ="Book title")
....
# API
@book_ns.route('/test')
@book_ns.expect(book_model)
class Test(Resource):
    @util.rest_workflow_permission_required('book_page')
    def post(self):
        data = book_parser.parse_args()
        return data

Nhưng vấn đề nảy sinh là nếu đầu vào là JSON lồng nhau thì mình chưa biết cách nào để làm, mình có tìm hiểu thì có “nested model”:

book_category = api.model('Book category', {
    'id': fields.Integer(description='The unique identifier of a book'),
    'title': fields.String(required=True, description='Book title'),
    'book': fields.Nested(book_model)
})
book_category = api.model('Book category', {
    'id': fields.Integer(description='The unique identifier of a book'),
    'title': fields.String(required=True, description='Book title'),
    'book': fields.List(fields.Nested(book_model))
})

Nhưng mà mình không biết cách nào để dùng parser lấy dữ liệu ra từ model này cả, mong được mọi người chỉ giáo.
Mình xin chân thành cảm ơn.

Mình không biết flask nhưng mà cố gắng trợ giúp bạn chút, bài post suốt hơn 5h rồi

  1. api.model thuộc về database, miêu tả database gồm những field nào
  2. reqparse dùng để lấy thông tin từ request gửi lên.

Nếu 2 nhận định trên của mình là đúng thì việc bạn nói nested_model nó không có liên quan gì tới reqparse cả. Lý do vì việc có/không sử dụng nested_model hay nói cách khác, cách mà bạn lưu dữ liệu trong database là quyền của bạn, nó không có ảnh hưởng tới việc lấy thông tin từ request. (bạn lưu dưới database là array, nhưng mà request gửi lên là string, thì sau khi nhận đc kết quả từ request, bạn convert nó lại thành array)

Tóm lại nếu cái mình nói ở trên đúng thì bài toán đưa về:

  • Cho 1 nested-json object, hay như ngôn ngữ của bạn: json lồng nhau
  • Làm sao lấy được data dạng json đấy từ request

Lời giải thì rất đơn giản:

  • Đọc request, lấy thông tin gửi về (gọi là parse request - hence the name reqparse)
  • Thông tin gửi về phụ thuộc vài api, api có thể nhận vào string, array, json…
  • Giả sử nhận vào string thì sau khi nhận parse request xong thì convert kết quả về json hoặc bất kì định dạng nào mình muốn

Nó không phụ thuộc vào ngôn ngữ. Nên python hay php, asp gì gì cũng thế mà thôi. Không bao giờ có kiểu web ở python thì kiểu dữ liệu nó sẽ khác web ở các ngôn ngữ khác.
Chỉ là cú pháp giữa các ngôn ngữ là khác nhau.

Cách làm như mình đã chỉ, dữ liệu nhận về là gì không cần biết, thao tác với dữ liệu sau khi parse mới là quan trọng. Thay vì return ngay data, bạn xử lý thêm theo ý bạn rồi return sau khi xử lý là ok

6 Likes

Đầu tiên mình xin chân thành cảm ơn bạn vì đã giúp đỡ mình. Mình cũng rất xin lỗi khi mình để bài viết của mình gây rối một chút. Mình đã update lại ‘flask-restfull’ thành ‘flask-restplus’.
Ở flask-restplus mình đang học thì model sẽ định nghĩa request body của mình có những field nào cần lấy, sau đó parser sẽ lấy các value của các field tương ứng. Kết quả cuối cùng là mình thu được request body chuẩn (nếu không chuẩn sẽ response 400 cho user cùng message là detail các field không chuẩn đó).
Ở đây, theo mình tìm hiểu thì đối với trường hợp mình đang gặp phải (nested JSON), restplus cung cấp field.Nested để handle trường hợp này nhưng mình tìm không thấy parser tương tự để có thể parse dữ liệu ra. Tham khảo trên mạng thì người ta sẽ parse n lần (n tương ứng với số cấp JSON). Nhưng cũng tại đây thì mình thấy không ổn, lỡ JSON đầu vào có tầm 10 cấp thì phải perse tận 10 lần, nó không ổn lắm.

4 Likes

Câu hỏi này nếu có hơi ngu ngơ tí thì mong bạn thông cảm. Tại sao bạn không parse JSON thành dictionary, list,… luôn? Trong Python đã hỗ trợ sẵn thư viện json, chỉ cần dùng method load là đã có thể chuyển toàn bộ dữ liệu thành dict, list,…mà bạn cần. Nếu muốn kiểm tra xem request body có chuẩn hay không thì check cái dữ liệu bạn cần có tồn tại hay không, check kiểu dữ liệu của nó là gì, check xem chuỗi có hợp lệ hay không thì dùng regex,…

1 Like

Sau khi đọc một vài link ở google thì mình thấy có vẻ như không hỗ trợ parse nhiều hơn 1 nested fields. Link

Ví dụ với nested fields: vd1, vd2

Tóm lại, phần này cần kiến thức về cái thư viện flaskplus này, mình thì không có nên chỉ có thể hỗ trợ bạn qua cách google, mà google thì không tính phí nên bạn có thể tự giúp bản thân bằng cách google tiếp hoặc đợi cao nhân biết về thư viện này vào giúp bạn

6 Likes

Mình suy nghĩ một cách đơn giản nhất, JSON lồng nhau thì thư viện json có sẵn của Python cũng làm được.

https://docs.python.org/3/library/json.html

Mình chưa từng dùng flask-restplus hay reqparse bao giờ, không biết có đúng yêu cầu của bạn không, nhưng mình nghĩ bạn có thể từ request -> response dưới dạng string -> parse.

6 Likes

À mình đang học thôi, ở chỗ mình làm họ đang sử dụng ấy mà. Nó validate input được luôn, làm nó cũng lẹ. Đương nhiên cách làm khác như bạn nói hoàn toàn khả thi nhưng mà nó không theo quy chuẩn chỗ mình làm ấy mà. Cảm ơn bạn topic nào cũng hỗ trợ nhiệt tình.

Hì hì, mình search nát cái google rồi đó chứ bí quá mới lên hỏi mà. Mình cũng nhận được kết quả giống bạn nhưng với mình “chưa được thỏa mãn” nên đi hỏi thêm. Các cụ bảo rồi “muốn biết phải hỏi” mà bạn :crazy_face::crazy_face::crazy_face:

Cảm ơn mod, cách làm thì như mod cùng mọi người nói thì có nhiều lắm. Nhưng mình đang học cái reqparse của restplus nên muốn hỏi cho rõ á mà. Cảm ơn mod cùng mọi người rất nhiều.

Bạn đã google rồi thì cứ trình bày ra là sau khi google qua link này, link này thì đc kết quả này, kết quả kia…
Và hơn nữa là nói chính xác phần bạn cần ra

Nhưng mình đang học cái reqparse của restplus nên muốn hỏi cho rõ á mà.

Làm vậy rồi thì bạn HK Boy đỡ mất công chỉ cách parse, vì đơn giản là bạn muốn đích xác câu trả lời cho cái lib đấy, không phải là cách ngoài luồng khác.
Còn bạn thì đỡ phải đọc mấy dòng giải thích của một thằng chả biết gì về python như mình

4 Likes

Official doc của reqparse không có đề cập trường hợp về json con của 1 property trong json cha. Nên hỏi là điều bình thường.

Còn giải pháp mình thì mình vote nên tạo issue trên github repo của tác giả luôn, để tác giả hướng dẫn. Hoặc nếu ông tác giả chưa code thì nhiều người góp ý để buộc ổng làm thêm nested json.

7 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?