I have 2 models named Recipe and Step..
I have serialized both to make an API for GET request.. I want to know is there a way to create for POST request so that I can send both the data (steps and recipe) in the same request?
models.py:
from django.db import models
class Recipe(models.Model):
title = models.CharField( max_length=50)
uuid = models.CharField( max_length=100)
def __str__(self):
return f'{self.uuid}'
class Step(models.Model):
step = models.CharField(max_length=300)
uuid = models.ForeignKey(Recipe, on_delete=models.CASCADE)
def __str__(self):
return f'{self.step} - {self.uuid}'
serializers.py:
from rest_framework import serializers
from .models import *
class RecipeSerializer(serializers.ModelSerializer):
class Meta:
model = Recipe
fields = ['title', 'uuid']
class StepSerializer(serializers.ModelSerializer):
class Meta:
model = Step
fields = ['step', 'uuid']
views.py:
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import *
from .models import *
#api_view(['GET'])
def apiOverview(request):
api_urls = {
'List':'/recipe-list/',
'Detail View':'/recipe-detail/<str:pk>/',
'Create':'/recipe-create/',
'Update':'/recipe-update/<str:pk>/',
'Delete':'/recipe-delete/<str:pk>/',
'Steps' : '/steps/<str:pk>'
}
return Response(api_urls)
#api_view(['GET'])
def recipeList(request):
recipes = Recipe.objects.all()
serializer = RecipeSerializer(recipes, many=True)
return Response(serializer.data)
#api_view(['GET'])
def recipeDetail(request, pk):
recipe = Recipe.objects.get(uuid=pk)
recipe_serializer = RecipeSerializer(recipe, many=False)
steps = Step.objects.filter(uuid=pk)
steps_serializer = StepSerializer(steps, many=True)
return Response({
'recipe' : recipe_serializer.data,
'steps' : steps_serializer.data
})
How can I create a view for POST and handle both the models?
Try:
from rest_framework import generics
from .models import *
class StepAndRecipe(generics.CreateAPIView):
queryset = Step.objects.all()
queryset = Recipe.objects.all()
serializer_class = StepSerializer
serializer_class = RecipeSerializer
Add in urls.py:
from django.urls import path
from .views import StepAndRecipe
urlpatterns = [
path('steprecipepost', StepAndRecipe.as_view(), name='steps_recipes')
This will only work with POST! And one more thing: take care with the raw data and the HTML form, maybe theses get a little confused since you are using two models in the same view.
Related
I want to add a new comment with the post method, but it gives an error
{'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got ModelBase.', code='invalid')]}
Serializers :
from rest_framework import serializers
from .models import Products,ProductsComments
class ProdcutsSerializers(serializers.ModelSerializer):
colors = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
category = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
sizes = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
class Meta:
model = Products
fields = '__all__'
class ProductsCommentsSerializers(serializers.ModelSerializer):
user = serializers.SlugRelatedField(many=True,read_only=True,slug_field='id')
product = serializers.SlugRelatedField(many=True,read_only=True,slug_field='id')
class Meta:
model = ProductsComments
fields = '__all__'
Views :
from rest_framework.decorators import api_view,permission_classes
from rest_framework.response import Response
from rest_framework import status
from .serializers import *
from .models import *
#api_view(['GET'])
def products_list(request):
products = Products.objects.all()
data = ProdcutsSerializers(products,many=True).data
return Response(data)
#api_view(['GET'])
def products_comments_list(request):
products_comments = ProductsComments.objects.all()
data = ProductsCommentsSerializers(products_comments,many=True).data
return Response(data)
#api_view(['POST'])
def products_comments_add(request):
data = ProductsCommentsSerializers(data=ProductsComments)
if data.is_valid():
print('Ok')
else:
print('not')
#print(data)
print(data.errors)
return Response({"M": "not"})
How can I send a 220,000-line CSV file to Django using the Rest Framework API? Thank you.
#Botta- How about something like this
from django.db import models
Create your models here.
class MyFile(models.Model):
file = models.FileField(blank=False, null=False,upload_to='images/')
description = models.CharField(null=True,max_length=255)
uploaded_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'MyFiles'
class MyFileView(APIView):
# MultiPartParser AND FormParser
# https://www.django-rest-framework.org/api-guide/parsers/#multipartparser
# "You will typically want to use both FormParser and MultiPartParser
# together in order to fully support HTML form data."
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
file_serializer = MyFileSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
from rest_framework import serializers
from .models import MyFile
class MyFileSerializer(serializers.ModelSerializer):
class Meta:
model = MyFile
fields = ('file', 'description', 'uploaded_at')
#Stacy Hi. I made the changes, but it didn't work. I would like the fields in the CSV file to go automatically to my models and to the REST API. I would like to import my CSV data when uploading the file. Thanks.
models.py
from django.db import models
class MyFile(models.Model):
file = models.FileField(blank=False, null=False,upload_to='images/')
description = models.CharField(null=True,max_length=255)
uploaded_at = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=150)
sex = models.CharField(max_length=150)
age = models.CharField(max_length=50)
height = models.CharField(max_length=150)
def __str__(self):
return self.description
class Meta:
verbose_name_plural = 'MyFiles'
serializers.py
from rest_framework import serializers
from .models import MyFile
class MyFileSerializer(serializers.ModelSerializer):
class Meta:
model = MyFile
fields = ("file", "description", "uploaded_at", "name", "sex", "age", "height",)
#Stacy- Hello. I was able to upload the csv file and pass it to my API as .CSV, however, I would like all fields in my CSV file to be transferred to API Rest. For example ID, Name, Age and Profile. It's possible? Thank you. Thank you.
serializers.py
from rest_framework import serializers
from .models import MyFile
class MyFileSerializer(serializers.ModelSerializer):
class Meta:
model = MyFile
fields = ('file', 'description', 'uploaded_at')
models.py
from django.db import models
class MyFile(models.Model):
file = models.FileField(blank=False, null=False,upload_to='images/')
description = models.CharField(null=True,max_length=255)
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.description
class Meta:
verbose_name_plural = 'MyFiles'
views.py
from rest_framework.parsers import MultiPartParser, FormParser
from .models import MyFile
from .serializers import MyFileSerializer
from rest_framework import generics
from rest_framework import viewsets
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.exceptions import NotFound
from rest_framework.response import Response
from rest_framework.views import APIView
class MyFileViewSet(viewsets.ModelViewSet):
queryset = MyFile.objects.all()
serializer_class = MyFileSerializer
urls.py
from .views import MyFileViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', MyFileViewSet)
urlpatterns = router.urls
Here I have an endpoint to create media content for users. The endpoint works, but I have a feeling my design implementation is incorrect.
Should validation logic be contained in serializers create? Is this bad practice? I attempted to move validation logic to models.py, but ran into issues with accessing the model, specifically this line - self.model(user=user, category=category).
view.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import UserMedia
from .renderers import UserMediaSerializerJSONRenderer
from .serializers import UserMediaSerializer
class UserMediaCreateAPIView(APIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserMediaSerializerJSONRenderer,)
serializer_class = UserMediaSerializer
def post(self, request):
userMedia = request.data.get('userMedia', {})
serializer = self.serializer_class(data=userMedia)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user, category=userMedia['category'])
return Response(serializer.data, status=status.HTTP_201_CREATED)
serializers.py
from rest_framework import serializers
from .models import UserMedia
class UserMediaSerializer(serializers.ModelSerializer):
category = serializers.CharField(allow_blank=False, required=True)
class Meta:
model = UserMedia
fields = ('category',)
read_only_fields = ('category',)
def get_category(self, obj):
if obj.category:
return obj.category
return 'N/A'
def create(self, validated_data):
if validated_data['user'] is None:
raise TypeError('User media must have a user')
if validated_data['category'] is None:
raise TypeError('User media must have a category.')
if validated_data['category'] not in dict(UserMedia.CATEGORY_CHOICES):
raise TypeError('User media category is not available.')
userMedia = UserMedia(**validated_data)
userMedia.save()
return userMedia
models.py
from django.db import models
class UserMedia(models.Model):
user = models.ForeignKey('authentication.User', on_delete=models.CASCADE, related_name='media')
MUSIC = 'M'
VIDEO = 'V'
CATEGORY_CHOICES = (
(MUSIC, 'Music'),
(VIDEO, 'Video'),
)
category = models.CharField(max_length=1, choices=CATEGORY_CHOICES, blank=False)
The validation should be done in your view. The serializers should just be for serializing data. The validation should be done in your view then the serializer is called from your view. As far as this line self.model(user=user, category=category) is concerned it does not appear that you ever import user any where.
I am new to both Python and Django and I would appreciate some guidance with a problem I'm having with Django REST, nested JSON and the serializer.
I wish to post:
{ "Server": [
{
"serverSerialNumber": "0000",
"serverUniqueKey": "2222"
},
{
"serverSerialNumber": "0001",
"serverUniqueKey": "2223"
}
]
}
This is my serializer:
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from .models import Api
class ApiSerializer(serializers.ModelSerializer):
"""Serializer to map the Model instance into JSON format."""
class Meta:
"""Meta class to map serializer's fields with the model fields."""
model = Api
fields = ('id', 'serverSerialNumber', 'serverUniqueKey', 'date_created', 'date_modified')
read_only_fields = ('date_created', 'date_modified')
depth = 1
I simply receive the following back:
{
"serverSerialNumber": [
"This field is required."
]
}
So I am not understanding how to use 'depth' or I'm doing something silly.
Adding View per request:
from django.shortcuts import render
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from rest_framework import generics
from .serializers import ApiSerializer
from .models import Api
class CreateView(generics.ListCreateAPIView):
"""This class defines the create behavior of our rest api."""
queryset = Api.objects.all()
serializer_class = ApiSerializer
def perform_create(self, serializer):
"""Save the post data when creating a new item."""
serializer.save()
Ok, so I've stumbled through some documentation and had another bash at this.
Still not working but the code seems to make more sense, here is the new code and error:
serializers.py
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from .models import Blade, Servers
class BladeSerializer(serializers.ModelSerializer):
class Meta:
model = Blade
fields = ('id', 'serverSerialNumber', 'serverUniqueKey', 'date_created', 'date_modified')
read_only_fields = ('date_created', 'date_modified')
class ServersSerializer(serializers.ModelSerializer):
Server = BladeSerializer(many=True)
class Meta:
model = Servers
fields = ['Server']
def create(self, validated_data):
servers_data = validated_data.pop('Server')
srv = Servers.objects.create(**validated_data)
for server_data in servers_data:
Blade.objects.create(srv=srv, **server_data)
return srv
views.py
from django.shortcuts import render
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from api.serializers import UserSerializer, GroupSerializer
from rest_framework import generics
from .serializers import BladeSerializer, ServersSerializer
from .models import Blade, Servers
class CreateView(generics.ListCreateAPIView):
queryset = Servers.objects.all()
serializer_class = ServersSerializer
def perform_create(self, serializer):
serializer.save()
models.py
from django.db import models
from inventory.models import Server
class Blade(models.Model):
instanceId = models.CharField(max_length=255, blank=True, unique=False)
chassisUniqueKey = models.CharField(max_length=255, blank=True, unique=False)
serverUniqueKey = models.CharField(max_length=255, blank=True, unique=False)
serverSerialNumber = models.CharField(max_length=255, blank=False, unique=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return "{}".format(self.name)
class Servers(models.Model):
Servers = models.CharField(max_length=10, blank=True, unique=False)
def __str__(self):
"""Return a human readable representation of the model instance."""
return "{}".format(self.name)
The error
Got AttributeError when attempting to get a value for field Server on serializer ServersSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Servers instance.
Original exception text was: 'Servers' object has no attribute 'Server'.
Try this,
class CreateView(generics.ListCreateAPIView):
queryset = Api.objects.all()
serializer_class = ApiSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, many=True)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
I am working on form models and get this error:
global name 'AdForm' is not defined
In my view I have:
from django.template import RequestContext, loader
from django.http import HttpResponse
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django import forms
#login_required
def create(request):
if request.POST:
ad = AdForm(request.POST)
if ad.is_valid():
test = 'valid'
else:
test = 'invalid'
else:
test = 'none'
template = loader.get_template('ads/create.html')
context = RequestContext(request, {
'test': test
})
return HttpResponse(template.render(context))
However it is not picking up my model. My model in my view is:
from django.db import models
from django.forms import ModelForm
TYPE_CHOICES = (
'Image',
'Code',
)
SIZE_CHOICES = (
'Leaderboard',
'Banner',
'Skyscraper',
'Square',
)
class Ad(models.Model):
title = models.CharField(max_length=40)
type = models.CharField(max_length=7)
size = models.CharField(max_length=16)
clicks = models.IntegerField()
media = models.ImageField(upload_to='ads')
link = models.URLField(null=True)
created = models.DateTimeField(auto_now_add=True)
expires = models.DateTimeField(null=True)
def __unicode__(self):
return self.name
class AdForm(ModelForm):
class Meta:
model = Ad
Does anyone know why it is not picking up the form model?
Thanks from a noob.
At the top of your view, you need:
from .models import AdForm
Also, forms usually go in forms.py, not with the models.