ModelForm saving value of submit button to database - python

I have a form in my project that just wouldnt grab whatever the user typed in and im stumped for why
no matter what i typed into the input field, the string 'Post' is what gets saved into the database, which is the value of the submit button, nd whatever i changed the value to is also what gets saved.
model
class Post(models.Model):
post = models.TextField(max_length=250)
author = models.CharField(max_length=64)
date_time = models.DateTimeField(default=timezone.now, blank=True)
def __str__(self):
return f"{self.author}, {self.date_time}, {self.post}"
form
class NewPostForm(ModelForm):
class Meta:
model = Post
fields = ['post']
views.py
def index(request):
newpostform = NewPostForm()
if request.user.is_authenticated:
username = request.user.get_username()
if request.method == 'POST':
post = Post(author=username)
newpostform = NewPostForm(request.POST,request.FILES, instance=post)
if newpostform.is_valid():
post = newpostform.save()
return render(request, "network/index.html")
return render(request, "network/index.html", {
"newpostform": newpostform
})
html
> <form action="{% url 'index' %}" method="post">
> {% csrf_token %}
> <div>
> {{ newpostform }}
> </div>
> <input id='post-btn' class="btn btn-primary" name="post" type="submit" value="Post">
> </form>

Related

Update a single object from a database - Django/Python

So I am trying to allow users to edit menu item prices that are in the database currently. The fields will auto-populate data into the page and users will be able to edit that data to change the price. Here is what I have. I have tried and asked many questions, but I am still lost. I have googled a lot and it helped me understand forms a bit, but I'm not able to fix it. Please let me know if you need more info.
Views.py:
def edit_menu(request):
queryset = Product.objects.all()
context = { "object_list": queryset }
if request.method == 'POST':
post=ProductModelForm(request.POST)
if request.POST.get('price') and request.POST.get('name'):
if 'name' == Product.name:
post.name= request.POST.get('name')
post.price= request.POST.get('price')
post.save()
return redirect('Edit Menu Item')
else:
return redirect('Edit Menu Item')
else:
return render(request, 'mis446/edit-menu-item.html', context)
else:
return render(request, 'mis446/edit-menu-item.html', context)
forms.py:
class ProductModelForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name','price'] # specify which field you need to be in the form
HTML:
<title>ACRMS - Edit Menu Price</title>
<div class = "container">
<form action = "" method = 'POST'>
{% csrf_token %}
{% for instance in object_list %}
<input name = "name" value = "{{ instance.name }}"></input>
<input type="number" name="price" value = "{{ instance.price }}"/><br>
{% endfor %}
</select>
<button type ="submit">Submit Changes</button>
</form>
</div>
Urls.py:
url('edit-menu/edit/',views.edit_menu, name='Edit Menu Item'),
models.py:
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.IntegerField()
slug = models.SlugField()
def __str__(self):
return self.name
For your current implementation, you do not need a form. Instead, update the view like this:
# view
def edit_single_menu(request, pk):
if request.method == 'POST':
post=Product.objects.get(pk=pk)
if request.POST.get('price') and request.POST.get('name'):
post.name= request.POST.get('name')
post.price= request.POST.get('price')
post.save()
return redirect('Edit Menu Item')
else:
return redirect('Edit Menu Item')
return render(request, 'mis446/edit-menu-item.html', context)
# url
url('edit-menu/edit/<pk:id>/',views.edit_single_menu, name='edit_single_menu'),
# template (mis446/edit-menu-item.html)
<title>ACRMS - Edit Menu Price</title>
<div class = "container">
{% for instance in object_list %}
<form action = "{% url 'edit_single_menu' instance.pk %}" method = 'POST'>
{% csrf_token %}
<input name = "name" value = "{{ instance.name }}"></input>
<input type="number" name="price" value = "{{ instance.price }}"/><br>
<button type ="submit">Submit Changes</button>
</form>
{% endfor %}
</div>
Here I am sending individual edit to a new separated view named edit_single_menu and store the changes there.
Update
New url is not meant to replace the old one. It is only to assist you to update individual product. So, you need to keep both of the urls. Also, here is an answer based on #brunodesthuilliers's suggestion:
# view
def edit_single_menu(request, pk):
if request.method == 'POST':
post=Product.objects.get(pk=pk)
form = ProductForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect('Edit Menu Item')
Also, do some changes on edit_menu view:
def edit_menu(request):
queryset = Product.objects.all()
context = { "object_list": queryset }
return render(request, 'mis446/edit-menu-item.html', context)
And urls should look like this:
from django.urls import include, path
# rest of the code
path('edit-menu/edit/<int:pk>/',views.edit_single_menu, name='edit_single_menu'),
path('edit-menu/edit/',views.edit_menu, name='Edit Menu Item'),

