Django: How to populate other model fields when someone leaves a comment - django

I am trying to let anyone post a comment on a blog but there are other fields in my model that need to get information that is not required in the form itself. I've tried adding it in the form_valid method but that method is not being called when the form is submitted. Any help is appreciated
views.py
class CommentView(CreateView):
template_name = "core/index.html"
model = Comment
form_class = CommentForm
def get_success_url(self):
return reverse_lazy("core:home")
def form_valid(self, form):
print("form is valid")
form.save()
return super().form_valid(form)
forms.py
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = [
"text",
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["text"].widget.attrs.update(
{"class": "form-control", "placeholder": "Enter Your Comment Here",}
)
models.py
class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(
BlogPost, on_delete=models.CASCADE, related_name="comments"
)
text = models.TextField(max_length=255, default="")
date_posted = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"({self.author})'s comment on ({self.post.title})"
urls.py
app_name = "blog"
urlpatterns = [
path("post/<int:pk>/", BlogPostDetailView.as_view(), name="detail"),
path("post/category/<int:pk>/", CategoryListView.as_view(), name="category"),
path("post/comment/<int:pk>/", CommentView.as_view(), name="comment"),
]

You can try like this:
class CommentView(CreateView):
template_name = "core/index.html"
model = Comment
form_class = CommentForm
def get_success_url(self):
return reverse_lazy("core:home")
def form_valid(self, form):
form.instance.post_id = self.kwargs['pk']
form.instance.author = self.request.user
return super().form_valid(form)
Here I am assuming you are passing value of Post(primary key) via pk attribute of url andform.instance has the new(not yet saved to DB) Comment object. Then I am attaching the value of request.user(current user) and post id with that instance.

Related

Django - Filtering Post Form option by currently logged-in User's Vehicle

I'm a django newbie and i'm making a form where a User can make a Post and pick one of his Vehicles for the Post. The Vehicle and the Post models are created like so:
*blog/models.py*
class Post(models.Model):
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE, null=True)
def get_absolute_url(self):
return reverse('post-detail', kwargs ={'pk': self.pk} )
*vehicles/models.py*
class Vehicle(models.Model)*:
TESLA = 'TESLA'
MAZDA = 'MAZDA'
VOLVO = 'VOLVO'
VEHICLE_CHOICES = (
(TESLA, "Tesla"),
(MAZDA, "Mazda"),
(VOLVO, "Volvo"),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
model = models.CharField(max_length=9,
choices=VEHICLE_CHOICES,
default=TESLA)
def __str__(self):
return self.model
My blog views:
*blog/views.py*
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = [ 'vehicle']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
I would like to filter the vehicles so that only the current logged in User's vehicles
show up in the form, i've tried a variety of different solutions but I seem to be going around in circles, if you could help me out that would be awesome. Thanks!
Since you are using createview, you can create a form in forms.py. First you have to send the logged in user to the form, then in the form, pop the user from kwargs and use it to filter the vehicles.
views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
form_class = PostForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['vehicle']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['vehicle'].queryset = Vehicle.objects.filter(owner=user)

Django - accessing the pk/id of Post module that is inside a Comment model

So i have this post module:
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
date_pub = models.DateTimeField(timezone.now)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog-home')
and this comment module:
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
comment_author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField(max_length=255)
def get_absolute_url(self):
return reverse('blog-home')
and this is my view for the comment:
class CreateComment(LoginRequiredMixin, CreateView):
model = Comment
template_name = 'my_blog/create_post.html'
fields = ['content']
def form_valid(self, form):
form.instance.comment_author = self.request.user
# form.instance.post_id =
return super().form_valid(form)
as for the urls:
/post/1 ===> will be post number 1
/post/1/comment ===> is the form the to post a new comment
I want the form.instance.post_id to be the post id that the comment belongs to.
How do I do that ?
I'm guessing you have a url pattern similar to this:
path('post/<int:pk>/comment', CreateComment.as_view(), name='create_comment')
Here's what I would do (assuming SingleObjectMixin works in combination with CreateView):
from django.views.generic.detail import SingleObjectMixin
class CreateComment(LoginRequiredMixin, CreateView, SingleObjectMixin):
model = Comment
template_name = 'my_blog/create_post.html'
fields = ['content']
def form_valid(self, form):
form.instance.comment_author = self.request.user
form.instance.post = self.get_object()
return super().form_valid(form)
form.instance.post_id = self.kwargs['pk']
was the thing i was looking for

How to specify a list of values ​in a form in which CheckboxSelectMultiple is used?

I have a problem with the form in django. It uses the CheckboxSelectMultiple widget, but I need to set a list of possible choices only for posts created by the currently logged in user.
Any idea?
form:
class CycleForm(BSModalForm):
class Meta:
model = Cycle
fields = ['title', 'description', 'posts']
widgets = {
'posts': forms.CheckboxSelectMultiple(),
}
models
class Cycle(models.Model):
title = models.CharField(max_length=200, unique=True)
description = models.TextField(max_length=500, default="Brak opisu")
date_created = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
posts = models.ManyToManyField(Post)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=50, unique=True)
content = MDTextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
numbers_of_entries = models.IntegerField(default=0)
views
class CycleCreateView(BSModalCreateView, LoginRequiredMixin):
template_name = 'blog/cycle_form.html'
form_class = CycleForm
def form_valid(self, form, **kwargs):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
class CycleUpdateView(BSModalUpdateView):
model = Cycle
template_name = 'blog/cycle_update.html'
form_class = CycleForm
success_message = 'Success: Cycle was updated.'
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
We can slightly alter the CycleForm form and add a user parameter. If that parameter is set, we filter the queryset of the posts field by only using Posts
class CycleForm(BSModalForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
if user is not None:
self.fields['posts'].queryset = Post.objects.filter(author=user)
class Meta:
model = Cycle
fields = ['title', 'description', 'posts']
widgets = {
'posts': forms.CheckboxSelectMultiple(),
}
Now we only need to pass the user to the form, we can override the get_form_kwargs method [Django-doc]:
class CycleCreateView(LoginRequiredMixin, BSModalCreateView):
template_name = 'blog/cycle_form.html'
form_class = CycleForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(user=self.request.user)
return kwargs
def form_valid(self, form, **kwargs):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
reverse_user = self.request.user
return reverse('profile', kwargs={'username': reverse_user})
You should do the same with the UpdateView. Note that your LoginRequiredMixin likely should be put first in the base classes.

Django - DetailView with FormMixin and initial

I have DetaiView for my post and I want to use a form in this view so I decided to use DetailView with FormMixin. I need to set some initial to this form and I don't know how to do it. Here is my code:
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", on_delete=models.CASCADE)
name = models.CharField("Nick", max_length=80)
email = models.EmailField()
body = models.TextField("Body")
created = models.DateTimeField("created", auto_now_add=True)
updated = models.DateTimeField("Updated", auto_now=True)
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = (
"name",
"email",
"body"
)
views.py
class PostDetailView(FormMixin, DetailView):
model = Post
form_class = CommentForm
template_name = "newspaper/post-detail.html"
def get_success_url(self):
return reverse("post-detail", kwargs={"slug": self.object.slug})
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context["form"] = self.get_form()
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
return super().form_valid(form)
So I want to post in CommentForm to post of this DetailView. I hope you understand :D.
Thanks in advance for the help!
With FormMixin you can specify form's initial using initial attribute:
class PostDetailView(FormMixin, DetailView):
model = Post
form_class = CommentForm
template_name = "newspaper/post-detail.html"
initial={'name': 'John'}
Or get_initial method:
def get_initial(self):
return {"post": self.get_object() }

ModelForm with user being request.user

I'm trying to make a form where user can submit a post/article.
I have this model:
class Post(models.Model):
title = models.CharField(max_length=150)
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
This form:
class PostForm(forms.ModelForm):
title = forms.CharField(required=True)
content = forms.CharField(widget=forms.Textarea)
class Meta:
model = Post
fields = ['title', 'content']
And this view:
class PostCreateView(FormView):
form_class = PostForm
template_name = 'template/create_post.html'
success_url = reverse_lazy('index')
def form_valid(self, form):
response = super(PostCreateView, self).form_valid(form)
form.user = self.request.user
form.save()
return response
I've set the user, but I'm still getting
IntegrityError at /new-post/
NOT NULL constraint failed: cyth_post.user_id
Here's the full traceback call: http://dpaste.com/0PJSTY2
What am I doing wrong here?
Thanks in advance for answers!
You need set form.instance user and then run super
def form_valid(self, form):
form.instance.user = self.request.user
return super(PostCreateView, self).form_valid(form)