I'm having trouble displaying all the jobs as options in the apply url view see image below.
I am getting the error which says
Lists are not currently supported in HTML input
The main function I am looking for is for a list of jobs that were posted to be available for selection when applying for the job.
models.py
class Job(models.Model):
"""A Job used to create a job posting"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
description = models.TextField()
job_type = models.CharField(max_length=12, choices=JOB_TYPE_CHOICES, default='Full-Time')
city = models.CharField(max_length=255)
def __str__(self):
return self.description[:50]
class Applicant(models.Model):
"""A applicant that can apply to a job"""
job = models.ForeignKey(Job, related_name='applicants', on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(max_length=254)
phone_number = PhoneNumberField()
resume = models.FileField(upload_to=resume_file_path, validators=[validate_file_extension])
def __str__(self):
return self.first_name
I've removed some of the attributes in Job so that the code is not so long.
serializers.py
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from core.models import Job, Applicant
class JobSerializer(serializers.ModelSerializer):
"""Serializer for tag objects"""
applicants = serializers.StringRelatedField(many=True)
class Meta:
model = Job
fields = ('id', 'description', 'job_type', 'city', 'state', 'salary', 'position', 'employer', 'created_date', 'is_active', 'applicants')
read_only_fields = ('id',)
def create(self, validated_data):
"""Create a job posting with user and return it"""
return Job.objects.create(**validated_data)
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
jobs = JobSerializer(many=True, queryset=Job.objects.all())
class Meta:
model = Applicant
fields = ('id','jobs', 'first_name', 'last_name', 'email', 'phone_number', 'resume')
read_only_fields = ('id',)
views.py
class ApplyJobView(generics.CreateAPIView):
"""Allows applicants to apply for jobs"""
serializer_class = serializers.ApplyJobSerializer
I've tried adding a queryset=Job.objects.all() as an argument to the JobSerializer() in the ApplyJobSerializer class in my serializers.py field. However I get an error that says
TypeError: __init__() got an unexpected keyword argument 'queryset'
You can select an existing job in the form.
class JobSerializer(serializers.PrimaryKeyRelatedField, serializers.ModelSerializer):
"""Serializer for tag objects"""
applicants = serializers.StringRelatedField(many=True)
class Meta:
model = Job
fields = ('__all__')
read_only_fields = ('id',)
def create(self, validated_data):
"""Create a job posting with user and return it"""
return Job.objects.create(**validated_data)
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
jobs = JobSerializer(many=True, queryset=Job.objects.all())
class Meta:
model = Applicant
fields = ('__all__')
read_only_fields = ('id',)
This result as I have created a new job with description is desc
Related
I have model Package with Supplier and PackageSize, foreign keys and a field to which is also a foreign key of a Shipping model which contains where the supplier wants to ship the package so to make sure I a user can submit the whole information in one request, I created my serializers and linked them like such.
serializers.py
from users.models import Supplier
from packages.models import Package , PackageSize , ShippingLocation , Shipping
class ShippingLocationSerializer(serializers.ModelSerializer):
class Meta:
model= ShippingLocation
fields = ['latitude','longitude']
def create(self, validated_data):
return ShippingLocation(**validated_data)
class PackageSizeSerializer(serializers.ModelSerializer):
class Meta:
model= PackageSize
fields = ['length', 'width' ,'height' ,'weight']
def create(self, validated_data):
"""
docstring
"""
pass
class ShippingSerializer(serializers.ModelSerializer):
location = ShippingLocationSerializer(source='location_set')
class Meta:
model = Shipping
fields = [
'first_name',
'last_name',
'phone_number',
'email',
'street_address',
'village',
'district',
'country',
'location'
]
def create(self, validated_data):
"""
docstring
"""
pass
class SupplierPackageSerializer(serializers.ModelSerializer):
size = PackageSizeSerializer(source='size_set')
shipping_location= ShippingSerializer(source='to_set')
class Meta:
model = Package
fields = ['supplier', 'name', 'size', 'shipping_location', ]
read_only_fields = ['supplier']
def create(self, validated_data):
user =Supplier.objects.get(username=self.context['request'].user)
return Package(supplier=user, **validated_data )
and created my views like such
view.py
from rest_framework import generics
from packages.models import Package
from .serializers import , SupplierPackageSerializer
from rest_framework.permissions import IsAuthenticated
class SupplierPackageViewSet(generics.ListCreateAPIView):
serializer_class = SupplierPackageSerializer
queryset = Package.objects.all().order_by('-name')
permission_classes = [IsAuthenticated]
models.py
from django.db import models
from django.conf import settings
from users.models import Supplier
class ShippingLocation(models.Model):
latitude = models.IntegerField()
longitude = models.IntegerField()
class Shipping (models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
phone_number = models.CharField(max_length=14)
email = models.EmailField()
street_address = models.CharField(max_length=30)
village = models.CharField(max_length=30)
district = models.CharField(max_length=30)
country = models.CharField(max_length=30)
location = models.OneToOneField(ShippingLocation , default=None, on_delete=models.CASCADE )
# Returns the string representation of the model.
def __str__(self):
return self.email
class PackageSize(models.Model):
length = models.IntegerField()
width = models.IntegerField()
height = models.IntegerField()
weight = models.IntegerField()
# Create your models here.
class Package(models.Model):
TYPE = (
('1', 'Envelope'),
('2', 'Parcel'),
('2', 'Soft'),
('2', 'Freezed'),
)
TYPE = (
('1', 'CREATED IN SYSTEM'),
('2', ''),
('2', 'Soft'),
('2', 'Freezed'),
)
name = models.CharField(max_length=30)
supplier = models.ForeignKey( Supplier , on_delete=models.DO_NOTHING)
to = models.ForeignKey(Shipping, default=None, on_delete=models.CASCADE )
size = models.ForeignKey( PackageSize, default=None, on_delete=models.CASCADE )
type = models.CharField(max_length=1, default="1", choices=TYPE)
def __str__(self):
return self.name
the challenge is when I submit the data it is validated very well but it cannot be saved and I get this error
TypeError at /supplier/package
Package() got an unexpected keyword argument 'size_set'
Model Package has foreign key to PackageSize ( only one size per package) so source is not size_set but just size
size = PackageSizeSerializer()
EDIT:
You will also have to override create method on serializer to save related object as documented in writable nested serializer
Something in a line of
def create(self, validated_data):
size_data= validated_data.pop('size', None)
if size_data:
package_size= PackageSize.objects.get_or_create(**size_data)[0]
validated_data['size'] = package_size
return Package.objects.create(**validated_data)
EDIT!
serializers.py
class StringSerializer(serializers.StringRelatedField):
def to_internal_value(self, value):
return value
class SupplierPackageSerializer(serializers.ModelSerializer):
item1 = StringSerializer()
item2 = StringSerializer()
size = serializers.SerializerMethodField()
shipping_location= serializers.SerializerMethodField()
class Meta:
model = Package
fields = ['supplier', 'name', 'size', 'shipping_location', ]
read_only_fields = ['supplier']
# add this
def get_size(self, obj):
return PackageSizeSerializer(obj.item1).data
def get_shipping_location(self,obj):
return ShippingSerializer(obj.item2).data
DOCS:
https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
https://www.django-rest-framework.org/api-guide/relations/#stringrelatedfield
So basically The StringSerializer() class is a way to return a string representation of the model data.
While SerializerMethodField This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.
I have a page where a blog post detail is displayed. Under the post, there is a section where user can comment after inputing thier name subject and text in a comment box. Now i have to make an api for this. I want to make a post api such that that comment is stored/associated to that particular blogpost detail. That means i need blogpost id to pass while posting comment. How to do that??
class BlogPost(models.Model):
CATEGORY_CHOICES = (
('travel_news', 'Travel News',),
('travel_tips', 'Travel Tips',),
('things_to_do', 'Things to Do',),
('places_to_go', 'Places to Go'),
)
image = models.ImageField(blank=True, null=True)
categories = models.CharField(max_length=64, choices=CATEGORY_CHOICES, default='travel_news')
description = models.CharField(max_length=255)
content = RichTextUploadingField()
# todo support for tags
tags = models.CharField(max_length=255, default='#travel') #todo
date_created = models.DateField()
#property
def html_stripped(self):
from django.utils.html import strip_tags
return strip_tags(self.content)
#property
def comments(self):
return self.comments_set.all()
Here are my serializers:
class CommentPostSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
# fields = '__all__'
fields = ['name', 'email', 'subject', 'comment',]
class BlogPostSerializer(serializers.ModelSerializer):
comments = CommentListSerializer(many=True)
class Meta:
model = BlogPost
fields = ['image', 'categories', 'description', 'content', 'tags', 'date_created', 'comments']
# fields = '__all__'
Here is my view:
class CommentCreateAPIView(CreateAPIView):
queryset = Comment.objects.all()
serializer_class = CommentPostSerializer
Assuming im using the default django model, a Post model (code below) and a SavedPost model that links a User to a Post (if the certain user with the certain post exists then that post is saved for that user) and a Follower model that links 2 user (similar to SavedPost).
What im trying to do: An API that for a user, they get all posts for the users they follow, in addition each of these posts has an extra 'field' to say if that post is saved or not.
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post_type = models.CharField(max_length=1, choices=[('B', 'Blog'), ('V', 'Video')], default='B')
file_path = models.URLField(null=True)
title = models.CharField(max_length=255)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class SavedPost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
# A user can save a post only once.
unique_together = ('user', 'post')
class Follower(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name="follower")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
# A user can follow another user only once
unique_together = ('user', 'follower')
Post serilializer:
class PostSerializer(serializers.ModelSerializer):
"""
Nested serializer for post using SimpleUser and Kingdom.
"""
class Meta:
model = Post
fields = ('id', 'user', 'post_type', 'file_path',
'title', 'description', 'created_at', 'updated_at')
def to_representation(self, instance):
data = super().to_representation(instance)
data['user'] = UserSerializer(
User.objects.get(pk=data['user'])).data
return data
API View:
#permission_classes([IsAuthenticated,])
#api_view(['GET'])
def get_following(request):
user = request.user
following = Follower.objects.filter(follower=user).values('user')
# saved_posts = SavedPost.objects.filter(user=user, post__user__in=following).order_by('-post__created_at')
posts = Post.objects.filter(user__in=following).order_by('-created_at')
serializer = PostSerializer(posts, many=True, context={'request': request})
return JsonResponse(serializer.data, safe=False)
So far with the view I made I can get all the posts that the request.user follows but it doesnt say if they are saved or not. I am looking for say 'is_saved' boolean on post to say if that post is saved for that user or not.
Any help/method to do this appreciated. Thank you.
Use serializers.SerializerMethodField as
class PostSerializer(serializers.ModelSerializer):
is_saved = serializers.SerializerMethodField()
def get_is_saved(self, post_instance):
return SavedPost.objects.filter(user=post_instance.user, post=post_instance).exists()
class Meta:
model = Post
fields = ['id', 'user', 'post_type', 'file_path',
'title', 'description', 'created_at', 'updated_at', 'is_saved']
def to_representation(self, instance):
data = super().to_representation(instance)
data['user'] = UserSerializer(
User.objects.get(pk=data['user'])).data
return data
First of all, just to be clear, I will be defining the related_name option for the ForeignKeys in SavedPost - it's up to you to decide whether to implement this or not:
class SavedPost(models.Model):
user = models.ForeignKey(User, related_name="saved", on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name="saved", on_delete=models.CASCADE)
...
Now, in your PostSerializer, you could add this field (remember to add it to the fields variable in the Meta inner class - that is if you're using ModelSerializer):
class PostSerializer(serializers.ModelSerializer):
saved = SavedPostSerializer(many=True)
...
To finish it off, define your SavedPostSerializer - above PostSerializer, if in the same file/module:
class SavedPostSerializer(serializers.ModelSerializer):
class Meta:
model = SavedPost
fields = "__all__"
With this, your json should have a nested field with the saved key containing an array of SavedPosts, if there are any related to the Posts retrieved.
Here are my models :
class Profile(models.Model):
user = models.ForeignKey(User, related_name="profile", on_delete=PROTECT)
plan = models.ForeignKey(Plans, on_delete=PROTECT)
full_name = models.CharField(max_length=2000)
company_name = models.CharField(max_length=50, null=True, blank=True)
activation_token = models.UUIDField(default=uuid.uuid4)
activated = models.BooleanField(default=False)
thumb = models.ImageField(upload_to='uploads/thumb/', null=True, blank=True)
renew_data = models.DateField()
is_paid = models.BooleanField(default=False)
And as you see the Profile model have user field that is related to the Abstract user of django framework. now here is how i call them using an API :
Serializers
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Profile
fields = ['company_name']
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile_set = ProfileSerializer(
read_only=True, many=True) # many=True is required
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile_set']
But when I call the API it shows only the fields username and 'id but not the profile_set
Your UserSerializer should like this,
class UserSerializer(serializers.HyperlinkedModelSerializer):
# no need to set `profile.all` as you have related name profile defined in your model
profile_set = ProfileSerializer(source='profile', many=True)
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile_set']
OR,
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = ProfileSerializer(many=True) # as you have related name `profile`
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile']
Try setting the source of your serializer:
profile_set = ProfileSerializer(
source='profile.all',
read_only=True, many=True
)
It looks like you've set the related_name on your foreign key:
user = models.ForeignKey(User, related_name="profile", on_delete=PROTECT)
This defines the reverse relation name, so that's how you need to refer to it in DRF, too:
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = ProfileSerializer(read_only=True, many=True)
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile']
Since it's clearly a plural, I'd also suggest you rename profile to profiles.
I am getting following error while using the PostSerializer:
Got AttributeError when attempting to get a value for field
full_name on serializer UserSerializer. The serializer field might
be named incorrectly and not match any attribute or key on the long
instance. Original exception text was: 'long' object has no attribute
'full_name'.
Serializers are as follows:
class PostSerializer(serializers.ModelSerializer):
author = UserSerializer(required=False, allow_null=True)
class Meta:
model = Post
fields = ('id', 'author', 'message', 'rating', 'create_date', 'close_date',)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'full_name',)
View:
class PostMixin(object):
model = Post
serializer_class = PostSerializer
permission_classes = [
PostAuthorCanEditPermission
]
queryset = model.objects.all()
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
User model:
class User(AbstractBaseUser):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True, null=True)
full_name = models.CharField(max_length=50, blank=False)
phone = models.CharField(max_length=20, unique=True, null=True)
about = models.CharField(max_length=255, blank=True)
type = models.CharField(max_length=1, default='U')
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(auto_now_add=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name']
def __unicode__(self):
return self.email
def get_full_name(self):
return self.full_name
def get_short_name(self):
return self.full_name
Problem
Got AttributeError when attempting to get a value for field full_name on serializer UserSerializer.
The model User in Django has no such field called full_name.
There is though a method get_full_name() that does what you want.
Solution
So try using it through a SerializerMethodField
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username') # no full_name here
full_name = serializers.SerializerMethodField('get_full_name')
This will add a field called full_name to your serialized object, with the value pulled from User.get_full_name()
Check you are using your custom model and not Django's User model
You've customized your own User model, but since that models has full_name, you shouldn't have gotten that error in the first place, so double check you are not referencing Django's default User model first.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User # <--- Make sure this is your app.models.User,
# and not Django's User model
fields = ('id', 'username', 'full_name',) # This is OK on your User model
or just
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name')