How create a custom form in django with database values - python

model.py
class Venue(models.Model):
venue_Name = models.CharField(max_length=100)
place = models.CharField(max_length=50)
rent = models.IntegerField()
parking_area = models.IntegerField()
class Decoration(models.Model):
rate = models.IntegerField()
I have printed the values in database as radio buttons what i want to do is that i want to get the total sum i.e venue.rent + decoration.rate and print it in another page What shoud i give in form action I'm not that familiar with forms.
html
<form action="{% %}" method="post">
{% for venue in venues %}
<input type="radio" name=venue value=venue.rent />{{ venue.venue_Name}}
{% endfor %}
{% for decoration in decorations %}
<input type="radio" name=decor value=decoration.rate />{{ decoration.rating }}
{% endfor %}
<input type="submit" value=" " />
</form>
what should i write in view and urls to get the sum

You can use Django's form for validation and parsing. For that you would set up a form like so:
forms.py
from django import forms
class TotalSumForm(forms.Form):
venue = forms.ModelChoiceField(queryset=Venue.objects.all(), required=True)
decoration = forms.ModelChoiceField(
queryset=Decoration.objects.all(), required=True)
def get_total(self):
# send email using the self.cleaned_data dictionary
return self.cleaned_data['venue'].rent +\
self.cleaned_data['decoration'].rate
And then using a class based view, add the result to context upon submission.
views.py
from myapp.forms import TotalSumForm(
from django.views.generic.edit import FormView
class TotalCost(FormView):
template_name = 'your_template.html'
form_class = TotalSumForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
total_result = form.get_total()
# return back to your_template.html with the total in context
return self.render_to_response(self.get_context_data(
form=form, total=total_result))
The urls are pretty simple:
urls.py
from django.conf.urls import patterns, url
import myapp.views
urlpatterns = patterns(
'',
url(r'^total_calc/$', myapp.views.TotalCost.as_view(), name='calculate_total'),
)
Your html could be modified like so
your_template.html
<html>
<body>
<h1>TEST SUCCESFULL!</h1>
{% if total %}
<p>Total cost for venue and decoration: {{ total }}</p>
{% endif %}
<form action="{% url 'calculate_total' %}" method="post">
{{ form.as_p }}
<input type="submit" value="Calculate Total" />
</form>
</body>
</html>

Related

How to make form html for updateview

I was making my own forms for CreateView and UpdateView with my html file because I don't want to display the form like this {{form.as_p}}.
forms.py
from django import forms
from .models import Post
class PostCreationForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'cover', 'text',)
widgets = {
'title': forms.TextInput(attrs={'class': 'title'}),
'cover': forms.FileInput(attrs={'class': 'image'}),
'text': forms.TextInput(attrs={'class': 'text'})
}
class PostDeleteForm(forms.ModelForm):
class Meta:
model = Post
fields = ('__all__')
views.py
from django.shortcuts import reverse
from django.http import HttpResponseRedirect
from django.views import generic
from .models import Post
from .forms import PostCreationForm, PostDeleteForm
class PostListView(generic.ListView):
model = Post
context_object_view = 'post_list'
template_name = 'forum/post_list.html'
class PostDetailView(generic.DetailView):
model = Post
context_object_view = 'post'
template_name = 'forum/post_detail.html'
class PostCreateView(generic.CreateView):
model = Post
form_class = PostCreationForm
template_name = 'forum/post_create.html'
def form_valid(self, form):
if form.is_valid():
response = form.save(commit = False)
response.author = self.request.user
response.save()
return HttpResponseRedirect(reverse('post_detail', args=[str(response.id)]))
class PostUpdateView(generic.UpdateView):
model = Post
context_object_view = 'post'
form_class = PostCreationForm
template_name = 'forum/post_edit.html'
def get_post(self, pk):
return get_object_or_404(Post, pk=pk)
def form_valid(self, form):
if form.is_valid():
response = form.save(commit = False)
response.save()
return HttpResponseRedirect(reverse('post_detail', args=[str(response.id)]))
class PostDeleteView(generic.DeleteView):
model = Post
context_object_view = 'post'
form_class = PostDeleteForm
template_name = 'forum/post_delete.html'
success_url = '/'
def get_post(self, pk):
return get_object_or_404(Post, pk=pk)
post_create.html
{% extends '_base.html' %}
{% block css %}
{% load static %}
<link rel="stylesheet" href="{% static 'css/post_create.css' %}">
{% endblock css %}
{% block title %}Questions{% endblock title %}
{% block content %}
<h1 class="m-title">New Post</h1>
<div class="form">
<form action="" method="post" enctype="multipart/form-data" id='postform'>
{% csrf_token %}
<p class="n-title"><label for="id_title">Title: </label></p>
<input id="id_title" type="text" name="title" class="title" maxlength="40" required>
<p class="n-image"><label for="id_cover">Image: </label></p>
<input id="id_cover" type="file" name="cover" class="image" required>
<p class="n-text"><label for="id_text">Text: </label></p>
<textarea id="id_text" placeholder="Enter your text here" name="text" class="text" form='postform' required></textarea>
<button class="btn btn-success" id="button" type="submit">Submit</button>
</form>
</div>
{% endblock content %}
And I also wanted to do for the UpdateView, but I don't know how to make the input fields display the current value of the post (title, text). The html file is the same as for CreateView. How do I make the input display the current value of the post that is being modified?
You probably don't want to be manually writing the html for the form like that.
If you must, you can pass in value like:
<input id="id_title" type="text" name="title" class="title" maxlength="40" value="{{ form.title.value }}" required>
Better would be to render the field using django so that your form field attributes like maxlength and required match your form class specification. For example, this will create the input for your title field:
{{ form.title }}
If you want more flexibility in styling look at crispy-forms or my preference floppyforms

