I have a problem with DRF
I have a model
from django.contrib.sites.models import Site
class Person(models.Model):
site = ForeignKey(Site, on_delete=models.CASCADE)
I want to create a viewset and serializer and I want to get the specific url:
/api/sites/{pk}/persons/
And get all persons that They have associate site
Or
/api/sites/{pk}/persons/{pk}
How can I do?
Try this
# serializers.py
from rest_framework import serializers
class PersonSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Person
# views.py
from rest_framework.viewsets import ModelViewSet
class PersonViewset(ModelViewSet):
serializer_class = PersonSerializer
def get_queryset(self):
return Person.objects.filter(site_id=int(self.kwargs['site_id']))
router config will be as
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'/api/sites/<site_id>/persons', views.PersonViewset)
Related
I'm trying to follow a tutorial from the book 'Django for APIs', this tutorial consists on doing a blog project API with django rest framework.
I cant get to work the UserDetail view at url: 'http://127.0.0.1:8000/api/v1/users/int:pk/'
it raises the following error ,although queryset is defined in the UserDetail class in views.py:
AssertionError at /api/v1/users/1/
'UserDetail' should either include a queryset attribute, or override the get_queryset() method.
here is the code:
urls.py
views.py
serializers.py
models.py
urls.py:
from django.urls import path
from .views import UserList, UserDetail, PostList, PostDetail
urlpatterns = [
path('users/',UserList.as_view()),
path('users/<int:pk>/', UserDetail.as_view()),
path('',PostList.as_view()),
path('<int:pk>/', PostDetail.as_view()),
]
views.py:
from django.contrib.auth import get_user_model
from rest_framework import generics
from .models import Post
from .permissions import IsAuthorOrReadOnly
from .serializers import PostSerializer, UserSerializer
# Create your views here.
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,)
queryset = Post.objects.all()
serializer_class = PostSerializer
class UserList(generics.ListCreateAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset_= get_user_model().objects.all()
serializer_class = UserSerializer
serializers.py:
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id','author','title','body','created_at',)
model = Post
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id','username',)
models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
author = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
Please check your UserDetail, it should queryset not queryset_
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = get_user_model().objects.all()
A newbie here in the world of Django. I am struggling with creating a hyperlink for a nested route.
The error I am getting is:
Could not resolve URL for hyperlinked relationship using view name "rest:campaign-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
Some project setup notes
Using django rest framework
using DRF-extensions to create the routes
Using ModelViewSet
Expected end points:
/accounts/
/accounts/< pk >/
/accounts/< pk >/campaigns/
/accounts/< pk >/campaigns/< pk >/
/accounts/< pk >/campaigns/adgroup/
/accounts/< pk >/campaigns/adgroup/< pk >/
Set a namespace of rest in urls.py
Using HyperlinkedIdentityField to create the hyperlink. It only works with the parent object i.e.
url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')
However fails with any nested object i.e.
url = serializers.HyperlinkedIdentityField(view_name='rest:campaign-detail')
The model is quiet simple, an Account can have many Campaigns, and a campaign can have many AdGroups. See code below:
models.py
from django.db import models
from django.db.models import Q
from model_utils import Choices
ORDER_COLUMN_CHOICES = Choices(
('0', 'id'),
('1', 'keyword'),
('2', 'status'),
('3', 'match_type'),
)
# Account
class Account(models.Model):
account_name = models.CharField(max_length=128)
def __str__(self):
return self.account_name
# Campaign
class Campaign(models.Model):
class Status(models.TextChoices):
Enabled = "Enabled"
Paused = "Paused"
account = models.ForeignKey(
to=Account, on_delete=models.CASCADE, related_name='campaigns'
)
campaign_name = models.CharField(max_length=128)
status = models.CharField(max_length=21, choices=Status.choices, default=Status.Paused)
def __str__(self):
return self.campaign_name
# AdGroup
class AdGroup(models.Model):
class Status(models.TextChoices):
Enabled = "Enabled"
Paused = "Paused"
campaign = models.ForeignKey(
to=Campaign, on_delete=models.CASCADE, related_name='adgroups'
)
adgroup_name = models.CharField(max_length=128)
status = models.CharField(max_length=21, choices=Status.choices, default=Status.Enabled)
def __str__(self):
return self.adgroup_name
views.py
from rest_framework import viewsets
from .serializers import *
from . import models
from rest_framework_extensions.mixins import NestedViewSetMixin
class AccountViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = AccountSerializer
queryset = models.Account.objects.all()
class CampaignViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = CampaignSerializer
queryset = models.Campaign.objects.all()
class AdGroupViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = AdGroupSerializer
queryset = models.AdGroup.objects.all()
serializers.py
from rest_framework import serializers
from . import models
class CampaignSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="rest:campaign-detail")
class Meta:
model = models.Campaign
fields = '__all__'
class AccountSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')
class Meta:
model = models.Account
fields = '__all__'
class AdGroupSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='rest:adgroup-detail')
class Meta:
model = models.AdGroup
fields = '__all__'
I have 2 URL files. The project is named Vanilla and an app named rest where the DRF logic sits.
Vanilla urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('rest.urls', namespace='rest')),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('admin/', admin.site.urls)
]
Rest urls.py
from django.urls import include, path
from . import views
from rest_framework_extensions.routers import ExtendedSimpleRouter
app_name = 'rest'
router = ExtendedSimpleRouter()
(
router.register(r'accounts',
views.AccountViewSet,
basename='account')
.register(r'campaigns',
views.CampaignViewSet,
basename='campaign',
parents_query_lookups=['account__id'])
.register(r'adgroups',
views.AdGroupViewSet,
basename='adgroup',
parents_query_lookups=['campaign__account', 'campaign'])
Thank You!
use hyperlinkedModelSerializer in all of your related serializer. that should work
I am trying to create a view set in which i want to filter all of the records that have the same reference number. there is a reference model field in the Member model, but it is telling me that it is an invalid field.
this is the viewset:
from groups.models import Member
from ..serializers import MemberSerializer
from rest_framework import viewsets
class MemberViewSet(viewsets.ModelViewSet):
queryset = Member.objects.filter(field_name='reference')
serializer_class = MemberSerializer
this is the models:
class Member(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
reference = models.CharField(max_length=22)
balance = models.DecimalField(max_digits=12, decimal_places=2)
open_tabs = models.IntegerField()
created = models.DateTimeField(auto_now_add=True)
this is the urls:
from groups.api.views.memberViews import MemberViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', MemberViewSet, base_name='member')
urlpatterns = router.urls
so i want to filter out all of the member objects with the same reference field value...
If you want Members that have a specific reference in your viewset, you should override the get_queryset method and add the parameter to the url.
in the viewset :
from groups.models import Member
from ..serializers import MemberSerializer
from rest_framework import viewsets
class MemberViewSet(viewsets.ModelViewSet):
serializer_class = MemberSerializer
def get_queryset(self):
reference = self.kwargs['reference']
return Member.objects.filter(reference=reference)
and in urls :
from groups.api.views.memberViews import MemberViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'(?P<reference>[-\w]+)', MemberViewSet, base_name='member')
urlpatterns = router.urls
see the drf guide to filtering
Referring to QuerySet
Can you try using the following approach where 'SearchKey' is the reference number you want to query against?
queryset = Member.objects.filter(reference__contains='SearchKey')
I am using the Django REST Framework toolkit with Django 1.11 and I am trying to filter the results against the url. Here is my setup:
models.py:
from django.db import models
class Package(models.Model):
name = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.name
serializers.py:
from rest_framework import serializers
from .models import Package
class PackageSerializer(serializers.ModelSerializer):
class Meta:
model = Package
fields = ('name',)
views.py:
from rest_framework import viewsets
from .models import Package
from .serializers import PackageSerializer
class PackageViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = PackageSerializer
queryset = Package.objects.all()
urls.py
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'package', views.PackageViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/', include(router.urls)),
]
Currently when I use this I can filter the results by the id field:
http://127.0.0.1:8000/api/v1/package/1/
I am hoping to filter the results by the name field of my package model instead by using this:
http://127.0.0.1:8000/api/v1/package/basic/
How would I be able to accomplish this?
Set the lookup_field attribute in the viewset, see the documentation.
class PackageViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = PackageSerializer
queryset = Package.objects.all()
lookup_field = 'name'
Use filter_fields in views.
filter_fields = ('name',)
lookup field is used to set lookup by default it would be model pk
if you wish to make your URL,
my_url/filter_field/
set lookup_field = "name"
if you want search from URL like ,
my_url/?name=something
you need to set filter_fields in views.
I am new to Django REST Frameworks and despite doing the tutorial twice and reading lots of documentation I can't work out exactly how to handle/access the arguments in a URL in the DRF ViewSet.
My URL looks like this:
/api/v1/user/<user-id>/<age>/update
In my base urls.py I have the urlpattern:
url(r'^api/v1/', include('api.urls'))
In the api/urls.py I have:
from django.conf.urls import url, include
from rest_framework import routers
from api import views
router = routers.DefaultRouter()
router.register(r'user', views.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls))
]
My question is what should my UserViewSet look like to handle the url, extract the user id and age fields, and update the UserDetails model so the given user has the given age?
My model hasn't been created yet but will look something like this:
class UserDetails(models.Model):
user = models.ForeignKey(User)
age = models.BigIntegerField(blank=True, null=True)
In the serializers.py adde the ParameterisedHyperlinkedIdentityField as a serializer.
serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
url = ParameterisedHyperlinkedIdentityField(view_name='user-detail', lookup_fields=(('id', 'id'), ('age', 'age')), read_only=True)
class Meta:
model = UserDetails
urls.py
from .viewsets import UserViewSet
user_list = UserViewSet.as_view({'get':'list'})
user_detail = UserViewSet.as_view({'get':'retrieve'})
urlpatterns= [
url(r'^user/(?P<id>\d+)/(?P<age>[-\w\d]+)/update/$', user_detail, name='user-detail')
]
viewsets.py
class UserViewset(viewsets.ModelViewSet):
lookup_field = 'id'
serializer_class = UserSerializer
queryset = UserDetails.objects.all()