How to display the Form properly? - django

I just want to show a Form on a HTML Page.
When I put it on the Page and look via Web Browser, there seems to show me the memory address instead of rendering the form..
[forms.py]
from django import forms
MODES=[('top10', 'Top 10 Songs'),
('last10', 'Last 10 Songs'),
('recentX', 'Recent X Songs')]
class chooseMode():
first_name = forms.CharField(required=True)
selectMode = forms.ChoiceField(label='Choose Mode', widget=forms.RadioSelect,choices=MODES)
[views.py]
def home(request):
modusFormular = chooseMode()
return render(request, 'home.html', {'modusForm' : modusFormular})
[home.html]
somewhere in body:
{{ modusForm }}
I expected the form to be shown on the page, but it shows me the following:
<mysongproject.forms.chooseMode object at 0x7fcdcae97710>

Your class needs to inherit from Form:
class chooseMode(forms.Form):

Related

How to integrate a form into a Detail View?

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__'

Django: How to add a print button to objects to print some (special) fields of a model instance

(Hopefully) not a duplicate:
I know this might seem to be quite similar to Django admin overriding - adding a print button
But the answer there is to use django-object-actions, which I already tried but it looks a bit too overloaded for such an simple task. Furthermore the buttons there are not placed behind the row.
My question:
I would like to create a printable view of some fields of a Django models instance.
Let's say I want to print an users
Name
Last Name
Number
What I image is something like this:
Clicking on a print button, shown at the list view:
An preformatted and easy to print website opens which contains the data:
What I have so far
I added the button by using the following code:
class MyModelAdmin(admin.ModelAdmin):
list_display = ('number', 'name', 'last_name', ..., 'account_actions')
...
def account_actions(self, obj):
return format_html(
'<form method="post" action="/print_view.htm"> \
<input type="hidden" name="name" value="{}"> \
<button type="submit" name="action">Print</button> \
</form>',
obj.name
)
account_actions.short_description = 'Actions'
account_actions.allow_tags = True
So my idea is to send the data which I want to get printed to another Website (via POST, on the same server). I would extract the data from the request then and create a printable view.
My question is:
Is it possible to do the same within Django (without leaving DjangoAdmin for the printable view)?
The current approach doesn't feel right too me, I bet there is a way to do that using just Django - a way which I don't know of since I am quite a beginner here.
I found a great module out there that is called django-admin-object-actions, it can be found here: https://github.com/ninemoreminutes/django-admin-object-actions
The maintainer/owner #cchurch helped me out with the following answer:
You can specify a custom view method that can render any template or
return any content you'd like. Here's the simplest example I can come
up with to do that:
class TestModelAdmin(ModelAdminObjectActionsMixin, admin.ModelAdmin):
# all of the normal model admin code here
object_actions = [
{
'slug': 'print',
'verbose_name': _('Print'),
'form_method': 'GET',
'view': 'print_view',
},
]
def print_view(self, request, object_id, form_url='', extra_context=None, action=None):
from django.template.response import TemplateResponse
obj = self.get_object(request, object_id)
return TemplateResponse(request, 'print.html', {'obj': obj})
Using the following template (print.html):
<p>Name: {{ obj.name }}</p>
<p>Enabled: {{ obj.enabled }}</p>

Understanding Django and Django FormView

