Unable to save form using django.views.generic.View - python

I was able to save before without an issue using django.views.generic.CreateView. However, I can't save the same form using View.
Below are my codes:
models.py
class Project(models.Model):
name = models.CharField(max_length=200, verbose_name='Project Name')
user = models.ForeignKey(User,
on_delete=models.CASCADE,
blank=True,
null=True)
client = models.ForeignKey(Client,
on_delete=models.SET_NULL,
blank=True,
null=True)
deadline = models.DateTimeField(blank=True, null=True)
views.py
from django.views.generic import View
class ProjectCreateView(LoginRequiredMixin, View):
form_class = ProjectCreateForm
success_url = reverse_lazy('dashboard')
template_name = 'translation/project_form.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
project_form = self.form_class(request.POST, instance=request.user)
if project_form.is_valid():
project_form.save()
return redirect(self.success_url)
else:
return render(request, self.template_name)
html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container mt-5 py-2 w-50 bg-dark text-white">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-success mt-3">Confirm</button>
</form>
</div>
{% endblock content %}
urls.py
path('project/new', views.ProjectCreateView.as_view(), name='project-add'),
When I submit the form in html, it doesn't render any error message. It simply redirects to the self.success_url and the intended object is not saved.
Any help or advice will be much appreciated. Thank you!
Edit:
Forgot to include the codes for the Form:
forms.py
class ProjectCreateForm(forms.ModelForm):
class Meta:
model = Project
widgets = {
'deadline' : forms.DateInput(attrs={'type':'date'})
}
fields = ['name', 'client', 'deadline']

Related

File from django model not uploading

These are my models
class Post(models.Model):
title = models.TextField(default="no title")
body = models.TextField(default="no body")
creation_date = models.DateTimeField(default=timezone.now)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
document = models.FileField(upload_to="uploads/", null=True, blank=True)
the one that isn't working is document, i have set up a form and when i "post" the form the other stuff like title ,body, creation date and creator are being saved but the document isn't, cant even find it in any folder
this is my view
class Post_List(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
posts = Post.objects.order_by("-creation_date")
form = PostForm()
context = {
"post_list" : posts,
"form" : form,
}
return render(request, 'social/post_list.html', context)
def post(self, request, *args, **kwargs):
posts = Post.objects.order_by('-creation_date')
form = PostForm(request.POST, request.FILES)
if form.is_valid():
new_post = form.save(commit=False)
new_post.creator = request.user
new_post.save()
context = {
'post_list': posts,
'form': form,
}
return redirect('/feed')
my html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form | crispy }}
<div class="form-group">
<button class="btn btn-success mt-3 mb-3 float-end" type="submit">Send</button>
</div>
</form>
I tried migrating again but nothing changed
i had no space between method="POST" and enctype="multipart/form-data", fixed it when i pasted the html here, i tested again and it works now

Getting NoReverseMatch while click the comment button

I was getting that same error while click the like button, But the error was solved..
again after creating comment view and its other staff I'm getting that error again...When I click the comment button then the error appears..I'm very new to Django,,, help me please..
My project models.py, template page, urls.py, views.py are attached herewith
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if not liked and not unliked %}
<h4> Like </h4>
<h4>Unlike</h4>
{% elif unliked %}
<h4> Like </h4>
{% elif liked %}
<h4>Unlike</h4>
{% endif %}
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<a class="btn btn-sm btn-info" href="{% url 'comment' %}">Comment</a>
</form>
</div>
{% endblock content %}
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
path("comment/", views.comment, name="comment"),
]
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
from . forms import CommentForm
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked, "blog": blog }
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked, 'blog': blog}
return render(request, "blog_app/blog_page.html", context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
context = {}
return render(request, "blog_app/blog_page.html", context)
Your comment button is just a link, is it normal ? I think, you want to submit your form when you click on?
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="{% url 'comment' %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
</div>
And i think, your problem occured because you dispolay this template from comment view without set blog in context data.
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=form.instance.blog.pk)
return HttpResponse(status_code=400) # error case
else:
return HttpResponse(status_code=501) # try to GET page
Better solution is to pass blog pk in the url for being able to render page with error:
path("blog/<int:pk>/comment/", views.comment, name="comment")
<form action="{% url 'comment' blog.pk %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
def comment(request, pk):
blog = get_object_or_404(Blog, pk=pk)
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=blog.pk)
return render(request, "...", {"blog": blog, "form": form})

Django form comment always returning GET requests, POST request 'Method Not Allowed'

