Django serializing Queryset with related entity fields - python

I'm trying to join 2 entities, get specific fields from them, and return a JSON of that.
I tried writing the following code:
import datetime
result = Foo.objects.all()
result = result.select_related('bar').extra(select={'bar_has_address':'IF(bar.has_address = '',0,1)'})
result = result.filter(time__gte=datetime.date.today())
return HttpResponse(serializers.serialize('json', result),mimetype="application/json")
Now I'm only getting a json containing the fields of Foo, whereas I want to get Bar's fields as well, ideally the returned JSON would have specific fields from both entities:
[{
'name': 'lorem ipsum', //from Foo
'has_address': 1, //from Bar
'address': 'some address', //from Bar
'id': 1, //from Foo
},... ]
even under result.values('...') I'm not getting any of Bar's fields
What am I missing here?

As far as I know, django built-in serializers cannot work with model related fields. Take a look at:
DjangoFullSerializers
this answer and suggested serializer
relevant open ticket in django issue tracker
Also see:
Django serialization of inherited model
Serialize django models with reverse One-To-One fields to JSON
Hope that helps.

Related

How to use different key name in MongoDB while working with Django?

I am working on developing a micro service using Django, where I use MongoDB as backend.
Folks who wrote the main code used java hence the data already present in the MongoDB collections follows camelcase pattern for e.g. firstName is the key name.
Now while working with python I like to name my variables and functions using snake casing like first_name and get_first_name().
What I want is that inside the code I want to refer first name as first_name everywhere but while saving/updating the first name in DB and while returning JSON response of the user data I want to return it as firstName?
Is there any way to achieve this behaviour? Please help me?
Use db_column as argument in your models field constructor as described here:
https://docs.djangoproject.com/en/4.0/ref/models/fields/#db-column
Edit: Regarding the API Output, you have two possibilities, either use a Serializer or the .values() function.
Serializer with django-restframework:
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila#example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
https://www.django-rest-framework.org/api-guide/serializers/
.values(): Blog.objects.values('id', 'name') where the arguments define the output key values, https://docs.djangoproject.com/en/4.0/ref/models/querysets/#values

Is there a way to retrieve the value of object instead of its ID?

Is there any way to retrieve the object instead of the ID (pk) when using django.core.serializers.serialize.
I have a model named MenuItem with a ManyToManyField releated to a MenuSubItem.
When I execute this code serializers.serialize('json', MenuItem.objects.all()) I got
{'model': 'support.menuitem', 'pk': 2, 'fields': {'type': 2, 'app_label': None, 'label': 'Intranet Administration', 'sub_item': [**3**]}}
But what I really wanna get is
{'model': 'support.menuitem', 'pk': 2, 'fields': {'type': 2, 'app_label': None, 'label': 'Intranet Administration', 'sub_item': [**objects or objects_attribute**]}}
Or if there is a workaround using other libs
Possible, It's actually a very common thing to do in APIs that there's an article in the docs about it, have a look at DRF serializer relations, This is called a nested serialization, When you want to serializer something that has another something serializable in it, DRF is very fun to learn, There's also JustDjango on YouTube who's explaining some basics to work with DRF
Your code should look look
class mySerializer(serializers.ModelSerializer):
Meta:
model = myModelThatIwantToNest
fields = ['....']
class myOtherSerializer(serializers.ModeSerializer):
myModelThatIwantToNest = mySerializer();
Meta:
model = myOtherModel
fields = ['myModelThatIwantToNest', '...']

Python/Django: Populating Model Form Fields with values from Imported JSON file

I have a model form that saves all form field inputs to the backend database as one entry. I also have a JSON file that contains multiple JSON objects whose fields corresponds to the model form field. This JSON file is being uploaded via FileField in the model. Ultimately, I want to be able to upload a JSON file with the multiple JSON objects into my model form and populate the fields with the corresponding values from the uploaded JSON file. Each JSON object will be a single entry to my database and they can have null values for at least one field. Ideally, I would like to be able to choose which JSON object (from the uploaded JSON file) gets loaded to my model form fields to eventually be saved in my database. How would I go about implementing this?
To unpack a JSON string into a Django model, you can use the Python Standard Library json package to convert it into a dict and then unpack it into the object as keyword arguments using **:
>>> from user.models import User
>>> import json
>>> some_json = '{"username": "cole","password": "testing123"}'
>>> User(**json.loads(some_json))
<User: cole>
>>> User(**json.loads(some_json)).username
'cole'
>>> User(**json.loads(some_json)).password
'testing123'
By the way, there's a nice StackOverflow answer about ** here.
You could use the django rest framework. It will provide a post function and serializers.
You'll wind up with some stuff like this:
# the model
class Book(Model):
title = TextField()
author = TextField()
# the serializer
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# the view
class BookView(generics.ListCreateApiView):
queryset = Book.objects.all()
serializer_class = BookSerializer
see the tutorial for more details:
http://www.django-rest-framework.org/tutorial/1-serialization/#tutorial-1-serialization
Then you can post your data to the database
data = [{'title': 'Moby Dick', 'author': 'Herman Melville'},
{'title': 'A Game of Thrones', 'author': 'George R. R. Martin'}]
for d in data:
r = requests.post('django_api_url/book/', d)
r.raise_for_status()
# the new record is returned if successful
print(r.json())

