Django Forms: Get selected item from ModelChoiceField? - python

I'd like to access the selected item from a ModelChoiceField, similar to this:
forms.py
class ManageFeedsForms(forms.Form):
active_feed = forms.ModelChoiceField(queryset=Feed.objects.all(),
empty_label=None,
widget=forms.Select(attrs={'onchange': 'this.form.submit();'}),
)
def __init__(self, *args, **kwargs):
super(ManageFeedsForms, self).__init__(*args, **kwargs)
self.fields['active_feed'].label = ''
Template.html
{% for entry in feed_form.active_feed.selected_item.entry_list %}
<tr>
<td>{{ entry.title }}</td>
<td>{{ entry.date }}</td>
</tr>
{% endfor %}
views.py (very basic, just for testing)
def overview(request):
if request.GET:
form = ManageFeedsForms(request.GET)
if form.is_valid():
pass
else:
pass
else:
# Empty ManageFeedsForms
form = ManageFeedsForms()
return render_to_response('feed_management/home.html',
{'header_title': 'Feeds',
'feed_form' : form,
},
context_instance=RequestContext(request))
I'm looking for something like '.selected_item', so I can access the model's attributes.
Thanks for any help!

You should modify your view like so:
def overview(request):
selection = None
if request.GET:
form = ManageFeedsForms(request.GET)
if form.is_valid():
selection = form.cleaned_data['active_feed']
else:
# Empty ManageFeedsForms
form = ManageFeedsForms()
return render_to_response('feed_management/home.html',
{'header_title': 'Feeds',
'feed_form' : form,
'selection' : selection,
},
context_instance=RequestContext(request))
And your template:
{% if selection %}
<tr>
<td>{{ selection.title }}</td>
<td>{{ selection.date }}</td>
</tr>
{% endif %}

Related

Python: Get multiple id's from checkbox

I wanted to get multiple id's from a list using checkbox. I got an error
Field 'id' expected a number but got [].
Below is my code.
sample.html
<button href="/sample/save">Save</button>
{% for obj in queryset %}
<tr>
<td><input type="checkbox" name="sid" value="{{obj.id}}"></td>
<td>{{ obj.sample_name }}</td>
<td>{{ obj.sample_type}}</td>
<td>{{ obj.number}}</td>
</tr>
{% endfor %}
views.py
def sample(request):
if request.method == 'GET':
queryset = SampleList.objects.all()
return render(request, 'lab_management/sample.html', {'queryset': queryset})
def save_doc(request):
sid = request.POST.getlist('sid')
sample = SampleList.objects.filter(id=sid)[0:10]
template = DocxTemplate("doc.docx")
context = {
'headers' : ['Name', 'Type', 'Number'],
'doc': [],
}
for samp in sample:
list = [samp.name, samp.type, samp.number]
context['doc'].append(list)
template.render(context)
template.save('new_doc.docx')
the field id should be int you passed a list, that's why you got error:
Field 'id' expected a number but got [].
Here you can use the in Filed lookup
Try this
sample = SampleList.objects.filter(id__in=sid)[0:10]
this will show all the SampleList items with the id's in sid
Update
Change your context to
context = {
'headers' : ['Name', 'Type', 'Number'],
'doc': sample,
}
then remove this for loop
# for samp in sample:
# list = [samp.name, samp.type, samp.number]
# context['doc'].append(list)
and in your template
{% for obj in doc %}
<tr>
<td><input type="checkbox" name="sid" value="{{obj.id}}"></td>
<td>{{ obj.name }}</td>
<td>{{ obj.type}}</td>
<td>{{ obj.number}}</td>
</tr>
{% endfor %}
NB: assuming name, type and number are the filed names of SampleList model

When trying to create a new Django CreateView form, my forms are being populated with the data that was entered in the last form

