I'm new to Django, using Django 2.7.1 and python 3.7.2, trying to make a thing, which will take data from field forms on my site, then handle this data, and finally render the result in another field form on the same page.
I've tried to make it by the model's methods, but didn't understood how.
Now i'm trying to do it by views. So i understood what i should do, but still don't recognize how to render the result.
this is my models.py
from django.db import models
# Create your models here.
class CombinatorCols(models.Model):
first_column = models.TextField("Column 1", null=True, blank=True)
second_column = models.TextField("Column 2", null=True, blank=True)
third_column = models.TextField("Column 3", null=True, blank=True)
fourth_column = models.TextField("Column 4", null=True, blank=True)
result = models.TextField("Result", help_text='Halo', blank=True,)
def __str__(self):
return self.first_column
this is my forms.py
from django import forms
from .models import CombinatorCols
class CombinatorForm(forms.ModelForm):
class Meta:
model = CombinatorCols
fields = ('first_column', 'second_column', 'third_column','fourth_column', 'result',)
this is my views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.template import loader
from .models import Combinate,CombinatorCols
from .forms import CombinatorForm,ResultForm
# Create your views here.
def get_col(request):
#column = get_object_or_404(CombinatorCols)
if request.method == "POST":
form = CombinatorForm(request.POST)
if form.is_valid():
column = form.save()
column.sender = request.user
first_handle = [i for i in column.first_column.split('\n') if i]
second_handle = column.second_column
third_handle = column.third_column
fourth_handle = column.fourth_column
column.result = first_handle
column.save()
print(first_handle)
print('Naiiiceee')
else:
form = CombinatorForm()
return render(request, 'index.html', {'form': form})
and the last, my index.html
<form action="" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit">
</form>
I expect the updating of 'result' form on my site, but i see only the source page. All that has been written in the form fields is staying on their places and sends to the DB. It's all the expected behavior, except the result field isn't updating. Print statements shows correctly.
When you get the POST call, after you have processed the form, in order to update the form on the same view, you need to reinitialise it with the new data that you want to show.
After saving result, reinitialise the form:
column.result = first_handle
column.save()
data = request.POST.dict().copy() # add these
data["result"] = first_handle # three lines
form = CombinatorForm(data) # to reinitialise the form
print(first_handle)
print('Naiiiceee')
This will solve you problem.
By the way, try using class based generic views for CRUD operation. You can learn about them here. They will make your life much more easier.
Related
I have seen this approach in many web applications (e.g. when you subscribe for an insurance), but I can't find a good way to implement it in django. I have several classes in my model which inherit from a base class, and so they have several fields in common. In the create-view I want to use that inheritance, so first ask for the common fields and then ask for the specific fields, depending on the choices of the user.
Naive example, suppose I want to fill a database of places
class Place(Model):
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
class Restaurant(Place):
cuisine = models.CharField(max_length=40)
website = models.CharField(max_length=40)
class SportField(Place):
sport = models.CharField(max_length=40)
Now I would like to have a create view when there are the common fields (name and address) and then the possibility to choose the type of place (Restaurant / SportField). Once the kind of place is selected (or the user press a "Continue" button) new fields appear (I guess to make it simple the page need to reload) and the old one are still visible, already filled.
I have seen this approach many times, so I am surprised there is no standard way, or some extensions already helping with that (I have looked at Form Wizard from django-formtools, but not really linked to inheritance), also doing more complicated stuff, as having more depth in inheritance.
models.py
class Place(models.Model):
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
class Restaurant(Place):
cuisine = models.CharField(max_length=40)
website = models.CharField(max_length=40)
class SportField(Place):
sport = models.CharField(max_length=40)
forms.py
from django.db import models
from django import forms
class CustomForm(forms.Form):
CHOICES = (('restaurant', 'Restaurant'), ('sport', 'Sport'),)
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Name'}))
address = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Address'}))
type = forms.ChoiceField(
choices=CHOICES,
widget=forms.Select(attrs={'onChange':'renderForm();'}))
cuisine = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Cuisine'}))
website = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Website'}))
sport = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Sport'}))
views.py
from django.http.response import HttpResponse
from .models import Restaurant, SportField
from .forms import CustomForm
from django.shortcuts import render
from django.views import View
class CustomView(View):
def get(self, request,):
form = CustomForm()
return render(request, 'home.html', {'form':form})
def post(self, request,):
data = request.POST
name = data['name']
address = data['address']
type = data['type']
if(type == 'restaurant'):
website = data['website']
cuisine = data['cuisine']
Restaurant.objects.create(
name=name, address=address, website=website, cuisine=cuisine
)
else:
sport = data['sport']
SportField.objects.create(name=name, address=address, sport=sport)
return HttpResponse("Success")
templates/home.html
<html>
<head>
<script type="text/javascript">
function renderForm() {
var type =
document.getElementById("{{form.type.auto_id}}").value;
if (type == 'restaurant') {
document.getElementById("{{form.website.auto_id}}").style.display = 'block';
document.getElementById("{{form.cuisine.auto_id}}").style.display = 'block';
document.getElementById("{{form.sport.auto_id}}").style.display = 'none';
} else {
document.getElementById("{{form.website.auto_id}}").style.display = 'none';
document.getElementById("{{form.cuisine.auto_id}}").style.display = 'none';
document.getElementById("{{form.sport.auto_id}}").style.display = 'block';
}
}
</script>
</head>
<body onload="renderForm()">
<form method="post" action="/">
{% csrf_token %}
{{form.name}}<br>
{{form.address}}<br>
{{form.type}}<br>
{{form.website}}
{{form.cuisine}}
{{form.sport}}
<input type="submit">
</form>
</body>
</html>
Add templates folder in settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
]
I've created a 2-page working example using modified Class Based Views.
When the form is submitted on the first page, an object of place_type is created. The user is then redirected to the second page where they can update existing details and add additional information.
No separate ModelForms are needed because the CreateView and UpdateView automatically generate the forms from the relevant object's model class.
A single template named place_form.html is required. It should render the {{ form }} tag.
# models.py
from django.db import models
from django.urls import reverse
class Place(models.Model):
"""
Each tuple in TYPE_CHOICES contains a child class name
as the first element.
"""
TYPE_CHOICES = (
('Restaurant', 'Restaurant'),
('SportField', 'Sport Field'),
)
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
place_type = models.CharField(max_length=40, blank=True, choices=TYPE_CHOICES)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('place_update', args=[self.pk])
# Child models go here...
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('create/', views.PlaceCreateView.as_view(), name='place_create'),
path('<pk>/', views.PlaceUpdateView.as_view(), name='place_update'),
]
# views.py
from django.http import HttpResponseRedirect
from django.forms.models import construct_instance, modelform_factory
from django.views.generic.edit import CreateView, UpdateView
from django.urls import reverse_lazy
from . import models
class PlaceCreateView(CreateView):
model = models.Place
fields = '__all__'
def form_valid(self, form):
"""
If a `place_type` is selected, it is used to create an
instance of that Model and return the url.
"""
place_type = form.cleaned_data['place_type']
if place_type:
klass = getattr(models, place_type)
instance = klass()
obj = construct_instance(form, instance)
obj.save()
return HttpResponseRedirect(obj.get_absolute_url())
return super().form_valid(form)
class PlaceUpdateView(UpdateView):
fields = '__all__'
success_url = reverse_lazy('place_create')
template_name = 'place_form.html'
def get_object(self, queryset=None):
"""
If the place has a `place_type`, get that object instead.
"""
pk = self.kwargs.get(self.pk_url_kwarg)
if pk is not None:
obj = models.Place.objects.get(pk=pk)
if obj.place_type:
klass = getattr(models, obj.place_type)
obj = klass.objects.get(pk=pk)
else:
raise AttributeError(
"PlaceUpdateView must be called with an object pk in the URLconf."
)
return obj
def get_form_class(self):
"""
Remove the `place_type` field.
"""
model = self.object.__class__
return modelform_factory(model, exclude=['place_type',])
We did something similar manually, we created the views and forms based on design and did the linkage based on if conditions.
I think a nice solution would be to dynamically access subclasses of the main class and then do the necessary filtering/lists building.
UPD: I've spent some more time today on this question and made a "less raw" solution that allows to use the inheritance.
You can also check the code below deployed here. It has only one level of inheritance (as in example), though, the approach is generic enough to have multiple levels
views.py
def inheritance_view(request):
all_forms = {form.Meta.model: form for form in forms.PlaceForm.__subclasses__()}
all_forms[models.Place] = forms.PlaceForm
places = {cls._meta.verbose_name: cls for cls in models.Place.__subclasses__()}
# initiate forms with the first one
context = {
'forms': [forms.PlaceForm(request.POST)],
}
# check sub-forms selected on the forms and include their sub-forms (if any)
for f in context['forms']:
f.sub_selected = request.POST.get('{}_sub_selected'.format(f.Meta.model._meta.model_name))
if f.sub_selected:
sub_form = all_forms.get(places.get(f.sub_selected))
if sub_form not in context['forms']:
context['forms'].append(sub_form(request.POST))
# update some fields on forms to render them on the template
for f in context['forms']:
f.model_name = f.Meta.model._meta.model_name
f.sub_forms = {x.Meta.model._meta.verbose_name: x for x in f.__class__.__subclasses__()}
f.sub_options = f.sub_forms.keys() # this is for rendering selector on the form for the follow-up forms
page = loader.get_template(template)
response = HttpResponse(page.render(context, request))
return response
forms.py
class PlaceForm(forms.ModelForm):
class Meta:
model = models.Place
fields = ('name', 'address',)
class RestaurantForm(PlaceForm):
class Meta:
model = models.Restaurant
fields = ('cuisine', 'website',)
class SportFieldForm(PlaceForm):
class Meta:
model = models.SportField
fields = ('sport',)
templates/inheritance.html
<body>
{% for form in forms %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{% if form.sub_options %}
<select class="change-place" name="{{ form.model_name }}_sub_selected">
{% for option in form.sub_options %}
<option value="{{ option }}" {% if option == form.sub_selected %}selected{% endif %}>{{ option }}</option>
{% endfor %}
</select>
{% endif %}
<button type="submit">Next</button>
</form>
{% endfor %}
</body>
What I didn't make here is saving the form to the database. But it should be rather trivial using the similar snippet:
for f in context['forms']:
if f.is_valid():
f.save()
Add a PlaceType table, and a FK, e.g. type_of_place, to the Place table:
class PlaceType(Model):
types = models.CharField(max_length=40) # sportsfield, restaurants, bodega, etc.
class Place(Model):
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
type_of_place = models.ForeignKey('PlaceType', on_delete=models.SET_NULL, null=True)
class Restaurant(Place):
cuisine = models.CharField(max_length=40)
website = models.CharField(max_length=40)
This allows you to create a new Place as either SportsField, restaurant or some other type which you can easily add in the future.
When a new place is created, you'll use the standard CreateView and Model Form. Then, you can display a second form which also uses a standard CreateView that is based on the type_of_place value. These forms can be on the same page (and with javascript on the browser side, you'll hide the second form until the first one is saved) or on separate pages--which may be more practical if you intend to have lots of extra columns. The two key points are as follows:
type_of_place determines which form, view, and model to use. For
example, if user chooses a "Sports Field" for type_of_place, then
you know to route the user off to the SportsField model form;
CreateViews are designed for creating just one object/model. When
used as intended, they are simple and easy to maintain.
There are lot of way you can handle multiple froms in django. The easiest way to use inlineformset_factory.
in your froms.py:
forms .models import your model
class ParentFrom(froms.From):
# add fields from your parent model
Restaurant = inlineformset_factory(your parent model name,Your Child model name,fields=('cuisine',# add fields from your child model),extra=1,can_delete=False,)
SportField = inlineformset_factory(your parent model name,Your Child model name,fields=('sport',# add fields from your child model),extra=1,can_delete=False,)
in your views.py
if ParentFrom.is_valid():
ParentFrom = ParentFrom.save(commit=False)
Restaurant = Restaurant(request.POST, request.FILES,) #if you want to add images or files then use request.FILES.
SportField = SportField(request.POST)
if Restaurant.is_valid() and SportField.is_valid():
ParentFrom.save()
Restaurant.save()
SportField.save()
return HttpResponseRedirect(#your redirect url)
#html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
#{{ Restaurant.errors}} #if you want to show error
{{ Restaurant}}
{{ SportField}}
{{form}}
</form>
you can use simple JavaScript in your html for hide and show your any froms fields
I'm beginning to use Django, and I have some problems. I want to create new post such as blog. So I use views.py with model.py and forms.py.
but when I enter the create.html, I was writing what i want to post, and then click 'create' button. but it wasn't save in django object. I check in admin site, but there is no object. I think it means save object is failed. but I don't know where is the problem. plz help me T.T
in views.py
def create(request):
if request.method =="POST":
filled_form = ObForm(request.POST)
if filled_form.is_valid():
filled_form.save()
return redirect('index')
Ob_form = ObForm()
return render(request, 'create.html', {'Ob_form':Ob_form})
in create.html
<body>
<!-- form.py 모델 생성 -->
<form method="POST" action="">
{% csrf_token %}}
{{Ob_form.as_p}}
<input type="submit" value="확인" />
</form>
</body>
in models.py
from django.db import models
class Ob(models.Model):
title = models.CharField(max_length=50)
image = models.ImageField(null=True)
content = models.TextField(null=True)
update_at = models.DateTimeField(auto_now=True)
in forms.py
from django import forms
from .models import Ob
# 모델폼을 상속받아서 모델폼이 되었음
class ObForm(forms.ModelForm):
# 어떤 모델과 대응되는지 말해줌
class Meta:
model = Ob
fields = ( "title", "image", "content")
# 모델 폼 커스텀
# init - 내장함수 - (해당 클레스에 들어오는 여러가지 인자를 받을 수 있는 파라미터)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].label = "제목"
self.fields['image'].label = "사진"
self.fields['content'].label = "자기소개서 내용"
self.fields['title'].widget.attrs.update({
'class': 'Ob_title',
'placeholder': '제목',
})
and urls.py
from django.urls import path
from .views import index, create, detail, delete, update
urlpatterns = [
path('', index, name="index"),
path('create/', create, name="create"),
path('detail/<int:Ob_id>', detail, name="detail"),
path('delete/<int:Ob_id>', delete, name="delete"),
path('update/<int:Ob_id>', update, name="update"),
]
A bit of guesswork here, but it's probably the case that filled_form.is_valid() is returning false, which will mean save() is never reached. To test this simply, just put an else and print on the if.
if filled_form.is_valid():
filled_form.save()
return redirect('index')
else:
print("Form validation failed")
print(filled_form.errors)
It's likely that you'd also want to return these errors to the user in the future, which means you'll need to make a couple of changes.
Right now, regardless of whether ObForm validates successfully, you are creating a new instance and passing that to the user. My typical approach would be to declare the form variable at the top of the function, and if it isn't already set when it comes to render the view, create a new instance of the form then. This way, if the form was populated by the user already (i.e. the request was a POST) then the errors will be returned with their input, instead of clearing their input (which is really annoying from a user's point of view!).
As a side note, I'm going to guess that you submitted a form with empty image and content fields, and were expecting that to be stored in your database? Try changing your field declarations to:
title = models.CharField(max_length=50)
image = models.ImageField(null=True, blank=True)
content = models.TextField(null=True, blank=True)
update_at = models.DateTimeField(auto_now=True)
null=True tells the database to allow null values, but blank=True tells the form validation to allow empty values.
i am new to django and i am unable to get to print to the html page.How do you display the information retrieved from the database into a blank html page?
blank.hml
<body>
<h1>Classes Added</h1>
{% for i in classInfo %}
<h1>{{ i.label }}</h1>
{% endfor %}
</body>
models.py
class EventType(models.Model):
'''
Simple ``Event`` classifcation.
'''
objects = models.Manager()
abbr = models.CharField(_('abbreviation'), max_length=4, unique=False)
label = models.CharField(_('label'), max_length=50)
class Meta:
verbose_name = _('event type')
verbose_name_plural = _('event types')
def __str__(self):
return self.label
views.py
def displayClass(TemplateView):
templateName = 'blank.html'
def get(self,request):
form = ClassCreationForm()
classInfo = EventType.objects.all()
print(classInfo)
args = {'form' : form, 'classInfo' : classInfo}
return render(request,self,templateName,{'form':form})
forms.py
class ClassCreationForm(forms.Form):
classroom = forms.CharField(label = 'Class Name',max_length=50)
I think you need to understand how the views.py file works. You should have your business logic included in there and the pass it along to the template to be rendered. It can be passed along by the return feature you have included in your code. Although, in your return feature you are only passing a templatename and the form you wanted to render. There isn't data related to the EventType queryset being passed to your template as it is not included in the return context.
Now, personally I like working with Django Class-Based-generic-Views (CBV), since a lot of the code is included in there for you. I am not sure if you have got to the point of learning these yet but I would check them out.
If you would like to add a form into this, you could do so by adding FormMixin which is part of the generic mixins Django provides.
How I would structure your view.py code using generic views is as follows:
from django.views import generic
from django.views.generic.edit import FormMixin
from YourApp.forms import ClassCreationForm
from YourApp.models import EventType
class DisplayClass(FormMixin,generic.ListView):
template_name = 'blank.html'
form_class = ClassCreationForm
def get_queryset(self, *args, **kwargs):
return EventType.objects.all()
If you decide to use class based views you will need to add additional criteria to your urls.py file (the .as_view()):
from django.urls import path
from . import views
urlpatterns = [
path('yoururlpath/', views.DisplayClass.as_view()),
]
Then in your template:
{% for i in object_list %}
<h1>{{ i.label }}</h1>
{% endfor %}
rendering your form...
{{ form.as_p }}
I'm working on a Django project and I'm having issues with my Model Forms rendering in my template. I've read through the documentation, tutorials as well as searched here; particularly this post here someone had with their input fields not showing. I thought that my issue was similar but I'm still not having any success. Basically, when I call {{ form.as_p }} nothing shows in the DOM. This occurs despite my csrf token working. Here's the code for my Model:
class Workout(models.Model):
upper_body = models.CharField(max_length=30, help_text="ex: Bench Press, Shoulder Press, Shrugs")
lower_body = models.CharField(max_length=30, help_text="Squats, Lunges, Deadlifts")
explosive = models.CharField(max_length=30, help_text="Hang Cleans, Box Jumps, Hang Snatch")
cardio = models.CharField(max_length=30, help_text="Jogging, Cycling, 110s")
speed = models.CharField(max_length=30, help_text="Sprints, 10 yard starts, Speed Sled")
skill = models.CharField(max_length=30, help_text="Boxing, Jump Shooting, Route Running")
athlete = models.ForeignKey(User, related_name='athlete')
def __unicode__(self):
return u"{}".format(self.athlete)
Here is the forms.py for that Model:
from django import forms
from .models import User, Workout, Meal
from django.forms import ModelForm
# Beginning of Workout Form
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
fields = ["upper_body",
"lower_body",
"explosive",
"cardio",
"speed",
"skill"]
# End of Workout Form
Here is my views.py for the form:
from .models import User, Workout, Meal
from Spartan.forms import UserForm, WorkoutForm, MealForm
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
def workout_form(request):
form = WorkoutForm(request.POST or None)
if form.is_valid():
workout = form.save(commit=False)
workout.athlete = request.user
workout.save()
return redirect('user/workouts.html')
Here is the actual the form that should be rendered on the template:
<div class="container">
<h3>Create your workout</h3>
<form method="POST" action=".">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit" value="Create Your Workout">CREATE WORKOUT</button>
</form>
</div>
As I've stated, the token is there, along with the form and button just no input fields. If anyone can assist me in pointing out what I'm not doing or what I'm overlooking it'll be GREATLY appreciated.
Thanks!
The problem is in your view. The else block doesn't matter because in your GET request is_valid is always returning False and you're redirecting to user/workouts.html without context.
One solution is to use an if/else statement to segment how you handle GET and POST:
def workout_form(request):
form = WorkoutForm() # Will be overridden if `is_valid` returns `False`
if request.method == "POST":
form = WorkoutForm(data=request.POST)
if form.is_valid():
workout = form.save(commit=False)
workout.athlete = request.user
workout.save()
return redirect('user/workouts.html')
return render(request, 'user/workouts.html',
{'form': form})
Figured it out. Silly mistake on my part. Basically had a view written for the page that was rendering while I styled it. Completely forgot it was being called and the function for the workout_form wasn't even being used. That's also why the pdb.set_trace() wasn't running either. All is well now. Thanks to everyone who assisted.
First of all, I apologize for the noobish question. I'm very new to Django and I'm sure I'm missing something obvious. I have read many other posts here and have not been able to find whatever obvious thing I am doing wrong. Thanks so much for any help, I am on a deadline.
I am using Django 1.6 with Python 2.7. I have one app called dbquery that uses a form to take data from the user and query a REST service. I am then trying to display the results on a results page.
Obviously there is more to add, this is just a very simple start.
The problem is that I can't seem to get the autoincremented id field from my search view into the url tag in the template properly. If I put the number 1 in like this {% url 'dbquery:results' search_id=1 %}, the page loads and works well, but I can't seem to get the variable name right, and the django documentation isn't helping- maybe this is obvious to most people. I get a reverse error because the variable ends up always being empty, so it can't match the results regex in my urls.py. I tested my code for adding an object in the command line shell and it seems to work. Is there a problem with my return render() statement in my view?
urls.py
from django.conf.urls import patterns, url
from dbquery import views
urlpatterns = patterns('',
# ex: /search/
url(r'^$', views.search, name='search'),
# ex: /search/29/results/ --shows response from the search
url(r'^(?P<search_id>\d+)/results/', views.results, name ='results'),
)
models.py
from django.db import models
from django import forms
from django.forms import ModelForm
import datetime
# response data from queries for miRNA accession numbers or gene ids
class TarBase(models.Model):
#--------------miRNA response data----------
miRNA_name = models.CharField('miRNA Accession number', max_length=100)
species = models.CharField(max_length=100, null=True, blank=True)
ver_method = models.CharField('verification method', max_length=100, null=True, blank=True)
reg_type = models.CharField('regulation type', max_length=100, null=True, blank=True)
val_type = models.CharField('validation type', max_length=100, null=True, blank=True)
source = models.CharField(max_length=100, null=True, blank=True)
pub_year = models.DateTimeField('publication year', null=True, blank=True)
predict_score = models.DecimalField('prediction score', max_digits=3, decimal_places=1, null=True, blank=True)
#gene name
gene_target = models.CharField('gene target name',max_length=100, null=True, blank=True)
#ENSEMBL id
gene_id = models.CharField('gene id', max_length=100, null=True, blank=True)
citation = models.CharField(max_length=500, null=True, blank=True)
def __unicode__(self):
return unicode(str(self.id) + ": " + self.miRNA_name) or 'no objects found!'
views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from dbquery.models import TarBase, SearchMainForm
from tarbase_request import TarBaseRequest
#main user /search/ form view
def search(request):
if request.method == 'POST': #the form has been submitted
form = SearchMainForm(request.POST) #bound form
if form.is_valid(): #validations have passed
miRNA = form.cleaned_data['miRNA_name']
u = TarBase.objects.create(miRNA_name=miRNA)
#REST query will go here.
#commit to database
u.save()
return render(request,'dbquery/results.html', {'id':u.id})
else: #create an unbound instance of the form
form = SearchMainForm(initial={'miRNA_name':'hsa-let-7a-5p'})
#render the form according to the template, context = form
return render(request, 'dbquery/search.html', {'form':form})
#display results page: /search/<search_id>/results/ from requested search
def results(request, search_id):
query = get_object_or_404(TarBase, pk=search_id)
return render(request, 'dbquery/results.html', {'query':query} )
templates:
search.html
<html>
<head><h1>Enter a TarBase Accession Number</h1>
</head>
<body>
<!--form action specifies the next page to load-->
<form action="{% url 'dbquery:results' search_id=1 %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Search" />
</form>
</body>
results.html
<html>
<head><h1>Here are your results</h1>
</head>
<body>
{{query}}
</body
The search results aren't created and don't have an ID until after you submit your form. The usual way to do this would be to have your form use its own URL as the action, then have the view redirect to the results view after successfully saving:
from django.shortcuts import redirect
def search(request):
if request.method == 'POST': #the form has been submitted
form = SearchMainForm(request.POST) #bound form
if form.is_valid(): #validations have passed
miRNA = form.cleaned_data['miRNA_name']
u = TarBase.objects.create(miRNA_name=miRNA)
#REST query will go here.
#commit to database
u.save()
return redirect('results', search_id=u.id)
else: #create an unbound instance of the form
form = SearchMainForm(initial={'miRNA_name':'hsa-let-7a-5p'})
#render the form according to the template, context = form
return render(request, 'dbquery/search.html', {'form':form})
Then in your template:
<form action="" method="post">
That causes your form to submit its data to the search view for validation. If the form is valid, the view saves the results, then redirects to the appropriate results page based on the ID as determined after saving.
In this case, you're likely better off passing your search parameter as a parameter, such as http://host/results?search_id=<your search value>.
This will allow you to specify your URL as url(r'results/', views.results, name ='results') and reference in your template as {% url dbquery:results %}.
Then in your view, you would change it to:
def results(request):
search_id = request.POST.get('search_id')
query = get_object_or_404(TarBase, pk=search_id)
return render(request, 'dbquery/results.html', {'query':query} )
Or if you want the query to actually show in the URL, change the form to be method="get" and the request.POST.get('search_id') to request.GET.get('search_id')