I am trying to create a Django web app that accepts text in a form/textbox, processes it and redirects to a webpage showing the processed text . I have written a half-functioning app and find de-bugging quite challenging because I don't understand most of what I've done. I'm hoping you will help me understand a few concepts, Linking to resources, also appreciated.
Consider this simple model:
class ThanksModel(models.Model):
thanks_text = models.CharField(max_length=200)
Is the only way to set the text of thanks_text through the manage.py shell? This feels like a pain if I just have one piece of text that I want to display. If I want to display a webpage that just says 'hi', do I still need to create a model?
Consider the view and template below:
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html'
form_class = TestForm
success_url = '/thanks/'
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
I need to create another model, view and html template and update urls.py for '/thanks/' in order for the success_url to redirect correctly? (That's what I've done.) Do I need to use reverse() or reverse_lazy() the success_url in this situation?
Models are used when you are dealing with Objects and Data and DataBases that can contain a lot of information.
For Example A Person would be a model. their attributes would be age, name, nationality etc.
models.py
class Person(models.Model):
Name = models.CharField(max_length=50)
age = models.IntegerField()
nationality = models.CharField(max_length=50)
Thi deals with multiple bits of information for one object. (the object being the person)
A Thank you message would not need this? so scrap the model for the thank you message. just have views where you create the view using a templates and setting the view to a url.
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html' # self explantory
form_class = TestForm # grabs the test form object
success_url = reverse_lazy('vader:thanks') # this makes sure you can use the name of the url instead of the path
def ThanksView(request): # its simple so you don't even need a class base view. a function view will do just fine.
return render(request,"thanks.html")
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
thanks.html
<h1>Thank you for Submitting</h1>
<h2> Come Again </h2>
url.py
from django.urls import path
from djangoapp5 import views
urlpatterns = [
path('', TestView.as_view(), name='test_form'),
path('thanks/', views.ThanksView, name='vader:thanks'),
]
I haven't tested this but hopefully it helps and guide you in the right direction

Trouble with Django form validation

I have been pounding my head on this problem, been looking up Django docs on how to do form validation and can't seem to get any progress so I'm turning to SO for help.
I have a website with a Django form on which I display two ChoiceFields. One contains a list of car makes and the other contains a list of car models. The second field is initially blank and is populated with my Javascript when the user selects a car make. When the user selects both a make and model and clicks Submit, then a page will be loaded with info pertaining to the make/model that the user selected.
Now, if the user selects only a make but no model or no make at all, I want to display an error saying "Please select a make and model to continue."
So far, no matter what I've tried, I am unable to get that functionality.
forms.py
from django import form
makes = (('Honda', 'Honda'), ('Ford', 'Ford'), ('Nissan', 'Nissan'), ('GM', 'GM'))
class SearchForm:
make = forms.ChoiceField(choices=makes, required=True, widget=forms.Select(attrs={'size':'5', 'autofocus'='on'}))
model = forms.ChoiceField(required=True, widget=forms.Select(attrs={'size':'5'}))
def clean(self):
cleaned_data = super(SearchForm, self).clean()
m1 = cleaned_data.get("make")
m2 = cleaned_data.get("model")
if not m1 or not m2:
raise forms.ValidationError("Please select a make and model to continue.")
return cleaned_data
def clean_model(self):
data = self.cleaned_data["model"]
if not data: // if the user didn't select a model
raise forms.ValidationError("Please select a model to continue.")
return data
views.py
from mysite.forms import SearchForm
def search(request):
searchform = SearchForm()
return render(request, "search.html", {"form" : searchform})
def car_info(request):
searchform = SearchForm(request.GET)
if searchform.is_valid():
// code to parse the make and model and return the corresponding page
return render(request, "car_info.html", {})
else: // there is an error so redisplay the page with the new form object
return render(request, "search.html", {"form" : searchform})
search.html
...
<form action="{% url 'mysite.views.car_info' %}" method="GET" name="sform">
{{ searchform.make }}
{{ searchform.model }}
<button>Search away!</button>
</form>
{% if searchform.errors %}
<div class="error">{{ searchform.non_field_errors.as_text }}</div>
{% endif %}
...
In my index.html, I have a link to the search page by having: {% url 'mysite.views.search' %}
The behavior that I am getting is that when I don't select a make, I get the error. This is correct. When I do select a make but don't select a model, I also get the error. Good. But, when I do select a make and model, I get the same error and it will not take me to the car_info.html page.
Any help would be greatly appreciated.
EDIT:
Something weird is happening. I changed my forms.py to raise the Validation Error just to see what would pop out.
raise forms.ValidationError(str(clean_make) + " " + str(clean_model))
Then, I selected both make and model and the error was raised outputting the correct make for the make but "None" for the model, even though I had selected a model! Why is this?
EDIT 2:
Okay, I may know why the model is outputting "None". In my forms.py, I don't specify the choices for the model because that will be filled in with this Javascript code that runs on the search.html page:
$(document).ready(function() {
$("#id_make").change(init);
});
function init() {
populateModel();
}
function populateModel() {
var make = $("#id_make")
var model = $("#id_model") //select fields created by Django ChoiceField widget
var mod_values = values[mak.val()];
model.empty();
$.each(mod_values, function(k,v) {
model.append($("<option></option>").attr("value", v).text(k));
});
}
var values = {
"Honda" : {
"Accord" : "accord",
"Civic" : "civic",
"Odyssey" : "odyssey",
},
"Ford" : {
"F-150" : "f150",
"Taurus" : "taurus",
"Fusion" : "fusion",
},
"Nissan" : {
"Sentra" : "sentra",
"Maxima" : "maxima",
"Altima" : "altima",
},
}
So, when I do:
model = cleaned_data.get("version")
that'll be empty, right?
Now, I am now unsure how to fix it.
As a first debugging step, since you are using the GET method, you should be able to inspect the URL for correctness. When you submit the form with both a make and model selected, the URL should look like:
?make=XXXX&model=YYYY
Since it does, you are absolutely correct that the form is cleaning out the model because essentially it believes there are no valid entries for model. You'll need to create a custom field that validates the model:
class ModelField(forms.ChoiceField):
def valid_value(self, value):
if value is not None and value != '':
return True
return False
Then, in your form:
model = ModelField(required=True, widget=forms.Select(attrs={'size':'5'}))

