How to print model fields as json output? - python

views.py
def districts_list(request):
obj_districts_list = Districts.objects.all()
data = serializers.serialize(
'json', obj_districts_list, fields=('district_name'))
return HttpResponse(data, content_type="application/json")
models.py
class Districts(models.Model):
id = models.AutoField(primary_key=True)
district_name = models.CharField(max_length=40)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
state = models.ForeignKey('States', on_delete=models.CASCADE)
def __str__(self):
return '{}'.format(self.district_name)
OUTPUT:
But i just want the fields inside the Accounts.districts as output in JSON format.

Use QuerySet.values() to retrieve the fields you're interested in as dicts, then pass this to json.dumps(), ie:
>>> qs = User.objects.values("username", "first_name", "last_name", "email", "userprofile__nickname")
>>> print(json.dumps(list(qs), indent=2))
[
{
"username": "toto",
"first_name": "",
"last_name": "",
"email": "toto#example.com",
"userprofile__nickname": "Toto le toto"
},
{
"username": "root",
"first_name": "Root",
"last_name": "Root",
"email": "root#example.com",
"userprofile__nickname": "Root"
},
]
Depending on your models fields, you may have to provide a custom JSONDecoder subclass for datetimes and other types not directly handled by the default JSONEncoder.

Related

How to show the values of an object without the name of foreign key class in Python (Django)

The Customer class has a foreign key to User class. I want to return this information but I don't want to show user__ before username, first_name, etc.
data = {"customers": list(p.values("id", "user__username", "user__first_name",
"user__last_name", "user__email", "phone",
"address", "balance"))}
How can I get something like that:
{
"customers": [
{
"id": 12,
"username": "leon2",
"first_name": "lee",
"last_name": "michalson",
"email": "hamed#example.com",
"phone": "042-22334455",
"address": "Tehran, No.1",
"balance": 20000
}
]
}
Use annotate:
from django.db.models import F
for field in ('username', 'first_name', 'last_name', 'email'):
p = p.annotate(**{field: F('user__' + field)})
data = {"customers": list(p.values("id", "username", "first_name",
"last_name", "email", "phone",
"address", "balance"))}

Django : This field is required on POST request

I'm trying to create a serializer which outputs the Report and also the User information.
My task is accomplished by this serializer:
class ReportSerializer(serializers.ModelSerializer):
latitude = serializers.CharField()
longitude = serializers.CharField()
city = serializers.IntegerField()
type = serializers.IntegerField()
# We have created a field which returns a value from get_marker_icon_url
marker_icon = serializers.SerializerMethodField('get_marker_icon_url')
status_str = serializers.SerializerMethodField('convert_status_toStr')
type_str = serializers.SerializerMethodField('convert_type_toStr')
status_color = serializers.SerializerMethodField('get_status_color')
likes = serializers.SerializerMethodField('random_likes')
user = ReportUserSerializer()
class Meta:
model = Reports
fields = [
'user',
'id',
'type',
'city',
'latitude',
'longitude',
'likes',
'type_str',
'status_str',
'status_color',
'attached_message',
'marker_icon',
'attached_photo',
'date_created'
]
...
With this code my serializer returns a response like this:
[
{
"user": {
"id": 1,
"username": "3nematix",
"profile_pic": "http://192.168.0.29:8000/frontend/static/frontend/images/reports/user_profile_pic.jpg",
"verified": false
},
"id": 1,
"type": 9,
"city": 0,
"latitude": "6.5123333",
"longitude": "51.512586",
"likes": 27,
"type_str": "OTHER",
"status_str": "PENDING",
"status_color": "orange",
"attached_message": "test",
"marker_icon": "OTHER",
"attached_photo": "http://192.168.0.29:8000/frontend/static/frontend/images/reports/user_profile_pic_VRjIYTs.jpg",
"date_created": "2020-10-21T23:19:06.899302Z"
},
......
]
And this is exactly what I need, but the problem is that when I'm trying to create a new object by a POST request, I get this response:
{
"user": [
"This field is required."
]
}
If I would remove 'user' from Meta and user = ReportUserSerializer() from the ReportSerializer class, then I can create a new object, but when I wish to get the Reports I with the Users information I need to add these two again, how can I fix it?
You need to fill the user field yourself before calling save.
Here's the easy way:
class YourView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Or slightly differently:
class YourView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.validated_data['user'] = self.request.user
return super().perform_create(serializer)

Django REST Framework Model Serializer is not showing all fields for POST method?