I'm trying to implement a feature where logged in users can comment on a blog post, but I'm a little stuck with the comments appearing on the page.
I can type in the comment and submit them. However, this is always returning a GET request. I tried adding method='post' to both the form and button tags, but this resulted in the following:
Method Not Allowed (POST): /post/1/
Method Not Allowed: /post/1/
I'm not really sure what the problem is. Any help would be much appreciated. Code snippets below.
post_detail.html with comment section:
<div class="content-section">
<legend class="border-bottom">Comments:</legend>
{% if user.is_authenticated %}
<form id="commentForm">
{% csrf_token %}
<fieldset class="form-group">
<div class="row">
<!-- <div class="col"></div> -->
<div class="col-1 text-right">
<img class="img-comment" src="{{ user.profile.image.url }}">
</div>
<div class="col-9">
<textarea type="text" id="commentIn" name="comment"
placeholder="Your comment..." required></textarea>
</div>
<div class="col"></div>
</div>
<div class="row">
<div class="col-10 text-right">
<button id="commentBtn" name="comment_button"
class="btn btn-outline-info" type="submit">Comment</button>
</div>
<div class="col"></div>
</div>
<hr>
</fieldset>
</form>
{% endif %}
<div id="commentDiv">
{% for cmnt in comments_list %}
<img class="img-comment"
src="{{cmnt.commentator.profile.image.url }}">
<a class="mr-2" >{{ cmnt.commentator }}</a>
<p class="article-content">{{ cmnt.comment }}</p>
<hr>
{% endfor %}
</div>
</div>
urls.py in blog app
urlpatterns = [
path('post/<int:pk>/', PostDetailView.as_view(), name="post-detail"),
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, related_name='like')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
commentator = models.ForeignKey(User, on_delete=models.CASCADE)
blog = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = models.CharField(max_length=200)
date_added = models.DateTimeField(default=timezone.now)
class meta:
verbose_name_plural = 'comments'
def __str__(self):
return self.comment
views.py
class PostDetailView(DetailView):
model = Post
form = CommentForm()
def get_context_data(self, **kwargs):
if self.request.method == 'GET':
print('Render a blank form for users to fill out')
print(self.form)
elif self.request.method == 'POST':
print('Get the data from the POST request')
print(self.form)
status = 0
if self.request.user in self.object.likes.all():
status = 1
context = super().get_context_data(**kwargs)
context['comments_list'] = Comment.objects.filter(blog=self.object)
context['status'] = status
return context
and finally, the form itself:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
Don't mix class-based-view with method-based-view. You have to provide function that reads method and behave as it should. For get you usually will have built-in solutions, like form_class - in post() you can call it via form = self.get_form(). It generally looks like this:
class PostDetailView(DetailView):
model = Post
form_class = CommentForm
def post(self, request, *args, **kwargs):
form = self.get_form()
print('Get the data from the POST request')
print(form)
def get_context_data(self, **kwargs):
status = 0
if self.request.user in self.object.likes.all():
status = 1
context = super().get_context_data(**kwargs)
context['comments_list'] = Comment.objects.filter(blog=self.object)
context['status'] = status
return context
Another things to check ie. here: https://stackoverflow.com/a/45661979/12775662

Django forms User form not summited

