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'),
Related
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>
I tried to make a blog that allows user posts, store the posts in the db along with the posted date time and the person who posted it.
My problem is that I somehow cannot load the {{form}} to my UI, which makes my form invalid and I just don't know why it doesn't show up the input text box.
I'm not sure if I need a get_post function, but I'll just put it in views.py. (I havnt write the html of that part yet. Just need to see the form first.)
I'm pretty new to Django, can somebody pls help me with this!!! Thanks!
Below are my files.
blog.html file:
{% block posts %}
<div>
<span>New Post: </span>
<form method="post" action="{% url 'posts' %}" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{form}}
<!--not showing in UI-->
</table>
<input id="id_post_button" type="submit" value="Submit" /><br>
</form>
<div>
{% endblock %}
urls.py
urlpatterns = [
path('posts', views.post_action, name='posts'),
path('post/<int:id>', views.get_post, name='post'),
]
Models.py
class PostModel(models.Model):
user_id = models.IntegerField()
post_input_text = models.CharField(max_length=100)
post_profile = models.CharField(max_length=30)
post_date_time = models.DateTimeField(default=timezone.now)
def __str__(self):
return 'id=' + str(self.user_id) + ", post_date_time=" + self.post_date_time + ", post_input_text=" + self.post_input_text + ", post_profile=" + self.post_profile
Views.py:
#login_required
def post_action(request):
print("----post action---")
context = {}
if request.method == "GET":
context['form'] = CreatePost()
context['posts']= PostModel.objects.get(user_id = request.user.id)
return render(request, "socialnetwork/blog.html", context)
form = CreatePost(request.POST, request.FILES)
if not form.is_valid():
print("not valid ~~~~~~~~")
context['form'] = form
context['posts'] = PostModel.objects.get(user_id = request.user.id)
return render(request, "socialnetwork/blog.html", context)
post_input_text = form.cleaned_data.get("post_input_text")
post_date_time = form.cleaned_data.get("post_date_time")
post_profile = form.cleaned_data.get("post_profile")
obj = PostModel.objects.get(
user_id = request.user.id,
)
obj.post_input_text = form.cleaned_data.get("post_input_text")
obj.post_date_time = form.cleaned_data.get("post_date_time")
obj.post_profile = form.cleaned_data.get("post_profile")
obj.save()
form = CreatePost() #refresh the form to original state
context['form'] = form
context['posts'] = obj
return render(request, "socialnetwork/blog.html", context)
def get_post(request, id):
item = get_object_or_404(PostModel, id=id)
print('Picture #{} fetched from db: {} (type={})'.format(id, item.post_input_text, item.post_profile, item.post_date_time))
if not item.post_input_text:
raise Http404
return HttpResponse(item.post_input_text)
forms.py
class CreatePost(forms.Form):
post_input_text = forms.CharField(max_length=100)
post_profile = forms.CharField(max_length=30)
post_date_time = forms.DateTimeField()
Update the template with {{ form.as_table }}, instead of {{form}}
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.
I need to get value from tag and redirect to '/value/' by submit.
Now I'm getting:
'ApartmentForm' object has no attribute 'cleaned_data'
I'm totally missing something.
forms.py
class ApartmentForm(ModelForm):
class Meta:
model = Apartment
fields = ['title']
views.py
def index(request):
context = {}
context['apartments'] = get_list_or_404(Apartment)
if request.method == 'POST':
form = ApartmentForm(request.POST or None)
context = {'form': form,}
id = form.cleaned_data.get('id', None)
return redirect(id)
else:
context['apartment_form'] = ApartmentForm
return render(request, 'main/main.html', context)
template
<form action="/{{ apartment.id }}" method="post">
{% csrf_token %}
<p><select size="10">
<option disabled>Chose apartment</option>
{% for apartment in apartments %}
<option value="{{ apartment.id }}">{{ apartment.title }}</option>
{% endfor %}
</select></p>
<input type="submit" value="Chose">
</form>
Update
Thanks Daniel!
It was such a fail not to call form in the template. I fixed that, but it still passing None to url (http://127.0.0.1:8000/None). Can't figure out why.
view.py
def index(request):
context = {}
context['apartments'] = get_list_or_404(Apartment)
if request.method == 'POST':
form = ApartmentForm(request.POST or None)
if form.is_valid():
id = form.cleaned_data.get('id', None)
return redirect(id)
else:
context['apartment_form'] = ApartmentForm
return render(request, 'main/main.html', context)
forms.py
APARTMENTS = ()
for apartment in Apartment.objects.all():
APARTMENTS += ((apartment.id, apartment.title),)
class ApartmentForm(Form):
apartment = ChoiceField(label='', widget=Select, choices=APARTMENTS)
template
<form action="." method="post">
{% csrf_token %}
{{ apartment_form }}
<input type="submit" value="Chose">
form.cleaned_data comes from form.is_valid(), so you sould change your views.py like this:
def index(request):
[...]
if request.method == 'POST':
form = ApartmentForm(request.POST or None)
if form.is_valid():
[...]
id = form.cleaned_data.get('id', None)
return redirect(id)
I'm not sure how to filter dropdown based on user id.
Not I want for user id 2.
I want exactly like this for user id 2.
Model
#python_2_unicode_compatible # only if you need to support Python 2
class PredefinedMessage(models.Model):
user = models.ForeignKey(User)
list_name = models.CharField(max_length=50)
list_description = models.CharField(max_length=50)
def __str__(self):
return self.list_name
class PredefinedMessageDetail(models.Model):
predefined_message_detail = models.ForeignKey(PredefinedMessage)
message = models.CharField(max_length=5000)
View
class PredefinedMessageDetailForm(ModelForm):
class Meta:
model = PredefinedMessageDetail
fields = ['predefined_message_detail', 'message']
exclude = ('user',)
def predefined_message_detail_update(request, pk, template_name='predefined-message/predefined_message_detail_form.html'):
if not request.user.is_authenticated():
return redirect('home')
predefined_message_detail = get_object_or_404(PredefinedMessageDetail, pk=pk)
form = PredefinedMessageDetailForm(request.POST or None, instance=predefined_message_detail)
if form.is_valid():
form.save()
return redirect('predefined_message_list')
return render(request, template_name, {'form':form})
html file
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
You can do it in view itself using
form = PredefinedMessageDetailForm(request.POST or None, instance=predefined_message_detail)
form.fields["predefined_message_detail"].queryset= PredefinedMessage.objects.filter(user=request.user)
But filtering happens based on request.user so it should be logged in.Consider that also. Hope this helps