In my Rest application I want to return json like JSONAPI format, but I need to create Schema class for it and create every field again that are already there in my model. So instead of creating every field in schema class can I not take it from DB Model..
below is my model class
class Author(db.Model):
id = db.Column(db.Integer)
name = db.Column(db.String(255))
I am defining Schema like below.
class AuthorSchema(Schema):
id = fields.Str(dump_only=True)
name = fields.Str()
metadata = fields.Meta()
class Meta:
type_ = 'people'
strict = True
So here, id and name I have defined it twice. so is there any option in marshmallow-jsonapi to assign model name in schema class so it can take all fields from model
Note: I am using marshmallow-jsonapifor it, I have tried marshmallow-sqlalchemy , it has that option but it not return json in JSONAPI format
You can use flask-marshmallow's ModelSchema and marshmallow-sqlalchemy in combination with marshmallow-jsonapi with the caveat that you have to subclass not only the Schema classes but also the SchemaOpts classes, like this:
# ...
from flask_marshmallow import Marshmallow
from marshmallow_jsonapi import Schema, SchemaOpts
from marshmallow_sqlalchemy import ModelSchemaOpts
# ...
ma = Marshmallow(app)
# ...
class JSONAPIModelSchemaOpts(ModelSchemaOpts, SchemaOpts):
pass
class AuthorSchema(ma.ModelSchema, Schema):
OPTIONS_CLASS = JSONAPIModelSchemaOpts
class Meta:
type_ = 'people'
strict = True
model = Author
# ...
foo = AuthorSchema()
bar = foo.dump(query_results).data # This will be in JSONAPI format including every field in the model
Related
I am using Django-import_export for exporting data. I have used the code given below that's not working correctly. It exported only dehydrated data instead of given fields.
class MemberResource(resources.ModelResource):
Brand=Field()
class meta:
model = model
fields=('title','Brand')
def dehydrate_Brand(self, obj):
return str(obj.Brand.title)
class modelAdmin(ImportExportModelAdmin):
resource_class = MemberResource
list_display=['title','Model_code','Chipset','chipset_description','Brand','categories']
search_fields = ['title','Model_code','Chipset',]
fields=('title','Model_code','Chipset','chipset_description','image','Brand','Cat')
admin.site.register(model,modelAdmin)
The name of the Meta subclass is Meta, not meta, so the ModelResource should look like:
class MemberResource(resources.ModelResource):
Brand=Field()
class Meta:
model = Member
fields = ('title','Brand')
def dehydrate_Brand(self, obj):
return str(obj.Brand.title)
I have the following models (and an enum) defined:
from tortoise import models, fields
from enum import Enum
class WorkspaceUserRole(str, Enum):
owner = "owner"
collaborator = "collaborator"
class User(models.Model):
id = fields.UUIDField(pk=True)
class Workspace(models.Model):
id = fields.UUIDField(pk=True)
class WorkspaceUser(models.Model):
id = fields.UUIDField(pk=True)
user = fields.ForeignKeyField("models.User", "workspace_users")
workspace = fields.ForeignKeyField("models.Workspace", "workspace_users")
role = fields.CharEnumField(WorkspaceUserRole)
I would like to do something like:
user = ... # fetch a User
workspaces = await user.workspaces.all()
But that relation does not exist. Adding it to User obviously conflicts with the
existing workspaceuser table.
How do I perform this query, or add the relation to the User model?
The following seems to have worked:
from tortoise import models, fields
from enum import Enum
class WorkspaceUserRole(str, Enum):
owner = "owner"
collaborator = "collaborator"
class User(models.Model):
id = fields.UUIDField(pk=True)
# Added the following relation:
workspaces = fields.ManyToManyField(
model_name="models.Workspace", through="workspaceuser"
)
class Workspace(models.Model):
id = fields.UUIDField(pk=True)
class WorkspaceUser(models.Model):
id = fields.UUIDField(pk=True)
user = fields.ForeignKeyField("models.User", "workspace_users")
workspace = fields.ForeignKeyField("models.Workspace", "workspace_users")
role = fields.CharEnumField(WorkspaceUserRole)
This enables both:
await user.workspaces.all()
and:
await workspace.users.all()
In our system, we have two similar(but not same) databases. So I built these sqlalchemy models:
# base.py
Base = declarative_base()
class T1(Base):
__tablename__ = 't1'
id = Column(Integer, primary_key=True)
name = Column(String)
# production1.py
from . import base
class T1(base.T1):
status1 = Column(String)
# production2.py
from . import base
class T1(base.T1):
status2 = Column(String)
# sessions.py
engine1 = create_engine(**production1_params)
session1 = scoped_session(sessionmaker(bind=engine1))
engine2 = create_engine(**production2_params)
session2 = scoped_session(sessionmaker(bind=engine2))
Then I can access different database by:
import production1, production2
session1().query(production1.T1)
session2().query(production2.T2)
Now, I want to build our API system by graphql. First, I inherit from SQLAlchemyConnectionField to support database switching.
class SwitchableConnectionField(SQLAlchemyConnectionField):
def __init__(self, type, *args, **kwargs):
kwargs.setdefault('db_type', String())
super
#classmethod
def get_query(self, model, info, sort=None, **args):
session = get_query(args['db_type'])
query = session.query(model)
...
But when I want to define my nodes, I found the definitions must be:
import production1, production2
class Production1Node(SQLAlchemyObjectType):
class Meta:
model = production1,T1
interfaces = (Node,)
class Production2Node(SQLAlchemyObjectType):
class Meta:
model = production2.T1
interfaces = (Node,)
There are two nodes definitions to support different databases. But I want to do something like:
import base
class ProductionNode(SQLAlchemyObjectType):
class Meta:
model = base.T1
interfaces = (Node,)
So that I can switch similar model at run time. However, even though I try to inherit from Node, I can't implement it. Does anyone know what should I do?
My design is as following about Django ModelSerializer.
There are model A and model B. Model B has a foreign key field of Model A. For some reasons, I can not use the primary key directly to serialize Model B. As my thought, what I need is to serialize two other fields(unique together in Model A).
And I see the SlugRelatedField must be used for one slug field.
I searched there is a NaturalKeyField can support NaturalKeyField. But it looks like it is superseeded by django-rest-framework. But I checked the django-rest-framework, there is no such field at all.
Can anyone help?? What should I do?
The code is as following.
Model A
class AssetModel(models.Model):
org = models.ForeignKey(Org, related_name='models')
name = models.CharField(max_length=128)
model_type = models.SmallIntegerField(default = 3,choices = MODEL_TYPE )
directory = models.CharField(max_length = 128)
...
class Meta:
unique_together = ('org', 'name',)
Model B
class Dataitem(models.Model):
mod = models.ForeignKey(AssetModel, related_name='dataitems')
name = models.CharField(max_length=128)
data_type = models.SmallIntegerField(default =0,choices = DATAITEM_DATATYPE)
...
Serializer of model A
class AssetModelSerializer(serializers.ModelSerializer):
org = serializers.SlugRelatedField(queryset=Org.objects.all(), slug_field='name')
class Meta:
model = AssetModel
fields = ('org', 'name', 'model_type',..
Serializer of model B
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
fields = ('mod', 'name','data_type'...)
The primary key of Model A is just a id Django auto added. When serialize the model B, I need to get the org and name of model A. Both read and write are needed.
Nested Serializer
You can do something like this, define a serializer for Dataitem that can reuse a serializer of the AssetModel model
class AssetModelSerializer(serializers.ModelSerializer):
class Meta:
model = AssetModel
# Fields org and name of AssetModel will be inlcuded by default
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
mod = AssetModelSerializer()
# This is the Dataitem.mod field
# which is a FK to AssetModel,
# Now it'll be serilized using the AssetModelSerializer
# and include the org and name fields of AssetModelSerializer
I prefer this approach because of the control I get.
If you serialize using the above you get a structure like this:
data_item = {'name': ..., 'mod': {'org': ..., 'name': ...}}
^
|___ AssetModel fields
Alternatively you can also use depth = n
You can also use depth = 1 in Dataitem
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
depth = 1 # Will include fields from related models
# e.g. the mod FK to AssetModel
Writable Nested Serializer
Because the behavior of nested creates and updates can be ambiguous,
and may require complex dependencies between related models, REST
framework 3 requires you to always write these methods explicitly.
We have to implement create/update to make this writable as per DRF's documentation
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
# Nested serializer
mod = AssetModelSerializer()
# Custom create()
def create(self, validated_data):
# First we create 'mod' data for the AssetModel
mod_data = validated_data.pop('mod')
asset_model = AssetModel.objects.create(**mod_data)
# Now we create the Dataitem and set the Dataitem.mod FK
dataitem = Dataitem.objects.create(mod=asset_model, **validated_data)
# Return a Dataitem instance
return dataitem
There seems to be a library that does this
drf-writable-nested
it handles the creation and serialisation of these types
OneToOne (direct/reverse)
ForeignKey (direct/reverse)
ManyToMany (direct/reverse excluding m2m relations with through model)
GenericRelation (this is always only reverse)
suppose I have this model:
id = models.AutoField(primary_key=True)
datetime_from = models.DateTimeField('time')
model = MyModel
def read(self, request, id=0):
if not id:
id = 0
MyModel.object
mmodel = MyModel.objects.filter(id__gt=id)
return mmodel
My question is, how do I possible get the model fields individually, because I need to validate the datetime_from before I have to output the data on json format
You don't need to create an id column yourself. The read method is not necessary, either. Just say
from django.db import models
class MyModel(models.Model):
datetime_from = models.DateTimeField('time')
You can then query the table like so
>>> obj = MyModel.objects.get(id=<target id here>)
>>> date = obj.datetime_from
etc.