I am new to Django and I am trying to create a form in a template. I think I have accomplished this however I a missing a piece. This is what I currently see:
I think I am missing something from my form class that should display the choices.
forms.py
from django import forms
class TestForm(forms.Form):
one = forms.ChoiceField(choices=('HDFS', 'HDFS'), widget=forms.RadioSelect())
two = forms.ChoiceField(choices=('HIVE', 'HIVE'), widget=forms.RadioSelect())
three = forms.ChoiceField(choices=('BOTH', 'Both of HDFS and HIVE'), widget=forms.RadioSelect())
beatle = [one, two, three]
event_textarea = forms.Textarea(attrs={'rows': '8', 'class': 'form-control', 'placeholder': 'Events...', 'id': 'event_textarea'})
views.py
def home(request):
if request == 'POST':
# create a form instane and populate it with data from the request
form = TestForm(request.POST)
if form.is_valid():
# process the data in form.cleaned_data as required
form.cleaned_data()
# redirect to a new URL:
return HttpResponseRedirect('/test/')
# if a GET (or any other method) we'll create a blank form
else:
form = TestForm()
return render(request, 'home/home_page.html', {'form': form})
template:
{% extends 'index/index.html' %}
{% load staticfiles %}
{% block head %}
<script type="text/javascript" src="{{ STATIC_URL }}home/js/home.js" async></script>
<link href="{{ STATIC_URL }}home/css/home.css" rel="stylesheet">
{% endblock head %}
{% block content %}
<div>Welcome to Trinity E2E testing</div>
<form id="test-form" action="/test/" method="post"> {# pass data to /test/ URL #}
{% csrf_token %}
{% for radio in form.beatle %}
<div class="btn btn-default btn-lg">
{{ radio }}
</div>
{% endfor %}
{{ form.event_textarea }}
<input id="submit-test" type="submit" class="btn btn-default btn-lg" value="Submit">
</form>
{% endblock content %}
beatle list contains references to class attributes, not instance attributes.
How about make it a instance method to return instance attributes (form fields):
def beatle(self):
return [self.one, self.two, self.three]
UPDATE
To correctly return bound fields:
def beatle(self):
return [self['one'], self['two'], self['three']]
or
def beatle(self):
return [self[name] for name in ['one', 'two', 'three']]
Related
I'm trying to create a frontend data entry page for an existing model. However, when clicking the link, I get an error:
crispy_forms.exceptions.CrispyError: |as_crispy_field got passed an invalid or inexistent field
Just to be clear, adding the data from Django Admin works with no issues at all.
Having looked through a number of answered questions here, one did highlight what I believe could be problem, but it was out of context and did not provide much of an explanation.
I am trying to create a frontend entry form for users that corresponds with a foreign key.
models.py
class NewHandoff(models.Model):
handoff_pk = models.AutoField(primary_key=True)
handoff_date = models.DateField(auto_now_add=True,verbose_name="Handoff Date")
shift1_pri = models.ForeignKey(Engineer,on_delete=models.CASCADE,verbose_name="Shift 1 Primary")
shift1_sec = models.ForeignKey(Engineer,on_delete=models.CASCADE,verbose_name="Shift 1 Secondary")
def __str__(self):
return f"{self.handoff_date}"
class Meta:
verbose_name_plural = 'Handoffs'
# New Handoff Form
class NewHandoffForm(forms.ModelForm):
class Meta:
model = NewHandoff
fields = ['shift1_pri','shift1_sec']
views.py
from django.shortcuts import redirect, render
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http.response import HttpResponse
from django.contrib import messages
from .models import AttentionForm, NewHandoffForm
# Handoff View Page
class NewHandoffView(LoginRequiredMixin,View):
def get(self, request):
greeting = {}
greeting['heading'] = "New Handoff"
greeting['pageview'] = "Handoff"
return render (request,'handoff/handoff-new.html')
def post(self, request):
if request.method == "POST":
if "add-new-handoff-button" in request.POST:
create_new_handoff_form = NewHandoffForm(request.POST)
create_new_handoff_form.save()
return redirect("/handoff/handoff-create")
handoff-new.html
{% extends 'partials/base.html' %}
{% load static %}
{% load humanize %}
{% load crispy_forms_tags %}
{% block extra_css %}
<link href="{% static 'libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet">
{% endblock %}
{% block contents %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<!-- New Form -->
<form method="POST">
{% csrf_token %}
<div class="row">
<div class="row-fluid pb-1">
<!-- Field 1 -->
<div class="mb-3">
{{ form.shift1_pri|as_crispy_field }}
</div>
<!-- End of Field 1 -->
</div>
</div>
<div class="d-flex flex-wrap gap-2">
<button type="submit" class="btn btn-primary waves-effect waves-light" name="add-new-handoff-button">Create New Handoff</button>
</div>
</form>
<!-- End of New Form -->
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_javascript %}
{% endblock %}
Someone mentioned in another post that forms should correlate with the declared form name {{ form.shift1_mod|as_crispy_field }} so it should actually be {{ create_new_handoff_form.shift1_mod|as_crispy_field }} but I have tried changing this and still get the same problem, plus, another model form works fine with just form despite the name of the form being attention_form.
Does anyone have any idea or can point me in the right direction? :)
You are not passing the form through the context in the template. As you are inheriting View, Add the following line in the get() and afterwards in the post() method appropriately:
form = NewHandoffForm()
# and then change return
return render(request,'handoff/handoff-new.html', {'form': form })
Also, you have a space after render in the get function. I hope this is a typo here, but not in your code.
I am attempting to render a form where the only field is a dropdown. I have the form, view, .html, url all set up. But when I access this url, it shows a different form and view and I suppose also a different .html. I am so confused on why this is happening as it had been working fine for quite some time so I obviously changed something.
forms.py
#this is the form for the dropdown
class ManifestDropDown(forms.Form):
References = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
manifest_references.html
<!--html for dropdown-->
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST" action="manifest">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Submit</button>
</form>
</div>
{% endblock %}
views.py
#view for dropdown
def manifest_references(request):
if request.method == 'POST':
if form.is_valid():
reference_id = form.cleaned_data.get('References')
form.save()
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
urls.py
url(r'^manifest_references', manifest_references, name='manifest_references'),
base.html
<!--showing the link to this url-->
...
<a class="dropdown-item" href="{% url 'manifest_references' %}">Edit Manifests</a>
When I access the url above - instead of showing the manifest_references view with the dropdown, it immediately jumps to a different view manifest which is referenced as the action in the manifest_references.html. Please someone help me determine why this is happening.
I need to iterate through a list of checkboxes and add a link to each of them. However I am not able to do so.
The template shows the complete form as a link istead of an individual checkbox being a list.
Below given is my code:
Here is my forms.py:
class GetTaskDescription(forms.Form):
get_tasks = forms.ModelMultipleChoiceField(
queryset=Task.objects.none(),
widget=forms.CheckboxSelectMultiple,
required=True
)
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(GetTaskDescription, self).__init__(*args, **kwargs)
self.fields['get_tasks'].queryset = self.user.task_set.all()
def get_task_description(self):
tasks = self.cleaned_data['get_tasks']
return tasks
Here is my html:
{% extends 'todoapp/base.html' %}
{% block title %}Select a Task{% endblock %}
{% block content %}
<h2>Select tasks to view description</h2>
<form method="get" action="{% url 'view_task_description' %}" name="view_task_description">
{% for tasks in view_tasks %}
{{ tasks }}
{% endfor %}
<br/>
<input type="submit" value="View Description">
<button onclick="location.href='{%url 'dashboard' %}?name=Go back'" type="button">Go back</button>
</form>
{% endblock %}
Here is my views.py:
#login_required(login_url='/login/')
def view_task_description(request):
task_description = GetTaskDescription(data=request.GET, user=request.user)
if task_description.is_valid():
obj = GetTaskDescription.get_task_description(task_description)
print obj
return render(request, 'todoapp/task_desc.html', context={'description': obj})
return render(request, 'todoapp/select_task_description.html', context={'view_tasks': GetTaskDescription(user=request.user)})
You're trying to iterate over a form instance:
'view_tasks': GetTaskDescription(user=request.user)
{% for tasks in view_tasks %}
To access field choices you should use view_tasks.fields.get_tasks.choices in template.
I need some help getting the add_page function to work properly. I am very new to HTML and even newer to Django. The chapter I am working on can be found here: http://www.tangowithdjango.com/book17/chapters/forms.html. Currently my relevent files look like this:
Forms.py
from django import forms
from rango.models import Page, Category
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
# Provide an association between the ModelForm and a model
model = Page
# What fields do we want to include in our form?
# This way we don't need every field in the model present.
# Some fields may allow NULL values, so we may not want to include them...
# Here, we are hiding the foreign key.
# we can either exclude the category field from the form,
exclude = ('category',)
#or specify the fields to include (i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
Views.py:
from django.shortcuts import render
from django.http import HttpResponse
from rango.models import Category, Page
from rango.forms import CategoryForm, PageForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-view')[:5]
context_dict = {'categories': category_list,
'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine.
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
context_dict['category_name_slug'] = category_name_slug
# Retrieve all of the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displays the "no category" message for us.
pass
# Go render the response and return it to the client.
print context_dict
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# Save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
# probably better to use a redirect here.
return category(request, category_name_slug)
else:
print form.errors
else:
form = PageForm()
context_dict = {'form':form, 'category': cat}
return render(request, 'rango/add_page.html', context_dict)
urls.py
from django.conf.urls import patterns, url
from rango import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
# url(r'^about/$', views.about, name='about'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$', views.add_page, name='add_page'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),)
I think this ^ is where I am encountering the issue. I manage to get to the "add a page" screen, but when I try to submit something, I receive an error that states I am only supplying 1 argument and add_page() requires 2. I think I may need an additional url that is similar to the "add_category" URL, but that must mean by other URL is pointing to the wrong place?
category.html
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>{{ category_name }}</h1>
{% if category %}
{% if pages %}
<ul>
{% for page in pages %}
<li>{{ page.title }}</li>
{% endfor %}
</ul>
{% else %}
<strong>No pages currently in category.</strong>
{% endif %}
<li>Add a New Page</li>
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
</body>
</html>
add_page.html:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/add_page/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Create Page" />
</form>
</body>
</html>
I edited the add_page function to include category_name_slug:
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
# probably better to use a redirect here.
return category(request, category_name_slug)
else:
print form.errors
else:
form = PageForm()
# made the change here
context_dict = {'form':form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
Then I edited the add_page.html to look like this:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/category/{{ category_name_slug }}/add_page/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Create Page" />
</form>
</body>
</html>
if you dont wanna edit your views.py
just doit
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/category/{{ category }}/add_page/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Create Page" />
</form>
</body>
</html>
but i have problem to it still cannot be save on database.
I wrote a simple app that is a custom DateField widget for mezzanine. Afaik it's, it's a simple case and besides overextending a template it would be the same in pure django or django-cms (feel free to correct me if I'm wrong).
The widget:
class DatePickerInput(forms.DateInput):
def __init__(self, attrs = None, format = None):
super(DatePickerInput, self).__init__(attrs, format)
self.attrs["class"] = "datepicker"
class Media:
css = { "all": ('css/ui-lightness/jquery-ui-1.10.3.custom.min.css',) }
js = (
"mezzanine/js/" + getattr(settings, "JQUERY_UI_FILENAME", "jquery-ui-1.9.1.custom.min.js"),
"js/datepicker_setup.js",)
I overextend base.html template to insert form.media:
{% overextends "base.html" %}
{% load pages_tags mezzanine_tags i18n future staticfiles %}
{% block extra_head %}{{ block.super }}
{{ form.media }}
{% endblock %}
Now, I create a form for my model class.
Here's the class:
class PlayerProfile(models.Model):
user = models.OneToOneField("auth.User")
# Can be later changed to use a setting variable instead of a fixed date
date_of_birth = models.DateField(default=date(1990, 1, 1))
Here's the model form:
from DateWidgets.widgets import DatePickerInput
from PlayerProfiles.models import PlayerProfile
class EditPlayerProfileForm(Html5Mixin, forms.ModelForm):
class Meta:
model = PlayerProfile
fields = ("date_of_birth", )
widgets = { 'date_of_birth': DatePickerInput }
def __init__(self, *args, **kwargs):
super(EditPlayerProfileForm, self).__init__(*args, **kwargs)
Here's the view:
#login_required
def profile_update(request, template="accounts/account_profile_update.html"):
"""
Profile update form.
"""
pform = forms.EditPlayerProfileForm
player_form = pform(request.POST or None, request.FILES or None, instance=request.user.playerprofile)
context = {"pform": player_form, "title": _("Update Profile"), "profile_user": request.user}
return render(request, template, context)
Here's the template:
{% overextends "accounts/account_profile_update.html" %}
{% load i18n mezzanine_tags %}
{% block main %}
<fieldset>
<legend>{{ title }}</legend>
<form method="post"{% if pform.is_multipart %} enctype="multipart/form-data"{% endif %}>
{% fields_for pform %}
<div class="form-actions">
<input class="btn btn-primary btn-large" type="submit" value="{{ title }}">
</div>
</form>
</fieldset>
{% endblock %}
Now if I view the form in a browser, the custom widget is there (I can tell because the input html tag has my custom class attribute value) but it doesn't inject the form media, it's missing. Any idea what's going on here? Thanks in advance! Cheers :-)
form isn't available in the template, because you've called your form variable pform.
Try {{ pform.media }}.
I was googled here with the same problem under different conditions and spotted another error that may appear under other conditions (my case is extending change_form.html in Django 2.1): I had to use extrahead instead of extra_head
{% block extrahead %}{{ block.super }}
{{ form.media }}
{% endblock %}