I would like to design models in order to get json output as below. I've been trying different alternatives, using foreignkey or manytomany fields but couldn't get it worked.
This is what I want to get. Every user may have different trainings and each training for the subject user may have more than one date.
{
"userid": "12345",
"username": "John",
"trainings": {
"trn1": [
"20-01-2018"
],
"trn2": [
"20-01-2018",
"20-01-2019"
],
"trn3": [
"20-01-2018",
"20-01-2019",
"15-04-2019"
]
},
"notes": "a note about the user"
}
Depending on the database you are using. Postgres can utilize an ArrayField for storing the list of dates. If you are using any other DB you will need aditional model for dates or save them as a JSON list into a TextField. Here are both options:
With Postgres:
class User(models.Model):
userid = models.CharField()
username = models.CharField()
class Training(models.Model):
trainingid = models.CharField()
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='trainings',
)
dates = ArrayField(
models.DateField()
)
With other DBs:
class User(models.Model):
userid = models.CharField()
username = models.CharField()
class Training(models.Model):
trainingid = models.CharField()
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='trainings',
)
class Date(models.Model):
date = models.DateField()
training = models.ForeignKey(
Training,
on_delete=models.CASCADE,
related_name='dates',
)
Here is how to recreate your json object for any DB option:
users = []
for user in User.objects.all():
current_user = {
'userid': user.userid,
'username': user.username,
'trainings': {}
}
for training in user.trainings:
current_user['trainings'][training.trainingid] = []
for date in training.dates:
current_user['trainings'][training.trainingid].append(date.date)
users.append(current_user)
json_users = json.dumps(users)
Related
I have a question regarding the way I can sort a list of results in a many to one relationship using GraphQL.
Let's take the example from graphene-sqlalchemy.
The schema is:
class Department(Base):
__tablename__ = 'department'
id = Column(Integer, primary_key=True)
name = Column(String)
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String)
hired_on = Column(DateTime, default=func.now())
department_id = Column(Integer, ForeignKey('department.id'))
department = relationship(
Department,
backref=backref('employees',
uselist=True,
cascade='delete,all'))
And here is my Schema :
import graphene
from models import (Employee as EmployeeModel, Department as DepartmentModel)
from graphene_sqlalchemy import (
SQLAlchemyObjectType
)
class Employee(SQLAlchemyObjectType):
class Meta:
model = EmployeeModel
class Department(SQLAlchemyObjectType):
class Meta:
model = DepartmentModek
class Query(graphene.ObjectType):
find_departments = graphene.List(of_type = Department)
def resolve_find_departments(root, info) :
return db.session.query(DepartmentModel).all()
In my query I would like to access the list of employee from my department and order the results by name. My query could look like :
query findDepartments(){
findDepartments{
department{
employee(orderBy : 'name'){
name
}
}
}
}
But this query won't work. How can I achieve the sorting of the nested field employee ?
There are multiple ways to do this, but a simple way is to create a custom resolver with the ordering that you want, i.e. something like
class Query(graphene.ObjectType):
find_departments = graphene.List(of_type = Department)
find_departments_by_name = graphene.List(of_type = Department)
def resolve_find_departments(root, info):
return db.session.query(DepartmentModel).all()
def resolve_find_departments_by_name(root, info):
return db.session.query(DepartmentModel).order_by("name").all() # this is a guess of how sqlalchemy sorting syntax
You can override resolver for employees:
import graphene
from models import (Employee as EmployeeModel, Department as DepartmentModel)
from graphene_sqlalchemy import (
SQLAlchemyObjectType
)
class Employee(SQLAlchemyObjectType):
class Meta:
model = EmployeeModel
class Department(SQLAlchemyObjectType):
class Meta:
model = DepartmentModel
employees = graphene.List(of_type=Employee, order_by=graphene.String())
def resolve_employees(root, info, **kwargs):
query = self.employees
order_arg = kwargs.get('order_by')
if order_org:
# should check that `order_arg` is a column of `Employee`
query = query.order_by(order_arg)
return query.all()
class Query(graphene.ObjectType):
find_departments = graphene.List(of_type = Department)
def resolve_find_departments(root, info) :
return db.session.query(DepartmentModel).all()
Suppose i have two models:
class Region(models.Model):
region_name = models.CharField(
max_length=50, null=False, blank=False, unique=True, verbose_name="Region Name"
)
def __str__(self):
return self.region_name
class Meta:
verbose_name_plural = "Regions"
class Country(models.Model):
region_id = models.ForeignKey(
Region,
null=True,
blank=True,
on_delete=models.CASCADE,
verbose_name="Region id",
)
country_name = models.CharField(
max_length=50, unique=True, null=False, blank=False, verbose_name="Country Name"
)
def __str__(self):
return self.country_name
class Meta:
verbose_name_plural = "Countries"
Now, when i access the country model through Djnago REST Framework, as /api/countries
I get country_name and region_id for example
[
{
"id": 1,
"country_name":"Taiwan",
"region_id": 1
},
...
...
]
Is there any way to get the result like:
[
{
"id": 1,
"country_name":"Taiwan",
"region_id": {
id: 1,
region_name: "Asia",
}
},
...
...
]
I have tried nested serializer example as on the DRF website, but it returns a list of countries if we get the regions api.
like:
[
{
"id": 1,
"region_name":"Asia",
"countries":
[
"Taiwan",
"Japan",
"Vietnam",
...
]
},
...
...
]
I need to know the region name of the country in one api get request. Right now i am using 2 requests. One to get country, and then get region name from region id.
This is my model and serializer if i use nested serializer.
class Region(models.Model):
region_name = models.CharField(
max_length=50, null=False, blank=False, unique=True, verbose_name="Region Name"
)
def __str__(self):
return self.region_name
class Meta:
verbose_name_plural = "Regions"
class Country(models.Model):
region_id = models.ForeignKey(
related_name="countries"
Region,
null=True,
blank=True,
on_delete=models.CASCADE,
verbose_name="Region id",
)
country_name = models.CharField(
max_length=50, unique=True, null=False, blank=False, verbose_name="Country Name"
)
class CountrySerializer(serializers.ModelSerializer):
class Meta:
model = Country
fields = "__all__"
class RegionSerializer(serializers.ModelSerializer):
countries = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='country_name'
)
class Meta:
model = Region
fields = ["id", "region_name", "countries"]
The reason you only get the slugs of the related Countrys is because you use the SlugRelatedField, that will thus list the slugs of the Countrys.
The trick is to make extra serializers that will serializer the related object(s). For example:
class ShallowRegionSerializer(serializers.ModelSerializer):
class Meta:
model = Region
fields = '__all__'
class CountrySerializer(serializers.ModelSerializer):
region_id = ShallowRegionSerializer()
class Meta:
model = Country
fields = '__all__'
class CountryRegionSerializer(serializers.ModelSerializer):
class Meta:
model = Country
fields = '__all__'
class RegionSerializer(serializers.ModelSerializer):
countries = CountryRegionSerializer(
many=True,
read_only=True
)
class Meta:
model = Region
fields = ['id', 'region_name', 'countries']
Now you can make use of the CountrySerializer and the RegionSerializer. When serializing objects, it will use other serializers, like the ShallowRegionSerializer and CountryRegionSerializer to serialize related object(s).
Behind the scenes, Django appends "_id" to the field name to create
its database column name.
Django ORM adds _id into ForeignKeys, so when I create json format, the column appears with _id at the end, how to remove _id ?
{
"ModelID_id": 1,
"ID": 1,
"DataDefinitionID_id": 1
},
// JSON Builder
ModelDependecy_queryset = Modeldatadependency.objects.values().all()
return Response({"ModelDataDependency": list(ModelDependecy_queryset)},200)
// Model file
class Modeldatadependency(models.Model):
ID = models.AutoField(primary_key=True)
ModelID = models.ForeignKey(Model, models.DO_NOTHING, db_column='ModelID', blank=True, null=True)
DataDefinitionID = models.ForeignKey(Datadefinition, models.DO_NOTHING, db_column='DataDefinitionID', blank=True, null=True)
class Meta:
managed = False
db_table = 'ModelDataDependency'
app_label = 'default'
You can add a method that will return what you need
class Modeldatadependency(models.Model):
ModelID = models.ForeignKey(Model, blank=True, null=True)
DataDefinitionID = models.ForeignKey(Datadefinition, blank=True, null=True)`enter code here`
def get_json(self):
return dict(
ModelID =self.ModelID,
ID =self.id,
DataDefinitionID =self.DataDefinitionID)
I am trying to return JSON or even a complete string of a returned one to many sqlalchemy query. I am using Marshmallow at this point to try do it but it keeps returning incomplete data
I have two models defined as :
class UserModel(db.Model):
__tablename__ = 'usermodel'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
password = db.Column(db.String(120))
weekday = db.relationship('weekDay', cascade='all,delete-orphan', single_parent=True, backref=db.backref('usermodel', lazy='joined'))
class weekDay(db.Model):
__tablename__ = 'weekday'
id = db.Column(db.Integer, primary_key=True)
#Defining the Foreign Key on the Child Table
dayname = db.Column(db.String(15))
usermodel_id = db.Column(db.Integer, db.ForeignKey('usermodel.id'))
I have defined two schemas
class WeekdaySchema(Schema):
id = fields.Int(dump_only=True)
dayname = fields.Str()
class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str()
password = fields.Str()
weekday = fields.Nested(WeekdaySchema)
and finally I run the command (I pass the name in userName variable)
userlist = UserModel.query.filter_by(parentuser=userName).all()
full_schema = UserSchema(many=True)
result, errors = full_schema.dump(userlist)
print (result)
I print the result to see before I attempt to Jsonify it:
My weekday object is completely empty
'weekday': {}
Doesn anyone know how I can do this correctly
It's a one-to-many relationship and you must indicate it on UserSchema, like that
class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str()
password = fields.Str()
weekday = fields.Nested(WeekdaySchema, many=True)
read more on documentation
I have a model called A with following fields
class A(models.Model):
f_name = models.CharField(max_length=30, null=True, blank=True)
l_name = models.CharField(max_length=30, null=True, blank=True)
email = models.EmailField(unique=False)
phone = models.CharField(max_length=30, null=True, blank=True)
Now I'm creating another model B from model A
class B(A):
class Meta:
proxy = True
admin class for B is
class BAdmin(admin.ModelAdmin):
list_display = ('email','first_name', 'last_name', 'phone')
I want to display only distinct email in model B from model A in admin site?
Note: I don't want disturb model A but i want to get unique email records in BAdmin
for example records in model A
test2#xyz.com test2 xxx
test2#xyz.com test2 xxx
test3#zxc.com test3 xyz
I want to display unique records in model B admin as
test2#xyz.com test2 xxx
test3#zxc.com test3 xyz
I tried by writing queryset in BAdmin by
def queryset(self, request):
qs = super(BAdmin, self).queryset(request)
qs = qs.distinct('email')
return qs
when i write above , I am getting DISTINCT ON fields is not supported by this database backend(MySQL) error is there another way to to display unique records in model B?
You can use queryset() method in ModelAdmin class to filter what you want:
class BAdmin(admin.ModelAdmin):
list_display = ('email', 'first_name', 'last_name', 'phone')
def queryset(self, request):
qs = super(BAdmin, self).queryset(request)
qs = qs.distinct('email')
return qs