In my Django App, I wrote a form with a forms.ChoiceField . The choice should be a list of items that are changing every couple of minutes in my DB. I would like to have the current list of items in a drop-down button when I reload the page.
My code works good except the forms.ChoiceField does not update. To update I have to restart the Django server.
I don't know what i am missing, Can you help me ? It must be something small.
from forms.py
class BookingForm(forms.ModelForm):
make_list_of_tuple = lambda list_machine : [tuple( [i,i]) for i in list_machine]
MACHINES= tuple( QA_machine_DB.objects.values_list('QAmachine',flat=True))
CHOICE_QA_MACHINES= make_list_of_tuple(MACHINES)
QAmachine= forms.ChoiceField(choices=CHOICE_QA_MACHINES)
class Meta():
model= QA_machine_DB
fields= ['QAmachine', 'owner', 'comments','status']
# http://nanvel.name/2014/03/django-change-modelform-widget
widgets = {
'owner':forms.TextInput(attrs={'placeholder':'owner'}),
'comments':forms.TextInput(attrs={'placeholder':'comments'}),
'status': forms.RadioSelect( choices=[('busy','busy'),('free','free')])}
from the template
<form class="form-group" method="post" novalidate >
{% csrf_token %}
<table >
<td>
{{ BookingForm.QAmachine}}
</td>
<td>
{{ BookingForm.owner.errors }}
{{ BookingForm.owner}}
</td>
<td>
{{ BookingForm.comments.errors }}
{{ BookingForm.comments}}
</td>
<td>
{% for radio in BookingForm.status %}
{{ radio }}
{% endfor %}
</td>
</table>
<input type="submit" class="btn btn-success" value="submit status change" style="float: right;" >
Tank you in Adavance
No, anything defined at class level will only be evaluated once, when the class is first imported.
You could do this in the __init__ method, but a better approach is to use the field that is meant for getting choices from querysets: ModelChoiceField.
Related
Django-ckeditor in for loop shows correctly only for the first iteration. For the remaining iterations, the default template form appears as shown below. I see element conflict error in the documentation but it doesn't say anything how to solve. ckeditor.js:21 [CKEDITOR] Error code: editor-element-conflict. Thank you in advance!
Here is my template code
<div class="d-none" id="comment-{{answer.id}}" >
{% for comment in answer.comment_set.all %}
<div class="card mb-2" >
<div class="card-body">
<p>{{comment.comment|safe}}</p>
<p> {{comment.user.username}} </p>
</div>
</div>
{% endfor %}
</div>
<div class="d-none" id="commentForm-{{answer.id}}">
{% if user.is_authenticated %}
<div class="commentform">
<form method="post">
<div class="form-group">
{% csrf_token %}
{{ commentForm.media }}
{{commentForm|crispy}}
<input type="hidden" name="answerid" value="{{ answer.id }}">
<input type="submit" name="submit" value="Submit" >
</div>
</form>
</div>
{% endif %}
I've figured out!
It happens because fields have the same ID, and CKEditor gets confused because it finds a few elements with the same ID.
Solution: change IDs dynamically when the page is being generated.
I don't know the structure of your model, but I can assume that your form is defined like this:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = “__all__”
Then you need to change it like this:
from ckeditor.widgets import CKEditorWidget
class CommentForm(forms.ModelForm):
base_textarea_id = "id_comment"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.textarea_id_counter = 0
self.fields['comment'].widget = CKEditorWidget(attrs={'id': self.get_textarea_next_id})
def get_textarea_next_id(self):
result = self.base_textarea_id + str(self.textarea_id_counter)
self.textarea_id_counter += 1
return result
class Meta:
model = Comment
fields = “__all__”
If I were you, I would make the form variable name using snake case and would change the name of the field "comment" inside the Comment model to something different (even "text" would be better), but it's up to you, of course.
I have a problem with trying to get a response from my HTML page using Django (admin).
I have a pretty simple div = contenteditable and need to pass data from this div back after the submit button was clicked.
Everything, including choosing selection and opening the intermediate page works fine. But when I tapped submit button, the condition if "apply" in request.POST failed to work.
Please, tell me, what I'm doing wrong?
This is my Django admin:
class QuestionAdmin(AnnotatesDisplayAdminMixin, admin.ModelAdmin):
def matched_skills(self, question):
return ', '.join(s.name for s in question.skills.all())
def update_skills(self, request, queryset):
if 'apply' in request.POST:
print("something")
skills = []
for question in queryset:
skills.append(self.matched_skills(question))
return render(request,
'admin/order_intermediate.html',
context={'skills': skills})
update_skills.short_description = "Update skills"
This is my order_intermediate.html page:
{% extends "admin/base_site.html" %}
{% block content %}
<form method="post">
{% csrf_token %}
<h1>Adjust skills. </h1>
{% for skill in skills %}
<div>
<div id="title" style="margin-left: 5px" contenteditable="true" > {{ skill }} </div>
</div>
{% endfor %}
<input type="hidden" name="action" value="update_status" />
<input type="submit" name="apply" value="Update skills"/>
</form>
{% endblock %}
Actually, request.POST is an HttpRequest object. For getting available keys in the body of the request, you need to use "request.POST.keys()" method. So, you can simply change your condition to:
if 'apply' in request.POST.keys():
print("something")
In my knowledge, you can not send div content with form submit. However you can use input tag with array in name attribute for this. This will send an array as post variable when submit
First, send skills as a enumerate object from your views
return render(request, 'admin/order_intermediate.html', context={'skills': enumerate(skills)})
Then edit your html to this (Note: if you have css in title id, change it to title class)
{% for i,skill in skills %}
<div>
<input class="title" name="skill[{{ i }}]" value="{{ skill }}" style="margin-left: 5px">
</div>
{% endfor %}
and handle array with any action you want to perform in update_skills()
for skill in request.POST.getlist('skill[]'):
# your code
I have the following models defined:
class Item(models.Model):
rfid_tag = models.CharField()
asset = models.OneToOneField('Assets', default=None, null=True,
on_delete=models.SET_DEFAULT,)
date = models.DateTimeField(name='timestamp',
auto_now_add=True,)
...
class Assets(models.Model):
id = models.AutoField(db_column='Id', primary_key=True)
assettag = models.CharField(db_column='AssetTag', unique=True, max_length=10)
assettype = models.CharField(db_column='AssetType', max_length=150)
...
class Meta:
managed = False
db_table = 'Assets'
ordering = ['assettag']
def __str__(self):
return f"{self.assettag}"
def __unicode__(self):
return f"{self.assettag}"
For which I have created the following form and formset:
class ItemDeleteForm(forms.ModelForm):
asset = forms.CharField(required=True,
help_text= "Item asset tag",
max_length=16,
label="AssetTag",
disabled=True,
)
delete = forms.BooleanField(required=False,
label="Delete",
help_text='Check this box to delete the corresponding item',
)
class Meta:
model = Item
fields = ['asset']
ItemDeleteMultiple = forms.modelformset_factory(model=Item,
form=ItemDeleteForm,
extra=0,
)
managed by the view:
class DeleteMultipleView(generic.FormView):
template_name = '*some html file*'
form_class = ItemDeleteMultiple
success_url = reverse_lazy('*app_name:url_name*')
def form_valid(self, form):
return super().form_valid(form)
And rendered in the template:
{% extends "pages/base.html" %}
{% block title %}
<title>Delete Multiple</title>
{% endblock %}
{% block content %}
<h1>Delete Multiple Items</h1>
<br>
<form class="ManualForm" action ="." method="POST"> {% csrf_token %}
{{ form.management_form }}
<table border="2">
<tr><th colspan="3" scope="row">Select Items to Delete</th></tr>
{% for item_form in form %}
<tr>
<td><label for="{{ item_form.asset.id_for_label }}">AssetTag {{forloop.counter}}:</label>
{% if item_form.non_field_errors %}
{{ item_form.non_field_errors }}
{% endif %}
{% if item_form.asset.errors %}
{{item_form.asset.errors}}
{% endif %}
</td>
<td>{{item_form.asset}}</td>
<td>{{item_form.delete}}
{% if item_form.delete.errors %}
{{item_form.delete.errors}}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
<form class="AutoForm" action ="." method="POST"> {% csrf_token %}
{{form.as_table}}
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
{% endblock %}
When I submit AutoForm, everything is great. It takes me to app_name:url_name, but if I sumbit ManualForm I don't get redirected. It will simply clear all data and reload the form page with empty fields.
The HTTP POST response status code for AutoForm is 302, while for ManualForm is 200.
I don't understand how the template could influence the behavior of the url redirection. What am I doing wrong in the manual rendering of the formset?
It seems that adding:
{% for field in item_form.hidden_fields %}
{{field}}
{% endfor %}
under {% for item_form in form %} will solve the issue.
I didn't understand very well from the docs:
Looping over hidden and visible fields
If you’re manually laying out a form in a template, as opposed to
relying on Django’s default form layout, you might want to treat
< input type="hidden"> fields differently from non-hidden fields. For
example, because hidden fields don’t display anything, putting error
messages “next to” the field could cause confusion for your users – so
errors for those fields should be handled differently.
I just thought this is about errors, so I didn't care. But one of the first thing it says about forms is this:
As an example, the login form for the Django admin contains several
< input> elements: one of type="text" for the username, one of
type="password" for the password, and one of type="submit" for the
“Log in” button. It also contains some hidden text fields that the
user doesn’t see, which Django uses to determine what to do next.
It also tells the browser that the form data should be sent to the URL
specified in the < form>’s action attribute - /admin/ - and that it
should be sent using the HTTP mechanism specified by the method
attribute - post.
Maybe it will help someone else.
I've made the sudoku generator and the templates, but now I stuck in posting the whole array(9x9) to Django (i.e. sudoku_checker) for checking the duplicates and determine whether the user can go next game.
Here is my template looks like in Django, and you'll see I've indexed/positioned every single table cell, thought it might help with later checking:
<table>
<caption>Sudoku of the day</caption>
{% for row in numbers %}
<tr>
{% for col in row %}
{% if col is 0 %}
<td>
<input class="d0" size="1" autocomplete="off" maxlength="1" name="{{ forloop.parentloop.counter0 }}{{ forloop.counter0 }}">
</td>
{% else %}
<td id="{{ forloop.parentloop.counter0 }}{{ forloop.counter0 }}">{{ col }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
<button class="btn btn-primary" type="submit">Submit</button>
but then what should I do next? Am I correct to use Form method to Post the data to Django? But how can i make sure all the data have been bundled up when passing through for checking, in terms of both the known numbers and unknown numbers(input by users)? any hints please?
This is the code of the views, but i only completed the numbers_fill_table one, i dont know what to write in second part of views and forms properly to post the exact data i want. Please help!
from .sudoku_generator import sudoku_generator
def board_fill(request):
context = {'numbers': sudoku_generator.final_board()}
template = 'sudoku_board.html'
return render(request, template, context)
When you have the view (you must map it to the url that is used as the form target) it gets the request object. From there you can read the user input:
request.POST.get('44', 0) # Will return 0 if 44 is not found
More hint about writing a view: https://docs.djangoproject.com/en/2.1/topics/http/views/ and mapping the view to the url: https://docs.djangoproject.com/en/2.1/topics/http/urls/
I'm making a simple blog for myself in Django, but having a strange issue. I have a simple model as shown below:
Entry:
- title
- content
This is the template I'm currently using:
{% for entry in context.entries %}
<div class="row">
<div class="col-xl-2 col-lg-2 col-md-2 hidden-sm hidden-xs"></div>
<div class="col-xl-8 col-lg-8 col-md-8 col-sm-12 col-xs-12">
<div class="entry">
<div class="header">
<table>
<tr>
<td class="title"><h2>{{ entry|title }}</h2></td>
<td class="datetime">01.01.2016 00:00:00</td>
</tr>
</table>
</div>
<div class="content">
{{ entry|content }}
</div>
<div class="footer">
#some
#tag
#right
#here
</div>
</div>
<div class="col-xl-2 col-lg-2 col-md-2 hidden-sm hidden-xs"></div>
</div>
</div>
{% endfor %}
However, I'm getting TemplateSyntaxError on the {{ entry|content }} line, which is strange.
views.py file:
import json, termcolor
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
# Create your views here.
def index(request, page="1"):
page = int(page)
context = {
"title": "Erdin's Blog",
"entries": []
}
entries = Entry.objects.all()
r_entries = entries[::-1]
del entries
interest = [page*10-10, page*10]
context["entries"].extend(r_entries[interest[0]:interest[1]])
print(termcolor.colored(context["entries"][0].content, "green"))
return render(request, "home.elms.html", context)
Further Investigation
I already have a single entry on database. I also checked if it's queried correctly into database with sqliteman. Assuming I named this single entry as entry variable, I called entry.id, entry.title and entry.content and printed out to terminal, that was successful. There's no problem on database.
Environment
python3
Django 1.8.7
A Complete Edit
I currently realized the problem was completely different. I called {% for entry in context.entries %} but I already called context into template, so the engine was looking for a context key inside context dictionary.
The | syntax is for template filters. To get the model values in the template there is a dot notation:
{{ entry.title }}
{{ entry.content }}
Note that the reason why {{ entry|title }} did not throw any errors is that there is a built-in title template filter. But there is no content template filter - this is why you see the error on the line containing {{ entry|content }}.
Since I solved my own problem, I'm writing here for the sake of other users having same problem.
Since I returned a render in views.py as below:
render(request, "home.elms.html", context)
The template should call for dictionary inside the context as:
{% for entry in entries %}
not:
{% for entry in context.entries %}