Using Class Based Views, ModelForms, and Inlline Formsets. I’m making a recipe application in Django. Each user has their own OneToOne RecipeBook object, which in turn can hold as many recipes as needed, as each Recipe has a ForeignKey relationship to the RecipeBook object. There are also Ingredient and Direction objects that each have a FK relationship to the Recipe object.
The good news is that I can create a Recipe object using my CreateView, with as many associated Ingredient and Direction objects as I want. The Ingredient/Direction objects should be unique to each Recipe object (and by extension, each User). However, when I create a Recipe object, and then I try to create a new Recipe object, its Ingredient and Direction fields are already populated on the new object, form the old object. So if I had just created a Recipe with 3 Ingredient/Direction fields all set to '1', and then go to create another Recipe, the new Recipe object will have all blank fields, but will have 3 Ingredient/Direction objects all set to 1. This will happen to each user that is logged in. I want to make it so these objects are all staying together.
I think the issue to this is that either my get_context_data or my form_valid methods are saving the Ingredient/Direction objects globally, when I just want each Ingredient/Direction object to only be associated with the specific recipe object. I’ve tried messing with the init function of my Forms, I’ve tried querying for the object before/while its being created, and it seems like no matter what I do I’m just running in circles. I’d appreciate any help/resources anyone can point me towards!
My Models:
class RecipeBook(models.Model):
"""Each user has a single associated RecipeBook object, linked in this OneToOne field"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Recipe(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4())
recipebook = models.ForeignKey(RecipeBook, related_name='recipe_set', on_delete=models.CASCADE)
title = models.CharField(max_length=150, help_text='Title of the recipe')
description = models.TextField(help_text='Description of the recipe', blank=True)
# image = models.ImageField(height_field=, width_field=, help_text='Image of the recipe', blank=True)
servings = models.PositiveSmallIntegerField(help_text='The amount of servings the recipe will yield', default=0, blank=True)
prep_time = models.PositiveSmallIntegerField(help_text='The preparation time', default=0, blank=True)
cook_time = models.PositiveSmallIntegerField(help_text='The cooking time', default=0, blank=True)
url = models.URLField(blank=True)
TIME_UNITS = (
('m', 'Minutes'),
('h', 'Hours')
)
def get_absolute_url(self):
return reverse('recipe_book:recipe-detail', args=[str(self.id)])
def __str__(self):
return self.title
class Ingredient(models.Model):
recipe = models.ForeignKey(Recipe, related_name='ingredient_set', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
amount = models.CharField(max_length=20, blank=True)
def __str__(self):
return self.name
class Direction(models.Model):
recipe = models.ForeignKey(Recipe, related_name='direction_set', on_delete=models.CASCADE)
step_instructions = models.TextField(help_text='Write the instructions of the step here')
My Forms:
class AddRecipeForm(ModelForm):
recipe = forms.ModelChoiceField(queryset=Recipe.objects.all())
class Meta:
model = Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
class AddIngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ['name', 'amount']
# def __init__(self, *args, **kwargs):
# self.recipe = kwargs.pop('recipe')
# super(AddIngredientForm, self).__init__(*args, **kwargs)
#
# if not self.instance:
# self.fields['name'].initial = self.recipe.default_name
# self.fields['amount'].widget = forms.TextInput(required=False)
#
# def save(self, *args, **kwargs):
# self.instance.recipe = self.recipe
# ingredient = super(AddIngredientForm, self).save(*args, **kwargs)
# return ingredient
IngredientFormset = inlineformset_factory(Recipe, Ingredient, form=AddIngredientForm, extra=1, can_delete=True)
class AddDirectionForm(ModelForm):
class Meta:
model = Direction
fields = ['step_instructions']
# def __init__(self, *args, **kwargs):
# self.recipe = kwargs.pop('recipe')
# super(AddDirectionForm, self).__init__(*args, **kwargs)
#
# if not self.instance:
# self.fields['step_instructions'].initial = self.recipe.default_step_instructions
#
# def save(self, *args, **kwargs):
# self.instance.recipe = self.recipe
# direction = super(AddDirectionForm, self).save(*args, **kwargs)
# return direction
DirectionFormset = inlineformset_factory(Recipe, Direction, form=AddDirectionForm, extra=1, can_delete=True)
My View:
class RecipeListView(LoginRequiredMixin, generic.ListView):
model = models.Recipe
context_object_name = 'recipes'
# Using this method ensures that the only recipes that are displayed are the ones associated with each user
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
class RecipeDetailView(LoginRequiredMixin, generic.DetailView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
context_object_name = 'recipe'
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
# Classes used to actually create full recipe objects
class RecipeCreate(LoginRequiredMixin, CreateView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
def get_context_data(self, **kwargs):
data = super(RecipeCreate, self).get_context_data(**kwargs)
#user = self.request.user
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(self.request.POST)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
else:
data['ingredients'] = IngredientFormset()
#queryset=models.Recipe.objects.filter(self.kwargs['id']))
data['directions'] = DirectionFormset()
#queryset=models.Recipe.objects.filter(self.kwargs['id']))
return data
def form_valid(self, form):
form.instance.recipebook = self.request.user.recipebook
context = self.get_context_data()
ingredients = context['ingredients']
directions = context['directions']
# self.object is the object being created
self.object = form.save()
if ingredients.is_valid():
ingredients.instance = self.object
ingredients.save()
if directions.is_valid():
directions.instance = self.object
directions.save()
return super(RecipeCreate, self).form_valid(form)
class RecipeUpdate(LoginRequiredMixin, UpdateView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
def get_context_data(self, **kwargs):
data = super(RecipeUpdate, self).get_context_data(**kwargs)
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST, instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(self.request.POST, instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
else:
data['ingredients'] = IngredientFormset(instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
return data
def form_valid(self, form):
form.instance.recipebook = self.request.user.recipebook
context = self.get_context_data()
ingredients = context['ingredients']
directions = context['directions']
self.object = form.save()
if ingredients.is_valid():
ingredients.instance = self.object
ingredients.save()
if directions.is_valid():
directions.instance = self.object
directions.save()
return super(RecipeUpdate, self).form_valid(form)
My Template:
{% extends 'base-recipe.html' %}
{# https://simpleit.rocks/python/django/dynamic-add-form-with-add-button-in-django-modelformset-template/ #}
{% block content %}
<div class="container">
<div class="card">
<div class="card-header">Create Recipe</div>
<div class="card-body">
<form action="" method="POST"> {% csrf_token %}
{# table for the Recipe object, manually rendering it for more control #}
<table class="table">
<tr>
<td>{{ form.title.label_tag }}</td>
<td>{{ form.title }}</td>
</tr>
<tr>
<td>{{ form.description.label_tag }}</td>
<td>{{ form.description }}</td>
</tr>
<tr>
<td>{{ form.servings.label_tag }}</td>
<td>{{ form.servings }}</td>
</tr>
<tr>
<td>{{ form.prep_time.label_tag }}</td>
<td>{{ form.prep_time }}</td>
</tr>
<tr>
<td>{{ form.cook_time.label_tag }}</td>
<td>{{ form.cook_time }}</td>
</tr>
<tr>
<td>{{ form.url.label_tag }}</td>
<td>{{ form.url }}</td>
</tr>
</table>
{# table for the ingredient(s) object(s) #}
<table class="table">
{{ ingredients.management_form }}
{% for form in ingredients.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="{% cycle row1 row2 %} formset_row-{{ ingredients.prefix }}">
{% for field in form.visible_fields %}
<td>
{# include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<table class="table">
{{ directions.management_form }}
{% for form in directions.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<!--<tr class="{% cycle row1 row2 %} formset_row-{{ directions.prefix }}">-->
<tr class="formset_row-{{ directions.prefix }}">
{% for field in form.visible_fields %}
<td>
{# include the hidden fields #}
{% if forloop.first %}
{% for field in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input class="btn btn-primary" type="submit" value="Submit">
<a class="btn btn-danger" href="{% url 'recipe_book:index' %}">Back to the recipe list</a>
</form>
</div>
</div>
</div>
{% load static %}
<script src="{% static 'js/jquery.formsets.js' %}"></script>
<script type="text/javascript">
$('.formset_row-{{ ingredients.prefix }}').formset({
addText: 'Add Another Ingredient',
deleteText: 'Remove',
prefix: '{{ ingredients.prefix }}',
});
$('.formset_row-{{ directions.prefix }}').formset({
addText: 'Add another',
deleteText: 'Remove',
prefix: '{{ directions.prefix }}',
});
</script>
{% endblock %}
For anyone who also has this issue, here's the fix, from the Django forum's user KenWhitesell:
You can chase this down through the source code if you really want to
understand what’s going on, but the Reader’s Digest version is that an
inline formset is created under the assumption that the formset is
linked to an existing instance. If one isn’t supplied, it selects one
from the database.
The fix, for me, was in the CreateView's get_context_data() method: since we don't want the inline_formset to be querying for any objects on a CreateView, you have to explicitly tell it not to with a queryset parameter on the GET request like this:
def get_context_data(self, **kwargs):
data = super(RecipeCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST)
data['directions'] = DirectionFormset(self.request.POST)
else:
data['ingredients'] = IngredientFormset(queryset=models.Ingredient.objects.none())
data['directions'] = DirectionFormset(queryset=models.Direction.objects.none())
return data
Here's a link to our forum post discussing the issue: https://forum.djangoproject.com/t/my-forms-are-being-populated-with-the-data-that-was-entered-in-the-last-createview/6278/12

Django-filter: count data

Does anybody knows how can I use count based on selected value using django_filters
Error
'UserFilter' object has no attribute 'count'
My Reference link
views.py
def search(request):
user_list = Person.objects.all()
user_filter = UserFilter(request.GET, queryset=user_list)
count = user_filter.count() #this will return an error
print(count)
return render(request, 'user_list.html', {'filter': user_filter})
filters.py
from django.contrib.auth.models import User
from .models import Person
import django_filters
class UserFilter(django_filters.FilterSet):
class Meta:
model = Person
fields = ['category', 'firstname', 'lastname' ]
user_list.html
{% extends 'base.html' %}
{% block content %}
<form method="get">
{{filter.form.as_p}}
<button type="submit" >Search</button>
</form>
<table class="table table-bordered">
<thead>
<tr>
<th>Firstname</th>
<th> Lastname</th>
<th>Caegory</th>
</tr>
</thead>
<tbody>
{% for user in filter.qs %}
<tr>
<td>{{ user.firstname }}</td>
<td>{{ user.lastname }}</td>
<td>{{ user.category }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5">No data</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
I want to count all the list base from data I filtered
You'll want the count of the resulting queryset, which you can get from the filter's qs property (as you do in your template!).
Change
count = user_filter.count()
to
count = user_filter.qs.count()
You can work with the .qs attribute:
def search(request):
user_list = Person.objects.all()
user_filter = UserFilter(request.GET, queryset=user_list)
count = user_filter.qs.count()
return render(request, 'user_list.html', {'filter': user_filter})
.qs [GitHub] is a property that generates a QuerySet by filtering the original queryset by values in the fields of the FilterSet.

Flask WTForms Dynamic Editable Table Fields with Field Names

How can I get the Field Names to return as text/string?
Highlighted "Field Names" I want returned as text, not fields
I am dynamically creating a list of fields and then appending values. But I can't seem to figure out a way to return the field names as plain text. The below code appends them to a field (fieldname)-- which is the only way I have been able to return them.
class ContractFields(FlaskForm):
fieldname = StringField()
fieldvalue = StringField()
class ContractForm(FlaskForm):
title = StringField('title')
contractfieldlist = FieldList(FormField(ContractFields))
#app.route('/tester.html', methods=['GET','POST'])
def contractfields():
form = ContractForm()
for f in object:
document_form = ContractFields()
document_form.fieldname = f.name #need this list object to return as table text, not a field
document_form.fieldvalue = f.value
form.contractfieldlist.append_entry(document_form)
return render_template('tester.html', form = form)
And from the template:
<div>
<form action="" method="post" name="form">
{{ form.hidden_tag() }}
<div>
<table>
<tr>
<th> ListNumber </th>
<th> Field Name </th>
<th> Field Value </th>
</tr>
{% for items in form.contractfieldlist %}
<tr>
<td>{{ items.label }}</td>
<td>{{ items.fieldname }}</td>
<td>{{ items.fieldvalue }}</td>
</tr>
{% endfor %}
</table>
</div>
<p><input type="submit" name="edit" value="Send"></p>
</form>
</div>
My experience with Python has largely been limited ETL and data transformation so I don't understand why this was so complicated. But after way too many hours I finally found the following solution worked for me.
Specifically modifying the associated excerpt from the above post to be the following:
class ContractFields(FlaskForm):
fieldname = HiddenField()
fieldvalue = StringField()
def __init__(self, *args, **kwargs):
super(ContractFields, self).__init__(*args, **kwargs)
if 'obj' in kwargs and kwargs['obj'] is not None:
self.fieldvalue.label.text = kwargs['obj'].fieldname
And the template html to:
<td>{{ items.label }}</td>
<td>{{ items.fieldvalue.label }}</td>
<td>{{ items.fieldvalue }}</td>

Django passing dictionary of tuples to template

If I made a set of code like this...
object_data = {}
object = Object.objects.all()
for o in object:
ratings = ObjectRating.objects.filter(recipe=r)
counter = 0
ratings_sum = 0
for s in ratings:
counter += 1
ratings_sum += s.rating
rating_average = ratings_sum / counter
object_data[`o.id`] = (o, rating_average,)
data = {
'search_by' : search_by,
'object' : object_data
}
If I pass the data dictionary to the page (render_to_response(page, data, context_instance=RequestContext(request))), how do I get the data from both parts of the tuple in the template.
This is how I thought I had to do it...
{% for o in object %}
<tr><td>{{ o.0.name }}</td><td>{{ o.0.description }}</td><td>{{ o.0.other_col }}</td><td>{{ o.0.another_col }}</td><td>{{ o.1 }}</td></tr>
{% endfor %}
This is driving me insane and any insight will be helpful. This is Django 1.6 (I know I need to move on, so do not mention that in your answer).
Why not just add rating_average as an attribute to your object?
for o in object:
... # calculate rating average for this object
o.rating_average = ratings_sum / counter
data = {
'search_by' : search_by,
'object' : object
}
{% for o in object %}
<tr><td>{{ o.name }}</td>
<td>{{ o.description }}</td>
<td>{{ o.other_col }}</td>
<td>{{ o.another_col }}</td>
<td>{{ o.rating_average }}</td>
</tr>
{% endfor %}
Like this example:
class HomeView(generic.TemplateView):
template_name = '_layouts/index.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
mydict = {'wat': 'coo'}
context['mydict'] = mydict
return context
Template:
{% for key, value in mydict.items %}
{{ key }} : {{ value }}
{% endfor %}

Categories

Resources