I'm trying to make custom create()method to save my user profile when a User is created, the serializer works perfect for the GET method, but for POST it only shows one field instead of all fields.
I specified the fields = '__all__' property, but still don't work
GET:
JSON Response:
[
{
"job_title": {
"id": 1,
"name": "Desarrollador"
},
"birthdate": "2019-11-06",
"roles": [
{
"id": 1,
"name": "Administrador",
"description": "Administrador del sistema",
"key": "ADMIN"
}
]
}
]
POST:
Expected JSON:
[
{
"birthdate": "2019-11-06",
}
]
Serializers:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
depth = 1
class UserSerializer(serializers.ModelSerializer):
user_profile = UserProfileSerializer(read_only=False, many=False)
class Meta:
model = User
fields = '__all__'
depth = 1
def create(self, validated_data):
profile_data = validated_data.pop('user_profile')
user = User.objects.create(**validated_data)
UserProfile.objects.create(user=user, **profile_data)
return user
views.py
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
profile = serializers.PrimaryKeyRelatedField(many=False, queryset=UserProfile.objects.all())
queryset = User.objects.all()
serializer_class = UserSerializer
class UserProfileList(generics.ListCreateAPIView):
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user_profile', on_delete=models.CASCADE)
birthdate = models.DateField(default=datetime.date.today)
job_title = models.ForeignKey(JobTitle, related_name='job_title', on_delete=models.CASCADE)
roles = models.ManyToManyField(Role)
def createProfile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.created(user=kwargs['instance'])
post_save.connect(createProfile, sender=User)
def __str__(self):
return self.user.username
I need that POST method also requires the full JSON, the same as the GET JSON response, in order to complete the create method. Need this for POST method:
{
"id": 1,
"user_profile": {
"job_title": {
"id": 1,
"name": "Desarrollador"
},
"birthdate": "2019-11-06",
"roles": [
{
"id": 1,
"name": "Administrador",
"description": "Administrador del sistema",
"key": "ADMIN"
}
]
},
"password": "pbkdf2_sha256$150000$0XdmQpeiPtVl$rQh2MEYV+IO5Y4gm2o1md2cVzgn/mL95r6m1TvRmG3g=",
"last_login": "2019-11-06T00:34:25-06:00",
"is_superuser": true,
"username": "aruiz",
"first_name": "",
"last_name": "",
"email": "correo#correo.com",
"is_staff": true,
"is_active": true,
"date_joined": "2019-11-05T11:37:49-06:00",
"groups": [],
"user_permissions": []
}

Django Python arrange json into a single node

I'm working with a legacy database which has 2 records, the data in each record contain the following values: Name, Email, Company, Phone
These 2 records contain the same data value except the value for Phone which is different.
When I retrieve them in JSON I get the following output:
"results": [
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "123456789"
},
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "1111111"
}
]
My question: As you can see there is some duplicate data in the output above, so is there a way to arrange the JSON output to the following:
"results": [
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "123456789"
"Phone 2": "1111111"
}
]
Here is the code for Views.py file:
class DataView(viewsets.ModelViewSet):
queryset = DataList.objects.all()
serializer_class = DataSerializer
Here is the code for Serializers.py file:
class DataSerializer(serializers.ModelSerializer):
data_details = serializers.SerializerMethodField()
class Meta:
model = DataList
fields = 'data_details'
def get_data_details(self, obj):
return [{
'name': obj.name,
'email': obj.email,
'company': obj.company,
'phone': obj.phone,
}]
Here is the code for models.py file:
class Data(models.Model):
name = models.CharField(db_column='name', primary_key=True, max_length=50)
email = models.CharField(db_column='email', max_length=50)
company = models.CharField(db_column='company', max_length=100)
phone= models.TextField(db_column='phone')
class Meta:
managed = False
db_table = 'data_table'
Thank you.

Create nested object (1-1 relationship) from flattened POST request

I'm trying to implement two serializer classes which will allow me to create both user and profile objects from a flattened POST request.
I tried the implementation described here and it works perfectly fine for updating (and only updating) existing objects.
Here is my current implementation:
# serializers.py
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True, required=True, style={"input_type": "password"}
)
class Meta:
model = User
fields = (
"username",
"password",
# ...
"date_joined",
)
read_only_fields = ("date_joined")
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
def to_representation(self, instance):
representation = super().to_representation(instance)
representation.update(representation.pop("user"))
return representation
def to_internal_value(self, data):
user_internal = {}
for key in UserSerializer.Meta.fields:
if key in data:
user_internal[key] = data.pop(key)
internal = super().to_internal_value(data)
internal["user"] = user_internal
return internal
def create(self, validated_data):
user_data = validated_data.pop("user")
user = User.objects.create(**user_data)
user.set_password(user_data["password"])
user.save()
profile = UserProfile.objects.create(user=user, **validated_data)
return profile
class Meta:
model = UserProfile
fields = (
"user",
"date_updated",
# ...
"phone_number",
)
# views.py
class Register(generics.CreateAPIView):
serializer_class = UserProfileSerializer
name = "userprofile-create"
I expect the app to take the flattened JSON and create both user and profile objects.
Example POST body:
{
"username": "test_user",
"password": "P#$$w0rd",
"first_name": "Foo",
"last_name": "Boo",
"email": "foo#example.com",
"street": "Random Street",
"street_number": "11",
"flat_number": "11",
"zip_code": "11-111",
"city": "Some City",
"province": 1,
"phone_number": "111222333"
}
When I'm browsing through the API, the view still expects JSON with nested User object:
{
"user": {
"username": "",
"password": "",
"first_name": "",
"last_name": "",
"email": ""
},
"street": "",
"street_number": "",
"flat_number": "",
"zip_code": "",
"city": "",
"province": null,
"phone_number": ""
}
Overriding to_internal_value() and to_representation() wasn't correct approach.
I've created only one serializer with all fields and overriden create() method:
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username")
password = serializers.CharField(
source="user.password",
write_only=True,
required=True,
style={"input_type": "password"},
)
first_name = serializers.CharField(source="user.first_name")
last_name = serializers.CharField(source="user.last_name")
email = serializers.EmailField(source="user.email")
def create(self, validated_data):
user_data = validated_data.pop("user")
user = User.objects.create(**user_data)
user.set_password(user_data["password"])
user.save()
profile = UserProfile.objects.create(user=user, **validated_data)
return profile
class Meta:
model = UserProfile
fields = (
"username",
"password",
"first_name",
"last_name",
"email",
"date_updated",
"street",
"street_number",
"flat_number",
"zip_code",
"city",
"province",
"phone_number",
)

Categories