I am now implementing a comment function on the post_detail page.
but occurred comment_create() got an unexpected keyword argument 'pk' error.
I also tried to change the def comment_creat(request, post_pk): part to def comment_creat(request, pk): on views.py.
and I try {% url 'comment_create' pk=post.pk %} --> post_pk=post.pk
views.py
#login_required
def comment_create(request, post_pk):
if request.method == 'POST':
post = get_object_or_404(Post, pk=post_pk)
content = request.POST.get('content')
com_user = request.user
if not content:
messages.info(request, 'Write please')
return redirect('post_detail', post_pk)
Comment.objects.create(post=post, comment_user=com_user, comment_content=content)
return redirect('post_detatil', post_pk)
urls.py
path('post_detail/<int:pk>/comment_create/',views.comment_create, name='comment_create')
post_detail.html
<form action="{% url 'comment_create' pk=post.pk %}" method="POST">
{% csrf_token %}
<input type="text", name="content", placeholder="comment...">
<input type="submit", value="Go">
</form>
Please help me.
In your view, the name of the argument is post_pk:
#login_required
def comment_create(request, post_pk):
# ...
but in your URL patterns, you use just pk:
path('post_detail/<int:pk>/comment_create/',views.comment_create, name='comment_create')
You can rename any of the two, but renaming the parameter in the urls.py, will result in updating all {% url ... %}s for that view as well, so it is likely that renaming the parameter in the view, will result in less editing:
#login_required
def comment_create(request, pk):
if request.method == 'POST':
post = get_object_or_404(Post, pk=pk)
content = request.POST.get('content')
com_user = request.user
if not content:
messages.info(request, 'Write please')
return redirect('post_detail', pk)
Comment.objects.create(post=post, comment_user=com_user, comment_content=content)
return redirect('post_detatil', pk)
Note that typically retrieving and validating data is done through a Form, not by the view itself.
Related
I have an update form to update information. Here problem is, product_title is updating but product_image is not working. Where is the problem that's for why the photo is not updating?
views.py:
def update_product(request,id):
product = Products.objects.get(pk=id)
form = update_product_info(request.POST or None, instance=product)
if request.method == 'POST' and form.is_valid():
form.save()
print(form.errors)
messages.success(request,"Successfully product information updated.")
return redirect("my_products")
context = {
'product':product,
"form":form
}
return render(request, "update_product.html", context)
update form:
class update_product_info(forms.ModelForm):
class Meta:
model = Products
fields = ('product_title','product_image')
widgets = {
'product_title':forms.TextInput(attrs={'class':'form-control', 'style':'font-size:13px;'}),
'product_image':forms.FileInput(attrs={'class':'form-control', 'style':'font-size:13px;'})
}
template:
<form action="" method="POST" class="needs-validation" style="font-size: 13px;" novalidate="" autocomplete="off" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<div class="d-flex align-items-center">
<button type="submit" class="btn btn-outline-dark ms-auto" value="Update" style="font-size: 13px;">Add</button>
</div>
You should pass both request.POST and request.FILES to the form:
from django.shortcuts import get_object_or_404
def update_product(request, id):
product = get_object_or_404(Products, pk=id)
if request.method == 'POST':
form = update_product_info(request.POST, request.FILES, instance=product)
if form.is_valid():
form.save()
messages.success(request, 'Successfully product information updated.')
return redirect('my_products')
else:
form = update_product_info(instance=product)
context = {'product': product, 'form': form}
return render(request, 'update_product.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: normally a Django model is given a singular name, so Product instead of Products.
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use ProductInfoForm instead of
update_product_info.
I'm trying to allow users to create category and post(that will be tagged to some category) I think I wrote the code right, but I'm getting 404 error with No Post matches the given query.
Here is my code.
this is my form
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="aa")
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput, required=False)
class Meta:
model = Category
fields =('name',)
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="bb")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Post
fields = ['title', 'content', 'image', 'views', 'category']
this is my view
#for adding category
def add_category(request):
if request.method == 'POST':
form = CategoryForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print form.errors
else:
form = CategoryForm()
return render(request, 'main/add_category.html', {'form':form})
#for adding post/see diff style :)
def add_post(request):
context = RequestContext(request)
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=True)
return redirect(index)
else:
print form.errors
else:
form = PostForm()
return render_to_response('main/add_post.html', {'form':form}, context)
And this is my url
url(r'^add_post/', views.add_post, name='add_post'),
url(r'^add_category/$', views.add_category, name='add_category'),
]
And finally my templates
{
% extends 'base.html' %}
{% block content %}
<form id="post_form" method="post" action="/main/add_post/" enctype="multipart/form-data">
{% csrf_token %}
{{form}}
<input type="submit" name="submit" value="Create Post">
</form>
{% endblock %}
You should use action="{% url 'main:add_post' %}" instead of action="/main/add_post/".
Also check that in your projects's urls.py main app's urls included with namespace like
url(r'^main/', include('main.urls', namespace="main"))
If you don't use namespace, than change to action="{% url 'add_post' %}".
If error reoccurs, please provide more information.
Which ulr exactly you enter in browser to get this error?
Your template makes the form post to main/add_post/ while your url for the view is add_post/. You should make them consistent.
This is rather weird. I've been using Django forms for a long time and can't figure this out.
I have a small form with 1 field for "Quantity". Whenever I submit the form nothing happens and it NEVER get's into my condition to check if the request method is a POST. I have put a pdb in the code as well and it never reaches. I am not sure why. Here is the code.
views.py
def show_product(request, product_slug, template_name='catalog/product.html'):
product_cache_key = request.path
product = cache.get(product_cache_key)
if not product:
product = get_object_or_404(Product, slug=product_slug)
cache.set(product_cache_key, product, settings.CACHE_TIMEOUT)
categories = product.categories.filter(is_active=True)
if request.method == 'POST':
import pdb; pdb.set_trace() # it NEVER hit's this
postdata = request.POST.copy()
form = ProductAddToCartForm(request, postdata)
if form.is_valid():
cart.add_to_cart(request)
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
url = urlresolvers.reverse('show_cart')
return redirect(url)
else:
form = ProductAddToCartForm(request=request)
form.fields['product_slug'].widget.attrs['value'] = product_slug
request.session.set_test_cookie()
context = RequestContext(request, locals())
return render_to_response(template_name, context)
forms.py
class ProductAddToCartForm(forms.Form):
quantity = forms.IntegerField(widget=forms.TextInput(attrs={'class': 'input-quantity', 'placeholder': 'Qty'}), error_messages={'invalid': 'Please enter a valid quantity.'}, min_value=1)
product_slug = forms.CharField(widget=forms.HiddenInput())
def __init__(self, request=None, *args, **kwargs):
self.request = request
super(ProductAddToCartForm, self).__init__(*args, **kwargs)
def clean(self):
if self.request:
if not self.request.session.test_cookie_worked():
raise forms.ValidationError("Sorry, please enable your cookies.")
return self.cleaned_data
template
<form method="post" action=".">
{% csrf_token %}
{{ form.quantity.errors }}
{{ form.quantity }}
<input type="submit" name="submit" value="Add to Cart" class="btn btn-danger" />
{{ form.product_slug }}
</form>
When I click "Add to Cart" the URL goes from http://localhost:8000/product/arm-glove/ to this one http://localhost:8000/product/arm-glove/?csrfmiddlewaretoken=RFG0F1Lg0Eu3GcDhtYwPPCpy9Oct5zCX&quantity=2&submit=Add+to+Cart&product_slug=arm-glove
What am I missing here?
Turns out there was an unclosed tag used for the search which is a GET request so the form's POST was never being seen.
My problem is not to show django form fields on template.It's silly but I just haven't found any solution.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'text']
def __init__(self, content_type, id, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.content_type = content_type
self.id = id
def save(self, commit=True):
post_type = ContentType.objects.get_for_model(Post)
comment_type = ContentType.objects.get_for_model(Comment)
comment = super(CommentForm, self).save(commit=False)
if self.content_type == 'post':
comment.content_type = post_type
comment.post = self.id
else:
parent = Comment.objects.get(id=self.id)
comment.content_type = comment_type
comment.post = parent.post
comment.object_id = self.id
if commit:
comment.save()
return comment
my view:
def add_comment(request, content_type, id):
if request.method == 'POST':
data = request.POST.copy()
form = CommentForm(content_type, id, data)
if form.is_valid():
form.save()
return redirect(reverse('index'))
my add_comment template:
<form method="post" action="{% url 'add_comment' 'post' post.id %}">
{% csrf_token %}
{% if not user.is_authenticated %}
{{ form.name.label_tag }}
{{ form.name }}
{{ form.email.label_tag }}
{{ form.email }}
{% endif %}
{{ form.text.label_tag }}
{{ form.text }}<br>
<input type="submit" value="Comment" />
</form>
and I included like:
<button id="button" type="button">Add Comment</button>
<div id="post_comment_form">{% include 'articles/add_comment.html' %}</div>
</article> <!-- .post.hentry -->
why not django rendered form fields,despite of showing buttons?
EDIT:
I'm rendering form in post view.
def post(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.objects.filter(post=post.id)
return render(request,
'articles/post.html',
{'post': post,
'form': CommentForm,
'comments': comments,
# 'child_comments': child_comments
}
)
You forgot to instantiate the form, change this line:
'form': CommentForm,
to this
'form': CommentForm(),
In your view, you're not sending any context variables to the template, so your 'form' object isn't available for your template to process.
For example, the following return statement will render your .html and pass along all local variables, this isn't necessarily the best option (how much do you want your template to have access to), but is simple:
from django.shortcuts import render
...
return render(request, "template.html", locals())
you can also pass a dictionary instead of all local variables. Here's the documentation for render
I have the following form that lives on the site root at /
<form action='/play/' method='post'>
{% csrf_token %}
{{ form.player_name }}
<input id='play' type='submit' value='Play'>
</form>
then I have the view that validates this form:
def login(request):
context = {}
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/play/')
else:
context.update(dict(form=form))
else:
context.update(dict(form=LoginForm(initial={'player_name':'Please tell us your name'})))
return render_to_response('login.html', context, context_instance=RequestContext(request))
And the actual play view:
def play(request):
p1 = briscola.Player(request.POST['player_name'])
The problem is that of course the redirect looses the POST data. But why doesn't it POST directly to the play view by itself when the form.is_valid?