Creating forms from models - django

i'm moving my first steps into Django and i'm tryin' to follow the tutorial at this link: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
but i can't get a form. It just returns a white page!
Can someone explain if i'm missing something?
my models.py:
from django.db import models
from django.forms import ModelForm
class UserProfile(models.Model):
name = models.CharField(max_length=30)
surname = models.CharField(max_length=30)
email = models.EmailField()
tel = models.CharField(max_length=30, null=True, blank=True)
def __unicode__(self):
return '%s %s' % (self.surname, self.name)
class Ad(models.Model):
title = models.CharField(max_length=50)
descr = models.TextField()
city = models.CharField(max_length=30)
price = models.FloatField(null=True, blank=True)
img = models.ImageField(upload_to='./uploaded_imgs', null=True, blank=True)
dateIn = models.DateField(auto_now_add=True)
dateExp = models.DateField(auto_now_add=True)
codC = models.ForeignKey('Cat')
codU = models.ForeignKey('UserProfile')
def __unicode__(self):
return '%s - %s' % (self.title, self.dateIn)
class Cat(models.Model):
cat = models.CharField(max_length=35, primary_key=True)
def __unicode__(self):
return self.cat
my forms.py:
from django import forms
class newAdForm(forms.Form):
title = forms.CharField(max_length=50)
descr = forms.CharField(widget=forms.Textarea)
city = forms.CharField(max_length=30)
price = forms.FloatField(required=False)
img = forms.ImageField(required=False)
dateIn = forms.DateField(auto_now_add=True)
dateExp = forms.DateField(auto_now_add=True)
codC = forms.ModelChoiceField(Cat)
codU = forms.ModelChoiceField(UserProfile)
my views.py:
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.http import HttpResponse
from django import forms
from models import *
from django.forms import *
from django.forms.models import modelformset_factory
[...]
def newAd(request):
newAdFormSet = modelformset_factory(Ad)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html', {'state':'Your ad has been successfull created.'}, context_instance = RequestContext(request),)
else:
formset = newAdFormSet()
return render_to_response('ad_form.html', context_instance = RequestContext(request),)
my ad_form_auto.html template:
{% extends "base.html" %}
{% block title %}Ads insertion form{% endblock %}
{% block content %}
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form method="post" action="">
{{ formset }}
</form>
{% endblock %}
Thanks a lot! This community looks just awesome! :)

You're not passing the form to the template - at present your 'formset' variable containing the form isn't included in the datadict being passed to the view.
return render_to_response('ad_form.html', context_instance = RequestContext(request),)
Should include the data (see render_to_response() docs) here I've renamed the form in your data and to your template as 'form' for ease of nomenclature:
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request))
Then, in your template (see forms in templates docs) replace {{formset}} with {{form.as_p}}. Also add a submit button to the form.
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>

Related

Django: How do I create a form of model A for each instance of model B

I am trying to create an app, where the user fills out forms (model A). The forms are based on variables (model B), which are defined by the admin.
The form should save the input in model A (i.e. input values) and therefore show the name/label of model B (i.e. the variable name) for each instance of B and the corresponding fields of A (the input value).
I am stuck with showing each input form separately. Technically this works, but creates a terrible user experience. How do I render all input forms for each variable on one page?
I would appreciate any help greatly!
models.py
Model A (input values):
class InputValue(models.Model):
variable = models.ForeignKey(Variable, on_delete=models.CASCADE, default="")
value_char = models.CharField(max_length=128, default="NA")
value_numeric = models.FloatField(default=0)
value_choice = models.CharField(max_length=128, default="NA")
def __str__(self):
return self.variable.var_label
Model B (variables):
class Variable(models.Model):
var_id = models.CharField(max_length=20, default="")
var_label = models.CharField(max_length=20, default="")
description = models.CharField(max_length=200, default="")
def __str__(self):
return self.var_id
For forms.py and view.py I tried something like this:
forms.py
from django import forms
from .models import InputValue
class InputForm(forms.ModelForm):
class Meta:
model = InputValue
fields = ("variable", "value_numeric")
view.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.forms import modelformset_factory
from .forms import InputForm
from .models import InputValue
def input_form(request):
SubmissionFormSet = modelformset_factory(InputValue, form=InputForm)
if request.method == 'POST':
formset = SubmissionFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(reverse('myapp:index'))
else:
formset = SubmissionFormSet()
return render(request, 'myapp/input_form.html', {'formset': formset})
And for the template:
input_form.html
<body>
<main class="container">
{% block content %}
<h2>Submission form</h2>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}
</main>
</body>

