New to Django and having problem seeing form fields displayed. What I see is just the submit button. If pressed, the form is finally presented, but with the format for a form that had bad data (typical 'this field is required' error for each box, red box, etc).
The form works fine after entering data and again pressing submit (stores entries in my db). I have a number of forms on the same page that have the same behavior.
Example of one form:
#model
class dbPara(models.Model): #parameters
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
username = models.CharField(max_length=10)
turns = models.FloatField(default=27)
units = models.FloatField(default=5)
rise = models.FloatField(default=2.9)
rescutL = models.FloatField(default=0.0833333333)
rescutH = models.FloatField(default=0.333333333)
LorR = models.CharField(max_length=1, default='R')
def __str__(self):
return self.timestamp, self.username, self.turns, self.units, self.rise, self.rescutL, self.rescutH, self.LorR
#form
class ParaForm(ModelForm):
class Meta:
model = dbPara
widgets = {'username': forms.HiddenInput()}
fields =['username', 'turns', 'units', 'rise', 'rescutL', 'rescutH', 'LorR']
#view
def importParameters(request):
if request.method == 'GET':
form = ParaForm()
else:
form = ParaForm(request.POST)
if form.is_valid():
entry=dbPara(username = request.POST.get('username'),
turns = request.POST.get('turns'),
units = request.POST.get('units'),
rise = request.POST.get('rise'),
rescutL = request.POST.get('rescutL'),
rescutH = request.POST.get('rescutH'),
LorR = request.POST.get('LorR')
)
entry.save()
return render(request, 'main.html',
{'ParaHTML' : form })
#url
urlpatterns = patterns('Inputs.views',
url(r'^importParameters/$', 'importParameters', name='urlParameters'),
)
#main.html
<div class='col-lg-3'>
<h4>Set Rosetta Parameters</h4>
<action="{% url "urlParameters" %}" method="post">{% csrf_token %}
{{ ParaHTML|crispy }}
<input type="hidden" name = "username" value = "{{ user.get_username }}">
<input type="submit" class="btn btn-primary" value="Set">
</form>
</div>
Appreciate any advice (better simple than 'most correct but complicated')
Could it be due to using default in the model? Would that not 'fill in the form' and result in 'POST' at the initial visit to the page, resulting in just the button? Thoughts?
One Suggesestion here ....
if Using request.POST.get('anything') simply then it Will raise error if particular string not find as in example('anything') string...
Because request.POST.get('anything') will return None if 'anything' is not in request.POST.
Additionally, .get allows you to provide an additional parameter of a default value which is returned if the key is not in the dictionary.
e.g: Corrected will be request.POST.get('anything', 'mydefaultvalue')
Related
I would like to do:
I am trying to create a form input on a detail view that will update a particular data column ('status') of the detailed model instance. Here is a picture of what I have in mind:
The selector would display the current status and the user could change it and update from the detail view without having to access the UpdateView.
my idea here would be to have this happen:
1. On submit, get the new user entered value.
2. get the model instance of the currently detailed class
3. assign the model instance attribute as the user entered value
4. save the model instance
I've tried: I don't know if this is the best way to do this but i've been trying to create an AJAX call, mostly by looking for examples online.
Results: Terminal shows Post on submit: "[19/Nov/2019 17:50:33] "POST /task/edit/4 HTTP/1.1" 200 41256". However, the data is not saved to the db. On refresh, the selector returns to previously saved status.
The console shows: "script is connected", and "Update Status" with no errors. On submit, the alert displays success message: "127.0.0.1:8000 says status updated".
Task_detail.html
<div class="deliv-box edit">
<form id="status-update-form" method='POST' action='{% url "task_edit" task.pk %}'>
{% csrf_token %}
{{task_form.status}}
<input id="status-update-btn" type="submit" value="Update Status" />
</form>
</div>
...
<script type="text/javascript">
var frm = $('#status-update-form');
frm.submit(function () {
console.log("script is connected")
console.log($('#status-update-btn').val())
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
$("#deliv-box edit").html(data);
alert("status updated");
},
error: function(data) {
alert("error");
}
});
return false;
});
</script>
forms.py
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = "__all__"
views.py
class TaskDetail(ModelFormMixin, DetailView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
def get_context_data(self, **kwargs):
context = super(TaskDetail, self).get_context_data(**kwargs)
context['task_form'] = self.get_form
return context
def update(request):
if request.method=='POST':
task_id = request.POST.get('id')
task = Task.objects.get(pk = task_id)
status_obj = request.POST.get('status')
task.status = status_obj
task.save()
return JsonResponse({'status':'updated...'})
else:
return JsonResponse({'status':'not updated'})
thank you.
A solution:
In the unlikely event that someone stumbles across this question and who is, like me, just trying to figure it out all by themselves, here is what I've learned about how this works: When a user wants to update a form, Django pre-populates the form with the existing data related to that instance. A user can then alter the data and re-submit the form.
Here, I was attempting to alter just one field of the exiting instance, but as I was only calling that one field, Django was assuming not, as I had hoped, that the other fields would remain the same, but that I intended the other fields to be submitted as blank. Where the fields are required one cannot return that field as blank. Therefore, Django was not able to validate the form and so the form did not get updated.
A solution that works is to call all the fields as hidden and show just the one you want to alter. This way Django can return the unaltered data and validate the form, and you get an update button on your detail view:
<form method="POST">
{% csrf_token %}
<h4> STATUS: </h4>
{% for field in form %}
{{ field.as_hidden }}
{% endfor %}
{{form.status}}
<button type="submit" class="btn btn-success">submit</button>
</form>
You are overriding the method update which does not exist, so it is never called.
You need to subclass UpdateView instead of the DetailView and the mixin.
class TaskUpdateView(UpdateView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
# you can use the line below instead of defining form_class to generate a model form automatically
# fields = ('status', )
def form_valid(self, form):
post = form.save(commit=False)
# do anything here before you commit the save
post.save()
# or instead of two lines above, just do post = form.save()
return JsonResponse({'status':'updated...'})
Here is how you would add readonly (disabled) fields to your form:
class TaskForm(forms.ModelForm):
# override the default form field definitions for readonly fields
other_field = forms.CharField(disabled=True)
another_field = forms.IntegerField(disabled=True)
class Meta:
model = Task
fields = ("status", "other_field", "another_field")
# you could also just do:
# fields = '__all__'
I'm trying to create my first django app - sports predictions game.
I want user to select from three possible results using 3 buttons (images) which pass 3 different values to the db:
1 - home team wins
0 - draw
2 - away team wins
I am able to save data using forms when I type something into it, but how do I pass value of these buttons to my database?
code on my game.html:
{% csrf_token %}
{{ form }}
<input type="submit" value = 1>
<input type="submit" value = 0>
<input type="submit" value = 2> </form>
and my view:
def game(request, Game_id):
thisgame = get_object_or_404(Game, pk=Game_id)
nextgame = int(thisgame.id)+1
template = loader.get_template('polls/game.html')
form = NewBetForm(request.POST or None)
current_user = request.user
allgames = Game.objects.all()
betchoices = BetChoice.objects.all()
context = { 'thisgame': thisgame,
'nextgame': nextgame,
'form': form,
'current_user': current_user,
'betchoices': betchoices,}
if form.is_valid():
bet = form.save(commit=False)
bet.gameid = Game.objects.get(id=Game_id)
bet.userid_id = current_user.id
bet.save()
else:
print (form.errors)
and my form:
class NewBetForm(forms.ModelForm):
class Meta:
model = GameBet
fields = ['bet']
and the error I get is Bet - this field is required
Thank you for all ideas!
you can set name for it like :
<input type="submit" name="send1" value ="1">
Note : you should value part like value ="1"
and in views.py:
if request.method == 'POST':
if request.POST["send1"] == "1":
//do some thing
elif request.POST["send1"] == "2":
//do domthing
else://request.POST["send1"] == "3"
//do something
i hope it will help you :)
As with any other type of form field, a submit button needs a name attribute before it will send any data to the backend. From there, you can just pick up its value via request.POST['whatever_the_name_is'] and assign it to your newly created object - or, if you use the name that is already a field in the form, it will be assigned automatically.
I'm a django newbie so a verbose answer will be greatly appreciated. I'm enforcing a capacity limit on any newly created Bottle objects in my model, like so:
class Bottle(models.Model):
name = models.CharField(max_length=150, blank=False, default="")
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name="bottles")
vintage = models.IntegerField('vintage', choices=YEAR_CHOICES, default=datetime.datetime.now().year)
capacity = models.IntegerField(default=750,
validators=[MaxValueValidator(2000, message="Must be less than 2000")
,MinValueValidator(50, message="Must be more than 50")])
My BottleForm looks like so:
class BottleForm(ModelForm):
class Meta:
model = Bottle
fields = '__all__'
My view (with form validation logic based on this answer):
def index(request):
args = {}
user = request.user
object = Bottle.objects.filter(brand__business__owner_id=user.id).all(). \
values('brand__name', 'name', 'capacity', 'vintage').annotate(Count('brand')).order_by('brand__count')
args['object'] = object
if request.method == "POST":
form = BottleForm(request.POST)
if form.is_valid():
bottle = form.save(commit=False)
bottle.save()
return redirect('index')
else:
form = BottleForm()
args['form'] = form
return render(request, template_name="index.pug", context=args)
And my template (in pug format), like so:
form(class="form-horizontal")(method="post" action=".")
| {% csrf_token %}
for field in da_form
div(class="form-group")
label(class="col-lg-3 col-md-3 col-sm-3 control-label") {{field.label_tag}}
div(class="col-lg-9 col-md-9 col-sm-9")
| {{ field|add_class:"form-control" }}
input(class="btn btn-primary")(type="submit" value="submit")
After a few hours of messing with my code and browsing SO, I managed to display the error by adding {{ form.errors }} to my template, but that only shows after the page has already been reloaded and in a very ugly form: see here.
What I'd like is to utilize django's built-in popover error messages without reloading page (see example on default non-empty field), which is so much better from a UX standpoint.
That is not a Django message. That is an HTML5 validation message, which is enforced directly by your browser. Django simply outputs the input field as type number with a max attribute:
<input type="number" name="capacity" max="750">
I'm not sure if your (horrible) pug templating thing is getting in the way, or whether it's just that Django doesn't pass on these arguments when you use validators. You may need to redefine the field in the form, specifying the max and min values:
class BottleForm(ModelForm):
capacity = forms.IntegerField(initial=750, max_value=2000, min_value=250)
(Note, doing {{ field.errors }} alongside each field gives a much better display than just doing {{ form.errors }} at the top, anyway.)
I have created a function for a search form form my database, method works fine, but I, don't know whether I should use queryBooks = request.GET['queryBooks'] or form.cleaned_data.get('queryBooks')
Here is my code.
# views.py
def SearchBook(request):
error = False
message = ''
books = Books.objects.all()
if 'queryBooks' in request.GET:
queryBooks = request.GET['queryBooks']
if not queryBooks:
error = True
message = u'enter book or author title'
else:
books = Books.objects.filter\
(
Q(book__icontains=queryBooks) | Q(Author__name__icontains=queryBooks)
)
contexto = {'Books': books, 'Error': error, 'Message': message}
return render(request, 'list_of_book.html', contexto)
# list_of_book.html
<form action="" method="get">
<input type="text" name="queryBooks">
<input type="submit" value="search">
</form>
# urls.py
url(r'^books/search/$', SearchBook, name='searchBook'),
There is no form in your view, so
form.cleaned_data.get('queryBooks')
Would give you an error.
In general, I recommend that you learn about Django forms, as they take care of rendering the html, and validating the input from the user. For your specific example, fetching the query string from request.GET is probably ok.
I've got a form which includes the option to upload an image. In my model, I've defined a default image name to use when no image is selected for upload. When selecting a file, the form uploads the file to my media directory and properly places the filename in the db field (working as it should). When not selecting a file, that field is left blank in the db. When adding an item to that same db table using Django Admin, the default filename is correctly placed in the db field when no image is selected (and works properly when an image is selected). It's only when using the form and not selecting an image does it not work properly. I've look around for a while but have yet to come up with anything that could help. Any ideas? Any help is much appreciated.
models.py
class Beer(models.Model):
beername = models.CharField(max_length=150)
brewer = models.ForeignKey(Brewery)
style = models.ForeignKey(BeerStyle)
abv = models.DecimalField(max_digits=4, decimal_places=2)
beerdescription = models.TextField()
picture = models.ImageField(upload_to='site_media/pictures/',
default='pictures/no_beer_picture.jpg')
def __unicode__(self):
return self.beername
forms.py
class BeerAddForm(forms.Form):
beername = forms.CharField(
label=u'Name',
widget=forms.TextInput(attrs={'size': 75})
)
style = forms.ModelChoiceField(
BeerStyle.objects.all(),
label=u'Style',
widget=forms.Select()
)
abv = forms.DecimalField(
label=u'ABV',
widget=forms.TextInput(attrs={'size': 8})
)
beerdescription = forms.CharField(
label=u'Description',
widget=forms.Textarea
)
picture = forms.ImageField(
required=False,
label=u'Picture',
widget=forms.FileInput,
initial='pictures/no_beer_picture.jpg'
)
views.py
def beeradd(request, brewery_id):
brewery = get_object_or_404(Brewery, id=brewery_id)
if request.method == 'POST':
form = BeerAddForm(request.POST, request.FILES)
if form.is_valid():
# Create or get beer
beer = Beer.objects.create(
beername = form.cleaned_data['beername'],
brewer = brewery,
style = form.cleaned_data['style'],
abv = form.cleaned_data['abv'],
beerdescription = form.cleaned_data['beerdescription'],
picture = form.cleaned_data['picture']
)
return HttpResponseRedirect('/beers/')
else:
form = BeerAddForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('beer_add.html', variables)
beer_add.html (the form in question)
{% extends "base.html" %}
{% block title %}Add a Beer{% endblock %}
{% block head %}Add a Beer{% endblock %}
{% block content %}
<form enctype="multipart/form-data" method="post" action=".">
{{ form.as_p }}
<input type="submit" value="save" />
</form>
{% endblock %}
I would set the default in the view code, after the user submitted the form. So take the initial argument for picture out of the form definition and do something like this in your view:
def beeradd(request, brewery_id):
brewery = get_object_or_404(Brewery, id=brewery_id)
if request.method == 'POST':
form = BeerAddForm(request.POST, request.FILES)
if form.is_valid():
# Create or get beer
pic = form.cleaned_data['picture']
if not pic:
pic = 'pictures/no_beer_picture.jpg'
beer = Beer.objects.create(
beername = form.cleaned_data['beername'],
brewer = brewery,
style = form.cleaned_data['style'],
abv = form.cleaned_data['abv'],
beerdescription = form.cleaned_data['beerdescription'],
picture = pic
)
...
I think the problem that you are seeing is that the initial may populate the file field with that value, but when the form gets submitted the value 'pictures/no_beer_picture.jpg' is not a valid file on the user's computer so no file is sent with the form. You can verify what is getting sent by printing out form.cleaned_data['picture'] before trying to save the model.
You may want to check to see if you can just assign a string value to the picture attribute on Beer or if you actually need to assign a file.