Django Rest Framework - writable HyperlinkedRelatedField - django-rest-framework

So, I have a HyperLinkedModelSerializer that creates a like on the post.
And I need to pass post_id with POST-request.
But the problem is HyperlinkedRelatedField can't build a URL on the post field.
The veiw_name is correct.
If I try to change HyperlinkedRelatedField to PrimaryKeyRelatedField - it works perfectly.
Any ideas why so?
p.s. I figured that I pass post_id as a string, e.g. 145, but the serializer waits for the URL.
But which way can I transform imputed post_id into a URL?
Use get_absolute_url? But how to transform it in serializer or view?
class LikeDetailSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="like-detail-api")
user = serializers.HyperlinkedRelatedField(
read_only=True, source="user.id", view_name="user-detail-update-destroy-api"
)
post = serializers.HyperlinkedRelatedField(
queryset=Post.objects.all(), view_name="post-detail-api",
)
class Meta:
model = Like
fields = "url", "id", "created", "user", "post"

Related

drf-spectacular: how to show the primary key in examples section of Swagger

I'm trying to show the primary key in the examples section of Swagger, I'm using drf-spectacular and my code looks like:
Serializers.py
class SerializerExample(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id','name')
Views.py
class BooksBulkUpdate(APIView):
#extend_schema(
request=SerializerExample(many=True),
responses={200:''},
)
def put(self, request, format=None):
with transaction.atomic():
for data in request.data:
book = Book.objects.get(pk=data['id'])
serializer = SerializerExample(book, data=data, partial=True)
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response()
Only the name field is showing:
The only solution that I found was using an inline serializer which is not the ideal solution because if I update my book serializer I'd have to remember to update also this inline serializer. I wonder if there is a better way of doing this.
AFAIK swagger shows input request schema.
For example, you want to add new person and your model is
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=30)
So you allowed to set only name parameter
Even if you post
{
"id": "someUUID",
"name": "NAME",
}
id will be ignored and Django create it automatically by own logic (because it is read only)
But you can set id field writeable:
class SerializerExample(serializers.ModelSerializer):
id = serializers.UUIDField(write_only=True)
name = serializers.CharField(write_only=True)
class Meta:
model = Person
fields = ('id','name')
write_only=True means that field will be active when you saving new data and receiving id from request json.
In opposite read_only=True will print id field at response (if you trying get data) but ignore it when you saving new data.
So you try to describe API for data adding, and of course that is not allow to set id field in request json.
Not sure if this theory applicable to your case, but hope that will be helpful.

DRF : CreateAPIView - UNIQUE constraint failed

I am using Django Rest Framework with React for the front.
I want to post Note linked to a ForeignKey User.
models.Note
class Note(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
content = models.TextField(blank=True, default='')
serializers.NoteSerializer
class NoteSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = Note
fields = ('user', 'content')
When I post {user: 1, content: "test"}, I get the following error message:
UNIQUE constraint failed: app_note.user_id
How can I link the new Note to an existing user, posting the user.id?
I think my current code is trying to create a new User Instance...
You are using OneToOneField in Note model. That means a user can have only one note.
use ForeignKey instead to have many notes for single user.

django rest-framework add fields to ModelSerializer

I have the following serializer:
class AMXModXAdminsSerializer(mixins.GetCSConfigMixin, serializers.ModelSerializer):
admin = serializers.CharField(label='Admin', max_length=35, required=True, write_only=True)
password = serializers.CharField(label='Password', max_length=35, required=False, write_only=True)
access_flags = serializers.MultipleChoiceField(choices=ACCESS_FLAGS_OPTIONS, required=True, write_only=True)
account_flags = serializers.MultipleChoiceField(choices=ACCOUNT_FLAGS_OPTIONS, required=True, write_only=True)
class Meta:
model = CS16Server
fields = ('name', 'amxadmins', 'admin', 'password', 'access_flags', 'account_flags')
read_only_fields = ('name', 'amxadmins',)
When I try to access the url it complains:
Got AttributeError when attempting to get a value for field `admin` on serializer `AMXModXAdminsSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `CS16Server` instance.
Original exception text was: 'CS16Server' object has no attribute 'admin'.
If I add write_only to each field, the error will go away.
The thing is that I have a similar serializer, for the same model, with fields which do not belong to the model and it works perfectly without adding "write_only=True" to each field.
Any idea why one would work and another one no ?
What do u mean "when i access" ? post get put patch ?
Error says:
'CS16Server' object has no attribute 'admin'.
Does it ? if not , where do u intend to write it to ?
If model does not have admin field (as mentioned in error ) you need something like this:
class AMXModXAdminsSerializer(mixins.GetCSConfigMixin, serializers.ModelSerializer):
admin= serializers.SerializerMethodField()
fields ...
...
def get_admin(self, obj):
do somthing with self (contains the request) or the obj you're working on
return theOUTcome
If you set required=False it will not complain anymore because it will not try to get those fields values from db.

How to add user in perform_create viewset (django rest framework)?

I want to make a "comment" table. On the table, there will be a field containing user_id that created the comment. The user related with the comment table is from Django default user model. This is the Comment model:
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
This is the Comment serializer:
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
This is the viewset to create new comment:
class CommentViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
permission_classes = (IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
I also integrate the user with django rest jwt for the authorization. This is the header & data i sent to the API.
Header:
Authorization: Bearer {jwt token}
Content-Type: application/json
body:
{
"content": "This is the comment"
}
But i get this response:
{
"user": [
"This field is required."
]
}
How to fix the serializer, so it will retrieve the user from the token (request.user)?
This is because of the user field isn't a read only field. So you have to make it so.
This DRF doc -- Specifying read only fields describes well about it
In your case, specifying read_only_fields in your serializer's Meta class will solve the problem :)
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
read_only_fields = ('user',) # change is here <<<

How to remove validator on id field in wtforms

I have created sqlalchemy class and wtform Form from class.
from wtforms.ext.sqlalchemy.orm import model_form
class ClientGroup(Base, BaseModel):
__tablename__ = 'client_groups'
id = Column(Integer, primary_key=True)
name = Column(String(255))
sale = Column(Integer)
def __unicode__(self):
return self.name
ClientGroupForm = model_form(ClientGroup, Form, field_args={
'name': {'validators' : [validators.Required(), validators.Length(min=5)]},
})
in app I have following code:
form = ClientGroupForm(request.form)
if form.validate():
.. save data
When i send a new data to app its returns me validation error. ID must be an integer field.
But a new data hasn't any id.
Please, give me advice How can I use wtforms with sqlalchemy?
Make it optional explicitly, by adding the following to the field_args:
'id': {'validators' : [validators.Optional()],
However, I think you should exclude the id field from the form completely:
ClientGroupForm = model_form(ClientGroup, Form, field_args={
'name': {'validators' : [validators.Required(), validators.Length(min=5)]},
exclude=['id'],
})

Resources