Python Django Form submit button not working as desired

I have been trying to learn Django.
I am stuck on this form part. A form has been created that allows the user to create an Album object where they can fill in the Artist, Album Name, Genre and upload an Album Logo. When I fill in the fields and then click submit, it should then redirect me to the details page for that particular Album that just got created. But nothing appears to happen when clicking the submit button and the object does not get created.
Here is the models.py code that contains an Album class with 4 fields; artist, album_name, genre and album_logo.
from django.db import models
from django.urls import reverse
# Create your models here.
class Album(models.Model):
artist = models.CharField(max_length=250)
album_name = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.ImageField()
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk':self.pk})
def __str__(self):
return self.album_name + " - " + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=100)
song_title = models.CharField(max_length=250)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
Here is the album_form.html code which contains the actual form. I have not used crispy_forms as I am not familiar with Bootstrap though I know CSS.
{% extends 'music/base.html' %}
{% block title %}Add a New Album{% endblock %}
{% block body %}
<form class="formContainer" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% if field.label != 'Album logo' %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="text" id="field{{ forloop.counter }}" name="" value="">
{% else %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="file" id="field{{ forloop.counter }}" name="" value="" accept="image/*">
{% endif %}
<br>
{% endfor %}
<input type="submit" id="submitBtn" name="" value="Add">
</form>
{% endblock %}
This is views.py code where I have made use of class based views and not function based views.
from django.views import generic
from .models import Album, Song
# Create your views here.
class IndexView(generic.ListView):
template_name = 'music/index.html'
queryset = Album.objects.all()
context_object_name = 'all_albums'
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
and finally this is my urls.py code:
from django.urls import path, include
from . import views
app_name='music'
urlpatterns = [
#/music/
path('', views.IndexView.as_view(), name='index'),
#/music/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
#/music/album/add/
path('album/add/', views.AlbumCreate.as_view(), name='album-add')
]
After clicking the submit button in the form, it should take me to the "detail" url for the primary key of the Album that got created. Am I missing something here?
In your views.py you need to override the get_success_url function in your CreateView and pass the id as an argument while redirecting.
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
def get_success_url(self):
return reverse('music:detail', args=(self.object.id,))
Seems you forgot to put action to your <form> tag
Try this
<form class="formContainer" action='{% url 'music:album-add'%}' method="post" enctype="multipart/form-data">
Edit: Also add success url using get_success_url function in your AlbumCreate view to redirect user to album detail page, like was mentioned in above answer
from django.urls import reverse_lazy
...
class AlbumCreate(generic.CreateView):
...
def get_success_url(self, **kwargs):
return reverse_lazy('music:detail', args = (self.object.id,))

Django - User Search

I'm trying to filter ListView based on post method from search bar in my basetemplate. So making it works like:
Insert name --> SearchBar-->GET Method-->SearchView class(in views.py)--> render html with usernames.
I have done this, but it wont work. Could you please tell me what I'm doing wrong?
views.py in my user app
class SearchView(ListView):
model = User
template_name = 'blog/list_of_users.html'
context_object_name = 'all_search_results'
def get_queryset(self):
result = super(SearchView, self).get_queryset()
query = self.request.GET.get('search')
if query:
postresult = User.objects.filter(username__contains=query)
result = postresult
else:
result = None
return result
urls.py in my blog app
path('users_search/?search=<str:username>', user_view.SearchView.as_view(), name='user_search'),
search form in html
<form class="example" method="GET">
<input type="search" placeholder="ユーザー検索..." name="user_name">
<button type="submit">
検索
</button>
rendered html with user names
{% for result in all_search_results %}
{{ result.username }}
{% empty %}
add something to show no results
{% endfor %}
override get_context_data method
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_name = self.request.GET.get('user_name', '')
context['all_search_results'] = User.objects.filter(username__icontains=user_name )
return context
In your template
<form class="example" method="GET">
<input type="text" placeholder="ユーザー検索..." name="user_name">
<button type="submit">
検索
</button>
</form>
{% for result in all_search_results %}
{{ result.username }}
{% empty %}
add something to show no results
{% endfor %}
Update:
in template, <input ........... name="search">
in views, user_name = self.request.GET.get('search', '')

Trying to pass form from generic.FormView to generic.DetailView

I'm new in Django and it's just a test for further model. I'm trying to pass a form from generic.FormView to generic.DetailView, and exhibit the datas inserted in the previous HTML (associated with the FormView) to another HTML (associated with the DetailView). I've thought it probably a problem with the link between the view.py and urls.py. The codes are:
views.py:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = 'dutos/detail.html'
#def form_valid(self, form):
#return HttpResponse(self.success_url)
#return super.form_valid(form)
class DetailView(generic.DetailView):
model = Dutos
template_name = 'dutos/detail.html'
forms.py
class GetDate(forms.Form):
dateDataInicial = forms.DateTimeField(label='dataInicial', initial=datetime.now().strftime("%d/%m/%Y %H:%M:%S"), required=False)
dateDataFinal = forms.DateTimeField(label='dataFinal', initial=datetime.now().strftime("%d/%m/%Y %H:%M:%S"), required=False)
urls.py:
from django.urls import path
from .views import views
urlpatterns = [
path('', views.IndexView.as_view(), name="index"),
path('detail/', views.DetailView.as_view(), name="detail"),
]
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
</head>
<body>
<h1>Teste HTML</h1>
<div class="container-fluid" id="wrapper">
<div class="row">
<form action="/detail/" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<div class="fieldWrapper">
{{ form.dateDataInicial.errors }}
<label for="{{ form.dateDataInicial }} Data Inicial: </label>
{{ form.dateDataInicial }}
</div>
<div class="fieldWrapper">
{{ form.dateDataFinal.errors }}
<label for="{{ form.dateDataFinal }} Data Final: </label>
{{ form.dateDataFinal }}
</div>
<input type="submit" value="Pesquisar">
</div>
</form>
</div>
</div>
</body>
</html>
detail.html:
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
</head>
<body>
<h1>Template HTML</h1>
{{form.cleaned_data['dateDataInicial']}}
{{form.cleaned_data['dateDataFinal']}}
</body>
</html>
I've already change the "{{form.cleaned_data['dateDataInicial']}}" to "form.dateDataInicial", or just cleaned everything and put "Test" to exhibit a simples HTML. I'm getting HTTP Error 405.
There's really quite a lot wrong with the code you've posted.
You're getting 405 because the form in your index template attempts to post directly to the detail URL, which is not set up to accept POST requests. An additional problem with doing this is that the form will not be validated, because the validation is supposed to happen in the IndexView, not the DetailView. Plus, the DetailView does not know anything about the form, so form.cleaned_data would not exist in the template context; and, Django template syntax does not support dictionary lookup via square brackets, so {{ form.cleaned_data['dateDataInicial'] }} would not work.
In order for validation to work you need to submit the form back to IndexView, which will then redirect to the detail view. (Another issue with your code is that success_url should be a URL, not a template path.) The problem then becomes how to get the data from one view to the other; the session is a good way to do that. So:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = reverse_lazy('detail')
def form_valid(self, form):
self.request.session['dates'] = form.cleaned_data
return super.form_valid(form)
change the form tag in index.html:
<form action="" method="post">
the detail view:
class DetailView(generic.DetailView):
model = Dutos
template_name = 'dutos/detail.html'
def get_context_data(self, **kwargs):
kwargs['dates'] = self.request.session.pop('dates', {})
return super().get_context_data(**kwargs)
and in detail.html:
{{ dates.dateDataInicial }}
{{ dates.dateDataFinal }}
Thanks to the help of Daniel and his code, I figured out the modifications that lead to my needs. I've changed the genericView of DetailView from "generic.DetailView" to "generic.ListView". When it was made another problem appeared. To pass "datetime" through JSON, it convert to string format and all the date was being treated as string, so I lost the possibility to show the two dates in separated fields in detail.html. To overcome this problem, I adapted the solution proposed to Daniel, and divided the field in two so I can get it by form.cleaned_data and converted it into string, and now I don't need to worry about JSON serializing a "datetime".
views.py:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = reverse_lazy('detail')
def form_valid(self, form):
#self.request.session['dates'] = json.dumps(form.cleaned_data, cls=DjangoJSONEncoder)
self.request.session['dateInicial'] = str(form.cleaned_data['dateDataInicial'])
self.request.session['dateFinal'] = str(form.cleaned_data['dateDataFinal'])
return super().form_valid(form)
class DetailView(generic.ListView):
model = Dutos
template_name = 'dutos/detail.html'
def get_context_data(self, **kwargs):
#kwargs['dates'] = self.request.session.pop('dates', {})
kwargs['dateInicial'] = self.request.session.pop('dateInicial', {})
kwargs['dateFinal'] = self.request.session.pop('dateFinal', {})
return super().get_context_data(**kwargs)
index.html:
<div class="container-fluid" id="wrapper">
<div class="row">
<form action="" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<div class="fieldWrapper">
{{ form.dateDataInicial.errors }}
<label for="{{ form.dateDataInicial }} Data Inicial: </label>
{{ form.dateDataInicial }}
</div>
<div class="fieldWrapper">
{{ form.dateDataFinal.errors }}
<label for="{{ form.dateDataFinal }} Data Final: </label>
{{ form.dateDataFinal }}
</div>
<input type="submit" value="Pesquisar">
</div>
</form>
</div>
</div>
detail.html:
<body>
<h1>Detalhes</h1>
{{ dateFinal }}
<br>
{{ dateInicial }}
</body>

Generate objects in django template dynamically

I have 2 models in my system:
class Display(models.Model):
name = models.CharField
UE = models.CharField
description
class Register(models.Model):
temp1 = models.FloatField()
temp2 = models.FloatField()
flow = models.FloatField()
I create displays using for inside a template, but the value of each display is a respective field in Register model. I can't make the loop with Register because i use only row (i can't loop fields). Understand?
Take a look of my code:
View:
def main(request):
dp_col = Display.objects.all()
reg = Registers.objects.latest('pk')
context = {
'dp_col': dp_col,
'reg':reg
}
return render(request,'operation.html',context)
Template:
{% for dp in dp_col %}
<div class='col-md-6'>
<div class="display-content">
<div class="display-data">
<h3 class="text-center display-desc">{{dp.name}}
<span>:</span>
<span class="text-center display-value">I need put the value of each field here</span>
<span class='display-unit'> {{dp.UE}}</span>
</h3>
</div>
</div>
</div>
{% empty %}
<!--colocar alguma coisa aqui, caso não tenha nada no for-->
{% endfor %}
Any ideas?
Thanks a lot!
This can be easily solved by using a Django Forms:
yourapp/forms.py
from django import forms
class DisplayForm(forms.ModelForm):
class Meta:
model = Display
fields = '__all__'
yourapp/views.py
from .forms import DisplayForm
def main(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = DisplayForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = DisplayForm()
return render(request, 'operation.html', {'form': form})
In operations.html:
<form method="post" action="">
{{ form }}
</form>
Or if you want custom html in each field:
<form method="post" action="">
{% for field in form %}
{{ field.label_tag }} {{ field }}
{% endfor %}
</form>
Reference:
https://docs.djangoproject.com/en/1.11/topics/forms/

Categories