I am using Django Rest Framework CreateAPIView in order to create a comment. So far everything is OK and here is my code.
Models
class Posts(models.Model):
title = models.CharField(max_length=512, null=True)
slug = models.CharField(max_length=512, null=True)
class Comments(models.Model):
post = models.ForeignKey(Posts, on_delete=models.CASCADE)
content = models.CharField(max_length=5000, null=True)
Serializer
class CommentCreateSerializer(ModelSerializer):
class Meta:
model = Comments
fields = [
'content',
'post'
]
and view
class CommentCreateView(CreateAPIView):
permission_classes = [IsAuthenticated]
queryset = Comments.objects.all()
serializer_class = CommentCreateSerializer
I sent a post request to the create route with post(ID) and content and everything worked. But the problem is I wanna pass post slug instead of post ID.
I am not sure how can I do that. I am familiar with lookup_fields but I am not certain how to apply them for ForeignKey match.
You can use SlugRelatedField in CommentCreateSerializer to use slug instead of pk when you pass the post value on Comment Create request, like this:
class CommentCreateSerializer(ModelSerializer):
post = serializers.SlugRelatedField(
queryset=Posts.objects.all(), slug_field='slug'
)
class Meta:
model = Comments
fields = [
'content',
'post'
]
In the CommentAPIview you need to overwrite the perform create method in to the lookup like so
def perform_create(self):
post_pk = self.kwargs.get("post_pk")
post = get_object_or_404(Post, pk=post_pk)
serializer.save(post=post)
Related
I am trying to update my Teachers view in DRF by instead of including the link to the department field, I would display the name of the department. When I added the PrimaryKeyRelated field, I was able to see the department.name but couldnt use update or create within DRF. Is there a way I could change the display without causing the need for the methods or is that not the case?
Error
The `.update()` method does not support writable dotted-source fields by default.
Write an explicit `.update()` method for serializer `school.serializers.TeacherSerializer`, or set `read_only=True` on dotted-source serializer fields.
The `.create()` method does not support writable dotted-source fields by default.
Write an explicit `.create()` method for serializer `school.serializers.TeacherSerializer`, or set `read_only=True` on dotted-source serializer fields.
models.py
class Department(models.Model):
name = models.CharField(max_length=300)
def __str__(self):
return self.name
class Teacher(models.Model):
name = models.CharField(max_length=300)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
tenure = models.BooleanField()
def __str__(self):
return f'{self.name} teaches {self.department}'
# dont need success url if get_absolute_url on create and update view
def get_absolute_url(self):
return reverse('teacher', kwargs={'pk': self.pk})
serializers.py
class TeacherSerializer(serializers.HyperlinkedModelSerializer):
department = serializers.PrimaryKeyRelatedField(
source='department.name', queryset=Department.objects.all())
class Meta:
model = Teacher
fields = ['url', 'name', 'department', 'tenure']
class DepartmentSerializer(serializers.HyperlinkedModelSerializer):
teacher_set = TeacherSerializer(many=True, required=False)
class Meta:
model = Department
fields = ['url', 'name', 'teacher_set']
views.py
class TeacherViewSet(viewsets.ModelViewSet):
queryset = Teacher.objects.all()
serializer_class = TeacherSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
class DepartmentViewSet(viewsets.ModelViewSet):
queryset = Department.objects.all()
serializer_class = DepartmentSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
have you tried add related_name for model Teacher in field foreign key and call in serializers? link to docs
I am new to Django and I am creating a simple blog web application. I would like to get the blog post of another user (not the user that is Authenticated) using the get_queryset Method. I tried the script below but, it shows an empty list on the template. I am able to use get_queryset to show all the blogpost, but my main concern is to show all the blogpost of a specific user (not the user that is authenticated)
View.py
class OtherUserProfileView(LoginRequiredMixin, ListView):
model = Post
template_name = "core/otheruser.html"
def get_queryset(self):
queryset = super(OtherUserProfileView, self).get_queryset()
queryset = queryset.filter(pk=self.user.id)
return queryset
Model.py
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=250)
content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
publish = models.BooleanField(blank=True, default=False)
def __str__(self):
return self.title
You can pass the id of the user that you want to filter the queryset by in the url pattern
urlpatterns = [
path('profile/<int:user_id>/', views.OtherUserProfileView.as_view(), name='profile'),
]
In your view you can access the user_id from the path via self.kwargs['user_id'] and use this to filter your queryset
class OtherUserProfileView(LoginRequiredMixin, ListView):
model = Post
template_name = "core/otheruser.html"
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.filter(user_id=self.kwargs['user_id'])
return queryset
I am a newbie in django and I have a question about how I can save and show only the data of logged user - since my application is multi-tenant.
my view
class ProjetoCreate(CreateView):
model = Projeto
fields = ['nomeProjeto',
'descricao',
'dtInicio',
'deadline',
'nomeSprint',
'status',
]
def get_queryset(self):
logged_user = self.request.user
return Projeto.objects.filter(User=logged_user)
class ProjetoList(ListView):
paginate_by = 2
model = Projeto
my model
class Projeto(models.Model):
nomeProjeto = models.CharField(max_length=20)
descricao = HTMLField()
dtInicio = models.DateField(auto_now=False, auto_now_add=False)
deadline = models.DateField(auto_now=False, auto_now_add=False)
nomeSprint = models.CharField(max_length=30)
status = models.CharField(max_length=20)
Thank you very much!
Add
user = models.ForeignKey(User, on_delete=models.CASCADE)
to Projecto model. Then, in your view, set project.user = self.request.user before saving your project model.
I think you are doing it completely wrong.
You shouldn't be using get_queryset() at all in CreateView - https://stackoverflow.com/a/24043478/4626254
Here's is what you can try instead.
Add a user field in Project model and apply migrations.
user = models.ForeignKey(User, on_delete=models.CASCADE)
Create a class inheriting Generic APIView instead of CreateView.
Create a POST method like def post(self, request): inside that class and get all the details for creating a Projeto object in the request payload using request.data or request.POST.
Get the logged in user using request.user
Create a Projecto object with all this information as Projeto.objects.create(**your_other_fields, user=request.user)
Next time when filtering the objects, use a filter on user field like user=request.user.
I have the following :
I am working with DRF, based JWT token.
I want to associate an experiment with a USER, i.e when a post request is arriving I want to be able to save that post request with the Foreginkey it needed for the author by the user whom sent the request.
The POST request is always authenticated and never anonymous, i.e request.user is always exist ( I can see it when debugging)
I tried to add the following
def create(self, request, **kwargs):
request.data["author"] = request.user
serializer = ExperimentsSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return....
But is_valid return always False ( the only time ts was true, was when I took out the author from the ExperimentsSerializers fields....
will be happy for any leads....
my code attached below
Model.py:
class User(AbstractUser):
pass
def __str__(self):
return self.username
class Experiments(models.Model):
name = models.CharField(max_length=40)
time = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
View.py:
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
serializer_class = ExperimentsSerializers
queryset = Experiments.objects.all()
filterset_fields = '__all__'
permission_classes = (permissions.IsAuthenticated,)
serializers.py
class ExperimentsSerializers(serializers.ModelSerializer):
class Meta:
model = models.Experiments
fields = '__all__'
You can just pass additional data with save arguments:
def create(self, request, **kwargs):
serializer = ExperimentsSerializers(data=request.data)
if serializer.is_valid():
serializer.save(author=request.user)
Note that you may need to specify author field as read_only so it would not be required in request body:
class ExperimentsSerializers(serializers.ModelSerializer):
class Meta:
model = models.Experiments
fields = '__all__'
read_only_fields = ['author']
One more approach can be to use
HiddenField with default value set to CurrentUserDefault
This way that field will not be exposed at the same time current user will be accessible and other operations can be done on that user context.
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
Something like this:
class ExperimentsSerializers(serializers.ModelSerializer):
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = models.Experiments
fields = '__all__'
Reference :
HiddenField - https://www.django-rest-framework.org/api-guide/fields/#hiddenfield
CurrentUserDefault - https://www.django-rest-framework.org/api-guide/validators/#currentuserdefault
I'm practicing with Django's Class-Based-View.
While practicing with the generic CreateView, I have trouble understanding why my "fields" attributeis not working... I'm trying to construct a Post Create page using the CreateView, and I want only the "post_title" and "post_content" fields to appear on the post page (In other words, I wan't to omit the "user" and "post_date" field on the form). I'm pretty sure the "fields" attribute is the right place to define this, but for some reason, all 4 fields appear on the Post Form.
Here are my codes:
models.py
class Post(models.Model):
user = models.ForeignKey(User)
post_title = models.CharField(max_length=200)
post_content = models.CharField(max_length=500)
post_date = models.DateTimeField('date posted')
views.py
class PostCreate(CreateView):
template_name = 'app_blog/post_save_form.html'
model = Post
fields = ['post_title', 'post_content']
Any idea why all 4 fields appear..? Thanks :)
You have to do that:
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['post_title', 'post_content']
class PostCreate(CreateView):
template_name = 'app_blog/post_save_form.html'
model = Post
form_class = PostForm