I'm writing a sports league app. I get a drop down list of all my teams. And I can display the wins/losses data on a separate view. But I can't get the StandingsView (with the form) to correct redirect to the TeamView (display information).
I've tried both POST and GET. I've run into a bunch of issues I don't understand. First, the url from the form is directed to
/teamview/?team_name=6
I don't understand why that is, even if my view specifies otherwise.
Second, the view doesn't redirect unless I do so in the form action. I think that's a product of the GET function, but I'm not sure. I'm hesitant to use POST because I'm not changing the DB
I've looked into RedirectView, but worry (as always) I'm overcomplicating this.
Thank you much,
Views.py
class StandingsView(FormView):
form_class = SelectTeam
template_name = 'teamsports/standings.html'
model = Teams
success_url = '/teamview/'
def form_valid(self, form):
team = form.cleaned_data['team']
return redirect('teamview', team = team)
def form_invalid(self,form):
HttpResponse ("This didn't work")
def TeamView(request, team):
try:
team = Teams.objects.filter(team=team).values()
except Teams.DoesNotExist:
raise Http404("Team does not exist")
return render(request, 'teamview.html', {'team':team})
urls.py
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^admin/', admin.site.urls),
url(r'^standings/$', views.StandingsView.as_view(), name="standings"),
url(r'teamview/(?P<team>[0-9]+)/$', views.TeamView, name="teamview")
forms.py
class SelectTeam(ModelForm):
team_name = forms.ModelChoiceField(queryset=Teams.objects.all(), initial=0)
class Meta:
model = Teams
fields = ['team', 'team_name']
standings.html
<form action= "/teamview/" method="GET">
{{ form }}
<input type="submit" value="Submit" />
{{ form.errors }}
</form>
{% endblock %}
Related
Good day everyone.
I am trying to build a form which queries the database based on user data inputs and then returns the results in a new page. but I don't know exactly how to do it and I am getting errors. I've looked for a solution but couldn't find any. Please help me if you know any solutions.
Thanks in advance.
Here are my codes:
forms.py
class AttendanceForm(forms.Form):
course = forms.CharField(max_length=50)
department = forms.CharField(max_length=10)
semester = forms.IntegerField()
views.py
class AttendanceForm(generic.FormView):
form_class = CrsAttForm
template_name = 'office/crsatt_form.html'
success_url = reverse_lazy('office:members_list')
class MembersList(generic.ListView):
template_name = "office/crs_att.html"
context_object_name = 'members'
def get_queryset(self):
return Members.objects.all()
# I know I should use .filter method but how could I set the parameters to data received from the form
urls.py
url(r'^CourseAttendanceForm/$', views.AttendanceForm.as_view(), name='courseattendance'),
url(r'^CourseAttendanceForm/Results/$',views.MembersList.as_view(), name='memebrs_list'),
I think that it will be easier for you to use function based views for this one.
You can do it like this:
views.py
def form_page(request):
form = AttendanceForm()
# you get to this "if" if the form has been filled by the user
if request.method == "POST":
form = AttendanceForm(request.POST)
if form.is_valid():
course = request.POST['course']
department = request.POST['department']
semester = request.POST['semester']
members = Member.objects.filter(#here you do your filters as you already have the course, department and semester variables)
context = {'members': members}
return render(request, 'second_page.html', context)
# if the form hasn't been filled by the user you display the form
context = {'form': form}
return render(request, 'form_page.html', context)
form_page.html
<form method="post" action="{% url 'form_page' %}">
{% csrf_token %}
{{ form }}
<button type="submit">Search!</button>
</form>
urls.py
path('form_page/', views.form_page, name='form_page')
second_page.html
{% for member in members %}
# here you display whatever you want to
{% endfor %}
I'm trying to add an edit form to an existing model, but it does not save every time and redirects me to the home page instead of the 'account' page. What am I doing wrong? why changes in the existing model are not visible? any help will be appreciated.
views.py
def account(request):
data_now = datetime.datetime.now().strftime("%Y-%m-%d")
#my form
time = get_object_or_404(Time, pk=52)
if request.method == "POST":
form = TimeEditForm(request.POST, instance=time)
if form.is_valid():
time = form.save(commit=False)
time.save()
return redirect('account')
else:
form = TimeEditForm(instance=time)
context = {'data_now': data_now, 'time_edit_form': form}
return render(request, 'account.html', context)
forms.py
class TimeEditForm(forms.ModelForm):
class Meta:
model = Time
fields = ('compartment',)
labels ={
'free_or_no': 'field name in my language?'
}
models.py
class Time(models.Model):
day_time = models.ForeignKey(DayTime, on_delete=models.CASCADE)
compartment = models.CharField(max_length=11)
free_or_no = models.BooleanField(default=True)
time_equivalent = models.IntegerField()
urls.py
urlpatterns = [
url(r'^$', views.masseur_detail, name='masseur_detail'),
url(r'^account$', views.account, name='account')
]
account.html
<form action="." method="post">
{% csrf_token %}
{{ time_edit_form|crispy }}
<button type="submit" class="btn btn-block btn-primary"> Save</button>
</form>
This is quite a subtle issue.
Usually in Django it's recommended to use URLs that end with a slash - eg "/account/" - but your URL is just "/account", without the slash.
Now, when you put action="." in your form, the browser interprets this as "post to the root of the current directory". If your URL did end with a slash, that would be resolve to the same page. But because it doesn't, the browser posts to the root itself, ie "/".
The best solution is to change your URL pattern to r'^account/$'; alternatively (but not recommended) you could change your form to use action="".
So I am working on django, I have a simple form with one text field named "sujet", here's the form.py code:
from django import forms
class ContactForm(forms.Form):
sujet = forms.CharField(max_length=100,
widget=forms.TextInput(
attrs={
'id': 'id_sujet',
'style': 'border-color: blue;',
'placeholder': 'Write your name here'
}
)
)
The template "contact.html" where the user can fill the form is the following:
<form id="myForm" action="{% url 'contact' %}" method="post">
{{ form.sujet }}
<input type="submit" value="Submit" />
</form>
<div id="response">
Sujet : <span id="sujeet"></span>
{{ sujet }}
</div>
In my "views.py" I want my contact function to render the variable "sujet" to the template so I can diplay it on "contact.html" after filling and submitting the form (the intended usage of this is later to display the result of the database query that concerns sujet and not the variable itself but I am still working on that), here's the code of the view function :
def contact(request):
form = ContactForm(request.POST or None)
if form.is_valid():
sujet = form.cleaned_data['sujet']
envoi = True
return redirect(request.META['HTTP_REFERER'], {'sujet':sujet})
else:
return render(request, 'voirkpi/contact.html', locals())
Here is the code of my "urls.py" :
from django.urls import path
from django.conf.urls import url
from . import views
urlpatterns = [
path('accueil', views.ligneerabstat),
path('spark', views.kpitest),
path('testchart', views.testchart),
path('contact', views.contact, name='contact'),
#path('test', views.test, name='test'),
url('test', views.test, name='test')
]
My problem is that after clicking submit sujet is empty and doesn't show anything, I did make this work with simple javascript, but that's not what I want as the intended usage of this is as I said later to query a database and return in that span the result of the query according to the "sujet" filled.
Any help would be very much appreciated, thank you.
Thanks for the help. You're right Resley Rodrigues, I solved my problem by changing my contact function in "views.py" like so:
def contact(request):
form = ContactForm(request.POST or None)
if form.is_valid():
sujet = form.cleaned_data['sujet']
envoi = True
form = ContactForm()
return render(request,'voirkpi/contact.html',locals(), {'sujet' : sujet})
else:
return render(request, 'voirkpi/contact.html', locals())
I'm using smart-selects.
Edited : Here is the code that works for me, after adding {{ form.media.js }} in the template , thanks to #Evangelos
models.py :
from django.db import models
from smart_selects.db_fields import ChainedForeignKey, ChainedManyToManyField
class ChoixTangente(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class ChoixModele(models.Model):
name = models.CharField(max_length=255)
tangentes = models.ManyToManyField('Choixtangente', blank=True)
def __str__(self):
return self.name
class TypeModele(models.Model):
tangente = models.ForeignKey(ChoixTangente, blank=True, null=True)
type_modele = ChainedForeignKey(
ChoixModele,
chained_field="tangente",
chained_model_field="tangentes",
show_all=False,
auto_choose=True,
blank=True, null=True
)
def __unicode__(self):
return str(self.pk)
form.py :
from django import forms
from .models import ChoixTangente, ChoixModele, TypeModele
class TypeModeleForm(forms.ModelForm):
class Meta:
model = TypeModele
fields = ('tangente', 'type_modele')
views.py
from .models import ChoixTangente, ChoixModele, TypeModele
from .forms import TypeModeleForm
def type_modele_new(request):
if request.method == "POST":
form = TypeModeleForm(request.POST)
if form.is_valid():
modele_instance = form.save()
return redirect('calculs.views.type_modele_detail', pk=modele_instance.pk)
else:
form = TypeModeleForm()
return render(request, 'calculs/type_modele_new.html', {'form': form})
def type_modele_detail(request, pk):
modele_instance = get_object_or_404(TypeModele, pk=pk)
return render(request, 'calculs/type_modele_detail.html', {'modele_instance': modele_instance})
template : type_modele_new.html
{% load staticfiles %}
<form method="POST">
{% csrf_token %}
**{{ form.media.js }}**
{{ form.as_p}}
<input type="submit" value="Submit">
</form>
urls.py
from django.conf.urls import url, include
from . import views
from smart_selects import urls as smart_selects_urls
urlpatterns = [
url(r'^chaining/', include('smart_selects.urls')),
url(r'^type_modele/new/$', views.type_modele_new, name='modele_new'),
url(r'^type_modele/(?P<pk>[0-9]+)/$', views.type_modele_detail, name='modele_detail'),
]
Edited : and here was the problem :
I have it working fine in admin :
I create ChoixTangente instances
I create ChoixModele
instances and select ChoixTangentes instances in the list
I can create TypeModele" instances by selecting "tangente" in a list of ChoixTangente and "type_modele" in the list of corresponding ChoixModele choices resulting from the steps 1) and 2)
see Admin form screenshot
I whish to have my users do the same through a form. But I can't have it working.
the field "Tangente" is populated with the list of ChoixTangente but when I choose a value the field "type_modele" stays empty instead of displaying a list of corresponding choices.
see form screenshot for the users
First of all where is your views?
Try to post more complete question with files for better understanding.
Where is the model Appareil in the models.py you are refering to in forms.py?
And your fields should be in list [].
Your forms.py should look like:
from django import forms
from .models import Modele
class AppareilForm(forms.ModelForm):
class Meta:
model = Modele
fields =['tangente', 'modele']
You don't need to write javascript.
Just remember to include url(r'^chaining/', include('smart_selects.urls')) to your urls.py
in your view call the AppareilForm Read about forms in views for details.
And in the template just use {{form.as_p}} and {{ form.media.js }} before to load javascript and make sure to load static in your template. {% load static % }
Your template should look something like this
{% load static % }
<form action="your url that points to your view" method="POST">
{% csrf_token %}
{{ form.media.js }}
{{ form.as_p}}
<input type="submit" value="Submit">
</form>
Read the django-selects description carefully.
What I am trying to do is the following: User will have a production (also known as podcast episode) already created with the necessary info until this point (production_id would be the id for this query). The idea is, when user arrives to ChapterMark template, he would be able to create several timestamps to point out certain topics he/she is talking throughout his/her episode. chaptermark_id is created since it would be a One-To-Many and with this id I can add as much timestamps as I want within that episode. With this in mind, which is the best approach for this type of situation and how I can implement it in my form, class view and template?
Thanks in advance
Here is my views.py:
from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden
from django.shortcuts import render, get_object_or_404
from django.views.generic import View, RedirectView, TemplateView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from .forms.client_setup import ClientSetupForm
from .forms.podcast_setup import PodcastSetupForm
from .forms.episode_info import EpisodeInfoForm
from .forms.image_files import EpisodeImageFilesForm
from .forms.wordpress_info import EpisodeWordpressInfoForm
from .forms.chapter_marks import EpisodeChapterMarksForm
from .forms.show_links import ShowLinksForm
from .forms.tweetables import TweetablesForm
from .forms.clicktotweet import ClickToTweetForm
from .forms.schedule import ScheduleForm
from .forms.wordpress_account import WordpressAccountForm
from .forms.wordpress_account_setup import WordpressAccountSetupForm
from .forms.wordpress_account_sortable import WordpressAccountSortableForm
from .forms.soundcloud_account import SoundcloudAccountForm
from .forms.twitter_account import TwitterAccountForm
from producer.helpers import get_podfunnel_client_and_podcast_for_user
from producer.helpers.soundcloud_api import SoundcloudAPI
from producer.helpers.twitter import TwitterAPI
from django.conf import settings
from producer.models import Client, Production, ChapterMark, ProductionLink, ProductionTweet, Podcast, WordpressConfig, Credentials, WordPressSortableSection, \
TwitterConfig, SoundcloudConfig
from django.core.urlresolvers import reverse
from producer.tasks.auphonic import update_or_create_preset_for_podcast
class EpisodeChapterMarksView(LoginRequiredMixin, View):
form_class = EpisodeChapterMarksForm
template_name = 'fc/forms_chapter_marks.html'
def get(self, request, *args, **kwargs):
initial_values = {}
user = request.user
# Lets get client and podcast for the user already. if not existent raise 404
client, podcast = get_fc_client_and_podcast_for_user(user)
if client is None or podcast is None:
raise Http404
# The production_id or the chaptermark_id must be passed on teh KWargs
production_id = kwargs.get('production_id', None)
chaptermark_id = kwargs.get('chaptermark_id', None)
if chaptermark_id:
chaptermark = get_object_or_404(ChapterMark, id=chaptermark_id)
production = chaptermark.production
elif production_id:
production = get_object_or_404(Production, id=production_id)
chaptermark = None
initial_values['production_id'] = production.id
if chaptermark is not None:
initial_values['chaptermark_id'] = chaptermark_id
initial_values['start_time'] = chaptermark.start_time
initial_values['title'] = chaptermark.title
form = self.form_class(initial=initial_values)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# lets get the data
production_id = form.cleaned_data.get('production_id')
chaptermark_id = form.cleaned_data.get('chaptermark_id')
start_time = form.cleaned_data.get('start_time')
title = form.cleaned_data.get('title')
# Get production
production = get_object_or_404(Production, id=production_id)
# if a chaptermark existed, we update, if not we create
if chaptermark_id is not None:
chaptermark = ChapterMark.objects.get(id=chaptermark_id)
else:
chaptermark = ChapterMark()
chaptermark.start_time = start_time
chaptermark.title = title
chaptermark.production = production
chaptermark.save()
return HttpResponseRedirect(reverse('fc:episodeshowlinks'))
return render(request, self.template_name, {'form': form})
chaptermark.py form:
from django import forms
class EpisodeChapterMarksForm(forms.Form):
production_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)
chaptermark_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)
start_time = forms.TimeField(required=False)
title = forms.CharField(max_length=200)
chaptermark template:
{% extends "fc/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-success active" role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="width: 50%">
<span class="sr-only">50% Complete</span>
</div>
</div>
<div class="panel panel-default box-shadow--16dp col-sm-6 col-sm-offset-3">
<div class="panel-body">
<div class='row'>
<div class='col-sm-12'>
{% if title %}
<h1 class='{% if title_align_center %}text-align-center{% endif %}'>{{ title }}<!-- : {{ get.clientsetup.company_name }} --></h1>
{% endif %}
{% if subtitle %}
<h3 class='{% if subtitle_align_center %}text-align-center{% endif %}'>{{ subtitle }}</h4>
{% endif %}
<h5>Chapter Marks</h5>
<form method='POST' action=''>{% csrf_token %}
{{ form|crispy }}
<hr/>
<button type="submit" class="btn btn-primary box-shadow--6dp"><i class="fa fa-chevron-right pull-right"></i> Continue
</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
----------------------UPDATE-------------------------
Was in views.py:
#login_required
def episodechaptermarks(request):
title = 'Podcast'
title_align_center = True
subtitle = 'Setup | Add Episode'
subtitle_align_center = True
form = ChapterMarksForm(request.POST or None)
context = {
"title": title,
"subtitle": subtitle,
"form": form
}
if form.is_valid():
instance = form.save(commit=False)
start_time = form.cleaned_data.get("start_time")
title = form.cleaned_data.get("title")
instance.start_time = start_time
instance.title = title
instance.user = request.user
instance.save()
return render(request, "pod_funnel/forms_chapter_marks.html", context)
else:
return render(request, "pod_funnel/forms_chapter_marks.html", context)
ModelForm:
from django import forms
from producer.models import ChapterMark
class ChapterMarksForm(forms.ModelForm):
class Meta:
model = ChapterMark
fields = ['start_time', 'title']
def clean_start_time(self):
start_time = self.cleaned_data.get('start_time')
return start_time
def clean_title(self):
title = self.cleaned_data.get('title')
return title
In essence, your production object has a series of timestamps that relate back via a FK. You need a set of views for CRUD at the production level. Let's assume your models are already created. There's a few things from my experience I want to point out that I think will point you in the right direction.
Unless absolutely necessary never use a Form class when creating a form object that mirrors a model; you are introducing a need for unnecessary complexity and opening the door for errors. Use a ModelForm, which can save objects to the DB straight from the view and help you manage cleaning, validation, and more. In addition, these can easily mesh with generic views of all sorts.
For this sort of relation (a model object with a varying number of model objects of a given type relating back that object) Django provides the powerful but difficult inlineformset_factory. This creates a series of inline forms as needed for a relation such as this.
So you have a model (production) and another related back to that (timestamp). You need to save these at the same time, possibly perform cleaning or validation, and really provide CRUD functionality for this relationship as a whole. For this, you could create a complex view from scratch or you could use django-extra-views and their generic CBVs for models with inlines. You can subclass CreateWithInlinesView, UpdateWithInlinesView. Why? Most Django devs would agree formsets are difficult to implement.
So, to give you a simplified version of how you can do this
from extra_views.advanced import CreateWithInlinesView, InlineFormSet, UpdateWithInlinesView
class TimeStampsInline(InlineFormSet):
model = models.TimeStamp
form = TimeStampForm # If you haven't created a custom ModelForm, can also specify "fields= ['field_1','field_2',...] and the CBV will create a ModelForm
extra = 0
class ProductionCreate(CreateWithInlinesView):
model=models.Production
inlines = [TimeStampsInline]
success_url = reverse('production-list') # the url to return to on successful create
exclude = ['created_by'] # render all fields except this in form
template_name = 'myapp/update.html'
class ProductionUpdate(UpdateWithInlinesView):
model=models.Production
inlines = [TimeStampsInline]
success_url = reverse('production-list')
exclude = ['created_by']
template_name = 'myapp/update.html'
Your template(s) will have to be built in specification with formsets; there's documentation and tutorials all over for that.
That's already a lot to digest, but you probably get the general idea. Don't build a horse from scratch ;)