In my django framework I collect user input from a form and create a matplotlib image. This image is displayed after a button push in a tagged field in an html file.
After each button push this image is updated, changes and is newly displayed. This works well. Now I intend to introduce a second image at a second tag, that shows up and changes after pressing a different button.
The problem that I have, is that after pushing the second button, the first image disappears and after pushing the first button, the second image disappears. Here is part of the html code:
<form method=post action="">
{% csrf_token %}
<table>
{% for field in form %}
<tr>
<td>{{ field.label }}</td>
<td>{{ field }}</td>
</tr>
{% endfor %}
</table>
<br>
<p><input type=submit name='button1' value='Create' class="btn btn-default"></form></p>
</form>
<p>
{% if result != None %}
{% load static %}
<img src="{% get_static_prefix %}{{ result }}" width=1000>
{% endif %}
</p>
<form method="post" class="topright">
{{form3}}
{% csrf_token %}
<p><input type=submit name='button2' value='Update' class="btn btn-default" default=1></p>
</form>
<form method=post action="">
{% csrf_token %}
<table>
{% for field in form4 %}
<tr>
<td>{{ field.label }}</td>
<td>{{ field }}</td>
</tr>
{% endfor %}
</table>
<p><input type=submit name='button3' value='Predict' class="btn btn-default" default=1></p>
</form>
<p>
{% if predictresult != None %}
{% load static %}
<img src="{% get_static_prefix %}{{ predictresult }}" width=1000>
{% endif %}
</p>
The image files are saved via: plt.savefig(plotfile) into the static folder. Most of the views code is the following:
def bayes_create_and_update(request):
#os.chdir(os.path.dirname(__file__))
global bandit
global invgammaresult
global predictresult
invgammaresult = None
predictresult = None
if request.method == 'POST' and 'button1' in request.POST:
form = InputForm(request.POST)
if form.is_valid():
form2 = form.save(commit=False)
bandit = gauss_bandit(form2.m, form2.s)
invgammaresult=pull_and_update(bandit,1)
invgammaresult=invgammaresult[7:]
form3= Sample_InputForm()
form4=Predict_InputForm()
elif request.method == 'POST' and 'button2' in request.POST:
form3 = Sample_InputForm(request.POST)
if form3.is_valid():
form2 = form3.save(commit=False)
invgammaresult=pull_and_update(bandit,form2.n)
invgammaresult=invgammaresult[7:]
form = InputForm(request.POST)
form4=Predict_InputForm()
elif request.method == 'POST' and 'button3' in request.POST:
form4 = Predict_InputForm(request.POST)
if form4.is_valid():
form2 = form4.save(commit=False)
predictresult=bandit.predict(form2.p1,form2.p2)
predictresult=predictresult[7:]
form = InputForm(request.POST)
form3= Sample_InputForm()
else:
form = InputForm()
form3= Sample_InputForm()
form4=Predict_InputForm
return render ( request, 'C:/Users/Jan/PycharmProjects/Newversion/newattempt/online_comp/templates/bayes/bayes.html',
{'form': form,
'result': invgammaresult,
'form3':form3,
'form4':form4,
'predictresult':predictresult
})
and my models that give rise to the form is this code:
from django.db import models
from django.forms import ModelForm
class Input(models.Model):
m = models.FloatField(
verbose_name=' Mean of the Normal Distribution:', default=0.0)
s = models.FloatField(
verbose_name=' Standard Deviation of the Normal Distribution:', default=1.0)
class InputForm(ModelForm):
class Meta:
model = Input
fields='__all__'
class Sample_Input(models.Model):
n = models.FloatField(
verbose_name=' Number of samples you wish to draw:', default=1)
class Sample_InputForm(ModelForm):
class Meta:
model=Sample_Input
fields='__all__'
class Predict_Input(models.Model):
p1 = models.FloatField(
verbose_name=' Lower bound', default=-1.0)
p2 = models.FloatField(
verbose_name=' Upper bound', default=1.0)
class Predict_InputForm(ModelForm):
class Meta:
model=Predict_Input
fields='__all__'
Thx
I think it would be helpful if you posted your view as well as the source for the forms you are putting into your html. One possibility is that you have the request.POST info switched in the views but would need to see.
Small detail but form method=post should be form method="post" everywhere correct?
I have solved the problem by creating two sub directories in the static folder and changing the path of saving the file in the compute file (not shown above). So the image output of both functions wouldn't interfere with each other.
Related
I am creating a movie review website. In it, I want to be able to allow a User to make one comment on one movie and then Update or Delete that comment. But I am only able to implement POST right now. How do I change the view, html or model?
Question to ask
How can I keep the comments posted by a user at the top of the comment list so that they can be updated and deleted?
An example of what we would like to implement is Rotten Tomatoes.
Models.py:
class Comment_movie(models.Model):
comment = models.TextField(max_length=1000)
stars = models.FloatField(
blank=False,
null=False,
default=0,
validators=[MinValueValidator(0.0),
MaxValueValidator(10.0)]
)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('user', 'movie')
indexes = [
models.Index(fields=['user', 'movie']),
]
views.py:
def view_movie_detail(request, movie_id):
if not(Movie.objects.filter(id=movie_id)):
Movie(id = movie_id).save()
movie = Movie.objects.get(id=movie_id)
if request.method == "POST":
form = Comment_movie_CreateForm(request.POST)
if form.is_valid():
Comment_movie(
comment = form.cleaned_data['comment'],
user = request.user,
stars = form.cleaned_data['stars'],
movie = movie
).save()
return redirect('view_movie_detail', movie_id=movie_id)
else:
form = Comment_movie_CreateForm()
data = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}?api_key={TMDB_API_KEY}&language=en-US")
recommendations = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}/recommendations?api_key={TMDB_API_KEY}&language=en-US")
comments = reversed(Comment_movie.objects.filter(movie_id=movie_id))
average = movie.average_stars()
context = {
"data": data.json(),
"recommendations": recommendations.json(),
"type": "movie",
"comments": comments,
"average" : average,
"form": form,
}
return render(request, "Movie/movie_detail.html", context)
movie.html:
<h2>Comments</h2>
{% if form.errors %}
<div class = "error_list">
{% for errors in form.errors.values %}
{% for error in errors %}
{{ error }}<br>
{% endfor %}
{% endfor %}
</div>
{% endif %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit">Post Comment</button>
</form>
{% endif %}
<hr>
Looks like you want to do multiple actions in one view. One form for each action and a template field to differentiate actions would be a solution. In this specific case, 'create' action and 'update' action can be automatically determined if we take advantage of unique_together.
from django.shortcuts import get_object_or_404
def view_movie_detail(request, movie_id):
# It makes little sense you create a movie with just an id attr
# So I use get_object_or_404 instead
movie = get_object_or_404(Movie, id=movie_id)
try:
comment_movie = Comment_movie.objects.get(user=request.user, movie=movie)
except Comment_movie.DoesNotExist:
comment_movie = None
if request.method == 'POST':
if request.POST.get('action') == 'delete':
comment_movie.delete()
return redirect('view_movie_detail', movie_id=movie_id)
else:
form = Comment_movie_CreateForm(request.POST, instance=comment_movie)
if form.is_valid():
form.save()
return redirect('view_movie_detail', movie_id=movie_id)
else:
form = Comment_movie_CreateForm(instance=comment_movie)
# Put your view logic outside of the conditional expression.
# Otherwise your code breaks when the form validates to False
data = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}?api_key={TMDB_API_KEY}&language=en-US")
recommendations = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}/recommendations?api_key={TMDB_API_KEY}&language=en-US")
comments = reversed(Comment_movie.objects.filter(movie_id=movie_id).exclude(user=request.user))
average = movie.average_stars()
context = {
"data": data.json(),
"recommendations": recommendations.json(),
"type": "movie",
"comments": comments,
"average" : average,
"form": form,
"comment_movie": comment_movie, # NOTE add the comment to context
}
return render(request, "Movie/movie_detail.html", context)
Note instance=coment_movie will make form use instance attribute when rendering in template.
And in your templates, render all three forms, and add ‘action’ to each form. One good place would be the submit button.
<h2>Comments</h2>
{% if form.errors %}
<div class = "error_list">
{% for errors in form.errors.values %}
{% for error in errors %}
{{ error }}<br>
{% endfor %}
{% endfor %}
</div>
{% endif %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
{% if comment_movie %}
<button type="submit">Edit Comment</button>
<button type="submit" name="action" value="delete">Delete Comment</button>
{% else %}
<button type="submit">Post Comment</button>
{% endif %}
</form>
{% endif %}
<hr>
{% for comment in comments %}
<div>{{ comment.comment }}</div>
{% endfor %}
Check out django-multi-form-view. This module does not fit your question perfectly, but shares some basic ideas.
Note two addtional submit buttons in template. They are rendered only if comment is not None, which means user has made comment before. The second button coresponds to action='delete'
To your question: Render the form first, and render the rest comments after the form such that user comment is always at top.
I have the following models defined:
class Item(models.Model):
rfid_tag = models.CharField()
asset = models.OneToOneField('Assets', default=None, null=True,
on_delete=models.SET_DEFAULT,)
date = models.DateTimeField(name='timestamp',
auto_now_add=True,)
...
class Assets(models.Model):
id = models.AutoField(db_column='Id', primary_key=True)
assettag = models.CharField(db_column='AssetTag', unique=True, max_length=10)
assettype = models.CharField(db_column='AssetType', max_length=150)
...
class Meta:
managed = False
db_table = 'Assets'
ordering = ['assettag']
def __str__(self):
return f"{self.assettag}"
def __unicode__(self):
return f"{self.assettag}"
For which I have created the following form and formset:
class ItemDeleteForm(forms.ModelForm):
asset = forms.CharField(required=True,
help_text= "Item asset tag",
max_length=16,
label="AssetTag",
disabled=True,
)
delete = forms.BooleanField(required=False,
label="Delete",
help_text='Check this box to delete the corresponding item',
)
class Meta:
model = Item
fields = ['asset']
ItemDeleteMultiple = forms.modelformset_factory(model=Item,
form=ItemDeleteForm,
extra=0,
)
managed by the view:
class DeleteMultipleView(generic.FormView):
template_name = '*some html file*'
form_class = ItemDeleteMultiple
success_url = reverse_lazy('*app_name:url_name*')
def form_valid(self, form):
return super().form_valid(form)
And rendered in the template:
{% extends "pages/base.html" %}
{% block title %}
<title>Delete Multiple</title>
{% endblock %}
{% block content %}
<h1>Delete Multiple Items</h1>
<br>
<form class="ManualForm" action ="." method="POST"> {% csrf_token %}
{{ form.management_form }}
<table border="2">
<tr><th colspan="3" scope="row">Select Items to Delete</th></tr>
{% for item_form in form %}
<tr>
<td><label for="{{ item_form.asset.id_for_label }}">AssetTag {{forloop.counter}}:</label>
{% if item_form.non_field_errors %}
{{ item_form.non_field_errors }}
{% endif %}
{% if item_form.asset.errors %}
{{item_form.asset.errors}}
{% endif %}
</td>
<td>{{item_form.asset}}</td>
<td>{{item_form.delete}}
{% if item_form.delete.errors %}
{{item_form.delete.errors}}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
<form class="AutoForm" action ="." method="POST"> {% csrf_token %}
{{form.as_table}}
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
{% endblock %}
When I submit AutoForm, everything is great. It takes me to app_name:url_name, but if I sumbit ManualForm I don't get redirected. It will simply clear all data and reload the form page with empty fields.
The HTTP POST response status code for AutoForm is 302, while for ManualForm is 200.
I don't understand how the template could influence the behavior of the url redirection. What am I doing wrong in the manual rendering of the formset?
It seems that adding:
{% for field in item_form.hidden_fields %}
{{field}}
{% endfor %}
under {% for item_form in form %} will solve the issue.
I didn't understand very well from the docs:
Looping over hidden and visible fields
If you’re manually laying out a form in a template, as opposed to
relying on Django’s default form layout, you might want to treat
< input type="hidden"> fields differently from non-hidden fields. For
example, because hidden fields don’t display anything, putting error
messages “next to” the field could cause confusion for your users – so
errors for those fields should be handled differently.
I just thought this is about errors, so I didn't care. But one of the first thing it says about forms is this:
As an example, the login form for the Django admin contains several
< input> elements: one of type="text" for the username, one of
type="password" for the password, and one of type="submit" for the
“Log in” button. It also contains some hidden text fields that the
user doesn’t see, which Django uses to determine what to do next.
It also tells the browser that the form data should be sent to the URL
specified in the < form>’s action attribute - /admin/ - and that it
should be sent using the HTTP mechanism specified by the method
attribute - post.
Maybe it will help someone else.
What am I doing ?
I'm training on a simple application where one can order a pizza and select his toppings, once the form submitted it shows the submitted queries in the template file.
What is the problem?
I'm having a really hard time showing the checked checkboxes from the form on the template file.
Here are my files :
models.py
class PickedDatas(models.Model):
name = models.CharField(max_length=255, blank=True, null=True)
class Picked(models.Model):
name = models.CharField(max_length=255)
picked = models.ManyToManyField(PickedDatas, blank=True)
forms.py
class CustomChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return mark_safe('%s' % (obj.name))
class SomeForm(forms.ModelForm):
class Meta:
model = Picked
fields = ['name', 'picked']
picked = CustomChoiceField(queryset=PickedDatas.objects.all(), widget=forms.CheckboxSelectMultiple())
views.py
def some_view(request):
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
...
else:
form = SomeForm
return render(request, 'features.html', {'form':form, 'picked':Picked.objects.all()})
As for the template file, I'm using the for loop to show Picked models datas.
How can I achieve what I am trying to do ?
EDIT
here is the template file features.html
<h2>Enter your name and choose your pizza toppings</h2>
<form method='post'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='submit'>
</form>
{% for p in picked %}
<h2>Pizza For : <strong>{{ p.name }}</strong></h2>
<p>{{ p.picked }}</p>
{% endfor %}
it gives me this for {{ p.picked }} : pizza.PickedDatas.None
Picked.picked is a many to many field, so you need to loop through the options:
{% for picked in picked %}<!-- Note renamed variable to prevent clash with inner loop -->
<h2>Pizza For : <strong>{{ picked.name }}</strong></h2>
<p>{% for p in picked.picked.all %}{{ p }}{% endfor %}</p>
{% endfor %}
I want to save and filter user’s objects in my django app. After inputting the below codes, the imagefield is not uploading any image to my database and it’s not returning any image in my template.
Models
class Fin(models.Model):
user=models.ForeignKey(User)
title=models.CharField(max_length=250, help_text='3 bedroom flat for lease')
main_view=models.ImageField(upload_to="photos",blank=True, null=True)
side_view=models.ImageField(upload_to="photos",blank=True, null=True)
address=models.CharField(max_length=200)
city=models.CharField(max_length=200)
state=models.CharField(max_length=200)
guideline=models.TextField(max_length=1000)
def __unicode__(self):
return self.title
class FinForm(ModelForm):
class Meta:
model=Fin
fields=('title','main_view','side_view', 'address','city','state','guideline')
exclude=('user')
Views
def fincrib(request):
extra_data_context={}
#if there's nothing in the field do nothing.
if request. method=="POST":
form =FinForm(request.POST)
if form.is_valid():
data=form.cleaned_data
newfincribs=Fin(
user= request.user,
title=data['title'],
main_view=data ['main_view'],
side_view=data['side_view'],
address=data['address'],
city=data['city'],
state=data['state'],
guideline=data['guideline'])
newfincribs.save()
extra_data_context.update({'FinForm':form})
else:
form = FinForm()
extra_data_context.update({'FinForm':form})
extra_data_context.update({'Fins':Fin.objects.filter(user=request.user)})
return render_to_response('post.html',extra_data_context,context_instance=RequestContext(request))
Template
{% block content %}
<form action="." method="POST">
{% csrf_token %}
<center> {{FinForm.as_p}} </center>
<input type="submit" value="Submit"/>
</form>
{% for Fin in Fins %}
<tr>
{{Fin.user}} </p> </strong>
<p>{{Fin.title}}</p>
<p><img src="{{MEDIA_URL}}/{{Fin.main_view}}"/></p>
<p> <img src="{{MEDIA_URL}}/{{Fin.side_view}}"/></p>
<p> {{Fin.address}} </p>
<p> {{Fin.city}}</p>
<p> {{Fin.state}}</p>
<p> {{Fin.guideline}}</p>
{% endfor %}
{% endblock %}
You're missing a number of things on the template and view layer.
Read this: https://docs.djangoproject.com/en/1.3/topics/http/file-uploads/#basic-file-uploads
Read binding uploaded files to a form from django official docs. I think it can help.
I'm new to Django and was needing some help on a view error i am getting.
I wrote a view that will display a data table of "Groups" if the request method is GET, or display a form to edit a particular "Group" if the request method is POST (item to edit is passed with POST data).
Also, if POST on an existing item, i'd like the form to be pre-populated with the data i already have in the table for that item. I've pretty much got it all down, except when i goto save an edited form, i keep getting this error:
"Cannot set values on a ManyToManyField which specifies an intermediary model"
Any help would be greatly appreciated. Also, I'm new to all this web dev stuff, so if i'm doing something completely silly or am missing a concept, please feel free to flame me accordingly. ;-)
Model
class Alias(models.Model):
def __unicode__(self):
return unicode(self.alias)
alias = models.CharField(max_length=32)
class Octet(models.Model):
def __unicode__(self):
return unicode(self.num)
num = models.IntegerField(max_length=3)
class Group(models.Model):
def __unicode__(self):
return unicode(self.name)
name = models.CharField(max_length=32) #name of the group
id = models.AutoField(primary_key=True) #primary key
octets = models.ManyToManyField(Octet, through='OctetAssignment', blank=True) #not required
aliases = models.ManyToManyField(Alias, through='AliasAssignment', blank=True) #not required
class OctetAssignment(models.Model):
octet = models.ForeignKey(Octet) #octet
group = models.ForeignKey(Group) #group that octet is assigned to
class AliasAssignment(models.Model):
alias = models.ForeignKey(Alias)
group = models.ForeignKey(Group)
View
def index(request):
if request.method == 'GET':
groups = Group.objects.all().order_by('name')
return render_to_response('groups.html',
{ 'groups': groups, },
context_instance = RequestContext(request),
)
elif request.method == "POST":
g = Group.objects.get(id=request.POST['id'])
form = GroupEditForm(instance=g)
return render_to_response('groups.html',
{ 'form': form, },
context_instance = RequestContext(request),
)
def save(request):
if request.method == "POST":
form = GroupEditForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/tradedesk/groups/') # Redirect after POST
To make it complete, here is the form template code i'm using that renders the table and edit page.
Template
<h1>Group Information</h1>
{% if groups %}
<table border=1>
{% for group in groups %}
<tr>
<td>{{group.name}}</td>
<td>{% for octet in group.octets.all %} {{octet}} {% endfor %}</td>
<td>{% for alias in group.aliases.all %} {{alias}} {% endfor %}</td>
<td>{{group.analyst}}</td>
</tr>
{% endfor %}
</table>
<br></br>
<form method="post" action="/groups/">{% csrf_token %}
<select name="id" >
{% for group in groups %}
<option value="{{group.id}}">{{group.name}}</option>
{% endfor %}
</select>
<input type="submit" value="Edit">
</form>
{% endif %}
{% if form %}
<form method="post" action="/groups/save/">{% csrf_token %}
{{form}}
<br></br>
<input type="submit" value="Save">
<form>
{% endif %}
</div>
Try to remove the intermediary models OctetAssignment and AliasAssignment. They should be used only when you want to add custom fields to them. Otherwise Django creates them and uses them transparently by itself.