i'm trying to use model formsets with Django. When i load forms template, i see that it's filled-up with previous values. Is there a caching mechanism that i should stop, or what?
Thanks for your help, here is my code:
models.py
class FooModel( models.Model ):
a_field = models.FloatField()
b_field = models.FloatField()
def __unicode__( self ):
return self.a_field
forms.py
from django.forms.models import modelformset_factory
FooFormSet = modelformset_factory(FooModel)
views.py
def foo_func(request):
if request.method == 'POST':
formset = FooFormSet(request.POST, request.FILES, prefix='foo_prefix' )
if formset.is_valid():
formset.save()
return HttpResponseRedirect( '/true/' )
else:
return HttpResponseRedirect( '/false/' )
else:
formset = FooFormSet(prefix='foo_prefix')
variables = RequestContext( request , { 'formset':formset , } )
return render_to_response('footemplate.html' , variables )
template:
<form method="post" action=".">
{% csrf_token %}
<input type="submit" value="Submit" />
<table id="FormsetTable" border="0" cellpadding="0" cellspacing="0">
<tbody>
{% for form in formset.forms %}
<tr>
<td>{{ form.a_field }}</td>
<td>{{ form.b_field }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ formset.management_form }}
</form>
The main problem here is in line:
formset = FooFormSet(prefix='foo_prefix')
When you instantiate FooFormSet() the queryset used to generate the forms is (by default):
FooModel.objects.all()
So, if you already have some FooModel() in your database they will be listed. In this case you can use:
formset = FooFormSet(prefix='foo_prefix', queryset=FooModel.objects.none())
You can see more information about this in Django's Documentation:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#changing-the-queryset
Related
I am trying to prepopulate my form with all records but i am receiving error
'QuerySet' object has no attribute '_meta' ,
I tried just passing my queryset through initial while i get no error the fields in my template aren't rendering initial={runninghours}
my views.py:
def runninghours(request):
runninghours = RunningHours.objects.all()
form = RunningHoursModelForm()
form_populated = RunningHoursModelForm(initial={runninghours})
if request.method == 'POST' and 'form-create' in request.POST:
form = RunningHoursModelForm(request.POST)
if form.is_valid():
form.save()
return redirect(request.path_info)
context = {"form": form,
"rhs": form_populated}
return render(request, 'runninghours.html', context)
The template:
<form method="POST" action="">
{% csrf_token %}
<td>{% render_field rhs.name %}</td>
<td>{% render_field rhs.current_runninghours %}</td>
<td>{% render_field rhs.last_runninghours %}</td>
<td>{% render_field rhs.last_modified %}</td>
<td> <input type="hidden" name="update_runninghours_id" value="{{ rhs.pk }}" />
<input name="form-delete" type="submit" class="button1" value='Update Runninghours' /></td>
</form>
the models.py:
class RunningHours(models.Model):
name = models.CharField(max_length=100)
current_runninghours = models.IntegerField(blank=True,null=True)
last_runninghours = models.IntegerField(blank=True,null=True,default=0)
last_modified = models.DateField(("Date"), default=datetime.date.today)
forms.py:
class RunningHoursModelForm(forms.ModelForm):
model = RunningHours
fields = ("name",
"current_runninghours",
"last_runninghours",)
I don't think you can pass a queryset, runninghours by using initial. That takes a dictionary as argument. What you might be able to do is use the queryset in making the form.
# forms.py
class RunningHoursModelForm(ModelForm):
def __init__(self,company,*args,**kwargs):
super (RunningHoursModelForm,self ).__init__(*args,**kwargs)
self.fields['the_field_you_want'].queryset = RunningHours.objects.all()
class Meta:
model = RunningHours
If you want to populate the form with an instance of RunningHours, you can just do
particularRunningHours = RunningHours.objects.get(name=name)
form_populated = RunningHoursModelForm(initial={
'current_runninghours': particularRunningHours.current_runninghours,
...
})
I would like to update my list after adding some inputs through a form but i cannot see my updated list. I see the existing items in my list ,but when i add a new item it does not appear on the list. I can manually add it using the admin pannel and view it in the list(a whole different path),but not with the form i created to take input and update the list. I was able to query my database and input from the form is not getting written to the database, that's why its not displaying any changes.Below is my code
models.py
class BlogPost(models.Model):
notes = models.CharField(max_length = 1000000000000000000000000000)
date = models.DateTimeField(auto_now_add=True)
done = models.BooleanField(default=False)
def __str__(self):
return self.notes
form.py
from blog.models import BlogPost
class BlogForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['notes', 'done',]
views.py
from django.shortcuts import render,redirect
from django.http import HttpResponse,HttpResponseRedirect,HttpRequest
from blog.models import BlogPost
from blog.form import BlogForm
def home(request):
context = {
'welcome_text': 'Welcome to the home page. View some more stuff soon'
}
return render(request,'home.html', context)
def blogpost(request):
if request.method == "POST":
form = BlogForm(request.POST)
if form.is_valid():
if form.save():
message.success(request, "the task was added")
return redirect('blogpost')
else:
all_blogs = BlogPost.objects.all
return render(request, 'blog.html',{'the_blogs': all_blogs } )
blog.html
{%extends 'base.html' %}
{% block title%}
<title> Blog </title>
{% endblock title%}
{%block content %}
<div class="container">
<br>
{%for message in messages%}
{{message}}
{% endfor %}
<form method = 'POST'>
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" name = 'blog' placeholder = 'new blog' >
</div>
<button type="submit" class="btn btn-primary">Add Blog</button>
</form>
<br>
<table class="table table-hover table-dark">
<thead>
<tr>
<th scope="col">Blog </th>
<th scope="col">Done</th>
<th scope="col">Date</th>
<th scope="col">Edit</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
{% for item in the_blogs %}
{% if item.done %}
<tr class="table-success">
<td >{{item.notes}}</td>
<td >Not-Completed</td>
<td>{{item.date}}</td>
<td>edit</td>
<td>delete</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{%endblock content%}
if you need more information regarding this, here is a link to my GitHub repository with more code.
https://github.com/wfidelis/Django-App
You have to correct the code indentation and the get call part, pass the form to context object and call it with double curly brackets on templates, also add an action attribute to the template.
def blogpost(request):
all_blogs = BlogPost.objects.all()
if request.method == "POST":
form = BlogForm(request.POST)
if form.is_valid():
if form.save():
message.success(request, "the task was added")
return redirect('blogpost')
else:
form = BlogForm()
return render(request, 'blog.html',{'form': form, 'the_blogs': all_blogs } )
<form method='POST' action="">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Add Blog</button>
<form/>
When you add a blog, don't redirect, try rendering the page with the new list the same as how you did it here:
all_blogs = BlogPost.objects.all
return render(request, 'blog.html',{'the_blogs': all_blogs } )
or try returning new object created as JSON format to the front-end (as a response of the POST request) and front-end will add it to the HTML with jQuery or JS
I am not able to GET a variable from a template into another view.
I have a table with some records. Each row has a button which I would like to click and retrieve more details about the record in another page. I have been looking online but I cannot figure out how I should implement this. Everything I have tried either crashed or gave back None.
list.html
{% for trainee in trainees_list %}
<tr>
<td>{{ trainee.last_name }}</td>
<td>{{ trainee.first_name }}</td>
<td><a class="btn btn-primary" href="{% url 'traineedetails'%}" value="{{ trainee.pk }}" >View</a></td>
</tr>
{% endfor %}
view.py
def traineedetails(request):
if request.method == 'GET':
trainee_details = request.POST.get('trainee.pk')
print(trainee_details)
return render(request, 'trainee_details.html')
def listoftrainees(request):
trainees_list = UserTraining.objects.all()
return render_to_response('list.html', {'trainees_list': trainees_list})
url.py
urlpatterns = [
path('traineedetails', views.traineedetails, name='traineedetails'),
path('listoftrainees', views.listoftrainees, name='listoftrainees'),
]
form.py
class UserTrainingForm(forms.ModelForm):
scope_requirements = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=microscopes.MICROSCOPES)
class Meta:
model = UserTraining
fields = (
'first_name',
'last_name',
)
model.py
class UserTraining(models.Model):
first_name = models.CharField('first name', max_length = 100)
last_name = models.CharField('last name', max_length = 100)
I would like to be able to click on the button in the row of the table and retrive more information about the record.
You pass the value directly in the url like : traineedetails/<pk>
In the template:
{% for trainee in trainees_list %}
<tr>
<td>{{ trainee.last_name }}</td>
<td>{{ trainee.first_name }}</td>
<td><a class="btn btn-primary" href="{% url 'traineedetails' trainee.pk%}">View</a></td>
</tr>
{% endfor %}
Edit your urls.py:
path('traineedetails/<pk>', views.traineedetails, name='traineedetails'),
Then you can retrieve it in your view like this:
from django.shortcuts import get_object_or_404
def traineedetails(request, pk):
if request.method == 'GET':
#try to get your objet or throw a 404 error
trainee = get_object_or_404(UserTraining, pk=pk)
#pass it back to the template
return render(request, 'trainee_details.html',{'trainee':trainee})
I'm currently working on a fairly simple django project and could use some help.Currently I am stuck on saving form using checkboxes.
I have the following models with a ManyToMany and through relationship:
class ProfileMatch(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,unique=True)
profiles = models.ManyToManyField(UserProfile,blank=True)
def __unicode__(self):
return "Profile id: %s" %(self.user.id)
I created a HTML form for this with checkbox .Selected profiles_id should save with associate user_id
<form action="." method="POST" class="post-form">{% csrf_token %}
<thead>
<th>Select</th>
<th>Profile-ID</th>
</thead>
<tbody>
{% for user in userprofiles %}
<tr>
<label class="checkbox">
<input type="checkbox" name="user" data-toggle="checkbox" value="{{ user.pk }}">
</label>
<td>{{ user.profile_id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="save btn btn-default">Add Selected </button>
</form>
And a simple view to save the form:
def PremuiumUserProfileSelectList(request, pk):
match = ProfileMatch.objects.get(pk=pk)
if request.method == 'POST':
if request.POST.getlist("user", None):
checked = request.POST.getlist("user", None)
premium_user = User.objects.get(pk=pk)
m = match(user=premium_user, profiles=checked)
m.save()
else:
return render(request, "premiumuser/selected_list.html", context)
else:
return render(request, "premiumuser/selected_list.html", context)
This doesn't saves the form.Form fields were rendered and all selected profiles_id's are showing in a list .How do I save this Form ?I want to save all selected checkbox values in associated user.How do I save it?
You just do, assuming checked is list of ids.
match.profiles.add(*checked)
I have an Expense model and an ExpenseLineItem model. Just like a typical expense/invoice, one expense can have several line items to make up the total cost of an invoice. I'm trying to use class based views to create and update expenses. I've successfully coded the CreateView to make a new expense with multiple expense line items.
My problem is when I try and update an existing Expense which already has several expense line items. Here's my code below, and I can't figure out what the issue is. The mixins (TitleMixin, CancelSuccessMixin, SelectedApartment)are mine and work fine.
I'm getting an error that, I believe, means that it's trying to save a new copy of the ExpenseLineItems but fails since those already exist. Almost like I'm not providing an instance argument.
What am I doing wrong?
forms.py
class ExpenseForm(ModelForm):
class Meta:
model = Expense
fields = ['apart', 'inv_num', 'vendor', 'due_date']
ExpenseLineItemFormset = inlineformset_factory(Expense, ExpenseLineItem, fields=('description', 'account', 'amt'), can_delete=False)
Here's my ExpenseUpdate view:
class ExpenseUpdate(TitleMixin, CancelSuccessMixin, SelectedApartment, UpdateView):
model = Expense
form_class = ExpenseForm
template_name = 'accounting/expense.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
expense_line_item_form = ExpenseLineItemFormset(instance = self.object)
return self.render_to_response(self.get_context_data(form = form, expense_line_item_form = expense_line_item_form))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
expense_line_item_form = ExpenseLineItemFormset(self.request.POST, instance=self.object)
if (form.is_valid() and expense_line_item_form.is_valid()):
return self.form_valid(form, expense_line_item_form)
return self.form_invalid(form, expense_line_item_form)
def form_valid(self, form, expense_line_item_form):
self.object = form.save()
expense_line_item_form.instance = self.object
expense_line_item_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, expense_line_item_form):
return self.render_to_response(self.get_context_data(form=form, expense_line_item_form=expense_line_item_form))
Error code I get:
MultiValueDictKeyError at /stuff/2/accounting/update-expense/25/
"u'expenselineitem_set-0-id'"
Request Method: POST
Request URL: http://localhost:8000/stuff/2/accounting/update-expense/25/
Django Version: 1.8.3
Exception Type: MultiValueDictKeyError
Exception Value:
"u'expenselineitem_set-0-id'"
Exception Location: /usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py in __getitem__, line 322
Edit: Relevant part of my template:
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% load widget_tweaks %}
<div class="row">
<div class="col-md-12">
<table class="table table-tight">
<thead>
<th>Description</th>
<th class="text-right">Account</th>
<th class="text-right">Amount</th>
</thead>
<tbody>
{{ expense_line_item_form.management_form }}
{% for eli in expense_line_item_form %}
<tr>
<td>{{ eli.description|attr:'cols:29' }}</td>
<td class="text-right">{{ eli.account }}</td>
<td class="text-right">{{ eli.amt }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-md-12 text-right">
Cancel
<input class="btn btn-success btn-lg" type="submit" value="Post" />
</div>
<br><br>
</form>
EDIT -- Working Form Template I thought I would add the working version of my template, should someone else need it:
<tbody>
{{ expense_line_item_form.management_form }}
{% for eli in expense_line_item_form %}
<tr>
<td>{{ eli.id }} {{ eli.description|attr:'cols:29' }}</td> <!-- <<==== Here's where I simply added {{ eli.id }}. That's all I changed :) -->
<td class="text-right">{{ eli.account }}</td>
<td class="text-right">{{ eli.amt }}</td>
</tr>
{% endfor %}
</tbody>
You need to include the form id for each form in the formset (it won't be shown to the user, as it is rendered as a hidden input). Without that form, the value is missing from the POST data, and you get a KeyError as you are seeing.
From the formset docs:
Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If you’ve explicitly defined your own primary key that isn’t called id, make sure it gets rendered.)
In your case, you are looping through the formset with {% for eli in expense_line_item_form %}, so you need to include {{ eli.id }}.