Jsonify SQLAlchemy rezultatas nustatytas kolboje

Aš stengiuosi ištaisyti SQLAlchemijos rezultatą, nustatytą kolboje / Pythone.

„Flask“ adresų sąrašas pasiūlė tokį metodą: http://librelist.com/browser//flask/2011/2/16/jsonify-sqlalchemy-pagination-collection-result/#04a0754b63387f87e59dda564bde426e :

 return jsonify(json_list = qryresult) 

Tačiau gaunu šią klaidą:

 TypeError: <flaskext.sqlalchemy.BaseQuery object at 0x102c2df90> is not JSON serializable 

Ką aš čia matau?

Radau šį klausimą: kaip serijuoti „SqlAlchemy“ rezultatus JSON? kuris atrodo labai panašus, bet nežinojau, ar linai turi bet kokią magiją, kad ją palengvintų, kaip siūloma el. laiške.

Redaguoti: norint paaiškinti, tai atrodo mano modelis

 class Rating(db.Model): __tablename__ = 'rating' id = db.Column(db.Integer, primary_key=True) fullurl = db.Column(db.String()) url = db.Column(db.String()) comments = db.Column(db.Text) overall = db.Column(db.Integer) shipping = db.Column(db.Integer) cost = db.Column(db.Integer) honesty = db.Column(db.Integer) communication = db.Column(db.Integer) name = db.Column(db.String()) ipaddr = db.Column(db.String()) date = db.Column(db.String()) def __init__(self, fullurl, url, comments, overall, shipping, cost, honesty, communication, name, ipaddr, date): self.fullurl = fullurl self.url = url self.comments = comments self.overall = overall self.shipping = shipping self.cost = cost self.honesty = honesty self.communication = communication self.name = name self.ipaddr = ipaddr self.date = date 
100
18 авг. rinkinys mwan 18 rug . 2011-08-18 08:24 '11 at 8:24 am 2011-08-18 08:24
@ 15 atsakymų

Atrodo, kad jūs tikrai neatitinkėte savo prašymo. Pabandykite atlikti šiuos veiksmus:

 return jsonify(json_list = qryresult.all()) 

[Redaguoti] . „Jsonify“ problema yra ta, kad paprastai objektai negali būti automatizuoti. Netgi „Python“ data ir laikas nepavyksta;)

