I have a model
class Car(models.Model):
class ModelChoise(models.IntegerChoices):
Model_1 = 0
Model_2 = 1
Model_3 = 2
Model_4 = 3
name = models.TextField('Name')
model_id = models.IntegerField('model id', choices=ModelChoise.choices, default=1)
def __str__(self):
return self.name
And I created a form for it
class CarForm(ModelForm):
class Meta:
model = Car
fields = ['model_id']
I need to deduce both key and value from it
{% for mykey,myvalue in form.model_id %}
{{ mykey }} : {{ myvalue }}
{% endfor %}
<!--
Model_1 : 0
Model_2 : 1
Model_3 : 2
Model_4 : 3
-->
How should I do it? I can only get the key.
I'm not sure why in the CarForm you point to the model ExtraUser... model_id seems to be a field in your Car model so I don't know why you reference it in a form pointing to a different model..
However when dealing with choices in templates you can go about it like this:
{{ object.get_model_id_display }}
Basically get_ + field_name + _display will return the choice value
I have two fields in my django db which called like and dislike. I want to pass I need to pass the average of these two values to the template to be used as the width of <div style="width:x%">.
in views.py:
def PostListView(request):
posts = Post.objects.all()
context['posts'] = posts
return render(request, 'app/mytemplate.html', context)
and in template:
{% for post in posts %}
<div class="ratings-css-top" style="width: {% widthratio post.like post.dislike 100 %}">
</div>
{% endfor %}
how to pass this average value of fields as a width? like % (like + dislike ) * 100
You can .annotate() [Djanog-doc] the queryset with:
from django.db.models import F
def PostListView(request):
posts = Post.objects.annotate(
total_like=F('like') + F('dislike')
)
context['posts'] = posts
return render(request, 'app/mytemplate.html', context)
The Post objects that arise from this queryset will have an extra attribute .total_like that is the sum of .like and .dislike. We can then use this in the template:
<div style="width: {% widthratio post.like post.total_like 100 %}%" class="ratings-css-top">
I have a list of entries which are displayed in a webpage. Each entry has the same input form. But my problem arises when data is put into the input form, it appears on every single one of them. How do I change this.
Each input form is treated as a single cloned entity distributed over many entries.
views.py
def topic(request, topic_id, type): #
topic = Topic.objects.get(id = topic_id, type = 't_topic')
entries = topic.entry_set.order_by('-date_added')
images = Image.objects.filter(imgtopic__in = entries)
ArticleFormSet = formset_factory(CheckAnswer, extra = 2)
if request.method == 'POST':
formset = ArticleFormSet(request.POST)
if form.is_valid():
return HttpResponseRedirect(reverse('learning_logs:index'))
else:
formset = ArticleFormSet()
context = {'topic': topic, 'entries': entries, 'images': images, 'formset': formset}
return render(request, 'learning_logs/topic.html', context)
topic.html template
{%load staticfiles %}
{% block content %}
{% for entry in entries(n) %}
<div class = 'secondary-container'>
<li>
<div class = 'date'>
<p >{{ entry.date_added|date:'M d, Y H:i'}}</p>
</div>
{%include 'learning_logs/view_files.html'%}
<div class = 'video-container'>
{%include 'learning_logs/video.html' %}
</div>
<div class = 'entry-text'>
<p>{{ entry.text|linebreaks }}</p>
<p>$ {{entry.price_set.get.ptext}}</p>
</div>
</li>
<li>
<p> Enter Answer: </p>
<form action = "{%url 'learning_logs:topic' topic.id topic.type%}" method = 'post'>
{{formset.management_form}}
<table>
{% for form in formset%}
{{form.as_p}}
{% csrf_token %}
<button name = "submit">Submit answer</button>
{% endfor %}
</table>
</form>
</div>
forms.py
class CheckAnswer(forms.Form):
your_answer = forms.CharField(label = "Enter Your Key", max_length = 100)
def clean(self):
cleaned_data=super(CheckAnswer, self).clean()
your_answer = cleaned_data.get("your_answer")
try:
p = Keys.objects.get(key = your_answer)
except Keys.DoesNotExist:
raise forms.ValidationError("Incorrect code.")
My new problem is that I can't separate the forms into the different lists. Since extra = 2, I get 2 instances of forms on the same entry list.
I tried using the {%for form in formset%} command in the topic.html template to give each entry a form, but I get an of ['ManagementForm data is missing or has been tampered with'] when I click submit.
Image of the problem
I am having issues with a seemingly simple sqlalchemy query using Flask.
I have a table called Links and within that table there are columns called 'id', 'author_id', 'link', and 'group'. My models.py looks like this:
class Links(db.Model):
__tablename__='links'
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
link = db.Column(db.String, unique=False, nullable=True)
group = db.Column(db.String, unique=False, nullable=False)
def __init__(self, author_id=None, link=None, group=None):
self.author_id = author_id
self.link = link
self.group = group
def __repr__(self):
return'<Link %r>' %(self.link)
I would like to return the values of all groups associated with the user that is logged into the application. Here is my views.py file:
#app.route('/members/', methods=['GET','POST'])
#login_required
def members():
error=None
form = PostLink(request.form, csrf_enabled = False)
uid = session['user_id']
link = "NULL"
groups = Links.query.filter_by(author_id=uid).all()
if request.method=='POST':
if form.validate_on_submit():
new_group = Links(
uid,
form.group.data,
link,
)
try:
db.session.add(new_group)
db.session.commit()
flash("You have created a group!")
except IntegrityError:
error = 'That group did not work, maybe it already exists?'
else:
flash_errors(form)
return render_template('members.html', form=form, error=error, link = link, groups=groups)
And my 'members.html':
{% extends "base.html" %}
{% block content %}
<p>Add New Group: {{ form.group }}</p>
<input id="link" type="hidden" name="link" value= {{ link }}/>
<p><input type="submit" value="Request"></p>
</form>
<br/>
{% for group in groups %}
<li><p>
{{ group }}
</p></li>
{% endfor %}
{% endblock %}
Currently this is just returning a list of links and groups in an odd format:
<Link u'link2'>
<Link u'linky'>
<Link u'linkymaybe'>
<Link u'madeit'>
<Link u'BLAH'>
So the core of my question is how do I build a query using SQLAlchemy to display all groups associated with the logged in user (uid = session['user_id']) I am pretty new to Flask and this problem is becoming an issue as I have tried a number of filter_by and filter statements with no luck at all.
Thank you in advance!
It is displaying correctly the object "Link" returned by the query.
You need to format it in the template.
Thisi is link {{ group.link }} from author #{{ group.author_id }} in group named {{ group.group }}
Maybe you've chosen a bad name "group" when cycling on results in the template. It should be called link.
In the template, you can show the group name using {{ link.group }} instead of {{ link }}. The query is returning the whole object.
I would like to filter data in Django (admin.py) with text writen in HTML input textbox. I need to filter companies by city in which they are and list of all cities is too long. I would like to replace list of all cities in filter by one text input. I found something similar
here http://djangosnippets.org/snippets/2429/ but there are two problems:
author did not posted models.py, so it is difficuilt to change code for my needs (+ no comments)
there is used class UserFieldFilterSpec(RelatedFilterSpec): but I need to use AllValuesFilterSpec instead of RelatedFilterSpec (more in file django/contrib/admin/filterspecs.py), because list of towns are in the same class as comapny (there shoud by class of towns and they should be referencing to company by foreign key (ManyToMany relationship), but for some reasons it have to be done this way)
important part of models.py looks something like this
class Company(models.Model):
title = models.CharField(max_length=150,blank=False)
city = models.CharField(max_length=50,blank=True)
and something from admin.py
class CatalogAdmin(admin.ModelAdmin):
form = CatalogForm
list_display = ('title','city')
list_filter = ['city',]
So again, I need to:
1. instead of list od cities display one text input in Django filter
2. After inputing city neme in that text input, filter data by city (request for filtering can be sent with some submit button or through javascript)
Thank yoy for all posts.
In case anybody still need this. It is little hackish in template, but implemented without a piece of js.
filters.py:
from django.contrib.admin import ListFilter
from django.core.exceptions import ImproperlyConfigured
class SingleTextInputFilter(ListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, request, params, model, model_admin):
super(SingleTextInputFilter, self).__init__(
request, params, model, model_admin)
if self.parameter_name is None:
raise ImproperlyConfigured(
"The list filter '%s' does not specify "
"a 'parameter_name'." % self.__class__.__name__)
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice = {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [self.parameter_name]),
'display': _('All'),
}
return ({
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
}, )
templates/admin/textinput_filter.html:
{% load i18n %}
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
{#i for item, to be short in names#}
{% with choices.0 as i %}
<ul>
<li>
<form method="get">
<input type="search" name="{{ i.parameter_name }}" value="{{ i.current_value|default_if_none:"" }}"/>
{#create hidden inputs to preserve values from other filters and search field#}
{% for k, v in i.get_query.items %}
{% if not k == i.parameter_name %}
<input type="hidden" name="{{ k }}" value="{{ v }}">
{% endif %}
{% endfor %}
<input type="submit" value="{% trans 'apply' %}">
</form>
</li>
{#show "All" link to reset current filter#}
<li{% if i.all_choice.selected %} class="selected"{% endif %}>
<a href="{{ i.all_choice.query_string|iriencode }}">
{{ i.all_choice.display }}
</a>
</li>
</ul>
{% endwith %}
Then according to your models in admin.py:
class CatalogCityFilter(SingleTextInputFilter):
title = 'City'
parameter_name = 'city'
def queryset(self, request, queryset):
if self.value():
return queryset.filter(city__iexact=self.value())
class CatalogAdmin(admin.ModelAdmin):
form = CatalogForm
list_display = ('title','city')
list_filter = [CatalogCityFilter,]
Ready to use filter would look like this.
I'm running Django 1.10, 1.11 and r_black's solution didn't completely fit because Django was complaining that filter fields must inherit from 'FieldListFilter'.
So a simple change for the filter to inherit from FieldListFilter took care of Django complaining and not having to specify a new class for each field, both at the same time.
class SingleTextInputFilter(admin.FieldListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, field, request, params, model, model_admin, field_path):
super().__init__(field, request, params, model, model_admin, field_path)
if self.parameter_name is None:
self.parameter_name = self.field.name
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def queryset(self, request, queryset):
if self.value():
return queryset.filter(imei__icontains=self.value())
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice = {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [self.parameter_name]),
'display': _('All'),
}
return ({
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
}, )
templates/admin/textinput_filter.html (unchanged):
{% load i18n %}
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
{#i for item, to be short in names#}
{% with choices.0 as i %}
<ul>
<li>
<form method="get">
<input type="search" name="{{ i.parameter_name }}" value="{{ i.current_value|default_if_none:"" }}"/>
{#create hidden inputs to preserve values from other filters and search field#}
{% for k, v in i.get_query.items %}
{% if not k == i.parameter_name %}
<input type="hidden" name="{{ k }}" value="{{ v }}">
{% endif %}
{% endfor %}
<input type="submit" value="{% trans 'apply' %}">
</form>
</li>
{#show "All" link to reset current filter#}
<li{% if i.all_choice.selected %} class="selected"{% endif %}>
<a href="{{ i.all_choice.query_string|iriencode }}">
{{ i.all_choice.display }}
</a>
</li>
</ul>
{% endwith %}
Usage:
class MyAdmin(admin.ModelAdmin):
list_display = [your fields]
list_filter = [('field 1', SingleTextInputFilter), ('field 2', SingleTextInputFilter), further fields]
While it's not actually your question, this sounds like a perfect solution for Django-Selectables you can with just a few lines add an AJAX powered CharField Form that will have it's entries selected from the list of cities. Take a look at the samples listed in the link above.
Below is the fix for field name..in queryset function
class SingleTextInputFilter(admin.FieldListFilter):
"""
renders filter form with text input and submit button
"""
parameter_name = None
template = "admin/textinput_filter.html"
def __init__(self, field, request, params, model, model_admin, field_path):
super().__init__(field, request, params, model, model_admin, field_path)
if self.parameter_name is None:
self.parameter_name = self.field.name
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
def queryset(self, request, queryset):
variable_column = self.parameter_name
search_type = 'icontains'
filter = variable_column + '__' + search_type
if self.value():
return queryset.filter(**{filter: self.value()})
def value(self):
"""
Returns the value (in string format) provided in the request's
query string for this filter, if any. If the value wasn't provided then
returns None.
"""
return self.used_parameters.get(self.parameter_name, None)
def has_output(self):
return True
def expected_parameters(self):
"""
Returns the list of parameter names that are expected from the
request's query string and that will be used by this filter.
"""
return [self.parameter_name]
def choices(self, cl):
all_choice = {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [self.parameter_name]),
'display': ('All'),
}
return ({
'get_query': cl.params,
'current_value': self.value(),
'all_choice': all_choice,
'parameter_name': self.parameter_name
}, )