SelectMultipleField default value is not being selected on HTML - python

c.ingredientsI am creating a Flask sample app for learning purposes and I have a Form called CocktailForm that contains a SelectMultipleField. This form should be used for creating new cocktails objects as well as for updating them:
class CocktailForm(Form):
name = StringField('What is the coktail\'s name?', validators=[Required()])
ingredients = SelectMultipleField('Ingredients',
coerce=int,
)
submit = SubmitField('Submit')
For editing I want to load the same form with the cocktail data. It works for name, and for loading all choices but I also want to select those choices that are ingredients of that cocktail:
#main.route('/edit/<int:id>', methods=['GET', 'POST'])
def edit(id):
try:
c = Cocktail.query.filter(Cocktail.id == id).one()
form = CocktailForm()
form.ingredients.choices = [(i.id, i.name) for i in Ingredient.query.all()]
if form.validate_on_submit():
c.name = form.name.data
cocktail_ingredients = Ingredient.query.filter(Ingredient.id.in_(form.ingredients.data)).all()
c.ingredients.extend(cocktail_ingredients)
db.session.commit()
else:
form.name.data = c.name
form.ingredients.default = [(i.id, i.name) for i in c.ingredients]
return render_template('new.html', form=form)
except Exception, e:
print e
return redirect(url_for('.index'))
I get unexpected results since on the HTML those choices are not displayed but when I submit the form it seems like those choices are always selected even if you select a new ones.
The template is quite simple:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Cocktails{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>New Cocktail</h1>
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
This is what you can see in in the browser. I am editing Gintonic cocktail which is composed of gin and tonic. However they are not displayed as selected:
Browser
Thanks in advance, any tip will be appreciated

The line form.ingredients.default = [(i.id, i.name) for i in Ingredient.query.all()] does not set the selected values. You want to change it to be form.ingredients.data = [i.id for i in c.ingredients].
You should have a redirect/render_template in the validate block, but that is optional.

Related

Python Flask: Cannot find a way to set the default value in SelectForm (Flask WTF)

I cannot find any solution to set the default value in SelectForm (Flask WTF). I would like the default value (i.e. the initial value of the dropdown) to be set dynamically.
I am using Flask-WTF 0.14.3.
I am using the following macro to render all the fields in the template:
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
I use my custom form that inherits from FlaskForm class. Such form contains some fields of type SelectField. When configuring the class, I do not set the default values, as they are not known (they should be set when the application runs).
I tried the following:
Setting the form as follows:
#issues.route('/item', methods=["GET"])
def my_get():
the_item = request.args["item"]
# [BEGIN] This part will change in the following examples
form = MyForm()
form.my_item.choices = Item.query.with_entities(Item.id, Item.name).all()
form.my_item.data = the_item
# [END]
return render_template("my_form.html", form=form)
Whereas this works for other fields, it does not in this case: dropdown starts with the first value.
Setting the form as follows:
...
form = MyForm(my_item=the_item)
form.my_item.choices = Item.query.with_entities(Item.id, Item.name).all()
...
that gives TypeError: 'UnboundField' object is not callable on <dd>{{ field(**kwargs)|safe }}
Setting the form as follows:
form = MyForm()
form.my_item.choices = Item.query.with_entities(Item.id, Item.name).all()
form.my_item.data = the_item
form.my_item.default = the_item
with the same results as way #1.
Could you please show me how to overcome such issue?
I thank you in advance.
Theo
Like this
class PostForm(FlaskForm):
title = StringField(u'Title', validators=[Length(min=3, max=50, message='The title name must be between 3 and 20 digits long')],
render_kw={'class': '', 'rows': 50, 'placeholder': 'please input title'})
blog_type = SelectField(label=u'Cate',
default=0,
coerce=int)
blog_level = SelectField(label=u'Level', choices=[(1, 'public'), (2, 'private')], validators=[DataRequired()],
default=1, coerce=int)
brief_content = TextAreaField(u'desc', validators=[DataRequired()])
blog_img_file = FileField(label=u'image',
validators=[DataRequired(), FileAllowed(['png', 'jpg'], 'Only accept png and jpg images')],
render_kw={'value': "upload", 'class': 'btn btn-default'})
body = CKEditorField('Body', validators=[DataRequired(message='please input content')])
submit = SubmitField(u'Publish')
def __init__(self, default=0, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
categories = BlogType.query.all()
self.blog_type.choices = [(cate.id, cate.name) for cate in categories]
self.blog_type.data = default
I fixed it this way: this is how I get the choices after querying them:
form.my_item.choices = Item.query.with_entities(Item.id, Item.name).all()
I made sure that the first item of form.my_item.choices list is my desired default value (i.e., the first item of such list is the default). I just needed to swap 2 elements of the list.
Hope this helps someone else too.
Greetings,
Theo

Flask Python pass data on link click

I am working on a recipes database. My issue is with showing the result of a search. I can search the database by ingredient and get a list of recipes with that ingredient. I display those results on a new page; I show just the title of the recipe and I make it a link to a 'showrecipe' page. But I cannot find a way to send the recipe id to the new page so it knows which recipe to show. Here are the relevant bits of code so far:
The Search Form:
class SearchIngredientsForm(FlaskForm):
ingredients_string = StringField('ingredients_string', validators=[InputRequired(), Length(min=1)])
# search_string = StringField('Search string', [InputRequired()])
submit = SubmitField('Search')
and the search route:
#app.route('/search', methods=['GET','POST'])
def search():
form = SearchIngredientsForm()
if form.validate_on_submit():
search_ingredients_string = form.ingredients_string
search_ingredients_list = search_ingredients_string.data.split(',')
recipe_ids = []
ingredient_objects = []
if search_ingredients_list:
for ingredient_name in search_ingredients_list:
ingredient_objects.extend( Ingredient.query.filter(Ingredient.line.like(f'%{ingredient_name}%')).all() )
if ingredient_objects:
for ingredient in ingredient_objects:
recipe_ids.append(ingredient.recipe_id)
session['recipe_ids'] = recipe_ids
return redirect(url_for('results'))
return render_template('search.html', form=form)
and the results.html
{% extends 'layout.html' %}
{% block content %}
<h1>Results</h1>
{% for result in recipe_objects %}
{{ result.title }} which serves: {{ result.serves }}
{% endfor %}
{% endblock content %}
and finally the showrecipe route. I cannot seem to get the id to pass through.
#app.route('/showrecipe/<id>', methods=['POST', 'GET'])
def showrecipe(id):
recipe = Recipe.query.get(id)
return render_template('showrecipe.html', recipe=recipe)
When I click on the recipe title on the results page I get a 'url not found' error.
Thanks in advance for any help.
Update
Here is the results route:
#app.route('/results')
def results():
recipe_ids = session.get('recipe_ids')
recipe_objects = []
if recipe_ids:
for recipe_id in recipe_ids:
recipe_objects.append(Recipe.query.get(recipe_id))
return render_template('results.html', recipe_objects=recipe_objects)

Django form field not displaying correct queryset values

The following code is from an multi-vendor ecommerce portal. We need to display different shipping methods according to the store(or vendor) on the checkout summary page.
However even though I get correct queryset while print i.e Store 1 has Test Rest of World Shipping method and Store 2 has UPC and DHL, the rendered form shows incorrect values -
#########################################################
class ShippingCountryChoiceField(forms.ModelChoiceField):
widget = forms.RadioSelect()
def label_from_instance(self, obj):
price_html = format_price(obj.price.gross, obj.price.currency)
label = mark_safe('%s %s' % (obj.shipping_method, price_html))
return label
class ShippingMethodForm(forms.Form):
def __init__(self, country_code, *args, **kwargs):
stores = kwargs.pop('stores')
super(ShippingMethodForm, self).__init__(*args, **kwargs)
for count, store in enumerate(stores, start=1):
method_field = ShippingCountryChoiceField(
queryset=ShippingMethodCountry.objects.select_related(
'shipping_method').order_by('price').filter(shipping_method__store=store),
label=pgettext_lazy('Shipping method form field label', 'Shipping method for %s' % store),
required=True)
if country_code:
queryset = method_field.queryset
method_field.queryset = queryset.unique_for_country_code(country_code)
if self.initial.get('method') is None:
method_field.initial = method_field.queryset.first()
method_field.empty_label = None
self.fields['method_%d' % count] = method_field
print [q.queryset for q in self.fields.values()]
###################################################
#load_checkout
#validate_voucher
#validate_cart
#validate_is_shipping_required
#validate_shipping_address
#add_voucher_form
def shipping_method_view(request, checkout):
country_code = checkout.shipping_address.country.code
stores = checkout.cart.lines.values_list('variant__product__store', flat=True)
stores = Store.objects.filter(id__in=stores)
print checkout.shipping_method
shipping_method_form = ShippingMethodForm(
country_code, request.POST or None, initial={'method': checkout.shipping_method},
stores=stores)
if shipping_method_form.is_valid():
for count, store in enumerate(stores):
checkout.shipping_method[store] = shipping_method_form.cleaned_data['method_%s' % count]
return redirect('checkout:summary')
print [q.queryset for q in shipping_method_form.fields.values()]
return TemplateResponse(request, 'checkout/shipping_method.html', context={
'shipping_method_form': shipping_method_form, 'checkout': checkout})
##############################################################
{% extends "checkout/details.html" %}
{% load i18n %}
{% load gross from prices_i18n %}
{% load bootstrap_form from bootstrap3 %}
{% block forms %}
<h3>{% trans "Shipping address" context "Checkout shipping address title" %}</h3>
{% include "userprofile/snippets/address-short.html" with address=checkout.shipping_address only %}
<p>{% trans "Select other address" %}</p>
<hr>
<form method="post" novalidate>
{% csrf_token %}
{% bootstrap_form shipping_method_form show_label=True %}
<p class="text-md-right">
<button type="submit" class="btn primary">
{% trans "Continue" context "Checkout shipping method primary action" %}
</button>
</p>
</form>
{% endblock %}
I believe the problem is that you are instantiating the widget in the field definition. This could cause state to be shared between different fields. Try changing it to:
class ShippingCountryChoiceField(forms.ModelChoiceField):
widget = forms.RadioSelect
...

Django views is it possible to select only the first four elements for a specific model.item?

I have a profile model that is displaying various items.
One of those is the country attached to the profile.
Here is what happen in the view:
class ProfilePartnerListView(FormMixin, BaseProfilePartnerView, ListView):
model = ProfilePartner
context_object_name = 'profile_list'
view_url_name = 'djangocms_partner_profile:profile-list'
def get(self, request, *args, **kwargs):
context = {}
self.object_list = self.get_queryset().order_by('-date_created')
context.update(self.get_context_data(**kwargs))
context[self.context_object_name] = context['object_list']
country_for_articles = Country.objects.exclude(regions_partner_profile=None).order_by('name')
industries_qs = ProfilePartnerIndustry.objects.active_translations(
get_language()).order_by('translations__name')
budget_qs = ProfilePartner.objects.values_list('budget',
flat=True).distinct()
context['load_more_url'] = self.get_load_more_url(request, context)
context['regions_list'] = country_for_articles
context['industry_list'] = industries_qs
context['budget_list'] = budget_qs
return self.render_to_response(context)
I know, for example 'regions_list', how to return only 4 elements from it.
But the thing is, my main object 'profile_list' that I use in the template for the rendering, is displaying all the country of the item when I do:
{% for profile in profile_list %}
{% for country in profile.regions.all %}
<div class="col-xs-12">{{ country }}</div>
{% endfor %}
{% endfor %}
And some of the profiles got 5 or 6 country. I want to only display the first 4.
Is there a way of doing it?
Many thanks!
ps: region_list, industry_list and budget_list are use for categories, it has nothing to do with what I want here.
You could use slice filter for this:
{% for profile in profile_list %}
{% for country in profile.regions.all|slice:":4" %}
<div class="col-xs-12">{{ country }}</div>
{% endfor %}
{% endfor %}

django 1.5: not being able to get the values of variable in view

I am new to django. I have django 1.5. I want to take two variables from one template to some other template. but i am not receiving the value instead just nothing received.
Code of the Template from which i want to send variable as a part of url is:
<div class="tags">
{% for tags1 in document.tags.all %}
{% if tags1.name|length > 0 %}
{% with tags1.name as tagts %}{% endwith %}
{{ tags1.name }}
{% endif %}
{% endfor %}
</div>
Code of the URL where i am calling Second View is:
url(r'^tag_related/(?P<username>[-\w\.#]+)/(?P<tagts>)/$',
tag_related_document,
{'template_name': 'document/tag_related_document.html'},
name = 'tag_related_document'
),
Code of the View tag_related_document is:
def tag_related_document(request, username, tagts, template_name , page_template="userprofile/entry_index_page.html"):
"""
documents Related to tag """
try:
notifications = request.user.notifications.all()[:100]
except AttributeError:
notifications = ""
user = get_object_or_404(User, username = username)
try:
user_profile = user.get_profile()
except UserProfile.DoesNotExist:
messages.error(request, "Profile does not exist.")
return HttpResponseRedirect(reverse('homepage'))
documents = Document.objects.filter( Q(tags__in = user_profile.tags.all()) , date_deleted = None).order_by("-date_added")
if not documents:
documents = Document.objects.filter( date_deleted = None).order_by("?")
related_doc_widget = Document.objects.filter( Q(tags__in = user_profile.tags.all()) , date_deleted = None).order_by('?')
if not related_doc_widget:
related_doc_widget = Document.objects.filter( date_deleted = None).order_by("?")
followers_widget = Felloz.objects.get_followers(user = user_profile.user)
followings_widget = Felloz.objects.get_followings(user = user_profile.user)
# recommendations_widget = UserProfile.objects.filter(Q(~Q(user__in = followings_widget) or ~Q(user = request.user) ) ).order_by('?')
recommendations_widget = UserProfile.objects.filter( tags__in = user_profile.tags.all() ).distinct().exclude(user__in = followings_widget).exclude( user = user )
if not recommendations_widget:
recommendations_widget = UserProfile.objects.filter(~Q( user__in = followings_widget ) ).exclude( user = user ).order_by('?')
ideas_widget = Idea.objects.filter(user = user).order_by('?')
for idea in ideas_widget:
is_substring = "<a" in idea.idea_html
if(is_substring is False):
idea.idea_html = truncate_chars(idea.idea_html,50)
else:
idea.idea_html = htmltruncate.truncate(idea.idea_html,50,ellipsis='')
no_of_documents = len( Document.objects.filter(author = user) )
no_of_ideas = len(Idea.objects.filter(user=user))
try:
slug_status = SlugStatus.objects.get(user=user)
except SlugStatus.DoesNotExist:
slug_status = ''
context = {
'slug_status':slug_status,
'documents': documents,
'page_template': page_template,
'followers_widget': followers_widget,
'followings_widget': followings_widget,
'related_doc_widget': related_doc_widget,
'user': user,
'site': Site.objects.get_current(),
'profile':user_profile,
'recommendations_widget': recommendations_widget,
'no_of_documents':no_of_documents,
'no_of_ideas': no_of_ideas,
'notifications': notifications,
'notifications_unread': request.user.notifications.unread(),
'idea_widget': ideas_widget,
'tagts':tagts,
}
print '=============i m here==================='
print tagts
print '=============i m here==================='
#related_doc_widget = Document.objects.filter(~Q(author = user) and ~Q(tags__in = UserProfile.tags.all())).order_by('?')
#recommendations_widget = UserProfile.objects.filter(~Q(user__in = followings_widget) and ~Q(user = user)).order_by('?')
#documents_newsfeed = Document.objects.filter(Q(author = user) | Q(author__in = followings_widget), date_deleted = None).order_by("-date_added")
if request.is_ajax():
template_name = page_template
return render_to_response(template_name, context, context_instance=RequestContext(request))
return render_to_response(template_name, context, context_instance=RequestContext(request))
The code of the Second Template where i want to show that variable is:
{% if profile.user == request.user %}
<h2 class="mainHeading"> Documents Related To: {{tagts}} </h2>
{% else %}
<h2 class="mainHeading"> Documents Related To: {{tagts}}</h2>
{% endif %}
But i am getting here nothing.... Please help thanks in advance....
You are closing {% with %} before {% url %} so url is being based on empty value, i think it's the reason.
And please, in future avoid posting large pieces of irrelevant code. Shrink it down to minimal amount which is needed to reproduce error.
Should be like this unless the code doesn't resemble the one you posted.
{% for tags1 in document.tags.all %}
{% if tags1.name|length > 0 %}
{% with tags1.name as tagts %}
{{ tags1.name }}
{% endwith %}
{% endif %}
{% endfor %}

Categories

Resources