I am trying to add inlineformset to the Django Blog project. I got post and I want to add multiple images to the post via Class Based Views. But when I am trying to get_context_data I receive this error:
get_context_data() missing 1 required positional argument: 'form'
Models.py:
class Post(models.Model):
title = models.CharField(max_length=100)
content = RichTextField(blank=True, null=True)
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
image = models.ImageField(upload_to='gallery/')
description = models.CharField(max_length=300, blank=True)
Forms.py
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title' , 'content' ]
PostImageFormSet = inlineformset_factory(Post, PostImage, fields=['image', 'description'], exclude=['post'] , max_num=30, extra=3)
Views.py
class PostCreateView(LoginRequiredMixin, CreateView):
form_class = CreatePostForm
template_name = 'blog/post_form.html'
def get_context_data(self, form):
context = super(PostCreateView. self).get_context_data(**kwargs)
if self.request.POST:
context['post_images'] = PostImageFormSet(self.request.POST)
else:
context['post_images'] = PostImageFormSet()
return context
def form_valid(self, form):
context = self.get_context_data(form=form)
formset = context['post_images']
form.instance.author = self.request.user
if formset.is_valid():
response = super().form_valid(form)
formset.instance = self.object
formset.save()
return response
else:
return super().form_invalid(form)
Any idea why I am receiving this kind of error? Thank you.
You should remove the form parameter. The form is never used in the get_context_data anyway:
class PostCreateView(LoginRequiredMixin, CreateView):
form_class = CreatePostForm
template_name = 'blog/post_form.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
if self.request.POST:
context['post_images'] = PostImageFormSet(self.request.POST)
else:
context['post_images'] = PostImageFormSet()
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['post_images']
form.instance.author = self.request.user
if formset.is_valid():
response = super().form_valid(form)
formset.instance = self.object
formset.save()
return response
else:
return super().form_invalid(form)
Related
I'm trying to create a posts form that lets the user create posts on my site. I've been stuck on how to pass request.user into the fields "author" and "participants". Could anybody help?
Here is my view:
def home(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('')
My model:
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
body = models.TextField()
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
participants = models.ManyToManyField(User, related_name="participants", blank=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["-created"]
def __str__(self):
return self.body
And my form:
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = '__all__'
For the author you can use this.
def home(request):
if request.method == "POST":
form = PostForm(request.POST)
form.author = request.user
if form.is_valid():
form.save()
return redirect('')
For the participants you can wait until the new Post is created an then add the User
if form.is_valid():
new_post = form.save()
new_post.participants.add(user)
I have an example with class based views where is easy to accomplish.
class PostCreateView(CreateView):
template_name = 'Post/article_create.html'
form_class = ArticleModelForm
queryset = Article.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form_journal'] = JournalModelForm
return context
def dispatch(self, request, *args, **kwargs):
if request.method == 'POST':
want_redirect = request.POST.get('want_redirect')
if not want_redirect:
self.success_url = reverse_lazy('article:article-create')
return super(ArticleCreateView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
form.instance.user = self.request.user //I think this is what you are trying to do
return super().form_valid(form)
I am trying to get my head around how to upload and post an image through my Django form. I have sussed out how to post content, but not Images.
At the moment, when I try to upload an image with my Post, the following error is returned:
null value in column "author_id" violates not-null constraint
Views.py
class CreatePostView(LoginRequiredMixin, CreateView):
model = Post
fields = ['content', 'image']
template_name = 'core/post_new.html'
success_url = '/'
#login_required
def post_image(request):
form=upl()
if request.method == 'POST':
form = upl(request.POST, request.FILES)
upl.save()
return render(request, 'core/post_new.html', {'form': form})
def form_valid(self, form):
form.instance.author_id = self.request.user
return super().form_valid(form)
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['tag_line'] = 'Create new post'
return data
Models.py
class Post(models.Model):
content = models.TextField(max_length=1000)
date_posted = models.DateTimeField(default=timezone.now)
image = models.ImageField(default='default.png', upload_to='core_media')
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.content[:5]
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
UPDATED Views.py
class CreatePostView(LoginRequiredMixin, CreateView):
model = Post
fields = ['content', 'image']
template_name = 'core/post_new.html'
success_url = '/'
#login_required
def post_image(request):
form=upl()
if request.method == 'POST':
form = upl(request.POST, request.FILES)
upl.save()
return render(request, 'core/post_new.html', {'form': form})
def form_valid(self, form):
form.instance.author_id = self.request.user
return super().form_valid(form)
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['tag_line'] = 'Create new post'
return data
Any assistance/direction would be most appreciated. Thank you :)
The form_valid and get_context_data are here no members of your CreatePostView, but inner functions of the post_image function.
You should implement this as:
class CreatePostView(LoginRequiredMixin, CreateView):
model = Post
fields = ['content', 'image']
template_name = 'core/post_new.html'
success_url = '/'
# ↓ ↓ method of the CreatePostView
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
# ↓ ↓ method of the CreatePostView
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['tag_line'] = 'Create new post'
return data
I hope you are well.
I'm trying to create comment for user with one form field (content). I'd like to have the user field automatically filled in user value.
I. I started with this model but I got an error (1048, “Column 'user_id' cannot be null”):
models.py
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name="comments")
user = models.ForeignKey(User,on_delete=models.CASCADE)
content = models.TextField(max_length=160)
publishing_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.post.title
views.py
class PostDetail(generic.DetailView,FormMixin):
model = Post
context_object_name = 'post'
template_name = 'post_detail.html'
form_class = CreateCommentForm
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def form_valid(self, form):
if form.is_valid():
form.instance.post = self.object
form.save()
return super(PostDetail, self).form_valid(form)
else:
return super(PostDetail, self).form_invalid(form)
def post(self,*args,**kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_valid(form)
def get_success_url(self):
return reverse('post_detail',kwargs={"slug":self.object.slug})
forms.py
class CreateCommentForm(forms.ModelForm):
def __init__(self,*args,**kwargs):
super(CreateCommentForm, self).__init__(*args,**kwargs)
self.helper = FormHelper()
self.helper.form_method="post"
self.helper.layout = Layout(
Field("content",css_class="form-control",style="margin-bottom:10px",rows="1"),
)
self.helper.add_input(Submit('submit','Comment',css_class="btn btn-sm",style="background-color: #0d6ec5;border-color: #0d6ec5;"))
class Meta:
model = Comment
fields = [
'content'
]
II. It worked from my admin panel but not from my website (I got this error: (1048, “Column 'user_id' cannot be null”)).
So I've decided to change my models with:
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name="comments")
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
content = models.TextField(max_length=160)
publishing_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.post.title
The thing is if a user post a comment, content is ok but there is no user related to the comment. Anyone has an idea?
You need to specify the .user attribute, probably to the logged in user:
from django.contrib.auth.mixins import LoginRequiredMixin
class PostDetail(LoginRequiredMixin, FormMixin, generic.DetailView):
model = Post
context_object_name = 'post'
template_name = 'post_detail.html'
form_class = CreateCommentForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def form_valid(self, form):
form.instance.post = self.object
form.instance.user = self.request.user
return super().form_valid(form)
def post(self,*args,**kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_valid(form)
def get_success_url(self):
return reverse('post_detail',kwargs={"slug":self.object.slug})
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin mixin [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I was working on a comment section for post and was getting a django.db.utils.IntegrityError: NOT NULL constraint failed: new__score_comment.post_id
so I added null=True, blank=True to the post and user in the models.py class comment and proceeded with the comments addition section
but now when I am trying to link users and posts to the comment I am getting the same error
Here is the Models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
# reply = models.ForeignKey('Comment', null=True, related_name="replies")
content = models.TextField(max_length=160)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}-{}'.format(self.post.title, str(self.user.username))
Here is the views.py:
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data()
post = get_object_or_404(Post, slug=self.kwargs['slug'])
comments = Comment.objects.filter(post=post).order_by('-id')
total_likes = post.total_likes()
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
if self.request.method == 'POST':
comment_form = CommentForm(self.request.POST or None)
if comment_form.is_valid():
content = self.request.POST.get('content')
comment = Comment.objects.create(
post=post, user=request.user, content=content)
comment.save()
return HttpResponseRedirect("post_detail.html")
else:
comment_form = CommentForm()
context["total_likes"] = total_likes
context["liked"] = liked
context["comments"] = comments
context["comment_form"] = comment_form
return context
class PostCommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
form_class = CommentForm
def form_valid(self, form):
post = get_object_or_404(Post, slug=self.kwargs['slug'])
form.instance.user = self.request.user
form.instance.post = post
return super().form_valid(form)
def form_invalid(self, form):
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('score:post-detail', kwargs=dict(slug=self.kwargs['slug']))
On my page, i need to display the post detail and a comment form for viewer to post comment. I created 2 generic views:
# views.py
class PostDetailView (DetailView):
model = Post
context_object_name = 'post'
template_name = 'post.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['comment_form'] = CommentForm()
return context
class AddCommentView(FormView):
template_name = 'post.html'
form_class = CommentForm
success_url = '/'
def form_valid(self, form):
form.save()
return super(AddCommentView, self).form_valid(form)
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
detail = PostDetailView.as_view()
add_comment = AddCommentView.as_view()
# urls.py
....
url(r'^(?P<pk>\d+)/$', view='detail'),
url(r'^(?P<post_id>\d+)/add_comment/$', view='add_comment'),
....
Error would occur in the AddCommentView,since I haven't specified the post's id for the comment. How can I access the post_id in the AddCommentView?
self.kwargs['post_id'] or self.args[0] contains that value
Docs