Diplay ModelForm in html

I am creating a webapp in which a user can create a project, inside each project he can answer a set of question(in my app, I call them secondquestions).
I am trying to use ModelForm to ease the creation of the form by following this guide: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/
Howver I do not understand how I can display in my html my form.
secondquestions/views.py
def secondquestionstoanswer(request, project_id):
project = get_object_or_404(Project, pk=project_id)
if request.method == "POST":
form = SecondquestionForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'secondquestions/secondquestionstoanswer.html', {'project':project})
secondquestions/models.py
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
from projects.models import Project
from django.db import models
from django.forms import ModelForm
class Secondquestion(models.Model):
second_one = models.TextField()
second_two = models.TextField()
second_three = models.TextField()
second_four = models.TextField()
second_five = models.TextField()
second_six = models.TextField()
second_seven = models.TextField()
second_eighth = models.TextField()
second_nine = models.TextField()
developer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
project = models.OneToOneField(Project, on_delete=models.CASCADE)
class SecondquestionForm(ModelForm):
class Meta:
model = Secondquestion
fields = ['second_one', 'second_two', 'second_three', 'second_four', 'second_five', 'second_six', 'second_seven', 'second_eighth', 'second_nine']
secondquestions/secondquestionstoanswer.html
{% extends 'base.html' %}
{% block title %}First set{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Submit</button>
</form>
{% endblock %}
My problem:
In my html I just see the Submit button, not the form.
You never constructed a form that you passed to the template engine.
from django.shortcuts import redirect
def secondquestionstoanswer(request, project_id):
project = get_object_or_404(Project, pk=project_id)
if request.method == "POST":
form = SecondquestionForm(request.POST)
if form.is_valid():
form.instance.project = project
form.save()
return redirect('some_view')
else:
form = SecondquestionForm()
return render(
request,
'secondquestions/secondquestionstoanswer.html',
{'project':project, 'form': form}
)
With 'some_view', the name of the view to where you want to redirect in case the submission is successful.
In your <form> you specify in the action="..." attribute where what endpoint should be triggered, like:
<form method="post" action="{% url 'view_name_of_second_question' project.pk %}">
{% csrf_token %}
{{ form }}
<button type="submit">Submit</button>
</form>
You need a forms.py file that will contain your Model Form
secondquestions/forms.py
from django import forms
from .models import Secondquestion
class SecondquestionForm(forms.ModelForm):
class Meta:
model = Secondquestion
fields = ['second_one', 'second_two', 'second_three', 'second_four', 'second_five', 'second_six', 'second_seven', 'second_eighth', 'second_nine']

csrf token not showing input fields - Django

I am new to django. am using django==1.11
am trying to create a form which inputs details of users.
my
views.py
from django.shortcuts import render, render_to_response, redirect
from django.template import loader, Template, Context, RequestContext
from forms import UserForm
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators import csrf
def action(request):
if request.POST:
form = UserForm(data = request.POST)
if form.is_valid():
form.save(commit = False)
return HTTPResponseRedirect('/rfid/index')
else:
form = UserForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('reg.html', args)
forms.py
from django import forms
from models import UserDetails
class UserForm(forms.ModelForm):
class Meta:
model = UserDetails
fields = '__all__'
reg.html
{% extends "rfid/header.html" %}
{% block content %}
<div class="container">
<form action = "/" method="post">{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" name="submit" class="btn btn-default" value="Add User">
</form>
</div>
{% include "rfid/includes/htmlsnippet.html" %}
{% endblock %}
models.py
from django.db import models
# Create your models here.
class UserDetails(models.Model):
GENDER_CHOICES = (('M', 'Male'), ('F', 'Female'))
user_id = models.IntegerField(primary_key = True)
name = models.TextField(max_length = 50)
gender = models.CharField(max_length = 1, choices = GENDER_CHOICES)
dob = models.DateTimeField()
address = models.TextField(max_length = 200)
phone = models.IntegerField()
email = models.EmailField(max_length=254)
photo_url = models.CharField(max_length = 200)
def __str__(self):
return self.name
But it is only showing the submit button. Model-based fields are not displaying. I had gone through some Questions here but was not able to trace out what was the problem. can anyone help me out.
Hope all required details are given. pls, ask if I miss anything.
regards.
Check out the line with form.save(commit=False).
Except you want to give that line a name and later save the name like saved_form=form.save(commit=False) then saved_form.safe, then the commit=False line isn't necessary. I don't know if that is the problem, but will check and revert

Error uploading file in django

I am trying to attach a file in django models, but when I hit submit button the selected file immediately disappears and the form submission fails . What is going wrong here?
forms.py
from django import forms
from .models import IssueNotice
class IssueNoticeForm(forms.ModelForm):
class Meta:
model = IssueNotice
fields = ('title', 'content','issuer','attachment',)
models.py
from django.db import models
from django.utils import timezone
from django import forms
class IssueNotice(models.Model):
title = models.CharField(max_length=300)
content = models.TextField()
attachment = models.FileField(upload_to='attachments')
issuer = models.CharField(max_length=100)
issuer_id = models.ForeignKey('auth.User')
issued_date = models.DateTimeField(default = timezone.now)
def publish(self):
self.issued_date = timezone.now()
self.save()
def __str__(self):
return self.title
views.py
from django.shortcuts import render
from django.utils import timezone
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from .models import IssueNotice
from .forms import IssueNoticeForm
def issue_notice(request):
if request.method == "POST":
form = IssueNoticeForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['attachment'])
notice = form.save(commit = False)
notice.issuer_id = request.user
notice.issued_date = timezone.now()
notice.save()
return redirect('home_page')
else:
form = IssueNoticeForm()
return render(request, 'webadmin/issue_notice.html',{'form':form})
issue_notice.html
{% extends 'webadmin/base.html' %}
{% block content %}
<div class="col-md-8">
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Issue</button>
</form>
{% endblock %}

Django Dropdown populate from database

If I pass items to the template through the view, and I want the user to select one of the values that gets submitted to a user's record, I would only have dun a for loop in the template right?
What would that look like?
In the template:
<form method="POST"
<select>
</select>
</form>
Model:
class UserItem(models.Model):
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
class Item(models.Model):
name = models.CharField(max_length = 50)
condition = models.CharField(max_length = 50)
View:
def selectview(request):
item = Item.objects.filter()
form = request.POST
if form.is_valid():
# SAVE
return render_to_response (
'select/item.html',
{'item':item},
context_instance = RequestContext(request)
)
If I understood your need correctly, you can do something like:
<form method="POST">
<select name="item_id">
{% for entry in items %}
<option value="{{ entry.id }}">{{ entry.name }}</option>
{% endfor %}
</select>
</form>
By the way, you should give the name items instead of item, since it's a collection (but it's just a remark ;)).
Doing so, you will have a list of all the items in the database.
Then, in the post, here what you need to do:
def selectview(request):
item = Item.objects.all() # use filter() when you have sth to filter ;)
form = request.POST # you seem to misinterpret the use of form from django and POST data. you should take a look at [Django with forms][1]
# you can remove the preview assignment (form =request.POST)
if request.method == 'POST':
selected_item = get_object_or_404(Item, pk=request.POST.get('item_id'))
# get the user you want (connect for example) in the var "user"
user.item = selected_item
user.save()
# Then, do a redirect for example
return render_to_response ('select/item.html', {'items':item}, context_instance = RequestContext(request),)
Of course, don't forget to include get_object_or_404
Here is a more dry way to do this in 2021:
models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateField(null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
urls.py
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.PersonListView.as_view(), name='person_changelist'),
path('add/', views.PersonCreateView.as_view(), name='person_add'),
path('<int:pk>/', views.PersonUpdateView.as_view(), name='person_change'),
]
views.py
from django.views.generic import ListView, CreateView, UpdateView
from django.urls import reverse_lazy
from .models import Person
class PersonListView(ListView):
model = Person
context_object_name = 'people'
class PersonCreateView(CreateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
class PersonUpdateView(UpdateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
HTML
{% extends 'base.html' %}
{% block content %}
<h2>Person Form</h2>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Save</button>
Nevermind
</form>
{% endblock %}
RESULT:
Reference: https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html