I output datalist, but output pk. I read that it can be removed in data-value like this https://stackoverflow.com/a/48076273/9653855
How can I rewrite the code so that my datalist is displayed in this format <option data-value="1" value="DjangoOneLove"></option>?
my forms
class ListTextWidget(forms.Select):
template_name = 'include/_forms_orders_datalist.html'
def format_value(self, value):
if value == '' or value is None:
return ''
if self.is_localized:
return formats.localize_input(value)
return str(value)
class ChoiceTxtField(forms.ModelChoiceField):
widget=ListTextWidget()
class SimpleOrderAddForm(forms.ModelForm):
#service = forms.ModelChoiceField(queryset=Service.objects.all(), widget=ListTextWidget())
service = ChoiceTxtField(queryset=Service.objects.order_by('-used'))
class Meta:
model = Orders
fields = ['service']
my forms_orders_datalist.html
<input id="ajax_input_{{ widget.name }}" list="{{ widget.name }}" autocomplete="off"
{% if widget.value != None %} name="{{ widget.name }}" value="{{ widget.value|stringformat:'s' }}"{% endif %}
{% include "django/forms/widgets/attrs.html" %}>
<span class="badge rounded-pill bg-warning text-dark" id="ajax-{{ widget.name }}" name="ajax-{{ widget.name }}"></span>
<datalist id="{{ widget.name }}">
{% for group_name, group_choices, group_index in widget.optgroups %}
{% if group_name %}
<optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
{% include option.template_name with widget=option %}{% endfor %}{% if group_name %}
</optgroup>{% endif %}{% endfor %}
</datalist>
Related
urls.py
urlpatterns = [
path('',CourseList.as_view(),name='course_list'),
path('create/',CourseCreate.as_view(),name='course_create'),
path('<int:cid>/',CourseView.as_view(),name='course_view'),
]
views.py
COURSE_PERM_GUEST = 0
COURSE_PERM_STUDENT = 1
COURSE_PERM_TEACHER = 2
COURSE_PERM_MEMBER = 3
class CourseAccessMixin(AccessMixin):
permission = None
extra_context = {}
def dispatch(self,request,*args,**kwargs):
if not request.user.is_authenticated:
return super().handle_no_permission()
self.course = get_object_or_404(Course,id=kwargs['cid'])
user_perm = COURSE_PERM_GUEST
if self.course.teacher == request.user:
user_perm = COURSE_PERM_TEACHER
elif self.course.enroll_set.filter(student=request.user).exists():
user_perm = COURSE_PERM_STUDENT
if not request.user.is_superuser and self.permission is not None:
is_accessible = False
if self.permission == COURSE_PERM_GUEST and \
user_perm == COURSE_PERM_GUEST:
is_accessible = True
elif (self.permission & user_perm) != 0:
is_accessible = True
if not is_accessible:
return super().handle_no_permission()
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
class CourseView(CourseAccessMixin,DetailView):
extra_context = {'title':'檢視課程'}
model = Course
pk_url_kwarg = 'cid'
models.py
class Course(models.Model):
name = models.CharField('課程名稱',max_length=50)
enroll_password = models.CharField('選課密碼',max_length=50)
teacher = models.ForeignKey(User,models.CASCADE)
def __str__(self):
return '{}#{} ({})'.format(
self.id,
self.name,
self.teacher.first_name)
course_list.html
{% extends "base.html" %}
{% load user_tags %}
{% block content %}
{% if user|is_teacher %}
<div class="mb-2">
建立課程
</div>
{% endif %}
<div id="course_list">
{% for course in course_list %}
<div class="list-group">
<div class="list-group-item d-flex">
{% if user.is_authenticated %}
{{ course.name }}
{% else %}
{{ course.name }}
{% endif %}
<small class="ml-auto">{{ course.teacher.first_name }} 老師</small>
</div>
</div>
{% endfor %}
</div>
{% include 'pagination.html' %}
{% endblock %}
course_detail.html
{% extends 'base.html' %}
{% load user_tags %}
{% block content %}
<div id="course_view" class="card">
{% with b1 = "btn btn-sm btn-primary" b2 = "btn btn-sm btn-secondary" %}
<div class="card-header d-flex">
<div>
{{ course.name }}
<small>{{ course.teacher.first_name }} 老師</small>
</div>
{% if user.is_superuser or course.teacher == user %}
<div class="ml-auto">
<span class="badge badge-light">
選課密碼: {{ course.enroll_password }}
</span>
<a href="{% url 'course_edit' course.id %}" class="{{ b1 }}">
<i class="fas fa-edit"></i>編輯
</a>
</div>
{% endif %}
</div>
<div class="card-body">
{% block course_detail_body %}
<div id="student_op" class="btn-group">
{% if not course|has_member:user and not user.is_superuser %}
<a href="{% url 'course_enroll' course.id %}" class="{{ b1 }}">
<i class="fas fa-id-badge"></i>選修
</a>
{% else %}
<a href="{% url 'course_users' course.id %}" class="{{ b1 }}">
<i class="fas fa-users"></i>修課名單
</a>
{% if course|has_student:user %}
<a href="{% url 'course_seat' course.id %}" class="{{ b1 }}">
<i class="fas fa-chair"></i>更改座號
</a>
{% endif %}
{% endif %}
</div>
{% endblock %}
</div>
{% endwith %}
</div>
{% endblock %}
Error:
ValueError at /course/1/
The view course.views.CourseView didn't return an HttpResponse object. It returned None instead.
I had a view CourseView and when I try to access the detail of the corresponding course by clicking the hyperlink {{ course.name }} from the template course_list.html, I received the error message showing that it didn't return an HttpResponse object. I do not know what is missing in order to have the details accessible even though I had set the pk_url_kwarg?
You forget to add return super().dispatch(request,*args,**kwargs) and the end of dispatch function (you add it, only in if condition)
change this
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
To this:
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
return super().dispatch(request,*args,**kwargs)
views.py
def create(request):
choicenumber = 3
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if choicebutton:
choicenumber += 1
render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
I recently added the add_choice button to my template:
<input type="button" name="add_choice" value="Add choice">
Using this, I tried using a request.POST.get() to check if it has been clicked, and if so for it to increment 'choicenumber' and re-render the view with the increased value of choicenumber:
if choicebutton:
choicenumber += 1
return render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
Since the increment causes choicenumber to increase, within the create.html the for loop for producing the input boxes for each choice --
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
-- should loop once more than usual on the re-render. This does not happen however, and the website renders as originally.
Does anyone know how to make this work properly or improve my code? I am very new to the Django framework, so any advice would be great. Thanks!
EDIT::
updated views.py
def create(request):
choicenumber = 3
context = {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
}
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if request.method == 'GET':
request.session['choicenumber'] = 0
if request.method == 'POST':
if choicebutton:
request.session['choicenumber'] += 1
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
EDIT 2::
updated create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in {{ request.session.choicenumber }}|rangeof %}
# the update is here: choicenumber -> {{ request.session.choicenumber }}
# this defaults as 0 though, even if it is defined as 3.
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
I am working with a CreateView. When sending my form with all fields properly filled out, the field tickets (ManyToMany field) is also saved. However if I POST my form with some validation error (e.g. required field empty), then all the pre-filled fields are still field through request.POST. However, my pre-checked fields are not selected anymore. Do you know why?
Demonstration
view.py
class DiscountCreate(AdminPermissionRequiredMixin, SuccessMessageMixin,
FormValidationMixin, BaseDiscountView, CreateView):
form_class = DiscountForm
template_name = 'discounts/admin/create.html'
success_message = _("Discount Code has been successfully created.")
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['event'] = self.request.event
return kwargs
def get_success_url(self):
return reverse('discounts:admin:detail', kwargs={
'organizer': self.request.organizer.slug,
'event': self.request.event.slug,
'discount': self.instance.pk
})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['type_fixed'] = Discount.TYPE_FIXED
context['type_percentage'] = Discount.TYPE_PERCENTAGE
return context
def form_valid(self, form):
self.instance = form.save(commit=False)
self.instance.event = self.request.event
self.instance.status = Discount.STATUS_ACTIVE
return super().form_valid(form)
Template
<div class="card">
<div class="card-header">
<h4 class="card-header-title">
{% trans "Creating Discount Code" %}
</h4>
</div>
<div class="card-body">
<form method="post" autocomplete="off" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="{{ form.code.id_for_label }}">
{{ form.code.label }}
</label>
{{ form.code }}
{% if form.code.errors %}
<div class="invalid-feedback d-block">
{{ form.code.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.type.id_for_label }}">
{{ form.type.label }}
</label>
{{ form.type }}
{% if form.type.errors %}
<div class="invalid-feedback d-block">
{{ form.type.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group fixed{% if form.type.value != type_fixed %} d-none {% endif %}">
{{ form.value.label_tag }}
<div class="input-group">
{{ form.value }}
<div class="input-group-append">
<span class="input-group-text text-dark">{{ request.event.currency }}</span>
</div>
</div>
{% if form.value.errors %}
<div class="invalid-feedback d-block">
{{ form.value.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group percentage{% if form.type.value != type_percentage %} d-none {% endif %}">
{{ form.percentage.label_tag }}
<div class="input-group">
{{ form.percentage }}
<div class="input-group-append">
<span class="input-group-text text-dark">%</span>
</div>
</div>
{% if form.percentage.errors %}
<div class="invalid-feedback d-block">
{{ form.percentage.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
{{ form.available_amount.label_tag }}
{{ form.available_amount }}
{% if form.available_amount.errors %}
<div class="invalid-feedback d-block">
{{ form.available_amount.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.tickets.id_for_label }}">
{{ form.tickets.label }}
<span class="badge badge-light">{% trans "Optional" %}</span>
</label>
<small class="form-text text-muted mt--2">{{ form.tickets.help_text }}</small>
{% for ticket_id, ticket_label in form.tickets.field.choices %}
<div class="custom-control custom-checkbox">
<input
type="checkbox"
name="{{ form.tickets.html_name }}"
value="{{ ticket_id }}"
class="custom-control-input"
id="id_{{ form.tickets.html_name }}_{{ forloop.counter }}"
{% if ticket_id in form.tickets.value %}checked{% endif %}>
<label class="custom-control-label" for="id_{{ form.tickets.html_name }}_{{ forloop.counter }}">{{ ticket_label }}</label>
</div>
{% endfor %}
{% if form.tickets.errors %}
<div class="invalid-feedback d-block">
{{ form.tickets.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.valid_from.id_for_label }}">
{{ form.valid_from.label }}
<span class="badge badge-light">{% trans "Optional" %}</span>
</label>
<small class="form-text text-muted mt--2">{{ form.valid_from.help_text }}</small>
{{ form.valid_from }}
{% if form.valid_from.errors %}
<div class="invalid-feedback d-block">
{{ form.valid_from.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.valid_until.id_for_label }}">
{{ form.valid_until.label }}
<span class="badge badge-light">{% trans "Optional" %}</span>
</label>
<small class="form-text text-muted mt--2">{{ form.valid_until.help_text }}</small>
{{ form.valid_until }}
{% if form.valid_until.errors %}
<div class="invalid-feedback d-block">
{{ form.valid_until.errors|first }}
</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.comment.id_for_label }}">
{{ form.comment.label }}
<span class="badge badge-light">{% trans "Optional" %}</span>
</label>
<small class="form-text text-muted mt--2">{{ form.comment.help_text }}</small>
{{ form.comment }}
{% if form.comment.errors %}
<div class="invalid-feedback d-block">
{{ form.comment.errors|first }}
</div>
{% endif %}
</div>
<button type="submit" class="btn btn-primary btn-block">{% trans "Create Discount Code" %}</button>
</form>
</div>
</div> {# / .card #}
<a class="btn btn-block btn-link text-muted mb-4" href="{% url 'discounts:admin:index' request.organizer.slug request.event.slug %}">
{% trans "Cancel discount code creation" %}
</a>
forms.py
class DiscountForm(forms.ModelForm):
# Remove required attribute from HTML elements
use_required_attribute = False
value = forms.DecimalField(decimal_places=2, required=False)
percentage = forms.DecimalField(max_digits=4, decimal_places=2, required=False)
class Meta:
model = Discount
fields = (
'code',
'type',
'value',
'percentage',
'available_amount',
'tickets',
'valid_from',
'valid_until',
'comment',
)
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event')
super().__init__(*args, **kwargs)
for visible_field in self.visible_fields():
visible_field.field.widget.attrs['class'] = 'form-control'
self.fields['tickets'].queryset = self.event.tickets.all()
self.fields['code'].widget.attrs['autofocus'] = True
self.fields['valid_from'].widget.attrs['class'] = 'form-control start-date picker'
self.fields['valid_until'].widget.attrs['class'] = 'form-control end-date picker'
self.fields['valid_from'].widget.format = settings.DATETIME_INPUT_FORMATS[0]
self.fields['valid_until'].widget.format = settings.DATETIME_INPUT_FORMATS[0]
self.fields['valid_from'].widget.attrs['data-lang'] = get_lang_code()
self.fields['valid_until'].widget.attrs['data-lang'] = get_lang_code()
def clean(self):
cleaned_data = super().clean()
discount_type = cleaned_data.get('type')
if discount_type:
if discount_type == Discount.TYPE_FIXED:
value = cleaned_data.get('value')
cleaned_data['percentage'] = None
if not value:
message = _("Please enter how much discount you want to give.")
self.add_error('value', forms.ValidationError(message))
if discount_type == Discount.TYPE_PERCENTAGE:
percentage = cleaned_data.get('percentage')
cleaned_data['value'] = None
if not percentage:
message = _("Please enter how much discount you want to give.")
self.add_error('percentage', forms.ValidationError(message))
def clean_value(self):
value = self.cleaned_data['value']
if value:
value = smallest_currency_unit_converter(
value,
self.event.currency,
)
return value
def clean_percentage(self):
percentage = self.cleaned_data['percentage']
if percentage:
percentage /= 100 # convert 19 to 0.19
return percentage
def clean_valid_until(self):
valid_until = self.cleaned_data['valid_until']
if valid_until and valid_until > self.event.end_date:
valid_until = self.event.end_date
return valid_until
def clean_valid_from(self):
valid_from = self.cleaned_data['valid_from']
if valid_from and valid_from > self.event.end_date:
raise forms.ValidationError(_("Discount code should become valid \
before the event starts."), code='valid_from')
return valid_from
def clean_code(self):
code = self.cleaned_data['code']
code_check = self.event.discounts.filter(
code=code
).exclude(pk=self.instance.pk).exists()
if code_check:
raise forms.ValidationError(_("The code you chose as your discount code \
already exists for this event. Please change it."), code='code_exists')
return code
After I broke the problem down, the final solution that helped me can be found here: Django template: {% if 5 in ['4', '3', '5'] %} doesn't work
I am having trouble understanding code of website in tutorial. what i understood is that urls.py take a argument as product_slug which is used to get object in my show_product view and another argument is used in as template_name
but what is argument 'catalog_product' doing it is defined in my model.when I remove 'catalog_product' I get error as:
no reverse match at /category/guitar
please explain how does this argument get_absolute_url work and how and where I can use it?
model.py is:
def get_absolute_url(self):
return reverse('catalog_product', (), { 'product_slug': self.slug })
I am having uurls.py as:
url(r'^product/(?P<product_slug>[-\w]+)/$',show_product, {'template_name':'catalog/product.html'}, 'catalog_product')
and views.py:
def show_product(request, product_slug, template_name="catalog/product.html"):
p = get_object_or_404(Product, slug=product_slug)
categories = p.categories.filter(is_active=True)
page_title = p.name
meta_keywords = p.meta_keywords
meta_description = p.meta_description
return render(request, template_name, locals())
template product.html :-
% extends "catalog.html" %}
{% block content %}
<div class="product_image" >
{% load static %}
<img src="{% static 'images/products/main/{{ p.image}}' %}" alt="{{ p.name }}" />
</div>
<h1>{{ p.name }}</h1>
Brand: <em>{{ p.brand }}</em>
<br /><br />
SKU: {{ p.sku }}
<br />
In categor{{ categories.count|pluralize:"y,ies" }}:
{% for c in categories %}
{{ c.name }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
<br /><br />
{% if p.sale_price %}
Was: <del>$ {{ p.old_price }}</del>
<br />
Now: $ {{ p.price }}
{% else %}
Price: $ {{ p.price }}
{% endif %}
<br /><br />
[add to cart button]
<br /><br />
<div class="cb"><br /><br /></div>
<h3>Product Description</h3>
{{ p.description }}
{% endblock %}
I can't understand, why this code is not work:
{% set t_c = 'param_1' %}
<div class="col-sm-9">
<select id="category" name="category" class="form-control " required>
<option></option>
{% for c in categories %}
{% if c.id|string == org.category.id %}
{% set t_c = 'param9' %}
<option value="{{ c.id }}" selected>{{ c.name }} </option>
{% else %}
<option value="{{ c.id }}">{{ c.name }} </option>
{% endif %}
{% endfor %}
</select>
</div>
<input id="category_h" name="category_h" type="hidden" value="{{ t_c }}">
Why t_c in last line is 'param_1', when condition {% if c.id|string == org.category.id %} is true?
Thanks.
UPDATE
I have fast solution on JavaScript with jQuery+Select2 like:
var category = $("#category"),
category_h = $("#category_h");
category.select2();
category_h.val(category.find("option:selected").text());
t_c = 'param9' is local to the scope of the for loop
There are workarounds to extend beyond inner block scope