Does not display data after filling in the template

I make comments on the site and cannot understand why, after the user has filled out comment forms, they are not displayed, I try to display them through a template
P.S
I need to display the text and the nickname that the user would enter
views.py
def CommentGet(request):
if request.method == 'POST':
comment = Comments(request.POST)
name = request.POST['name']
text = request.POST['text']
if comment.is_valid():
comment.save()
return HttpResponseRedirect(request.path_info)
comments = CommentModel.objects.all()
else:
comment = Comments(request.POST)
comments = CommentModel.objects.all()
return render(request, 'news/post.html', {'comment': comment,'comments':comments})
post.html
<form method="post" action="{% url 'comment' %}">
{% csrf_token %}
<input type="text" name="name" value="{{ name }}">
<input type="text" name="text" value="{{ text }}">
<input type="submit">
</form>
{% for comm in comments %}
<h1> {{ comm.name }} </h1>
<h1> {{ comm.text }} </h1>
{% endfor %}
models.py
class CommentModel(models.Model):
name = models.CharField(max_length=100)
text = models.TextField(default='')
dates = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-dates']
def __str__(self):
return self.name
I'd suggest using a ModelForm to make things simpler, Try something like this:
# views.py
def CommentGet(request):
if request.method == 'POST':
comment_form = CommentForm(request.POST)
comment_form.save()
else:
comment_form = CommentForm()
comments = CommentModel.objects.all()
return render(request, 'news/post.html', {'comment_form': comment_form,'comments':comments, })
# forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = CommentModel
fields = ['name', 'text']
Then, in your template, replace the two text fields with {{ comment_form }}

How to get the image id via a button to use it in views.py?

I am pretty new to django and coding in generall, I'm trying to build an Instagram clone.. so my question is.. how can I comment on a post that is on the newsfeed(list of all uploaded images by every user), without leaving the newsfeed?
So my approach is to give every send button an id? or name? and somehow use it inside my views.py
views.py:
def newsfeed(request):
images = Image.objects.all().order_by('-pub_date')
if request.method == 'POST':
c_form = CommentForm(request.POST)
if c_form.is_valid():
new_comment = c_form.save(commit=False)
new_comment.owner = request.user
new_comment.image = #here should be something that points to the image i'm commenting on
c_form.save()
return redirect('upload_img:newsfeed')
else:
c_form = CommentForm()
context = {'images_temp': images, 'c_form': c_form}
return render(request, 'newsfeed.html', context)
models.py:
class Comment(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
image = models.ForeignKey(Image, on_delete=models.CASCADE, default=1)
text = models.CharField(max_length=225)
pub_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s comments on %s image' % (self.owner, self.image.owner)
newsfeed.html:
{% for image in images_temp %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ c_form|crispy }}
<button name="{{ image.image }}" type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i></button>
</form>
{% endfor %}
You can add id to every comment in a way that makes them unique like adding the post pk and the number of the comments in the post like
POST 6
comment-1
comment-2
comment-3 <-- This comment would have the id P6C3
And after that in your redirect function you can simply do
redirect(newsfeed + '#' + comment_id)
This would scroll into the new comment.

