I'm using Django Rest Framework and I want to send a string array as response as follows:
['data2','data3']
These data are dynamically generated from the model where only values are selected corresponsing to key 'field1' with a filter criterion 'field3'='type1'
If following is the data I've in my model:
[{
'field1':'data1',
'field2':'nodata1',
'field3':'type2'
},
{
'field1':'data2',
'field2':'nodata2'
'field3':'type1'
},
{
'field1':'data3',
'field2':'nodata3',
'field3':'type1'
}]
I've tried with Response(). And using that I could able to send a string but not an array.
NB: I don't want to generate a JSON reponse as shown below.
[{
"field1": "data2"
},
{
"field1": "data3"
}]
Updating the answer:
You can achieve this by using the base APIView class. Below is the sample code:
views.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Label
class LabelList(APIView):
def get(self, request):
response = []
labels = Label.objects.all()
response = [label.field1 for label in labels]
return Response(response)
------------Old Answer-------------
Use generics.ListAPIView to provide the data in an array and use serializer to only have field1.
Let see the sample code.
views.py:
# I am assuming your data to be a label, you can use any name for the class.
class LabelList(generics.ListAPIView):
serializer_class = LabelSerializer
def get_queryset(self):
# For perform any filters based upon loggedin user
return Label.objects.filter(owner=self.request.user)
serializers.py:
class LabelSerializer(serializers.ModelSerializer):
class Meta:
model = Label
fields = [
'field1',
]
Related
How do I make sure that Many-To-Many relationships are considered in my POST-request to a Django Rest Framework API?
I have the following models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Blog(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
tags = models.ManyToManyField(Tag, blank=True, related_name="blogs")
url = models.URLField(max_length=250, unique=True)
owner = models.ForeignKey(User, related_name="blogs", on_delete=models.CASCADE)
slug = models.CharField(max_length=20, default="blogs")
def __str__(self):
return self.name
And I am making the request like:
Frontend (don't mind the missing brackets)
const addContent = (content) => {
axiosInstance
.post(`/content/blogs/`, content, tokenConfig(auth.token))
.then((res) => {
dispatchMessages(
createMessage({ contentAdded: "Submitted successfully" })
);
The content object I am passing in looks like:
const content = {
name: "content title",
description: "content description",
url: "content URL",
tags: ["tag1", "tag2", "tag3"],
};
The POST request itself is going through and all the fields are posted correctly except for the tags, which appear empty.
Example Response:
{
"id": 2,
"tags": [],
"name": "Blog #1",
"description": "Its the best",
"url": "https://website.com",
},
My serializer looks like:
serializers.py
class BlogSerializer(serializers.ModelSerializer):
tags = serializers.SlugRelatedField(many=True, read_only=True, slug_field="name")
owner = CustomOwnerField(read_only=True)
class Meta:
model = Blog
fields = "__all__"
And the viewset:
api.py
class BlogViewSet(viewsets.ModelViewSet):
permission_classes = [
permissions.IsAuthenticatedOrReadOnly
]
serializer_class = BlogSerializer
def get_queryset(self):
return Blog.objects.all()
Thank you for any tips
you have done all the tedious work. The only thing that is not allowing the tags to get saved is the read_only=True in the SlugRelatedField argument. This argument ignores the field when it is posted. So you have to remove read_only=True so that tags get parsed. I would go a little further and add queryset in the slugrelatedfield as queryset=Tags.objects.all()
This would only work if you have already created tags in your db and then you add the same names in your list. If you want to create them dynamically when you post them you have to modify the default create method in your serializer(check here)
I want to send an image array in a JSON as follows:
{"id":1,"timeIntervel":4,"images":["http://127.0.0.1:8000/images/i1.jpg","http://127.0.0.1:8000/images/i2.jpg","http://127.0.0.1:8000/images/i3.jpg","http://127.0.0.1:8000/images/i4.jpg","http://127.0.0.1:8000/images/i5.jpg"]}
I tried this with a foreignkey to my model. But failed to get a response as above.
model.py
class slidesModel(models.Model):
images = models.ImageField(upload_to='')
def __str__(self):
return str(self.images.name)
class slideImageArrayModel(models.Model):
timeIntervel=models.IntegerField()
images = models.ForeignKey(slidesModel, on_delete = models.CASCADE)
def __str__(self):
return str(self.id)
serializer.py
class slideSerializer(serializers.ModelSerializer):
class Meta:
model = slidesModel
fields='__all__'
class slideImgArraySerializer(serializers.ModelSerializer):
class Meta:
model = slideImageArrayModel
fields='__all__'
depth = 1
views.py
class slidesViewSet(viewsets.ViewSet):
def retrieve(self, request, pk=None):
queryset = slideImageArrayModel.objects.all()
user = get_object_or_404(queryset, pk=1) #it will always sends the first object
serializer = slideImgArraySerializer(user)
return Response(serializer.data)
My existing output is something which needs some modification to achieve the actual output:
{
"id": 1,
"timeIntervel": 4,
"images": {
"id": 8,
"images": "/images/b1.jpg"
}
}
I'm testing this in localhost and it's not showing complete url. I've included MEDIA_ROOT url already in settings and urls.py
Just add localhost:8000 in frontend part.
Like this code
<img src={"http://localhost:8000"+ note.img} alt="" role={'button'} onClick={(e)=> window.open(e.target.src)}/>
That will solve your issue.
When I create a post request with json ex.
{
"title":"test",
"company" : "test",
"location" :"test",
"link" :"http://www.google.com/1"
}
The response I recieve is:
{"id":538,"link":"http://www.google.com/1"}
Why are not all of my fields saving to the database?
I've changed fields = '__all__' to fields = ('title', 'company', 'location', 'link') but I get an error:
TypeError at /api/listings/ Object of type TextField is not JSON
serializable
from django.db import models
# Model:
class Listing(models.Model):
title = models.TextField(max_length=100,blank=True),
company = models.TextField(max_length=50, blank=True),
location = models.TextField(max_length=50, blank=True),
link = models.URLField(max_length=250, unique=True)
#------------------------------------------------
from rest_framework import serializers
from listings.models import Listing
#Listing Serializer:
class ListingSerializer(serializers.ModelSerializer):
class Meta:
model = Listing
fields = '__all__'
#------------------------------------------------
from listings.models import Listing
from rest_framework import viewsets, permissions
from .serializers import ListingSerializer
#Listing Viewset:
class ListingViewSet(viewsets.ModelViewSet):
queryset = Listing.objects.all()
#.objects.all().delete()
permissions_classes = [
permissions.AllowAny
]
serializer_class = ListingSerializer
Ended up solving my issue by creating a new project with the same app setup. I am assuming there was some issue with the initial migration of the app model.
I'm using AngularJS on the front-end with Django managing the backend and API along with the Django REST framework package. I have a Project model which belongs to User and has many (optional) Intervals and Statements. I need to be able to create a 'blank' project and add any intervals/statements later, but I'm hitting a validation error when creating the project. Below are the relevant code sections.
Django model code (simplified):
class Project(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='projects', on_delete='models.CASCADE')
project_name = models.CharField(max_length=50)
class Statement(models.Model):
project = models.ForeignKey(Project, related_name='statements', on_delete='models.CASCADE', null=True, blank=True)
class Interval(models.Model):
project = models.ForeignKey(Project, related_name='intervals', on_delete='models.CASCADE', null=True, blank=True)
Django view code (simplified):
class ProjectList(APIView):
def post(self, request, format=None):
serializer = ProjectSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Angular controller code (simplified):
$scope.createProject = function(){
var projectData = {
"user": $scope.user.id,
"project_name": $scope.newProject.project_name
};
apiSrv.request('POST', 'projects', projectData,
function(data){},
function(err){}
);
};
Angular service code (simplified):
apiSrv.request = function(method, url, args, successFn, errorFn){
return $http({
method: method,
url: '/api/' + url + ".json",
data: JSON.stringify(args)
}).success(successFn);
};
Server response:
{"intervals":["This field is required."],"statements":["This field is required."]}
Am I missing something here? I should be able to create a project without a statement or interval, but I'm not able to. Thanks for any suggestions.
Edit: Added Relevant section from ProjectSerializer
class ProjectSerializer(serializers.ModelSerializer):
intervals = IntervalSerializer(many=True)
statements = StatementSerializer(many=True)
class Meta:
model = Project
fields = (
'id',
'project_name',
[removed extraneous project fields]
'user',
'intervals',
'statements'
)
You need to set the read_only attribute on the 'interval' and 'statements' fields
class ProjectSerializer(serializers.ModelSerializer):
intervals = IntervalSerializer(many=True, read_only=True)
statements = StatementSerializer(many=True, read_only=True)
class Meta:
model = Project
fields = ('id', 'project_name', 'user', 'intervals','statements')
or you can specify the read_only fields like this,
class Meta:
model = Project
fields = ('id', 'project_name', 'user', 'intervals','statements')
read_only_fields = ('intervals','statements')
I am creating small Django/AngularJS app. User can create account, view all created posts and add his own posts.
The current version of app is here: GitHub
Models: models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
# Post model
class Post(models.Model):
date = models.DateTimeField(default=datetime.now)
text = models.CharField(max_length=250)
author = models.ForeignKey(User)
Views: views.py
from django.shortcuts import render
from rest_framework import generics, permissions
from serializers import UserSerializer, PostSerializer
from django.contrib.auth.models import User
from models import Post
from permissions import PostAuthorCanEditPermission
...
class PostMixin(object):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [
PostAuthorCanEditPermission
]
def pre_save(self, obj):
"""Force author to the current user on save"""
obj.author = self.request.user
return super(PostMixin, self).pre_save(obj)
class PostList(PostMixin, generics.ListCreateAPIView):
pass
class PostDetail(PostMixin, generics.RetrieveUpdateDestroyAPIView):
pass
...
Serializers: serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
from models import Post
class UserSerializer(serializers.ModelSerializer):
posts = serializers.HyperlinkedIdentityField(view_name='userpost-list', lookup_field='username')
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name', 'posts', )
class PostSerializer(serializers.ModelSerializer):
author = UserSerializer(required=False)
def get_validation_exclusions(self, *args, **kwargs):
# Need to exclude `user` since we'll add that later based off the request
exclusions = super(PostSerializer, self).get_validation_exclusions(*args, **kwargs)
return exclusions + ['author']
class Meta:
model = Post
But when I create request (main.js) to add new post to DB like this:
var formPostData = {text: $scope.post_text};
$http({
method: 'POST',
url: '/api/posts',
data: formPostData,
headers: {'Content-Type': 'application/json'}
})
it raises error:
Request Method: POST
Request URL: http://127.0.0.1:8000/api/posts
Django Version: 1.7.6
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: nucleo_post.author_id
I thought, that this code adds author to the post model before saving. But it doesn't work correctly now.
def pre_save(self, obj):
"""Force author to the current user on save"""
obj.author = self.request.user
return super(PostMixin, self).pre_save(obj)
So I need some help...
this is because the request does not have the user information. For request.user to work, the request should include the authorization related information. Inclusion of this information depends on what authorization mechanism you are using. If you are using token or session based authentication then token or session key should be the part of request header or query param(depends on server implementation). If you are using rest_framework's login view then you should pass username:password along with the request.