CreateView + get_absolute_url - django

I'm trying to use CreateView, here is some problem and I'm stacking it.
enter code here
First of all, i'm trying to create a post and dynamically fill user field who create post. It save the post but don't save the user:
Image from admin
#views.py
class PostCreateView(CreateView):
model = Post
template_name = 'blog/post_create.html'
fields = ('title', 'slug', 'body',)
def form_valid(self, form):
form.instance.blog__user = self.request.user
return super(PostCreateView,self).form_valid(form)
#models.py
The second one, i think main problem, i don't use get_absolute_url correctly and I get this problem:
No URL to redirect to.
But it good works for post_detail.
class Blog(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
slug = models.SlugField(max_length=50)
def __str__(self):
return self.user.username
def create_blog(sender, **kwargs):
if kwargs['created']:
user_blog = Blog.objects.create(user=kwargs['instance'], slug=kwargs['instance'])
post_save.connect(create_blog, sender=User)
class Post(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
slug = models.SlugField(max_length=50, db_index=True)
title = models.CharField(max_length=120, db_index=True)
body = models.TextField(blank=True, db_index=True)
pub_date = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self):
return reverse('post_detail_url', kwargs={'slug': self.slug,
'username': self.blog})
#urls.py
urlpatterns = [
path('<username>/create/', PostCreateView.as_view(), name='post_create'),
path('<username>/<str:slug>/', PostDetailView.as_view(), name='post_detail_url'),
path('<username>/', PostListView.as_view(), name='post_list_url'),
path('<username>/<str:slug>/update/', PostUpdateView.as_view(), name='post_update'),
]
I am tried to define get_success_url and I get this: NoReverseMatch
Please help I am really lost in the clouds!

Try below code
class PostCreateView(CreateView):
model = Post
template_name = 'blog/post_create.html'
fields = ('title', 'slug', 'body', 'blog')
def get_success_url(self):
return self.post_instance.get_absolute_url()
def form_valid(self, form):
form.instance.blog.user = self.request.user
self.post_instance = form.instance
return super(PostCreateView,self).form_valid(form)

Related

Django get_absolute_url is redirecting to random blog posts

I've created a website with a blog, and I'm trying to redirect the user to the previous blog post after sending a comment. However, it redirects to random blog posts rather than the previous one.
Models.py:
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", on_delete=models.CASCADE)
name = models.CharField(max_length=255)
comment = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.post.title and self.name
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk':self.pk})
Views.py:
class CommentView(LoginRequiredMixin, CreateView):
model = Comment
template_name = 'comment.html'
fields = '__all__'
def form_valid(self, form):
form.instance.post_id = self.kwargs['pk']
return super().form_valid(form)
urls.py:
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
You should use the self.post_id for the primary key of the post, otherwise you redirect to the post that "happens" to have the same primary key as the primary key of the comment,so:
class Comment(models.Model):
post = models.ForeignKey(
Post, related_name="comments", on_delete=models.CASCADE
)
# …
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.post_id})
Note: Django's DateTimeField [Django-doc]
has a auto_now_add=… parameter [Django-doc]
to work with timestamps. This will automatically assign the current datetime
when creating the object, and mark it as non-editable (editable=False), such
that it does not appear in ModelForms by default.

Is there a more elegant way to implement an modification to save() method when using CreateView and ModelForm in Django?

I'm learning the Class-Based View and ModelForm of Django, and I feel so confused with those things.
I want to create a page where users can post articles.
My implementation is as following:
models.py
class Post(models.Model):
id = models.CharField(primary_key=True, null=False, max_length=20)
owner = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
content = models.TextField()
count_like = models.IntegerField(default=0)
created_time = models.DateTimeField()
last_modified = models.DateTimeField()
def save(self, *args, **kwargs):
''' On save, update last_modified '''
if not self.id:
count = Post.objects.count()
self.id = "PO" + str(count)
self.created_time = timezone.now()
self.last_modified = timezone.now()
return super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
print("pk"*100, self.pk)
return reverse('post_detail', kwargs={'pk': self.pk})
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['content']
def save(self):
return super().save(commit=False)
views.py
class PostCreateView(generic.CreateView):
model = Post
form_class = PostForm
template_name="post/create.jinja"
def form_valid(self, form):
self.object = form.save()
self.object.owner = self.request.user
self.object.save()
return HttpResponseRedirect(self.get_success_url())
urlpatterns
path('create/', PostCreateView.as_view(), name="post_create")
I checked and this works.
As you can see, the Post model has many attributes, but I just want users to fill 1 field content, the others would be automatically initiated. Is there any way to improve my implementation, because it's seperated into many places (model save() method, form save() method, valid_form() method).
One more question is what is self.object role? After assigned to a Post model instance, what would it be used for?
Please help me, if you don't understand what I say please ask in comment. Thanks ^^

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

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.

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 redirect user to Detailview in django

I have this following error after creating a Model from a form request:Generic detail view SugboxDetailView must be called with either an object pk or a slug.
my urls.py
urlpatterns = [
url(r'^box/(?P<pk>[0-9A-Za-z-]+)/$', views.get_box, name='box'),
url(r'^sugbox/$', views.SugboxForm.as_view(), name='sugbox'),
url(r'^liste/$', views.IndexView.as_view(), name='index'),
url(r'^(?P<id>[0-9A-Za-z]+)/$', views.SugboxDetailView.as_view(), name='detail'),
url(r'^suggies/$', views.SuggestionForm.as_view(), name='suggies'),
#url(r'^$', views.Homepage.as_view(), name='root'),
url(r'^$', views.SugboxForm.as_view(), name='sugbox'),
my models.py
#python_2_unicode_compatible
class Box(models.Model):
"""
Box model
"""
def __str__(self):
return self.title
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=40, blank=True, null=True)
identify = models.BooleanField(default=False)
activate = models.BooleanField(default=False)
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
my views.py
class SugboxForm(FormView):
"""
for user to Create a Suggestion Box
"""
template_name = 'boxes/sugbox_form.html'
form_class = SugboxForm
success_url = '/boxes/detail/'
""" Send to a page that will show the slug
so that the user can share it SuggestionBox
to others
"""
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.save()
messages.success(self.request, "Successfully Created")
print(self.request)
return super(SugboxForm, self).form_valid(form)
class SugboxDetailView(generic.DetailView):
model = Box
template_name = "boxes/details.html"
context_object_name = "sugbox"
class SuggestionForm(FormView):
"""
for user to put their suggestion
"""
template_name = 'boxes/suggestion.html'
form_class = SuggestionForm
success_url = '/suggestion/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.save()
return super(SuggestionForm, self).form_valid(form)
my error is on http://localhost:8002/boxes/detail/
try this:
class SugboxDetailView(generic.DetailView):
model = Box
template_name = "boxes/details.html"
context_object_name = "sugbox"
pk_url_kwarg = 'id'
def get_queryset(self):
qs = super(SugboxDetailView, self).get_queryset()
return qs.filter(...., attr=self.kwargs.get('id'))