How to display function based view endpoint in django rest frameworks - python

I am having a hard time to understand how to display function based views URLS with Django REST FRAMEWORK.
I have the setup below of my project but for some reason I am unable to display the endpoint while MovieListViewSet works.
PROJECT.URLS
from users import views
router = routers.DefaultRouter()
router.register(r'movies', MovieListViewSet)
urlpatterns = [
path('', include(router.urls)),
path('admin/', admin.site.urls),
path('profile/', views.ProfileList, name='ProfileList')
]
users.model
User = settings.AUTH_USER_MODEL
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500)
location = models.CharField(max_length=50)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return self.user.username
serializers
from rest_framework import serializers
from users.models import Profile
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
class Meta:
model = Profile
fields = (
'id',
'user',
#'bio',
#'location',
'image',
)
I have comment bio and location because when they are uncommented, I receive this message.
Got AttributeError when attempting to get a value for field `bio` on serializer `ProfileSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'bio'.
users.views (app)
#api_view(["GET"])
def ProfileList(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer(profile)
return Response(serializer.data)
I am unable to see ProfileList view as endpoint
Can someone point me to what I am doing wrong to display this endpoint to django rest framework.

You should specify many=True while serialization.
serializer = ProfileSerializer(profile, many=True)

You are mixing up functions and class based view definition here:
#api_view(["GET"])
def ProfileList(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer(profile)
return Response(serializer.data)
Either you define a class based view like this:
class ProfileView(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer
def list(request):
return Response(self.serializer_class(self.get_queryset(), many=True).data)
Or a function base view like:
#api_view(["GET])
def profile_list(request):
return Response(ProfileSerializer(Profile.objects.all(), many=True).data)

Related

Could not resolve URL for hyperlinked relationship using view name "rest:campaign-detail"

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

How to obtain a user instance in django application

I'm trying to obtain a user instance for the profile page in django app but I'm finding some difficulties implementing that functionality. I have the following blocks of code:
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, default="")
image = models.ImageField(upload_to="images/user_profile_pics/", default="images/default_profile_pics/default.jpg")
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
def __str__(self):
return f'{self.lastname} profile'
serializers.py
class user_profile_serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
views.py
class user_profile(generics.GenericAPIView):
serializer_class = user_profile_serializer
def get(self, request, *args, **kwargs):
user = self.get_serializer(request.user).data
if request.user.is_authenticated:
return Response(user, status=status.HTTP_200_OK)
else:
pass
urls.py
urlpatterns = [
path('profile/', user_profile.as_view(), name="user-profile"),
]
When ever I assess the profile url, I get an error message 'AnonymousUser' object has no attribute 'data' I have tried a couple of approaches but none worked. Please, how do I obtain a specific user from the database?
request.user is AnonymousUser when the user is not logged in. In that case that object does not have data attribute. Hence the error you get. One thing you can do is check request.user.is_authenticated and if the user is not authenticated, return some other value / or None. And try logging in before trying to access the user.data value.

Django edit user profile with Class Based Views

I am trying to develop a profile edit page in Django 3.1. I am new to this so if something is funky just say so. I copied some of this from Django edit user profile
Views.py
from myapp.forms import UserForm, UserProfileInfoForm
from django.views.generic import (View, TemplateView, UpdateView)
from myapp.models import UserProfileInfo
class UpdateProfile(UpdateView):
model = UserProfileInfoForm
fields = ['first_name', 'last_name', 'email', 'phone', 'title', 'password']
template_name = 'profile.html'
slug_field = 'username'
slug_url_kwarg = 'slug'
models.py
class UserProfileInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = PhoneField(blank=True, help_text='Contact phone number')
title = models.CharField(max_length=255)
system_no = models.CharField(max_length=9)
def __str__(self):
return self.user.username
forms.py
#...
from myapp.models import UserProfileInfo
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username', 'email', 'password', 'first_name', 'last_name')
class UserProfileInfoForm(forms.ModelForm):
class Meta():
model = UserProfileInfo
fields = ('phone', 'title', 'system_no')
myapp/urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
path('', views.index,name='index'),
path('about/',views.AboutView.as_view(),name='about'),
path('register/', views.register,name='register'),
path('profile/', views.UpdateProfile.as_view(), name='profile'),
]
I have a link that only show after login in:
base.html (href only)
<a class="nav-link active" href="{% url 'myapp:profile' %}">Profile</a>
Can you tell me what to fix? After clicking on the above link I get an error message in the browser
AttributeError at /profile/
type object 'UserProfileInfoForm' has no attribute '_default_manager'
well you have done very good till here. Note these :
1.if you are using UpdateView class based view the model field must be the name of the model not the form.(UserProfileInfo)
2.if you are using class based view it is better for you to have a success url in class to redirect after successful attempt
3.if you are using UpdateView no need to have form in forms.py for that model. all you need is a form tag in your template update view will handle it for you and save the changes automatically.
if you want to use form (if you want to save sth in instances that class with not automatically do it ) , better to use FormView and remember here you have to save the form by yourself
link to FormView
If you want to use django for long time I strongly recommend to check this link and start reading the documents https://docs.djangoproject.com/en/3.1/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView

The User ForiegnKey is now showing up as a field in django rest framework viewset

I am building a backend for a web app using django rest framework. I have a profile model that has a user forieingkey referencing a django user. Everything is loading correctly except for one issue which is that the User field is not showing up in the django rest framework backend urls so that I can assign a user to the profile object i want to create... does anyone know why this is happening...
models.py:
class Profile(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE
)
synapse = models.CharField(max_length=25, null=True)
bio = models.TextField(null=True)
profile_pic = models.ImageField(
upload_to='./profile_pics/',
max_length=150
)
facebook = models.URLField(max_length=150)
twitter = models.URLField(max_length=150)
updated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username + ' profile'
viewset:
from users.models import Profile
from users.api.serializers.ProfileSerializer import ProfileSerializer
from rest_framework import viewsets
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'user__username'
url:
from users.api.views.ProfileView import ProfileViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', ProfileViewSet, base_name='profile')
urlpatterns = router.urls
serializer:
from rest_framework import serializers
from users.models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
depth=2
That happens when you set a depth bigger that 0, foreign key fields become not editable (if you send a POST with that field containing some value, DRF viewset would ignore it, and if the field is required, it will raise an exception).
One solution for that is to override to_representation() method of the serializer and set the depth and restore it to zero:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
def to_representation(self, instance):
self.Meta.depth = 2
representation = super().to_representation(instance)
self.Meta.depth = 0
return representation

AttributeError at /app/api/get

I got an error,
AttributeError at /app/api/get
Got AttributeError when attempting to get a value for field task_name on serializer TaskSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Color instance.
Original exception text was: 'Color' object has no attribute 'task_name'.
Now I wanna make a page that shows model's content in json format.
models.py is
from django.db import models
# Create your models here.
class Color(models.Model):
name = models.CharField(max_length=255)
background_color = models.CharField(max_length=255)
h1_color = models.CharField(max_length=255)
p_color = models.CharField(max_length=255)
def __str__(self):
return self.name
serializers.py is
from .models import Color
from rest_framework import serializers
class TaskSerializer(serializers.Serializer):
task_name = serializers.CharField(max_length=100)
status = serializers.SerializerMethodField('get_task_status')
def get_task_status(self, instance):
return instance.status.status
class Meta:
model = Color
fields = ('name',
'background_color',
'h1_color',
'p_color',
'task_name')
urls.py is
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'api/get',views.TaskGet.as_view(),name='task-get')
]
views.py is
from django.shortcuts import render
from .models import Color
from .forms import ColorForm
from .serializers import TaskSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
# Create your views here.
def index(request):
d = {
'colors': Color.objects.all(),
'form': ColorForm(),
}
return render(request, 'index.html', d)
class TaskGet(APIView):
def get(self, request, format=None):
obj = Color.objects.all()
serializers = TaskSerializer(obj, many=True)
return Response(serializers.data, status.HTTP_200_OK)
I wrote url(r'api/get',views.TaskGet.as_view(),name='task-get') in urls.py,so I really cannot understand why this error happens.I already run commands of migration of model. How can I fix this?
My ideal web page is like
You try get status by foreign key instance.status.status but in your model class Color i don't see any foreign keys or methods for it.
And for task_name did you want to see the model field name try to add source params
task_name = serializers.CharField(max_length=100, source='name')
# ^^^^^^^^^
are you sure you want serialize Task for model Color?
new edit
in your get_task_status the 'instanceis instance of serializer model, so if your modelColorhas no property or methodstatus` you will catch an error

Categories