Paprastai tai buvo pridėti papildomą turtą (pvz., serialize ) į klases, kurios turėtų būti serializuotos:

 def dump_datetime(value): """Deserialize datetime object into string form for JSON processing.""" if value is None: return None return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")] class Foo(db.Model): # ... SQLAlchemy defs here.. def __init__(self, ...): # self.foo = ... pass @property def serialize(self): """Return object data in easily serializeable format""" return { 'id' : self.id, 'modified_at': dump_datetime(self.modified_at), # This is an example how to deal with Many2Many relations 'many2many' : self.serialize_many2many } @property def serialize_many2many(self): """ Return object relations in easily serializeable format. NB! Calls many2many serialize property. """ return [ item.serialize for item in self.many2many] 

Ir dabar, kai pateiksiu, kad galiu padaryti:

 return jsonify(json_list=[i.serialize for i in qryresult.all()]) 

Tikiuosi, kad tai padės;)

144
18 авг. atsakymas pateikiamas 18 d. 2011-08-18 09:52 '11 ne 9:52 2011-08-18 09:52

Turėjau tą patį poreikį serializuoti Džonso. Pažvelkite į šį klausimą . Jis rodo, kaip programiškai aptikti stulpelius. Taigi, nuo to aš sukūriau toliau pateiktą kodą. Jis veikia man ir aš jį naudosiu savo žiniatinklio programoje. Laimingas kodavimas!

 def to_json(inst, cls): """ Jsonify the sql alchemy query result. """ convert = dict() # add your coversions for things like datetime # and what-not that aren't serializable. d = dict() for c in cls.__table__.columns: v = getattr(inst, c.name) if c.type in convert.keys() and v is not None: try: d[c.name] = convert[c.type](v) except: d[c.name] = "Error: Failed to covert using ", str(convert[c.type]) elif v is None: d[c.name] = str() else: d[c.name] = v return json.dumps(d) class Person(base): __tablename__ = 'person' id = Column(Integer, Sequence('person_id_seq'), primary_key=True) first_name = Column(Text) last_name = Column(Text) email = Column(Text) @property def json(self): return to_json(self, self.__class__) 
34
17 марта '12 в 3:42 2012-03-17 03:42 atsakymas suteikiamas bitciklas kovo 17 d., 12 val. 3:42 2012-03-17 03:42

Štai kas paprastai man pakanka:

Sukuriu serializuotą mišinį, kurį naudoju su savo modeliais. Serializacijos funkcija iš esmės išskiria visus atributus, kuriuos SQLAlchemijos inspektorius teikia ir nurodo į diktą.

 from sqlalchemy.inspection import inspect class Serializer(object): def serialize(self): return {c: getattr(self, c) for c in inspect(self).attrs.keys()} @staticmethod def serialize_list(l): return [m.serialize() for m in l] 

Viskas, ko reikia dabar, yra išplėsti SQLAlchemijos modelį naudojant Serializer mixin klasę.

Jei yra laukų, kurių nenorite išplėsti arba kuriems reikia specialaus formato, paprasčiausiai iš naujo serialize() funkciją modelio poklasyje.

 class User(db.Model, Serializer): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String) password = db.Column(db.String) # ... def serialize(self): d = Serializer.serialize(self) del d['password'] return d 

Savuose valdikliuose viskas, ką jums reikia padaryti, yra skambinti funkcijai serialize() (arba serialize_list(l) jei užklausos rezultatai pateikiami sąraše):

 def get_user(id): user = User.query.get(id) return json.dumps(user.serialize()) def get_users(): users = User.query.all() return json.dumps(User.serialize_list(users)) 
30
14 янв. Carl Ekerot atsakymas dėl sausio 14 d 2015-01-14 23:16 '15, 23:16, 2015-01-14 23:16

Štai mano požiūris: https://github.com/n0nSmoker/SQLAlchemy-serializer

„pip“ įdiegti „SQLAlchemy serializer“

Jūs galite lengvai pridėti maišytuvą prie savo modelio, o paskui paprasčiausiai skambinti .to_dict () metodu.

Taip pat galite parašyti savo „mixeria“ pagal „SerializerMixin“

15
14 янв. Atsakymas pateikiamas n0nSmoker 14 jan. 2013-01-14 19:20 '13, 19:20, 2013-01-14 19:20

Jei naudosite flask-restful , galite naudoti maršalą :

 from flask.ext.restful import Resource, fields, marshal topic_fields = { 'title': fields.String, 'content': fields.String, 'uri': fields.Url('topic'), 'creator': fields.String, 'created': fields.DateTime(dt_format='rfc822') } class TopicListApi(Resource): def get(self): return {'topics': [marshal(topic, topic_fields) for topic in DbTopic.query.all()]} 

Turite aiškiai nurodyti, ką grįžtate, ir tipą, kurį aš norėčiau bet kuriuo atveju naudoti „api“. Serializacija yra lengva prižiūrėti (nereikia jsonify ), datos taip pat nėra problema. Atkreipkite dėmesį, kad uri lauko turinys automatiškai sukuriamas pagal galutinio taško topic ir identifikatorių.

4
26 дек. atsakymą pateikė Adversus gruodžio 26 d 2015-12-26 13:11 '15, 13:11 2015-12-26 13:11

Dėl vienodo užklausos (be ryšio) galite tai padaryti

 @app.route('/results/') def results(): data = Table.query.all() result = [d.__dict__ for d in data] return jsonify(result=result) 

ir jei norite iš duomenų bazės grąžinti tik tam tikras stulpelius, galite tai padaryti

 @app.route('/results/') def results(): cols = ['id', 'url', 'shipping'] data = Table.query.all() result = [{col: getattr(d, col) for col in cols} for d in data] return jsonify(result=result) 
4
04 мая '13 в 0:24 2013-05-04 00:24 atsakymas pateikiamas reubano 04 gegužės 13 d. 0:24 2013-05-04 00:24

Na, aš dirbau keletą valandų, ir aš sukūriau tai, kas, mano manymu, yra pats pythoninis sprendimas. Šie kodo fragmentai yra python3, bet neturėtų būti pernelyg baisūs, jei reikia.

Pirmas dalykas, kurį ketiname padaryti, yra pradėti su mixin, kuris jūsų db modelius veikia kaip dict :

 from sqlalchemy.inspection import inspect class ModelMixin: """Provide dict-like interface to db.Model subclasses.""" def __getitem__(self, key): """Expose object attributes like dict values.""" return getattr(self, key) def keys(self): """Identify what db columns we have.""" return inspect(self).attrs.keys() 

Dabar mes nustatysime savo modelį paveldėdami mišinį:

 class MyModel(db.Model, ModelMixin): id = db.Column(db.Integer, primary_key=True) foo = db.Column(...) bar = db.Column(...) # etc ... 

Norėdami gauti „ MyModel() egzempliorių MyModel() prieš MyModel() , norint gauti tikro MyModel() pavyzdį, nuo kurio jis praėjo, tai mums suteikia gana ilgą kelią, kad „ jsonify() suprantamas. Tada turime išplėsti JSONEncoder kad galėtume gauti kitą kelią:

 from flask.json import JSONEncoder from contextlib import suppress class MyJSONEncoder(JSONEncoder): def default(self, obj): # Optional: convert datetime objects to ISO format with suppress(AttributeError): return obj.isoformat() return dict(obj) app.json_encoder = MyJSONEncoder 

Premijos taškai: jei jūsų modelis turi apskaičiuotus laukus (t. Y., Kad norite, kad JSON išvestyje būtų laukų, kurie nėra faktiškai saugomi duomenų bazėje), tai taip pat lengva. Tiesiog nustatykite apskaičiuotus laukus kaip @property s ir tęskite keys() metodą taip:

 class MyModel(db.Model, ModelMixin): id = db.Column(db.Integer, primary_key=True) foo = db.Column(...) bar = db.Column(...) @property def computed_field(self): return 'this value did not come from the db' def keys(self): return super().keys() + ['computed_field'] 

Dabar tai yra nereikšminga, kai jsonify:

 @app.route('/whatever', methods=['GET']) def whatever(): return jsonify(dict(results=MyModel.query.all())) 
4
30 сент. atsakymas, kurį pateikė Robru 30 Sep 2015-09-30 12:43 '15 , 12:43 val. 2015-09-30 12:43

Aš žiūrėjau į šią problemą didžiąją dienos dalį, ir čia aš sužinojau (kreditas ngn-wiki.ru.site/questions/58651 / ... nukreipti mane šia kryptimi).

(Pastaba: naudoju kolbą-sqlalchemy, todėl mano skelbimo modelio formatas šiek tiek skiriasi nuo tiesioginio sqlalchemy).

Mano models.py faile:

 import json class Serializer(object): __public__ = None "Must be implemented by implementors" def to_serializable_dict(self): dict = {} for public_key in self.__public__: value = getattr(self, public_key) if value: dict[public_key] = value return dict class SWEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Serializer): return obj.to_serializable_dict() if isinstance(obj, (datetime)): return obj.isoformat() return json.JSONEncoder.default(self, obj) def SWJsonify(*args, **kwargs): return current_app.response_class(json.dumps(dict(*args, **kwargs), cls=SWEncoder, indent=None if request.is_xhr else 2), mimetype='application/json') # stolen from https://github.com/mitsuhiko/flask/blob/master/flask/helpers.py 

ir visi mano modelio objektai atrodo taip:

 class User(db.Model, Serializer): __public__ = ['id','username'] ... field definitions ... 

Mano nuomone, kreipiuosi į SWJsonify visur, kur norėčiau paskambinti Jsonify , pavyzdžiui:

 @app.route('/posts') def posts(): posts = Post.query.limit(PER_PAGE).all() return SWJsonify({'posts':posts }) 

Atrodo, kad viskas veikia gerai. Net ir santykiuose. Aš nebuvau toli, taigi YMMV, bet iki šiol man tai patinka.

Pasiūlymai yra sveikintini.

2
06 июля '12 в 4:09 2012-07-06 04:09 Atsakymą pateikė Kenny Winker liepos 12 d. 12 val. 2012-07-06 04:09

Flask-Restful 0.3.6 Prašymas analizuoti rekomenduoti Zephyr

marshmallow yra ORM / ODM / Framework nepriklausoma biblioteka, skirta konvertuoti sudėtingus duomenų tipus, pvz., objektus, į ir iš vietinių Python duomenų tipų.

Žemiau pateikiamas paprastas marshmallow pavyzdys.

 from marshmallow import Schema, fields class UserSchema(Schema): name = fields.Str() email = fields.Email() created_at = fields.DateTime() from marshmallow import pprint user = User(name="Monty", email="monty@python.org") schema = UserSchema() result = schema.dump(user) pprint(result) # {"name": "Monty", # "email": "monty@python.org", # "created_at": "2014-08-17T14:54:16.049594+00:00"} 

Pagrindinės funkcijos yra

Schemos deklaracija
Objektų serijavimas („Reset“)
Objektų deserizavimas („Įkeliama“)
Objektų rinkinių apdorojimas
Patikrinkite
Atributų pavadinimų nustatymas
Serializacijos / deserializacijos raktų nustatymas
Refactoring: netiesioginio lauko kūrimas
Nutraukimas
Laukai skaityti tik ir rašomi tik
Nurodykite numatytasis serializacijos / deserializacijos reikšmes
Nested Schemes
Priskirti laukai

1
22 окт. atsakymą pateikė Shihe Zhang spalio 22 d. 2018-10-22 06:39 '18, 6:39 2018-10-22 06:39

Čia yra būdas pridėti as_dict () metodą kiekvienai klasei, taip pat bet kurį kitą metodą, kurį norite naudoti kiekvienai klasei. Nežinote, ar tai yra norimas būdas, ar ne, bet jis veikia ...

 class Base(object): def as_dict(self): return dict((c.name, getattr(self, c.name)) for c in self.__table__.columns) Base = declarative_base(cls=Base) 
1
05 мая '15 в 3:22 2015-05-05 03:22 atsakymas pateikiamas tahoe 05 gegužės 15 d. 3:22 2015-05-05 03:22

Aš ieškojau kažko panašaus į „ActiveRecord to_json“ naudojamą bėgių metodą ir įgyvendinome kažką panašaus, naudodamas šį „Mixin“, po nepatenkinimo kitais pasiūlymais. Jis apdoroja įdėtus modelius ir apima arba neįtraukia aukščiausio lygio atributų arba įdėtus modelius.

 class Serializer(object): def serialize(self, include={}, exclude=[], only=[]): serialized = {} for key in inspect(self).attrs.keys(): to_be_serialized = True value = getattr(self, key) if key in exclude or (only and key not in only): to_be_serialized = False elif isinstance(value, BaseQuery): to_be_serialized = False if key in include: to_be_serialized = True nested_params = include.get(key, {}) value = [i.serialize(**nested_params) for i in value] if to_be_serialized: serialized[key] = value return serialized 

Tada, norint gauti „BaseQuery“ serializuotą, aš pratęsiau „BaseQuery“

 class SerializableBaseQuery(BaseQuery): def serialize(self, include={}, exclude=[], only=[]): return [m.serialize(include, exclude, only) for m in self] 

Šiems modeliams

 class ContactInfo(db.Model, Serializer): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) full_name = db.Column(db.String()) source = db.Column(db.String()) source_id = db.Column(db.String()) email_addresses = db.relationship('EmailAddress', backref='contact_info', lazy='dynamic') phone_numbers = db.relationship('PhoneNumber', backref='contact_info', lazy='dynamic') class EmailAddress(db.Model, Serializer): id = db.Column(db.Integer, primary_key=True) email_address = db.Column(db.String()) type = db.Column(db.String()) contact_info_id = db.Column(db.Integer, db.ForeignKey('contact_info.id')) class PhoneNumber(db.Model, Serializer): id = db.Column(db.Integer, primary_key=True) phone_number = db.Column(db.String()) type = db.Column(db.String()) contact_info_id = db.Column(db.Integer, db.ForeignKey('contact_info.id')) phone_numbers = db.relationship('Invite', backref='phone_number', lazy='dynamic') 

Jūs galite padaryti kažką panašaus

 @app.route("/contact/search", methods=['GET']) def contact_search(): contact_name = request.args.get("name") matching_contacts = ContactInfo.query.filter(ContactInfo.full_name.like("%{}%".format(contact_name))) serialized_contact_info = matching_contacts.serialize( include={ "phone_numbers" : { "exclude" : ["contact_info", "contact_info_id"] }, "email_addresses" : { "exclude" : ["contact_info", "contact_info_id"] } } ) return jsonify(serialized_contact_info) 
1
17 июля '16 в 8:57 2016-07-17 08:57 atsakymas duodamas zwalker liepos 17 d. 16 val. 8:57 2016-07-17 08:57

Dirbau su „RowProxy“ objektų sąrašų defaultdict sql užklausa su pavadinimu jobDict, tai užtruko šiek tiek laiko išsiaiškinti, kokie objektai yra.

Tai buvo labai paprastas būdas greitai išspręsti bet kokį gryną „jsonEncoding“, paprasčiausiai nurodant eilutę eilutėje ir iš pradžių apibrėžiant diktą su sąrašo verte.

  jobDict = defaultdict(list) def set_default(obj): # trickyness needed here via import to know type if isinstance(obj, RowProxy): return list(obj) raise TypeError jsonEncoded = json.dumps(jobDict, default=set_default) 
0
09 мая '14 в 18:52 2014-05-09 18:52 atsakymas duotas Nick May 09 '14, 18:52 2014-05-09 18:52

Štai mano atsakymas, jei naudojate deklaracinę bazę (naudodami kai kuriuos jau paskelbtus atsakymus):

 # in your models definition where you define and extend declarative_base() from sqlalchemy.ext.declarative import declarative_base ... Base = declarative_base() Base.query = db_session.query_property() ... # define a new class (call "Model" or whatever) with an as_dict() method defined class Model(): def as_dict(self): return { c.name: getattr(self, c.name) for c in self.__table__.columns } # and extend both the Base and Model class in your model definition, eg class Rating(Base, Model): ____tablename__ = 'rating' id = db.Column(db.Integer, primary_key=True) fullurl = db.Column(db.String()) url = db.Column(db.String()) comments = db.Column(db.Text) ... # then after you query and have a resultset (rs) of ratings rs = Rating.query.all() # you can jsonify it with s = json.dumps([r.as_dict() for r in rs], default=alchemyencoder) print (s) # or if you have a single row r = Rating.query.first() # you can jsonify it with s = json.dumps(r.as_dict(), default=alchemyencoder) # you will need this alchemyencoder where your are calling json.dumps to handle datetime and decimal format # credit to Joonas @ http://codeandlife.com/2014/12/07/sqlalchemy-results-to-json-the-easy-way/ def alchemyencoder(obj): """JSON encoder function for SQLAlchemy special classes.""" if isinstance(obj, datetime.date): return obj.isoformat() elif isinstance(obj, decimal.Decimal): return float(obj) 
0
30 авг. atsakymas pateikiamas VinnyQ77 30 rug . 2016-08-30 02:12 '16 at 2:12 2016-08-30 02:12

Aš tik noriu pridėti savo metodą.

tiesiog nustatykite „custome json“ koduotoją, skirtą „db“ modeliams serializuoti.

 class ParentEncoder(json.JSONEncoder): def default(self, obj): # convert object to a dict d = {} if isinstance(obj, Parent): return {"id": obj.id, "name": obj.name, 'children': list(obj.child)} if isinstance(obj, Child): return {"id": obj.id, "name": obj.name} d.update(obj.__dict__) return d 

tada jūsų peržiūros funkcija

 parents = Parent.query.all() dat = json.dumps({"data": parents}, cls=ParentEncoder) resp = Response(response=dat, status=200, mimetype="application/json") return (resp) 

ji veikia gerai, nors tėvui yra santykiai

0
02 июня '16 в 10:44 2016-06-02 10:44 atsakymas duotas tyan 02 birželio 16 d. 10:44 2016-06-02 10:44

Yra daug kartų, ir yra daug galiojančių atsakymų, tačiau, atrodo, šis kodo blokas veikia:

 my_object = SqlAlchemyModel() my_serializable_obj = my_object.__dict__ del my_serializable_obj["_sa_instance_state"] print(jsonify(my_serializable_object)) 

Žinau, kad tai nėra idealus sprendimas, ne toks pat elegantiškas kaip kiti, bet tiems, kurie nori greitai ją išspręsti, jie gali tai išbandyti.

-1
22 окт. atsakymas, kurį pateikė radalinas 2014-10-22 16:03 '14, 16:03, 2014-10-22 16:03