Model Forms in Django

I am doing a web interface using HTML and django. My problem is that I want to show a form in the website so that the user can fill the fields of one of the models. Although I've read some examples and documentation about how to do it, I cannot see the form in my website.
In my django app, I have the following model:
class Signature(models.Model):
sig = models.ForeignKey(Device)
STATE = models.CharField(max_length=3, choices=STATE_CHOICES)
interval = models.DecimalField(max_digits=4, decimal_places=2)
As the form is related with that model, I have created this ModelForm class:
class SignatureForm(ModelForm):
class Meta:
model = Signature
After that, I have define the following view:
def SigEditor(request):
if request.method == 'POST':
form = SignatureForm(request.POST)
if signature_form.is_valid():
# Create a new Signature object.
signature_form.save()
return HttpResponseRedirect('eQL/training/form.html')
else:
form = SignatureForm()
return render_to_response('eQL/training/showImage.html',
{'signature_form' : SignatureForm })
Finally, I can represent the form in my website by adding:
<fieldset><legend>Device Information</legend>
<form action="" method="post">
{{ signature_form }} < br>
<input type="submit" value="Submit">
</form>
</fieldset>
If I open the website, there are no errors but I don't see the form. However, before the submit button, appears:
< class 'eQL.models.SignatureForm' >
Can anyone help me? I am quite new in this web framework. Thanks!!
Update:
you have 2 problems here:
1st mistake: you name the form instance with 2 names depending on form method (but this would have raised an exception if it's not for the 2nd error you made)
2nd error: you should give the form instance to the template,
not the class ('signature_form' : SignatureForm):
return render_to_response('eQL/training/showImage.html',
{'signature_form' : form})
The template tag {{signature_form}} is expanded as < class 'eQL.models.SignatureForm' > because it is a class not an object.
You write a reference to the class not an object instance
You have to write :
return render_to_response('eQL/training/showImage.html', {'signature_form' : form})
Instead of :
return render_to_response('eQL/training/showImage.html', {'signature_form' : SignatureForm})