models.py:
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
LEXERS = [item for item in get_all_lexers() if item[1]]
class Classname(models.Model):
class_name = models.CharField(max_length=5)
owner = models.ForeignKey('auth.User', related_name='fab')
highlighted = models.TextField()
def save(self, *args, **kwargs):
lexer = get_lexer_by_name(self.class_name)
options = self.class_name and {'class': self.class_name} or {}
formatter = HtmlFormatter(full=True, **options)
self.highlighted = highlight(self.class_name, lexer, formatter)
super(Classname, self).save(*args, **kwargs)
serializers.py:
from django.forms import widgets
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Classname
class ClassSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='fab-highlight', format='html')
class Meta:
model = Classname
fields = ('id', 'owner', 'class_name', 'highlight',)
class UserSerializer(serializers.ModelSerializer):
fab = serializers.HyperlinkedRelatedField(many=True, view_name='user-detail', read_only=True)
class Meta:
model = User
fields = ('id', 'username', 'fab',)
urls.py:
from django.conf.urls import url, patterns
from rest_framework.urlpatterns import format_suffix_patterns
from . import views
urlpatterns = [
url(r'^class/$', views.ClassList.as_view()),
url(r'^class/(?P<pk>[0-9]+)/$', views.ClassDetail.as_view()),
url(r'^section/$', views.SectionList.as_view()),
url(r'^section/(?P<pk>\d+)/$', views.SectionDetail.as_view()),
url(r'^teacher/$', views.TeacherList.as_view()),
url(r'^teacher/(?P<pk>[0-9]+)/$', views.TeacherDetail.as_view()),
url(r'^attend/$', views.AttendanceList.as_view()),
url(r'^attend/(?P<pk>[0-9]+)/$', views.AttendanceDetail.as_view()),
]
When I changed my serializers.py file and try to add HyperLinked as per the tutorial then I got the above error, I'm not using ViewSets and Routers. I don't know what's the problem b'coz I've checked my url's and views everything seems to be fine.
I'm confused, Please help me to find and fix the issue....
Thanks in advance.....
The exact issue is that I'm using namespace in urls and I've used it in my project level urls.py file also. So in the views file I have to follow django-namespacing like this:
'users': reverse('student:user-list', request=request, format=format),
while 'student' is the namespace that I've used in my project level urls like:
url(r'^stu/', include('app.urls', namespace = 'student'),
Related
I have a Django REST Framework project which uses a ModelViewSet to create APIs for a model containing a FileField.
I've shared a full example of a Django project demonstrating this issue here. But to summarise the key components:
models.py
from django.db import models
class Profile(models.Model):
image = models.FileField(upload_to='uploads/%Y/%m/%d/')
views.py
from rest_framework import (
viewsets,
serializers,
parsers,
)
from sample import models
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = models.Profile
fields = ['id', 'image']
read_only_fields = ['id']
class ProfileViewSet(viewsets.ModelViewSet):
serializer_class = ProfileSerializer
queryset = models.Profile.objects.all()
urls.py
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from rest_framework.routers import DefaultRouter
from sample import views
router = DefaultRouter()
router.register('profile', views.ProfileViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/schema/', SpectacularAPIView.as_view(), name='api-schema'),
path(
'api/docs/',
SpectacularSwaggerView.as_view(url_name='api-schema'),
name='api-docs',
),
path('', include(router.urls)),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py (REST_FRAMEWORK configuration only):
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
requirements.txt
Django==3.2.3
djangorestframework==3.12.4
drf-spectacular==0.16.0
I am generating browsable Swagger-UI docs using drf-spectacular to document the API.
The problem is that the FileField input in Swagger-UI is a string input, and doesn't give the option to set a file:
I would like to have a file input where I can choose a file which will be sent to the API.
My question is: How can I configure DRF or drf-spectacular to show this field?
After some digging through the drf-spectacular docs and GitHub issues, I found that the FileField can be set to binary by adding the following to in settings.py:
SPECTACULAR_SETTINGS = {
'COMPONENT_SPLIT_REQUEST': True
}
Also in Swagger UI, make sure you change the content-type from application/json to multipart/form-data and click Try it out. The upload button will apppear.
I am currently implementing an API client for which I want to validate the request sent using serializers.
To do so, I create my serializer like this:
class TransactionRequestSerializer(serializers.Serializer):
counterparty = serializers.UUIDField(required=False)
from_datetime = serializers.DateTimeField(required=False, source='from')
to_datetime = serializers.DateTimeField(required=False, source='to')
transaction_type = serializers.CharField(required=False, source='type')
Issue is that source doesn't fit my usage, because when I do serializer.data, I get:
{'from_datetime': '2020-07-07T16:08:00.313236+02:00'}
Instead of
{'from': '2020-07-07T16:08:00.313236+02:00'}
Those data are then passed as params for my request, like requests.get('', params=params)
Of course, I cannot name the field "from" as it is reserved. Any idea about how can I get "from" in my serializer.data?
I tink this has already been answered.
Please take a look at this question: How to change field name in Django REST Framework
I think the same solution will work for you.
I think it's not possible, so I switched to Serializer.validated_data instead so I can use source.
this example as same the question :
model:
from django.db import models
class ReceiveCallbackUrl(models.Model):
From = models.CharField(max_length=14)
to = models.CharField(max_length=14)
message = models.CharField(max_length=255)
messageid = models.IntegerField()
serializer:
from rest_framework.serializers import ModelSerializer,SerializerMethodField
from .models import ReceiveCallbackUrl
class ReceiveCallbackUrlModelSerializer(ModelSerializer):
From = SerializerMethodField('from')
class Meta:
model = ReceiveCallbackUrl
fields = ['From', 'to', 'message', 'messageid']
view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializer import ReceiveCallbackUrlModelSerializer
class ReceiveCallbackUrlAPIView(APIView):
def post(self, request):
serializer = ReceiveCallbackUrlModelSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(request.POST, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)
How to deal with ordering in drf_yasg?
I have a View:
class ContentView(ModelViewSet):
....
ordering_fields = ['price',]
But when I open swagger I cant see this possibility.
I found a solution, maybe somebody need this too.
I use django_filters package and in this case we should use filter_class on our view and there we can define ordering as we need.
Example:
from django_filters import rest_framework as filters, OrderingFilter
from contents.models import Content
class ContentFilter(filters.FilterSet):
order = OrderingFilter(
# tuple-mapping retains order
fields=(
('price', 'price'),
),
field_labels={
'price': 'Content price',
}
)
class Meta:
model = Content
fields = ['price']
# my view in views.py
class ContentView(ModelViewSet):
filter_class = ContentFilter
.....
Now you can use ordering ?order=price or ?order=-price and you can see it on swagger docs
More info about OrderingFilter in django_filters here
from rest_framework.filters import OrderingFilter
class OrderingFilterWithSchema(OrderingFilter):
def get_schema_fields(self, view):
self.ordering_description = [enter image description here][1]ordering choicese: " + ', '.join(view.ordering_fields)
return super().get_schema_fields(view)
And in your view:
class ListView(ListAPIView):
filter_backends = [OrderingFilterWithSchema]
ordering_fields = ['price', 'created_at', 'manufacturer_year', 'spent_kilometers']
And the URL will be like:
?ordering=-price or ordering=price
...etc
I need to combine external json using request and Internal Database, But the condition is when someone call API we need to get empidlong from Model for call external API from specific URL, Then external API will return JSON and i need to merge this JSON with my json that create by Django REST API Framework
Here is my code
models.py :
from django.db import models
import requests
from django.core.files import File
from urllib import request
import os
# Create your models here.
class getData(models.Model):
company = models.CharField(max_length=150)
description = models.CharField(max_length=150)
period = models.CharField(max_length=150)
plate_no = models.CharField(max_length=150, primary_key=True)
project_code = models.CharField(max_length=150)
costcenter = models.CharField(max_length=150)
empidlong = models.CharField(max_length=150)
class Meta:
db_table = 'car_information'
serializers.py
from rest_framework import serializers
from .models import getData
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = getData
fields = "__all__"
views.py
from django.shortcuts import render
from rest_framework import viewsets, filters
from .models import getData
from .serializers import CarSerializer
import requests
class CarViewSet(viewsets.ModelViewSet):
queryset = getData.objects.all()
serializer_class = CarSerializer
filter_backends = (filters.SearchFilter,)
#search_fields = ('plate_no')
__basic_fields = ('plate_no',)
search_fields = __basic_fields
serializer = CarSerializer(queryset, many=True)
data = serializer.data
for a in data:
empid= a['empidlong']
r = requests.get('http://192.168.10.32/Employees/'+empid)
def get_queryset(self):
queryset = getData.objects.all()
emp = self.request.query_params.get('emp', None)
if emp is not None:
queryset = queryset.filter(empidlong=emp)
return queryset
I have no idea how to do it. I stuck this for week.
Thank in advance.
Where are you expecting the json from? if from a user, you can access the json from the request. Then you can use it in your orm query. You CarViewSet seem to be doing way more than it should be. What is your goal exactly?
I am creating APIView for book list and add, delete.
Is this serialization the right way?
I want to show a list of books, but I do not know what to put in '?'.
member/models.py
class MyUser(AbstractBaseUser, PermissionsMixin):
username = models.EmailField(unique=True, max_length=256)
nickname = models.CharField(max_length=256)
is_staff = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
mybook = models.ManyToManyField(Book)
book/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=256)
author = models.CharField(max_length=200)
def __str__(self):
return self.title
book/seralizers.py
from rest_framework import serializers
from book.models import Book
class MyBookSerializer(serializers.ModelSerializer):
mybook = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Book
fields = (
'title',
'author',
)
apiview.py
class MyBook(APIView):
def get(self, request):
mybook = Book.objects.filter(myuser=?)
serializer = MyBookSerializer(mybook)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request):
pass
def delete(self, request):
pass
If you want create a CRUD for model, depends on a request.user you can simply use ModelViewSet:
from rest_framework import viewsets
class MyBookViewSet(viewsets.ModelViewSet):
serializer_class = MyBookSerializer
def get_queryset(self, request):
return Book.objects.filter(myuser=self.request.user)
That's all for view. You only need to specify router for a viewset.
urls.py:
from rest_framework import routers
router = routers.DefaultRouter()
router.register('books', MyBookViewSet)
urlpatterns = []
urlpatterns += router.urls
Include this usl file in a root urls and you are done.
You also need to specify related_name for m2m field if you want to use myuser name:
mybook = models.ManyToManyField(Book, related_name='myuser')
And you don't need this field in a serializer:
mybook = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
viewsets docs
routers docs