Update multiple fields on Google NDB entity

Working with Google App Engine for Python, I am trying to create and then update an ndb entity. To update a single property, you can just access the property using a dot, e.g.
post.body = body
But I would like to know if there is a simple way to update multiple fields within an ndb entity. The following code:
class Create(Handler):
def post(self):
## code to get params
post = Post(author = author,
title = title,
body = body)
post.put()
class Update(Handler):
def post(self, post_id):
post = post.get_by_id(int(post_id))
fields = ['author', 'title', 'body']
data = get_params(self.request, fields)
for field in fields:
post[field] = data[field]
post.put()
The "Create" handler works fine, but the "Update" handler results in:
TypeError: 'Post' object does not support item assignment
So it seems I would need to access the properties using a dot, but that is not going to work when I have a list of properties I want to access.
Can someone provide an alternative way to update multiple properties of an NDB entity after it has been created?
You should use setattr.
for field in fields:
setattr(post, field, data[field])
(Note that GAE objects do actually provide a hidden way of updating them via a dict, but you should use the public interface.)
You can use the populate method:
post.populate(**data)

Django/Tastypie - DELETE requests deleting everything

I have the following model
class Open(models.Model):
name=models.TextField()
opened=models.DateTimeField(auto_now_add=True)
user=models.ForeignKey(User)
and the following resources
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
class OpenResource(ModelResource):
user = fields.ForeignKey(UserResource,'user')
class Meta:
queryset = Open.objects.all()
resource_name = 'open'
I'm trying to delete an Open object from some User's open_set.
For posting, I use the following code (using Requests):
content={"name":file_path,
"user":"/api/v1/user/2/"}
requests.post(
url='http://localhost:8000/api/v1/open/',
data=json.dumps(content),
headers={'content-type':'application/json'},
)
which works perfectly and does exactly what I want.
However, when trying to use similar code for deleting:
content={"name":file_path,
"user":"/api/v1/user/2/"}
requests.delete(
url='http://localhost:8000/api/v1/open/',
data=json.dumps(content),
headers={'content-type':'application/json'},
)
it just deletes all the Open objects from that user (in this case, user with id=2), instead of deleting only the Open objects whose "name" is file_path and whose "user" is "/api/vi/user/2/"
What am I missing?
Distinction between list and detail.
The RESTful methods are split into two kinds:
detail (for GET, PUT and DELETE):
/api/v1/objects/1/
and list (for GET, PUT and DELETE):
/api/v1/objects/
POST and PATCH are bit different.
Means that DELETE /api/v1/objects/ will remove all objects.
To delete one object you have to provide path with id:
DELETE /api/v1/objects/1/
Link to documentation
How filtering works in Tastypie:
You cannot just add things to content and wish to be picked up by Tastypie. All not meant to be there information will be ignored by Tastypie.
If you want to filter your list use queryset parameters:
/api/v1/objects/?name=asdfasdf&user=2
And allow filtering of these:
from tastypie.constants import ALL, ALL_WITH_RELATIONS
class Open(models.Model):
name=models.TextField()
opened=models.DateTimeField(auto_now_add=True)
user=models.ForeignKey(User)
filtering = {'name': ALL, 'user': ALL_WITH_RELATIONS}
After these changes you will be able to delete set of objects:
DELETE /api/v1/objects/?name=asdfasdf&user=5
Link to documentation
Edit:
So your call will look like this:
import urllib
content={"name":file_path,
"user":"/api/v1/user/2/"} # If doesn't work change '/api/v1/user/2/' into 2 I am not sure about this
url = 'http://localhost:8000/api/v1/open/?' + urllib.urlencode(content)
requests.delete(
url=url,
data=None,
headers={'content-type':'application/json'},
)

Categories