Image not saving in UserProfileForm (Django)

I have a model form to update the user profile and everything is saving correctly except of them image. If I use admin it updates fine but when I use my form it just stays as the default profile image.
Here is my form:
class EditProfileForm(forms.ModelForm):
birth_date = forms.DateField(label='birth_date', input_formats=['%Y-%m-%d'])
class Meta:
model = UserProfile
fields = (
"image",
"bio",
"location",
"birth_date",
)
Here is my model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
Here is my view:
def edit_profile(request):
instance = get_object_or_404(UserProfile, user=request.user)
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return redirect('/')
else:
form = EditProfileForm(instance=request.user)
return render(request, 'edit_profile.html', {'form': form})
And here is my html:
{% extends 'base.html' %}
{% block content %}
<h1>Edit Profile</h1>
<form method='POST' action=''>{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-outline-success">Save</button>
</form>
</body>
{% endblock %}
For file upload you need to specify form's enctype:
<form method='POST' action='' enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-outline-success">Save</button>
</form>
And you should pass request's files to form instance in view:
form = EditProfileForm(request.POST, request.FILES, instance=instance)
Check this doc for details.

MultiValueDictKeyError when I trying to post image

When I trying to add image from admin panel all OK, but when I trying to add image from site, I have this error: image of error. When I trying to post Detail without image, I have the same problem. Before this wasn't.
views.py:
def new_detail(request):
if request.user.is_authenticated:
if request.user.is_superuser:
if request.method == 'POST':
car = request.POST['car']
author = request.user
detail = request.POST['detail']
price = request.POST['price']
description = request.POST['description']
image = request.FILES['images']
detail = Detail(car = car, author = author, detail = detail, price = price, description = description, images = image)
detail.save()
return redirect('/new_detail/')
else:
return redirect('/login/')
return render(request, 'shop/new_detail.html')
new_detail.html:
{% extends 'base.html' %}
{% block content %}
<div class="content container">
<div class="row">
<div class="col-md-8">
<div class=".signin">
<form action="" method="POST">
{% csrf_token %}
<h3>Автомобіль: </h3>
<select name="car">
<option selected>Audi A8 D2 3.3 TDI</option>
<option>Audi A8 D2 3.7</option>
...
...
...
<h3>Ціна: </h3><textarea name="price"></textarea>
<h3>Фотки: </h3><input type="image" name="images" />
<p>
<input type="submit" value="Опублікувати" />
</form>
</div>
</div>
</div>
models.py:
from django.db import models
class Detail(models.Model):
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,)
car = models.CharField(max_length=100)
detail = models.TextField()
description = models.TextField()
price = models.CharField(max_length=30)
images = models.ImageField(upload_to='details', null = True, blank = True)
def __unicode__(self):
return self.detail
def __str__(self):
return self.detail
The first problem is that you are missing enctype="multipart/form-data" from your form tag in the template. See the docs on file uploads for more info.
<form action="" method="POST" enctype="multipart/form-data">
Secondly, your view doesn't handle the case when data is missing from the form. Instead of doing request.POST['detail'] you should be checking if 'detail' in request.POST or using request.POST.get('detail').
However it would be very time consuming to check every field individually. You should look at Django forms and model forms, which can handle a lot of this for you.
from django import forms
class DetailForm(forms.ModelForm):
class Meta:
model = Detail
fields = ['car', 'author', 'detail', 'price', 'description', 'images']
Then your view will be something like
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda u: u.is_superuser)
def new_detail(request):
if request.method == 'POST':
form = DetailForm(request.POST)
if form.is_valid():
detail = form.save()
return redirect('/new_detail/')
else:
form = DetailForm(request.POST)
return render(request, 'shop/new_detail.html', {'form': form})
You can use the form to simplify your template as well:
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
</form>
See the docs on rendering fields manually if you need more control in the template.

Categories

Resources