I need help with my code. I have read through the code several times and I didn't see anything wrong with it.
The user is expected to submit a job application and redirect the user to the dashboard, but it did not submit the job application neither does it direct the user to the dashboard.
here is my code:
mode.py
from django.db import models
from django.contrib.auth.models import User
class Job(models.Model):
title = models.CharField(max_length=255)
short_description = models.TextField()
long_description = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='jobs', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
changed_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Application(models.Model):
job = models.ForeignKey(Job, related_name='applications', on_delete=models.CASCADE)
content = models.TextField()
experience = models.TextField()
created_by = models.ForeignKey(User, related_name='applications', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
Views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import AddJobForm, ApplicationForm
from .models import Job
def job_detail(request, job_id):
job = Job.objects.get(pk=job_id)
return render(request, 'jobs/job_detail.html', {'job': job})
#login_required
def add_job(request):
if request.method == 'POST':
form = AddJobForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.created_by = request.user
job.save()
return redirect('dashboard')
else:
form = AddJobForm()
return render(request, 'jobs/add_job.html', {'form': form})
#login_required
def apply_for_job(request, job_id):
job = Job.objects.get(pk=job_id)
if request.method == 'POST':
form = ApplicationForm(request.POST)
if form.is_valid():
application = form.save(commit=False)
application.job = job
application.created_by = request.user
application.save()
#create_notification(request, job.created_by, 'application', extra_id=application.id)
return redirect('dashboard')
else:
form = ApplicationForm()
return render(request, 'jobs/apply_for_job.html', {'form': form, 'job': job})
forms.py
from django import forms
from .models import Job, Application
class AddJobForm(forms.ModelForm):
class Meta:
model = Job
fields = ['title','short_description','long_description']
class ApplicationForm(forms.ModelForm):
class Meta:
model = Application
fields = ['content', 'experience']
apply_for_job.html
{% extends 'core/base.html' %}
{% block content %}
Apply for job - {{ job.title }}
<form method="post" action=".">
{% csrf_token %}
{% if form.errors %}
{% for error in form.errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
{% endif %}
<div class="field">
<label>Content</label>
<div class="control">
<textarea class="textarea" name="content" id="id_content"></textarea>
</div>
</div>
<div class="field">
<label>Experience</label>
<div class="control">
<textarea class="textarea" name="experience" id="id_experience"></textarea>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-success">Submit</button>
</div>
</div>
</form>
{% endblock %}
what could be wrong with my code?
the error in this line
<form method="post" action=".">
just delete the point, and it should work,
<form method="post" action="">

Django: post form and post list on the same page

I make a site with multiple users, making posts with images and ability to add/remove friends.
So it's easy to make two different pages for post list and creating a new one. But of course it looks better when you can read posts and make new at the same place.
As I understand (learn django for less than a month), I can't connect 2 views to the same url, so the most logical way I see is to join 2 views in one, I also tried to play with template inheriting to render post form by including template, but actually it doesn't work.
Below you can see my views, Post model, and templates. Thank you for attention.
views.py:
from braces.views import SelectRelatedMixin
from . import models
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
class PostList(SelectRelatedMixin, generic.ListView):
model = models.Post
select_related = ('user',)
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
fields = ('post_message', 'post_image')
model = models.Post
select_related = ('user',)
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
models.py:
import misaka
class Post(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE, related_name = 'posts')
posted_at = models.DateTimeField(auto_now = True)
post_message = models.TextField()
message_html = models.TextField(editable = False)
post_image = models.ImageField(upload_to = 'postpics', blank = True)
def __str__(self):
return self.post_message
def save(self, *args, **kwargs):
self.message_html = misaka.html(self.post_message)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('posts:all')
class Meta:
ordering = ['-posted_at']
unique_together = ['user', 'post_message']
urls.py:
app_name = 'posts'
urlpatterns = [
path('', views.PostList.as_view(), name = 'all'),
path('new/', views.CreatePost.as_view(), name = 'create'),
]
post_form.html (template, that allows to make a new post, which will be seen in post_list.html):
{% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-form">
<form action="{% url 'posts:create' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.post_message }}</p>
<p>{{ form.post_image }}</p>
<input id='post-submit' type="submit" value="Post">
</form>
</div>
{% endblock %}
post_list.html:
{% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-container">
{% for post in post_list %}
<div class="current-post-container">
{% include 'posts/_post.html'%}
</div>
{% endfor %}
</div>
{% endblock %}
_post.html(pages, which render by Misaka):
<div class="post-info">
<h5 id='post-owner' >{{post.user.first_name}} {{post.user.last_name}}</h5>
<h6>{{ post.posted_at }}</h6>
<p>{{ post.message_html|safe }}</p>
<div>
<img class='post-image' src="/media/{{ post.post_image }}" alt="">
<div>
{% if user.is_authenticated and post.user == user and not hide_delete %}
<a href="{% url 'posts:delete' pk=post.pk %}" title = 'delete'>Delete</a>
{% endif %}
</div>
</div>
</div>
post_base.html:
{% extends 'base.html' %}
{% block content%}
{% block prepost %}{% endblock %}
{% block post_content %}{% endblock %}
{% block post_post %}{% endblock %}
{% endblock %}
EDIT:
Task was solved. I added two template_name strings to both of my views, so now they look like:
CreatePost in views.py:
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
fields = ('post_message', 'post_image')
model = models.Post
select_related = ('user',)
template_name = 'posts/post_list.html'
template_name = 'posts/post_form.html'
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
PostList in views.py:
class PostList(SelectRelatedMixin, generic.ListView):
model = models.Post
select_related = ('user',)
template_name = 'posts/post_list.html'
template_name = 'posts/post_form.html'
You can put the post_create_form on the same page as post_list_view there is no need to make a separate view for post creation but You need to make ones for editing and deleting.
You can give all of these views the same HTML page with different URLs.
Using template_name = 'example/example.html' ,in Class_Based_Views.
I hope I understand your problem if not clarify more why you can't join two views in one.
def posts(request):
posts = Post.objects.all()
form = PostForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if form.is_valid():
...
context={
'posts' : page_obj,
'create_or_update_post_form' : form,
}
return render(request, 'post/posts.html',context)
Do you struggle to do this in Class-based-view?
You can do easily with django class based views.
Create views as
from django.views.generic import ListView
from django.views.generic.edit import CreateView
class ModelCreate(CreateView):
model = ModelName
fields = ['field1', 'field2']
template_name = 'same_page.html'
success_url = reverse_lazy('list_view')
class ModelList(CreateView, ListView):
model = ModelName
fields = ['field1', 'field2']
paginate_by = 5
template_name = 'same_page.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['form'] = self.get_form()
return context
# If form post redirect to ModelCreate View
def post(self, request, *args, **kwargs):
return ModelCreate.as_view()(request)
app/urls.py
from django.urls import path
from app import views
path('list', views.ModelList.as_view(), name='list_view'),
path('add', views.ModelCreate.as_view(), name='add_view'),
Finally in templates/same_page.html
<div class="row">
<div class="col-sm-5">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type="submit" value="submit" class="btn btn-primary btn-sm float-right">Submit</button>
</form>
</div>
<div class="col-sm-5">
{% if object_list %}
{% for object in object_list %}
<p>{{object.field1}}</p>
<p>{{object.field2}}</p>
{% endfor %}
{% endif %}
</div>
</div>
Hope, this helps.

Categories